Implantar servidores MCP remotos
Exponha uma API existente a agentes de IA como ferramentas MCP a partir de uma function na Azion, com WAF e rate limit na frente e um log para cada tool call.
Uma equipe de plataforma ou de produto quer que agentes de IA, os seus ou os dos seus clientes, usem os seus serviços pelo Model Context Protocol (MCP). Os serviços já existem como uma API HTTP, e um agente não consegue chamar essa API como ferramenta até que algo descreva cada operação em termos de MCP. Esta página implanta um servidor MCP como uma function na Azion sobre o transporte streamable HTTP, mapeia cada ferramenta para uma chamada à API existente, coloca na frente dele um firewall com WAF e um rate limit e envia uma linha de log por tool call. O resultado é medido pela latência das tool calls, pela taxa de erro por ferramenta e pelas chamadas que o firewall recusa.
Este caso de uso não cobre a criação dos agentes que chamam os servidores. Para isso, consulte Criar agentes de IA.
Pré-requisitos
- A Azion CLI, instalada e com login feito, e Node.js com npm. A CLI cria o projeto e faz o deploy dele, como mostra Execute um MCP server na Azion.
- Um firewall com WAF ativado nas suas configurações principais, vinculado ao workload que o
azion deploycria. Para ativar o WAF, consulte Defina as configurações principais de um firewall. Para vincular o firewall, consulte Vincule um firewall a um workload. - Um rule set do WAF chamado
mcp-waf, com todas as famílias de ameaças em sensibilidade média. Para criá-lo, consulte Crie um rule set em sensibilidade média. - Um personal token, para as etapas de API. Para criar um, consulte Gerencie personal tokens.
- Um endpoint HTTPS da sua plataforma de logs que aceite requisições
POST, para os logs das tool calls. - Os valores da sua própria API. Esta página mapeia um serviço de pedidos em
https://api.example.com, que responde aGET /v1/orders/{id}eGET /v1/orders?customer_id={id}&limit={n}e esperaAuthorization: Bearer <backend-token>. Ela usamy-mcp-serverpara o projeto e<your-domain>para o domínio que oazion deploymostra. Substitua cada valor pelo seu em todas as etapas.
Produtos necessários
| O servidor MCP precisa de | O que significa | Produto | Documentado em |
|---|---|---|---|
| Um servidor que os agentes alcançam pelo transporte streamable HTTP | Uma function criada com o MCP SDK, que responde a POST /mcp | Functions | Execute um MCP server na Azion |
| Cada ferramenta mapeada para uma operação da API existente | Um handler de ferramenta que traduz os seus argumentos em uma chamada fetch() e a resposta em saída da ferramenta | Functions | Fetch API |
| Payloads de ataque filtrados antes de chegarem ao servidor | Uma regra de firewall em /mcp com o behavior Set WAF em modo de bloqueio | WAF | Aplique um rule set a toda requisição |
| Um agente em loop não consegue sobrecarregar o servidor nem a API atrás dele | O behavior Set Rate Limit na mesma regra, contado por endereço IP do cliente | Firewall | Aplique WAF e um rate limit a um caminho |
| Um registro de cada tool call | Uma linha de log por chamada, enviada da fonte de dados Functions para a sua plataforma de logs | Data Stream | Envie logs para um endpoint HTTP |
Arquitetura de referência
Esta página constrói o MCP gateway over existing APIs: cada ferramenta encaminha para a API que já executa o serviço, então nenhuma lógica de negócio passa para a function.
Leia o diagrama da function até a API existente. Cada tool call passa por essa seta, então a API está no fluxo de requisição de cada chamada e no seu fluxo de falha: uma API lenta ou com falha é uma ferramenta lenta ou com falha. Cada lado da seta fala o seu próprio schema. Um agente vê o nome de uma ferramenta, uma descrição e um schema de entrada tipado. A API vê um método, um caminho e os seus próprios campos. A function traduz entre os dois, e esse mapeamento é a principal decisão de design. O firewall na frente decide quais requisições chegam à function.
Fluxo de dados
- O cliente MCP de um agente envia uma requisição JSON-RPC como um
POSTpara/mcpno domínio do workload. - O firewall aplica o rule set
mcp-wafe o rate limit. Uma requisição que o rule set bloqueia responde400, e uma requisição acima da taxa responde429. - Uma requisição permitida chega à aplicação, cuja regra executa a function do servidor MCP. A function responde
initializeetools/listela mesma, a partir das ferramentas que registra. - Em
tools/call, a function valida os argumentos contra o schema de entrada da ferramenta, monta a requisição à API a partir do método, do caminho e da query e chama a API existente com o token do backend. A chamada é limitada por um timeout. - A function retorna os campos de que o agente precisa como resultado da ferramenta, ou uma mensagem que diz o que falhou quando a API responde com um erro ou não responde a tempo.
- A function grava uma linha de log por tool call, e o Data Stream envia as linhas para a sua plataforma de logs.
Componentes
- Functions: executa a tradução de MCP para API. O servidor é criado com o MCP SDK sobre o transporte streamable HTTP, registra uma ferramenta por operação da API e chama a API com
fetch(). Toda decisão de schema fica aqui: quais operações viram ferramentas, como os argumentos se mapeiam para uma requisição e quais campos da resposta chegam ao agente. - API de backend: a integração que é o serviço existente, aqui o serviço de pedidos em
https://api.example.com. Ela mantém a sua própria lógica, os seus dados e as suas credenciais, e cada tool call chega a ela, então a latência e os erros dela são a latência e os erros da ferramenta. - firewall: o Platform Resource que é o ponto de aplicação. Uma regra em
/mcprecebe cada requisição antes da aplicação, então uma requisição recusada nunca executa a function nem chega à API. - WAF: filtra o tráfego de agentes em busca de payloads de ataque, pelo behavior Set WAF da regra, com o rule set
mcp-waf. O behavior Set Rate Limit da mesma regra limita a velocidade com que um cliente pode chamar, o que limita a carga que um agente preso em um loop coloca sobre a API. - KV Store: guarda sessões, para um servidor que mantém estado entre as requisições de uma conexão de agente. Um servidor criado sem ID de sessão não mantém nenhuma, e cada requisição carrega tudo de que precisa.
- Data Stream: envia os logs das tool calls que a function grava, da fonte de dados Functions, para a sua plataforma de logs. A taxa de erro e a latência por ferramenta são calculadas lá.
- aplicação: o Platform Resource que encaminha as requisições para a function. A regra dela executa a function, e o workload que serve a aplicação também vincula o firewall.
Outros designs para este caso de uso
- Remote MCP server on Functions: para ferramentas cuja lógica pode ser executada na Azion. A function implementa cada ferramenta ela mesma em vez de encaminhá-la a uma API existente e mantém o estado das sessões no KV Store atrás do mesmo firewall, então uma tool call só sai da Azion quando a própria ferramenta chama algo externo.
Configure os mapeamentos de ferramentas
Os mapeamentos de ferramentas são o src/index.ts do servidor: uma ferramenta registrada por operação da API. Comece pelo projeto Hono que Execute um MCP server na Azion cria com azion init --name my-mcp-server, com @modelcontextprotocol/sdk e zod@3 instalados. A rota, o transporte e o tratamento de erros ficam como o guia os escreve. Só getServer() muda.
As decisões de mapeamento, cada uma tomada uma vez aqui:
- Duas ferramentas, nomeadas com verbo e substantivo.
get_ordermapeiaGET /v1/orders/{id}, elist_customer_ordersmapeiaGET /v1/orders?customer_id={id}&limit={n}. Um agente escolhe uma ferramenta pelo nome e pela descrição, então cada descrição diz quando usá-la. - Os argumentos são tipados e limitados.
limité um inteiro de 1 a 20, então um agente não consegue pedir à API uma página sem limite. Cada segmento de caminho e valor de query é codificado antes de entrar na URL. - O resultado traz apenas os campos de que um agente precisa. O handler retorna o ID, o status, o total e a data de criação do pedido e descarta todos os outros campos que a API retorna, então dados internos não chegam a um agente.
- Uma falha é uma mensagem, não uma exceção. Um status de erro ou uma chamada que passa de 8 segundos vira um resultado de ferramenta que diz o que falhou. Oito segundos deixam ao agente tempo para tentar de novo dentro do seu próprio timeout, e o limite de tempo de execução da function é de 5 minutos.
- O token do backend fica fora do código. A function o lê da variável de ambiente
BACKEND_API_TOKEN.
Para armazenar o token do backend, execute:
Uma key que contém token é armazenada como secret por padrão. Substitua getServer() em src/index.ts por este código e adicione a linha declare e os dois helpers acima dela:
Remova o import de ResourceTemplate, que o servidor do guia usa e este não usa. Depois, faça o deploy a partir da pasta do projeto:
A CLI mostra a URL do domínio do projeto, no formato https://xxxxxxxxxx.map.azionedge.net, e o servidor responde em https://<your-domain>/mcp. O primeiro deploy pode levar vários minutos para responder de todas as localizações.
list_customer_orders supõe que a API retorna um array JSON. Mapeie os nomes de campo em pickOrder e o formato da resposta para os que a sua API retorna.
Configure o firewall para o tráfego de agentes
Uma regra de firewall carrega as duas proteções, porque Set WAF é um dos dois behaviors que outro behavior pode seguir. O critério é ${request_uri} starts with /mcp. Toda requisição MCP é um POST cujo payload fica no corpo, e um critério na query string a ignoraria.
O rate limit conta por endereço IP do cliente: uma média de 10 requisições por segundo com um burst de 20. Um agente abre uma conexão com initialize, notifications/initialized e tools/list em sequência rápida e depois envia uma requisição por tool call. O burst admite essa abertura, e a média para um agente preso em um loop antes que ele sobrecarregue a API atrás das ferramentas.
Crie a regra como Aplique WAF e um rate limit a um caminho descreve, com estes valores:
- Nome:
mcp - waf and rate limit. - Critério:
Request Uristarts with/mcp. - Set WAF: o rule set
mcp-wafem modo Blocking. - Set Rate Limit: Req/s, Client IP address, um Average Rate Limit de
10e um Maximum Burst Size de20.
Na API, os dois behaviors vão nesta ordem:
Cada requisição para /mcp é pontuada pelo mcp-waf e contada contra a taxa antes de chegar à function. Uma requisição que o rule set bloqueia responde 400 com a página padrão Bad Request, e uma requisição acima da taxa responde 429 com a página padrão Too Many Requests. Nenhuma das respostas traz um header que indique o firewall ou um tempo para tentar de novo.
Configure o stream de logs das tool calls
A function grava uma linha JSON por tool call, com o nome da ferramenta, o status da API, se ela teve sucesso e o tempo que levou. O Data Stream envia essas linhas da fonte de dados Functions para a sua plataforma de logs, onde a taxa de erro e a latência são calculadas por ferramenta.
Crie o stream como Envie logs para um endpoint HTTP mostra, com estes valores:
- Data Source: Functions. Na API,
functions_console. - Template: Functions Event Collector, cuja variável
$log_messagecarrega cada linha que a function grava. - Opção: Filter Workloads, com o workload que o
azion deploycriou como o único workload escolhido. Um filtro impede que este stream desative os outros streams da conta, o que salvar um stream ativo com amostragem faz. - Connector: Standard HTTP/HTTPS POST, com a URL da sua plataforma de logs e o header que ela exige para aceitar a requisição.
O stream fica ativo de um a dois minutos depois de salvo. A sua plataforma de logs passa a receber uma linha por tool call, cada uma com o $request_id da requisição que a gerou.
Verifique a configuração
-
O servidor responde ao handshake MCP. Envie uma requisição
initialize:ShellO servidor responde
200comcontent-type: text/event-streame um evento cujos dados indicamorders-mcp-server. -
As duas ferramentas são listadas. Envie
tools/listpara a mesma URL com o corpo{"jsonrpc":"2.0","id":2,"method":"tools/list"}. O resultado listaget_orderelist_customer_orders, cada uma com o schema de entrada que o código declara. -
Uma ferramenta chega à API. Chame
get_ordercom o ID de um pedido que existe:ShellO
result.contentdo evento guarda um itemtextcomid,status,totalecreated_atdo pedido, e nenhum outro campo. Um ID que não existe retorna um texto que indica o status que a API respondeu. -
O rate limit recusa um loop. Envie 60 requisições
tools/list, 30 de cada vez, para que cheguem mais rápido que 10 por segundo:ShellA contagem mostra
200e429: a taxa e o burst admitem algumas das requisições, e o firewall recusa as outras. -
Cada tool call é registrada. Depois da chamada a
get_order, a sua plataforma de logs recebe uma linha cuja mensagem guarda"event":"tool_call"e"tool":"get_order".
Uma regra de firewall nova leva alguns minutos para se propagar. Quando uma verificação falhar depois disso, leia as linhas de log da function na fonte de dados Functions Console do Real-Time Events.
Medindo resultados
| Métrica | Onde ler | Como é quando funciona |
|---|---|---|
| Latência das tool calls | O campo ms das linhas tool_call na sua plataforma de logs, por tool | Estável por ferramenta. Um aumento em uma ferramenta aponta para a operação da API dela, não para o servidor |
| Taxa de erro por ferramenta | As linhas tool_call com "ok":false sobre o total de linhas, por tool | Baixa e estável. status 0 conta timeouts, e qualquer outro valor é o status que a API respondeu |
| Chamadas que o firewall recusa | Requisições para /mcp com status 400 ou 429, na fonte de dados HTTP Requests do Real-Time Events | 429 apenas de agentes em loop, e 400 apenas em payloads que o rule set sinaliza |
Boas práticas
- Retorne apenas os campos de que um agente precisa. Um agente passa cada campo de um resultado de ferramenta a um modelo, e o modelo pode repeti-lo a um usuário.
pickOrderé onde essa decisão é tomada, um lugar por ferramenta. - Trate cada ferramenta como segura para ser chamada duas vezes. Um agente repete uma chamada que acredita ter falhado, inclusive uma chamada que expirou depois que a API agiu. Mapeie primeiro as operações de leitura e dê a uma operação de escrita um ID de requisição que a API possa deduplicar antes de expô-la como ferramenta.
- Dimensione o rate limit para agentes atrás de um único endereço. O limite conta por endereço IP do cliente, então vários agentes atrás de um único endereço de rede compartilham uma única cota. Aumente a média quando a contagem de
429subir sem nenhum loop nos logs. - Adicione autenticação antes de compartilhar a URL. O servidor desta página não verifica nenhuma credencial, então qualquer um que conheça a URL pode chamar as suas ferramentas. Decida como os agentes provam quem são e verifique isso na function ou no firewall antes de publicar a URL. Para as verificações de que um servidor precisa antes que outros o usem, consulte Prepare o servidor para agentes.