- Início
- Documentation
- MCP
- Criação de servidores e ferramentas MCP
Criação de servidores e ferramentas MCP
Este documento explica como definições de servidores MCP se tornam ferramentas mcp_* invocáveis no coding-agent, e o que os operadores devem esperar quando as configurações são inválidas, duplicadas, desabilitadas ou protegidas por autenticação.
Arquitetura em visão geral
Seção intitulada “Arquitetura em visão geral”Config sources (.xcsh/.claude/.cursor/.vscode/mcp.json, mcp.json, etc.) -> discovery providers normalize to canonical MCPServer -> capability loader dedupes by server name (higher provider priority wins) -> loadAllMCPConfigs converts to MCPServerConfig + skips enabled:false -> MCPManager connects/listTools (with auth/header/env resolution) -> MCPTool/DeferredMCPTool bridge exposes tools as mcp_<server>_<tool> -> AgentSession.refreshMCPTools replaces live MCP tools immediately1) Modelo de configuração do servidor e validação
Seção intitulada “1) Modelo de configuração do servidor e validação”src/mcp/types.ts define a forma de autoria usada por escritores de configuração MCP e pelo runtime:
stdio(padrão quandotypeestá ausente): requercommand, opcionaisargs,env,cwdhttp: requerurl, opcionaisheaderssse: requerurl, opcionaisheaders(mantido para compatibilidade)- campos compartilhados:
enabled,timeout,auth
validateServerConfig() (src/mcp/config.ts) valida os requisitos básicos de transporte:
- rejeita configurações que definem tanto
commandquantourl - requer
commandpara stdio - requer
urlpara http/sse - rejeita
typedesconhecido
config-writer.ts aplica esta validação para operações de adição/atualização e também valida nomes de servidores:
- não vazio
- máximo de 100 caracteres
- apenas
[a-zA-Z0-9_.-]
Armadilhas de transporte
Seção intitulada “Armadilhas de transporte”typeomitido significa stdio. Se você pretendia HTTP/SSE mas omitiutype,commandse torna obrigatório.sseainda é aceito, mas tratado como transporte HTTP internamente (createHttpTransport).- A validação é estrutural, não de acessibilidade: uma URL sintaticamente válida ainda pode falhar no momento da conexão.
2) Descoberta, normalização e precedência
Seção intitulada “2) Descoberta, normalização e precedência”Descoberta baseada em capacidades
Seção intitulada “Descoberta baseada em capacidades”loadAllMCPConfigs() (src/mcp/config.ts) carrega itens canônicos MCPServer via loadCapability(mcpCapability.id).
A camada de capacidades (src/capability/index.ts) então:
- carrega provedores em ordem de prioridade
- desduplicar por
server.name(primeira ocorrência vence = maior prioridade) - valida os itens desduplicados
Resultado: nomes de servidores duplicados entre fontes não são mesclados. Uma definição vence; duplicatas de menor prioridade são ocultadas.
.mcp.json e arquivos relacionados
Seção intitulada “.mcp.json e arquivos relacionados”O provedor de fallback dedicado em src/discovery/mcp-json.ts lê mcp.json e .mcp.json da raiz do projeto (baixa prioridade).
Na prática, servidores MCP também vêm de provedores de maior prioridade (por exemplo, .xcsh/... nativo e diretórios de configuração específicos de ferramentas). Orientação de autoria:
- Prefira
.xcsh/mcp.json(projeto) ou~/.xcsh/mcp.json(usuário) para controle explícito. - Use
mcp.json/.mcp.jsonna raiz quando precisar de compatibilidade como fallback. - Reutilizar o mesmo nome de servidor em múltiplas fontes causa ocultação por precedência, não mesclagem.
Comportamento de normalização
Seção intitulada “Comportamento de normalização”convertToLegacyConfig() (src/mcp/config.ts) mapeia MCPServer canônico para MCPServerConfig de runtime.
Comportamento principal:
- transporte inferido como
server.transport ?? (command ? "stdio" : url ? "http" : "stdio") - servidores desabilitados (
enabled === false) são descartados antes da conexão - campos opcionais são preservados quando presentes
Expansão de variáveis de ambiente durante a descoberta
Seção intitulada “Expansão de variáveis de ambiente durante a descoberta”mcp-json.ts expande placeholders de variáveis de ambiente em campos de string com expandEnvVarsDeep():
- suporta
${VAR}e${VAR:-default} - valores não resolvidos permanecem como strings literais
${VAR}
mcp-json.ts também realiza verificações de tipo em runtime para JSON de usuário e registra avisos para valores inválidos de enabled/timeout em vez de falhar completamente o arquivo.
3) Autenticação e resolução de valores em runtime
Seção intitulada “3) Autenticação e resolução de valores em runtime”MCPManager.prepareConfig()/#resolveAuthConfig() (src/mcp/manager.ts) é a passagem final pré-conexão.
Injeção de credenciais OAuth
Seção intitulada “Injeção de credenciais OAuth”Se a configuração possui:
auth: { type: "oauth", credentialId: "..." }e a credencial existe no armazenamento de autenticação:
http/sse: injeta headerAuthorization: Bearer <access_token>stdio: injeta variável de ambienteOAUTH_ACCESS_TOKEN
Se a busca de credencial falhar, o manager registra um aviso e continua com autenticação não resolvida.
Resolução de valores de headers/env
Seção intitulada “Resolução de valores de headers/env”Antes de conectar, o manager resolve cada valor de header/env via resolveConfigValue() (src/config/resolve-config-value.ts):
- valor começando com
!=> executa comando shell, usa stdout com trim (em cache) - caso contrário, trata o valor como nome de variável de ambiente primeiro (
process.env[name]), fallback para valor literal - valores de comando/env não resolvidos são omitidos do mapa final de headers/env
Ressalva operacional: isso significa que um comando/chave de env de segredo digitado incorretamente pode silenciosamente remover aquela entrada de header/env, produzindo falhas 401/403 downstream ou falhas na inicialização do servidor.
4) Ponte de ferramentas: MCP -> ferramentas invocáveis pelo agente
Seção intitulada “4) Ponte de ferramentas: MCP -> ferramentas invocáveis pelo agente”src/mcp/tool-bridge.ts converte definições de ferramentas MCP em CustomTools.
Nomenclatura e domínio de colisão
Seção intitulada “Nomenclatura e domínio de colisão”Os nomes de ferramentas são gerados como:
mcp_<sanitized_server_name>_<sanitized_tool_name>Regras:
- converte para minúsculas
- caracteres não
[a-z_]tornam-se_ - underscores repetidos são colapsados
- prefixo redundante
<server>_no nome da ferramenta é removido uma vez
Isso evita muitas colisões, mas não todas. Nomes brutos diferentes ainda podem ser sanitizados para o mesmo identificador (por exemplo my-server e my.server são sanitizados de forma similar), e a inserção no registro é última-escrita-vence.
Mapeamento de esquema
Seção intitulada “Mapeamento de esquema”convertSchema() mantém o JSON Schema do MCP praticamente como está, mas corrige esquemas de objetos sem properties com {} para compatibilidade com provedores.
Mapeamento de execução
Seção intitulada “Mapeamento de execução”MCPTool.execute() / DeferredMCPTool.execute():
- chama MCP
tools/call - achata conteúdo MCP em texto exibível
- retorna detalhes estruturados (
serverName,mcpToolName, metadados do provedor) - mapeia
isErrorreportado pelo servidor para resultado de textoError: ... - mapeia falhas de transporte/runtime lançadas para
MCP error: ... - preserva semântica de cancelamento traduzindo AbortError em
ToolAbortError
5) Ciclo de vida do operador: adicionar/editar/remover e atualizações ao vivo
Seção intitulada “5) Ciclo de vida do operador: adicionar/editar/remover e atualizações ao vivo”O modo interativo expõe /mcp em src/modes/controllers/mcp-command-controller.ts.
Operações suportadas:
add(assistente ou adição rápida)remove/rmenable/disabletestreauth/unauthreload
As escritas de configuração são atômicas (writeMCPConfigFile: arquivo temporário + renomeação).
Após as alterações, o controller chama #reloadMCP():
mcpManager.disconnectAll()mcpManager.discoverAndConnect()session.refreshMCPTools(mcpManager.getTools())
refreshMCPTools() substitui todas as entradas mcp_ do registro e imediatamente reativa o conjunto mais recente de ferramentas MCP, então as alterações entram em vigor sem reiniciar a sessão.
Diferenças de modo
Seção intitulada “Diferenças de modo”- Modo interativo/TUI:
/mcpfornece UX dentro do aplicativo (assistente, fluxo OAuth, texto de status de conexão, revinculação imediata em runtime). - Integração SDK/headless:
discoverAndLoadMCPTools()(src/mcp/loader.ts) retorna ferramentas carregadas + erros por servidor; sem UX do comando/mcp.
6) Superfícies de erro visíveis ao usuário
Seção intitulada “6) Superfícies de erro visíveis ao usuário”Strings de erro comuns que usuários/operadores veem:
- falhas de validação ao adicionar/atualizar:
Invalid server config: ...Server "<name>" already exists in <path>
- problemas de argumentos na adição rápida:
Use either --url or -- <command...>, not both.--token requires --url (HTTP/SSE transport).
- falhas de conexão/teste:
Failed to connect to "<name>": <message>- texto de ajuda sobre timeout sugere aumentar o tempo limite
- texto de ajuda de autenticação para
401/403
- fluxos de auth/OAuth:
Authentication required ... OAuth endpoints could not be discoveredOAuth flow timed out. Please try again.OAuth authentication failed: ...
- uso de servidor desabilitado:
Server "<name>" is disabled. Run /mcp enable <name> first.
JSON de fonte com problemas na descoberta é geralmente tratado como avisos/logs; os caminhos do config-writer lançam erros explícitos.
7) Orientação prática de autoria
Seção intitulada “7) Orientação prática de autoria”Para autoria MCP robusta neste codebase:
- Mantenha nomes de servidores globalmente únicos em todas as fontes de configuração compatíveis com MCP.
- Prefira nomes alfanuméricos/underscore para evitar colisões de nomes sanitizados nos nomes de ferramentas
mcp_*gerados. - Use
typeexplícito para evitar padrões stdio acidentais. - Trate
enabled: falsecomo desligamento definitivo: o servidor é omitido do conjunto de conexão em runtime. - Para configurações OAuth, armazene um
credentialIdválido; caso contrário, a injeção de autenticação é ignorada. - Se usar resolução de segredos baseada em comando (
!cmd), verifique se a saída do comando é estável e não vazia.