
HTTP-прокси-мост для тестирования безопасности удалённых MCP-серверов, позволяющий стандартным HTTP-инструментам отправлять JSON-RPC-сообщения и управлять сессиями.
Этот проект реализует HTTP-сервер, который выступает в роли моста между HTTP/1.1-запросами и удалённым MCP-сервером, используя Python-библиотеку mcp (GitHub).
Основная цель этой инициативы — дать возможность использовать HTTP-инструменты безопасности для тестирования удалённых MCP-серверов с использованием удалённых транспортных механизмов (HTTP+SSE или Streamable HTTP).
Было замечено, что при отправке JSON-RPC-V2 сообщений с одинаковым id с использованием параллельных потоков ответы могут объединяться. Имейте это в виду при использовании инструмента в ходе оценки. Пока мы исправляем эту проблему, убедитесь, что вы тестируете с использованием одного потока.
Для начала клонируйте репозиторий и установите необходимые зависимости:
git clone <repository-url>
cd http-mcp-bridge
pip install -r requirements.txt
Чтобы запустить HTTP-сервер, выполните следующую команду:
python3 main.py --remote-url="http://127.0.0.1:8787/mcp"
HTTP-сервер будет прослушивать интерфейс и порт по умолчанию (http://127.0.0.1:8000), а MCP-подключение будет установлено к указанному удалённому URL-адресу. По указанному адресу должен существовать удалённый MCP-сервер, реализующий поддерживаемый транспортный механизм. Ранее HTTP-сервер автоматически определял правильный транспортный механизм — Streamable HTTP или HTTP+SSE, но это создавало проблемы в некоторых производственных средах, поэтому теперь эта функция отключена. По умолчанию использовался транспортный механизм Streamable HTTP. Мы создадим флаг для принудительного использования HTTP+SSE, но пока вы можете просто отредактировать код и включить этот транспортный механизм.
Затем вы можете отправлять HTTP-запросы на сервер, который будет передавать их SSE/Streamable HTTP-клиентам.
Механизм, реализованный в Python SDK, устанавливает канал чтения и канал записи для связи с конечной точкой с использованием соответствующего транспортного механизма. Этот HTTP-MCP мост пересылает HTTP-запросы в канал записи и ожидает ответ (если применимо) в канале чтения. После получения этот ответ пересылается в качестве ответа на HTTP-запрос.
HTTP-запросы поддерживают параметр timeout, который ограничивает максимальное количество секунд ожидания мостом ответа в канале чтения перед возвратом сообщения об ошибке. Если timeout равен нулю, HTTP-MCP мост вообще не ждёт.
Поскольку HTTP-MCP мост поддерживает несколько сессий с MCP-сервером, первым шагом необходимо получить идентификатор сессии, который будет использоваться в последующих запросах.
Request:
GET /mcp/messages HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 0
Response:
HTTP/1.1 400 Bad Request
date: Fri, 02 May 2025 15:40:32 GMT
server: uvicorn
content-length: 87
content-type: application/json
{"detail":"Invalid session id. Try /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c"}
Этот идентификатор сессии отличается от идентификатора сессии, устанавливаемого между MCP-клиентом и сервером, и не зависит от него. Последний обрабатывается библиотекой mcp под капотом.
Существует метод ping, который можно вызвать для проверки того, что MCP-сервис доступен и выбранный транспортный механизм корректен.
Request:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 40
{"method":"ping","jsonrpc":"2.0","id":2}
Response:
[{"jsonrpc":"2.0","id":2,"result":{}}]
Первым шагом в MCP-взаимодействии является рукопожатие при инициализации, в ходе которого обе стороны обмениваются информацией о доступных возможностях.
Request:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 213
{"method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {"sampling": {}, "roots": {"listChanged": true}}, "clientInfo": {"name": "mcp", "version": "0.1.0"}}, "jsonrpc": "2.0", "id": 0}
Response:
[{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"Demo","version":"1.0.0"}}}]
Рукопожатие необходимо завершить с помощью этого сообщения, на которое нет ответа, поэтому в данном случае мы можем использовать timeout=0. Мы получим сообщение об ошибке тайм-аута, но это ожидаемо.
Request:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c?timeout=0 HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Authorization: Bearer [REDACTED]
Content-Length: 54
{"method":"notifications/initialized","jsonrpc":"2.0"}
Response:
{"message":"Timeout waiting for messages"}
После завершения рукопожатия мы можем вызывать доступные методы, такие как tools/list (получение списка инструментов).
Request:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 46
{"method":"tools/list","jsonrpc":"2.0","id":1}
Response:
[{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"add","inputSchema":{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}]}}]
Наконец, мы можем вызывать инструменты или использовать другие возможности.
Request:
POST /mcp/messages/7fc2cce5-3b0b-4d63-9df6-e703c1df091c HTTP/1.1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: python-httpx/0.28.1
Content-Type: application/json
Cache-Control: no-store
Content-Length: 100
{"method":"tools/call","params":{"name":"add","arguments":{"a":1, "b":2 }},"jsonrpc":"2.0","id":2}
Response:
[{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"3"}]}}]
Вклад приветствуется! Пожалуйста, создавайте issue или отправляйте pull request для любых улучшений или исправлений ошибок.
Этот проект лицензирован в соответствии с MIT License. Подробнее см. в файле LICENSE.