
Ponte proxy HTTP para testes de segurança de servidores MCP remotos, permitindo que ferramentas HTTP padrão enviem mensagens JSON-RPC e gerenciem sessões.
Este projeto implementa um servidor HTTP que atua como uma ponte entre requisições HTTP/1.1 e um servidor MCP remoto, utilizando a biblioteca mcp do Python (GitHub).
O principal objetivo desta iniciativa é permitir o uso de ferramentas de segurança HTTP para testar servidores MCP remotos utilizando os mecanismos de transporte remotos (HTTP+SSE ou Streamable HTTP).
Foi observado que, ao enviar mensagens JSON-RPC-V2 com o mesmo id, usando threads concorrentes, pode acontecer de as respostas serem mescladas. Tenha isso em mente ao usar a ferramenta em sua avaliação. Enquanto corrigimos esse problema, certifique-se de estar testando usando uma única thread.
Para começar, clone o repositório e instale as dependências necessárias:
git clone <repository-url>
cd http-mcp-bridge
pip install -r requirements.txt
Para executar o servidor HTTP, execute o seguinte comando:
python3 main.py --remote-url="http://127.0.0.1:8787/mcp"
O servidor HTTP ficará ouvindo na interface e porta padrão (http://127.0.0.1:8000), e a conexão MCP será estabelecida com a URL remota fornecida. Um servidor MCP remoto que implemente um mecanismo de transporte suportado deve existir na URL fornecida. O servidor HTTP costumava detectar automaticamente o mecanismo de transporte correto, Streamable HTTP ou HTTP+SSE, mas isso estava causando problemas em alguns ambientes de produção, então agora está desabilitado. Ele usava o mecanismo de transporte Streamable HTTP por padrão. Criaremos uma flag para forçar o uso de HTTP+SSE, mas, enquanto isso, você pode simplesmente editar o código e habilitar esse mecanismo de transporte.
Você pode então enviar requisições HTTP para o servidor, que as encaminhará para os clientes SSE/Streamable HTTP.
O mecanismo implementado no SDK do Python estabelece um canal de leitura e um canal de escrita para se comunicar com o endpoint usando o mecanismo de transporte correspondente. Esta Ponte HTTP para MCP encaminha as requisições HTTP para o canal de escrita e aguarda a resposta (se aplicável) no canal de leitura. Uma vez recebida, essa resposta é encaminhada como resposta da requisição HTTP.
As requisições HTTP aceitam o parâmetro timeout, que limita a quantidade máxima de segundos que a ponte aguarda pela resposta no canal de leitura antes de retornar uma mensagem de erro. Se o timeout for zero, a Ponte HTTP para MCP não aguarda de forma alguma.
Como a Ponte HTTP para MCP suporta várias sessões com o servidor MCP, o primeiro passo é obter um id de sessão, que será usado em requisições posteriores.
Requisição:
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
Resposta:
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"}
Este id de sessão é diferente e independente do id de sessão estabelecido entre o cliente MCP e o servidor. Este último é tratado pela biblioteca mcp internamente.
Existe um método ping que pode ser invocado para verificar se o serviço MCP está disponível e se o mecanismo de transporte escolhido está correto.
Requisição:
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}
Resposta:
[{"jsonrpc":"2.0","id":2,"result":{}}]
O primeiro passo em uma comunicação MCP é o handshake de inicialização, onde ambos os pares compartilham suas capacidades disponíveis.
Requisição:
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}
Resposta:
[{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"Demo","version":"1.0.0"}}}]
O handshake precisa ser finalizado usando esta mensagem, que não possui resposta, então podemos usar timeout=0 neste momento. Receberemos uma mensagem de erro de timeout, mas isso é esperado.
Requisição:
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"}
Resposta:
{"message":"Timeout waiting for messages"}
Depois que o handshake for concluído, podemos invocar os métodos disponíveis, como tools/list (listagem de ferramentas).
Requisição:
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}
Resposta:
[{"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#"}}]}}]
Por fim, podemos invocar ferramentas ou fazer uso de outras capacidades.
Requisição:
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}
Resposta:
[{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"3"}]}}]
Contribuições são bem-vindas! Abra uma issue ou envie um pull request para quaisquer melhorias ou correções de bugs.
Este projeto está licenciado sob a Licença MIT. Consulte o arquivo LICENSE para mais detalhes.