CodeGym /Cursos /ChatGPT Apps /Inspeção e depuração MCP: MCP Jam, Inspector, logs

Inspeção e depuração MCP: MCP Jam, Inspector, logs

ChatGPT Apps
Nível 6 , Lição 4
Disponível

1. Por que um MCP‑inspetor é necessário

Imagine que você está depurando o front-end, mas proibiram você de abrir o DevTools. A vida sem um MCP‑inspetor é mais ou menos assim. O protocolo MCP acontece “por baixo do capô” do ChatGPT e do Apps SDK; se você olha apenas para a resposta no chat e pensa: “Por que ele não vê a minha ferramenta?”, você está, na prática, atirando no escuro.

Inspetores como o MCP Inspector (oficial) ou o MCP Jam são clientes MCP para desenvolvedores. Eles sabem:

  • se conectar ao seu servidor MCP exatamente como o ChatGPT faz;
  • passar pelo handshake / capabilities;
  • solicitar a lista de tools/resources/prompts;
  • chamar qualquer tool manualmente com argumentos arbitrários;
  • mostrar mensagens JSON brutas (requests / replies / errors).

Na essência, é “um Postman para MCP, mas com cérebro”. Diferente de um cliente REST comum, o inspetor conhece as particularidades do MCP: ele entende tools/list, tools/call, consegue exibir os esquemas dos argumentos e às vezes até suporta fluxo OAuth para servidores protegidos.

Se você não tem um inspetor, a depuração fica assim: você abre o ChatGPT, tenta chamar o App, vê “Error talking to app” ou percebe que a tool nem é chamada e começa a adivinhar: foi o modelo que não quis chamar a ferramenta, seu MCP não subiu ou é um erro de JSON? Com o inspetor, você pode verificar cada camada separadamente: primeiro o servidor MCP cara a cara com o inspetor, depois o par ChatGPT ↔ MCP.

2. Visão geral rápida dos inspetores: MCP Inspector, Jam e companhia

Na prática, você usará com mais frequência dois tipos de inspetores para MCP.

Em primeiro lugar, existe o MCP Inspector oficial do repositório Model Context Protocol. É um aplicativo web (geralmente um SPA em React) que roda localmente ou via npx/Docker e consegue se conectar ao seu servidor MCP por HTTP/SSE.

Em segundo lugar, há inspetores do tipo MCP Jam, que muitas vezes acrescentam conveniências relacionadas ao OAuth. Eles podem ler .well-known/oauth-protected-resource, extrair de lá authorization_endpoint e token_endpoint, realizar o fluxo PKCE e então acessar o MCP já em estado autenticado.

O MCP Jam foi criado pelos desenvolvedores com base no MCP Inspector. Se o MCP Inspector implementa o conjunto mínimo de ferramentas de depuração, o MCP Jam implementa tudo o que um desenvolvedor precisa no dia a dia com MCP. Pessoalmente, recomendo usar direto o MCP Jam, para não ter que reaprender depois.

Do ponto de vista do nosso curso, a diferença é:

  • o Inspector básico é necessário sempre, até para um servidor MCP mais simples e não protegido;
  • o MCP Jam (ou semelhante) se torna útil quando você chegar aos módulos de autenticação e autorização.

Mas a ideia geral é a mesma: é um cliente MCP comum, só que capaz de exibir de forma clara o que o ChatGPT faz “em silêncio”.

3. Cenário típico de uso com um MCP‑inspetor

Vamos percorrer um cenário típico: você escreveu uma nova tool no seu servidor MCP e quer garantir que ela realmente funciona.

Na aula anterior, você já colocou no ar um servidor MCP mínimo. Agora vamos adicionar uma abordagem sistemática de verificação: executar o ciclo completo “servidor → inspetor → lógica JSON” passo a passo.

Etapa 1 — iniciar o servidor MCP

Você já fez isso na aula anterior: suponha que você tenha um script npm run mcp-dev:

# exemplo de execução do servidor MCP
npm run mcp-dev
# por baixo dos panos, algo como: ts-node src/mcp-server.ts

É importante que o servidor escute o transporte escolhido: no curso, geralmente é o endpoint HTTP /mcp em alguma porta, por exemplo http://localhost:4001/mcp.

Etapa 2 — iniciar o MCP Jam

Segundo terminal:

# uma das formas de iniciar o MCP Jam
npx @mcpjam/inspector@latest
# se necessário, adicione --port 4002 etc.

Depois disso, o inspetor abre no navegador, geralmente em http://localhost:6274 ou em porta semelhante.

Na tela inicial do MCP Jam, será solicitado o URL do servidor MCP. Você digita:

http://localhost:4001/mcp

ou seu URL tunelado, caso você já esteja usando algo como ngrok.

Etapa 3 — handshake / capabilities

Assim que o MCP Jam se conecta, ele automaticamente faz o mesmo que o ChatGPT:

  1. Envia uma requisição de inicialização (initialize) com dados do cliente.
  2. Recebe a resposta com a versão do protocolo e as capabilities do seu servidor.
  3. Com base nas capabilities, entende se o servidor suporta tools, resources, prompts e outros recursos.

No UI, isso geralmente aparece como algo assim:

Connected
Protocol: mcp/2025-06-18
Capabilities:
- tools: list, call
- resources: list, read
- prompts: list, get

Se já nessa etapa o inspetor não conseguir se conectar (connection refused, CORS, 500, etc.), você vê o erro de cara e entende: o problema certamente não está no modelo nem no ChatGPT, mas sim na sua parte de servidor ou na rede.

Etapa 4 — discovery: ver tools/resources/prompts

Após um handshake bem-sucedido, o inspetor normalmente chama métodos como tools/list, resources/list, prompts/list para preencher a barra lateral. Você verá:

  • uma lista de ferramentas com descrições e o JSON Schema dos argumentos de entrada;
  • uma lista de recursos, agrupados por coleções/caminhos;
  • uma lista de prompts com descrições curtas.

Se você acabou de adicionar uma nova tool, mas ela não aparece na lista, significa que foi registrada incorretamente no servidor ou o servidor não subiu com o código atualizado. É muito mais fácil notar isso aqui do que adivinhar por que o ChatGPT “não quer” chamar sua ferramenta.

4. Chamada manual de tools via MCP Jam

A função mais útil do MCP Jam é a chamada manual de ferramentas. É sua interface para tools/call.

Escolher a ferramenta e preencher os argumentos

Suponha que, no módulo anterior, você escreveu a tool suggest_gifts:

// em algum lugar em src/mcp/tools/suggestGifts.ts
export const suggestGiftsTool = {
  name: "suggest_gifts",
  description: "Seleciona ideias de presente por idade, orçamento e interesses",
  inputSchema: {
    type: "object",
    properties: {
      age: { type: "number" },
      budget: { type: "number" },
      interests: {
        type: "array",
        items: { type: "string" }
      }
    },
    required: ["age", "budget"]
  },
  // handler definido separadamente
};

No MCP Jam, você clica em suggest_gifts. À direita, abre-se um formulário gerado a partir de inputSchema. Ali você preenche:

{
  "age": 30,
  "budget": 100,
  "interests": ["jogos", "livros"]
}

e clica em “Call” ou botão equivalente.

O inspetor envia a requisição MCP tools/call, e você vê imediatamente:

  • os dados JSON brutos da requisição (o que exatamente está indo para o servidor);
  • os dados JSON brutos da resposta (result ou error);
  • possivelmente, um preview amigável do resultado.

Lendo logs JSON no inspetor

Normalmente o inspetor mostra algo como:

// Request
{
  "id": "1",
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "suggest_gifts",
    "arguments": {
      "age": 30,
      "budget": 100,
      "interests": ["jogos", "livros"]
    }
  }
}
// Reply
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "1) Jogo de tabuleiro ... 2) Vale-presente para livraria ..."
      }
    ]
  }
}

Se seu handler lançar uma exceção, você verá error no estilo JSON‑RPC:

{
  "id": "1",
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal error",
    "data": "TypeError: Cannot read properties of undefined ..."
  }
}

Muito importante: é aqui que você vê o nível do protocolo. Se a resposta não está no formato que o Apps SDK/ChatGPT espera, você percebe antes de começar a culpar “bugs do GPT”.

5. Depuração de recursos e prompts

Ferramentas não são tudo o que o MCP faz. Você já sabe que existem também resources e prompts.

No inspetor você pode:

  • abrir a lista de recursos (resources/list) e ver seus metadados;
  • ler um recurso específico (resources/read) e garantir que os dados retornados estão corretos;
  • executar busca por recursos (se você implementou essa possibilidade);
  • ver prompts pré-definidos e seus textos.

Por exemplo, se você tem o recurso gift_catalog:

// pseudocódigo de registro do recurso
registerResource({
  uri: "resource://giftgenius/catalog",
  name: "Catálogo de presentes",
  mimeType: "application/json",
  handler: async () => {
    return JSON.stringify(giftCatalogData);
  }
});

No inspetor, você verá esse recurso, clicará nele e poderá ver o JSON imediatamente. Se acontecer de o JSON ser inválido ou o tipo MIME estar estranho, você pega isso antes de o ChatGPT tropeçar ao tentar ler ou incorporar em um widget.

6. Logs do servidor MCP: o quê, onde e como registrar

O MCP Jam é ótimo, mas não é suficiente: você precisa dos logs do próprio servidor MCP. Sem eles, qualquer produção vira uma loteria.

O que registrar

Mínimo útil:

  • cada mensagem MCP de entrada (request/notification) com:
    • timestamp;
    • método (tools/call, tools/list etc.);
    • nome da ferramenta (se houver);
    • argumentos truncados (sem dados sensíveis);
  • cada resposta de saída:
    • status (sucesso / erro);
    • tempo de execução;
    • uma versão reduzida do resultado ou ao menos o tipo;
  • erros técnicos:
    • parsing de JSON;
    • exceções inesperadas nos handlers.

Ao mesmo tempo, é muito importante não registrar PII e segredos por completo: tokens, senhas, textos integrais de requisições confidenciais. As recomendações de logging em produção geralmente falam explicitamente em registrar dados com PII truncada.

Onde registrar: stdout / stderr

O MCP tem um requisito importante: as mensagens JSON devem ir pelo “canal correto”, e todos os logs de depuração — por outro. Por exemplo, se você usa transporte sobre stdout/stderr, então:

  • as mensagens JSON‑RPC devem ir para stdout;
  • todos os console.log, console.error etc. devem ir para stderr.

Se você misturar JSON e logs de texto no mesmo fluxo, o cliente (MCP Jam ou ChatGPT) simplesmente não conseguirá fazer o parsing das mensagens, porque no meio do JSON vai aparecer de repente uma linha como Server started at http://localhost:4001. Esse é um dos erros mais comuns em servidores MCP.

No cenário HTTP, o problema é um pouco mais simples, mas o princípio é o mesmo: a resposta HTTP deve conter JSON puro, e todos os logs — no console/arquivo, não no corpo da resposta.

Logger simples para um servidor MCP em TypeScript

Vamos adicionar um pequeno logger ao nosso servidor MCP hipotético:

// src/logger.ts
export function logRequest(method: string, details: unknown) {
  console.error(
    JSON.stringify({
      level: "info",
      type: "request",
      method,
      details,
      ts: new Date().toISOString(),
    })
  );
}

export function logError(method: string, error: unknown) {
  console.error(
    JSON.stringify({
      level: "error",
      type: "error",
      method,
      error: String(error),
      ts: new Date().toISOString(),
    })
  );
}

E no handler de tools:

// src/mcp-server.ts (trecho)
server.setRequestHandler("tools/call", async (req) => {
  logRequest("tools/call", {
    name: req.params?.name,
    // aqui é melhor não colocar todo o payload, só os campos seguros
  });

  try {
    const result = await handleToolCall(req);
    return result;
  } catch (e) {
    logError("tools/call", e);
    throw e;
  }
});

Assim você verá no console logs JSON estruturados, que depois são fáceis de correlacionar entre si pelo ts ou por um requestId adicional.

7. Combinação: MCP Jam + logs

A estratégia correta de depuração MCP quase sempre é:

  1. Você reproduz o problema no inspetor: vê que tools/list retorna lista vazia, tools/call falha, a resposta JSON é estranha etc.
  2. Ao mesmo tempo, você olha os logs do servidor MCP: o que ele imprime na inicialização, que erros exibe para cada mensagem, se há stack trace.
  3. Correlaciona id, method, ts nos logs com o que o inspetor vê.

Por exemplo, você vê no inspetor:

{
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}

E em paralelo nos logs:

{
  "level": "error",
  "type": "error",
  "method": "tools/call",
  "error": "TypeError: Cannot read properties of undefined (reading 'age')",
  "ts": "2025-11-21T10:15:12.345Z"
}

Pronto, diagnóstico claro: em algum ponto do handler você espera age, mas o schema/argumentos são outros.

8. Mini checklist “o servidor MCP está pronto para integrar com o App?”

Antes de conectar o servidor MCP a um ChatGPT App real, vale passar por um pequeno checklist usando o inspetor.

Primeiro, handshake e capabilities devem ocorrer sem erros. O MCP Jam deve mostrar que o servidor suporta as entidades de que você precisa: pelo menos tools e, se usados, resources / prompts.

Segundo, a lista de tools/resources/prompts no inspetor deve coincidir com o conjunto de ferramentas, recursos e prompts que você considera implementados. Typos em name, registros esquecidos etc. aparecem aqui na hora.

Terceiro, chamadas de ferramentas com argumentos válidos devem retornar de forma estável um result correto. Idealmente, teste alguns casos típicos (requisições que você realmente espera em produção).

Quarto, chamadas com argumentos inválidos devem retornar error claros no estilo JSON‑RPC, e não cair com 500. Por exemplo, se falta um parâmetro obrigatório, é bom retornar um erro estruturado, que o ChatGPT possa transformar em uma mensagem compreensível para o usuário.

Quinto, os logs do servidor não devem soterrar o console com gigabytes de stack trace a cada mínimo problema. Os erros devem ser estruturados e os dados sensíveis — cuidadosamente filtrados.

Se tudo isso estiver ok no inspetor, você pode conectar o servidor MCP ao Apps SDK com muito mais tranquilidade e brincar com widgets no Dev Mode.

9. Bugs comuns do servidor MCP e como capturá-los via inspetor

Agora vamos ao que há de mais interessante — o que quebra com mais frequência e como enxergar isso.

Configuração e conexão

Às vezes parece que “o servidor não funciona”, mas o problema é que ele nem está escutando a porta ou o endpoint corretos. O inspetor, nesse caso, informa claramente connection refused ou simplesmente não consegue se conectar. Causas frequentes: URL incorreta (por exemplo, /mcp em vez de /api/mcp), porta ocupada por outro processo, túnel inativo ou CORS bloqueando as requisições.

JSON inválido / mistura de logs e protocolo

Uma das situações mais dolorosas é quando você imprime console.log("Server started") em stdout, e por cima disso deveriam trafegar mensagens JSON‑RPC. O cliente espera JSON puro, mas recebe texto + JSON, tenta fazer parsing e cai com erro de formato.

A solução é simples: separar estritamente o que vai no fluxo do protocolo (stdout ou corpo da resposta HTTP) do que vai para os logs (stderr ou arquivo de log separado).

Incompatibilidade entre schema e implementação da ferramenta

Outro erro popular: no inputSchema você declarou uma coisa, mas no código espera outra. Por exemplo, o schema diz: age — número, interests — array de strings opcional, mas o código tenta fazer arguments.interests.toLowerCase(). O modelo (e o inspetor) enviam interests como null ou nem enviam o campo — e tudo quebra.

O inspetor permite ver explicitamente qual JSON realmente vai em tools/call e confrontar isso com o seu código.

Nomes incorretos de tools/resources

Se nas capabilities / tools/list você exporta a tool como suggest_gifts_v2, mas no manifesto do App ou widget você espera suggest_gifts, o “instrumento não encontrado” vai acompanhá-lo até o fim do projeto. No inspetor, pela lista de tools e seus campos name, isso fica visível de imediato, sem tentar adivinhar o que o GPT pensa.

Tools lentas ou travando

Se uma chamada de ferramenta no inspetor leva 30 segundos e depois cai por timeout, não espere que o ChatGPT reaja melhor. O MCP‑inspetor ajuda a entender em que etapa você está lento: chamada de rede, BD, API externa. Nos logs, é bom ter tempo de início e fim do processamento de cada requisição, para ver rapidamente os outliers.

10. Erros comuns ao inspecionar e depurar MCP

Erro nº 1: tentar depurar MCP apenas via ChatGPT.
Muitos desenvolvedores conectam primeiro o MCP ao App, veem que “algo não funciona” e começam a mudar prompts, descrição da ferramenta e até a versão do modelo. Enquanto isso, o servidor MCP nem subiu ou o tools/list está vazio. Sempre comece pelo inspetor: se ali está ruim, o modelo não é o culpado.

Erro nº 2: misturar JSON‑RPC e logs no mesmo fluxo.
Quando o cliente MCP espera JSON puro e você imprime em stdout linhas de depuração, o resultado é previsível — o parsing quebra, o Inspector mostra erros estranhos. Logs devem ir separados (stderr, arquivos, sistemas externos de logging), enquanto as mensagens do protocolo — estritamente no seu canal.

Erro nº 3: não olhar para capabilities e lista de tools.
Muitas vezes a ferramenta “some” simplesmente porque você esqueceu de registrá-la ou habilitar a capability correspondente. Se você não olhar para capabilities e tools/list no inspetor, vai passar tempo demais achando que a culpa é do modelo, e não do seu código de registro.

Erro nº 4: ignorar erros de schema e incompatibilidade de JSON.
Quando o inputSchema e o JSON efetivo divergem, o modelo e o inspetor começam, naturalmente, a se comportar de forma estranha. Se você não olha as mensagens JSON brutas no inspetor e não valida o schema, esses erros aparecerão nos momentos mais inesperados.

Erro nº 5: registrar tudo, incluindo PII e tokens.
No ímpeto da depuração, é fácil começar a imprimir nos logs o corpo completo da requisição, incluindo dados pessoais ou segredos. Em produção, isso vira uma bomba-relógio: vazamentos, problemas de compliance etc. Registre apenas o necessário para diagnóstico, com dados truncados/anonimizados.

Erro nº 6: não reproduzir o problema com casos mínimos.
Às vezes o bug aparece em um diálogo complexo via ChatGPT, e o desenvolvedor tenta depurar exatamente assim. É muito mais eficaz reproduzir o mesmo cenário no inspetor com uma ou duas requisições MCP, eliminando a influência de prompts, histórico de diálogo e o “humor” do modelo.

1
Pesquisa/teste
Protocolo MCP, nível 6, lição 4
Indisponível
Protocolo MCP
MCP: protocolo, servidor e inspeção
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION