wake-graphql-mcp
v0.0.3
Published
MCP server para consultar e inspecionar o GraphQL do Wake Storefront API (FBITS).
Readme
wake-graphql-mcp
Servidor MCP (Model Context Protocol) que expõe ao seu agente de IA um conjunto de ferramentas para consultar e inspecionar o GraphQL do Wake Storefront API (FBITS) durante o desenvolvimento de componentes, integrações e investigações de schema.
Para que serve? Em vez do agente "chutar" nomes de campos do storefront ou abrir um cliente GraphQL externo, ele pode introspectar o schema, descobrir o tipo certo, validar uma operação real e ler os erros — tudo via tool calls do MCP.
Sumário
- O que ele entrega
- Requisitos
- Instalação
- Configuração
- Como conectar no Cursor / Claude Desktop
- Tools expostas
- Tratamento de erros
- Troubleshooting
- Estrutura do código
- Desenvolvimento
O que ele entrega
| Tool | Para que serve |
| --------------------------- | ---------------------------------------------------------------------------------------------------------- |
| wake_graphql_query | Executa uma query/mutation GraphQL real e devolve data, errors, status HTTP e tempo decorrido. |
| wake_graphql_introspect | Roda introspection no endpoint e devolve umresumo do schema (com cache em memória). |
| wake_graphql_type | Mostra os detalhes deum tipo: campos, args, enumValues, possibleTypes. |
| wake_graphql_search | Procura uma substring nos nomes de tipos e campos do schema. |
A introspection é cacheada por endpoint (TTL configurável), então wake_graphql_type e wake_graphql_search ficam baratos depois da primeira chamada.
Requisitos
- Node.js 18+ (precisa de
fetchglobal eAbortController).
Instalação
npm install wake-graphql-mcpAlternativa (sem instalar no projeto): você pode rodar via
npx(ver exemplos na seção de configuração do Cursor/Claude).
Configuração
A configuração é resolvida nesta ordem (mais alta primeiro):
- Argumento da chamada (campos
endpoint/accessTokenno input da tool). - Variáveis de ambiente.
- Arquivo
wake-mcp.config.jsonna raiz docwdem que o servidor é iniciado. - Defaults internos.
Arquivo wake-mcp.config.json
{
"graphqlEndpoint": "https://storefront-api.fbits.net/graphql",
"schemaCacheTtlMs": 60000,
"requestTimeoutMs": 15000,
"accessToken": "SEU_TOKEN",
"accessTokenHeader": "TCS-Access-Token"
}| Campo | Default | Descrição |
| --------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| graphqlEndpoint | https://storefront-api.fbits.net/graphql | Endpoint GraphQL alvo. |
| schemaCacheTtlMs | 60000 | TTL em ms do cache de introspection. |
| requestTimeoutMs | 15000 | Timeout em ms das chamadas HTTP. |
| accessToken | (vazio) | Token enviado no header accessTokenHeader. Sem token, nenhum header de auth é adicionado. |
| accessTokenHeader | TCS-Access-Token | Nome do header em que o token é enviado. |
Variáveis de ambiente
Todas opcionais — quando definidas, sobrescrevem o arquivo:
| Variável | Equivalente |
| ------------------------------------ | --------------------- |
| WAKE_GRAPHQL_ENDPOINT | graphqlEndpoint |
| WAKE_GRAPHQL_SCHEMA_CACHE_TTL_MS | schemaCacheTtlMs |
| WAKE_GRAPHQL_TIMEOUT_MS | requestTimeoutMs |
| WAKE_GRAPHQL_ACCESS_TOKEN | accessToken |
| WAKE_GRAPHQL_ACCESS_TOKEN_HEADER | accessTokenHeader |
Como conectar no Cursor / Claude Desktop
Cursor
Edite ~/.cursor/mcp.json (ou o equivalente por workspace) e adicione:
{
"mcpServers": {
"wake-graphql": {
"command": "npx",
"args": ["-y", "wake-graphql-mcp@latest"],
"env": {
"WAKE_GRAPHQL_ENDPOINT": "https://storefront-api.fbits.net/graphql",
"WAKE_GRAPHQL_ACCESS_TOKEN": "SEU_TOKEN_AQUI"
}
}
}
}Se você preferir fixar uma versão (recomendado em times), troque por
wake-graphql-mcp@<versão>.
Para desenvolvimento local (rodando o arquivo TypeScript do repo, sem build), você pode apontar diretamente para src/index.ts:
{
"mcpServers": {
"wake-graphql": {
"command": "npx",
"args": ["-y", "tsx", "CAMINHO/ABSOLUTO/PARA/SEU/REPO/src/index.ts"],
"env": {
"WAKE_GRAPHQL_ENDPOINT": "https://storefront-api.fbits.net/graphql"
}
}
}
}Claude Desktop
claude_desktop_config.json segue o mesmo formato que o mcpServers acima.
Tools expostas
Todas as tools devolvem um único bloco de texto contendo um JSON identado. Quando algo dá errado (input inválido, tipo não encontrado, exceção), a resposta vem com isError: true e o JSON tem um campo error (e opcionalmente details) — assim o agente consegue diferenciar erro de sucesso.
wake_graphql_query
Executa uma operação GraphQL (query ou mutation) contra o endpoint configurado.
Input:
| Campo | Tipo | Obrigatório | Descrição |
| ----------------- | ---------------- | ------------ | ---------------------------------------------- |
| query | string | sim | Documento GraphQL completo. |
| variables | object | não | Mapa de variáveis. |
| operationName | string | não | Quando o documento tem múltiplas operações. |
| endpoint | string (URL) | não | Override do endpoint para esta chamada. |
| accessToken | string | não | Override do token para esta chamada. |
Exemplo (input):
{
"query": "query Common($url: String!) { menuGroups(url: $url) { menuGroupId } }",
"variables": { "url": "" }
}Saída (texto JSON):
{
"endpoint": "https://storefront-api.fbits.net/graphql",
"status": 200,
"elapsedMs": 142,
"data": { "menuGroups": [{ "menuGroupId": 1 }] },
"errors": null
}errors segue o formato GraphQL padrão (array com message, path, extensions) e é null quando não há erros.
wake_graphql_introspect
Roda introspection no endpoint e devolve um resumo do schema. O resultado é cacheado em memória — chamadas subsequentes dentro do schemaCacheTtlMs voltam com fromCache: true.
Input:
| Campo | Tipo | Obrigatório | Descrição |
| --------------------- | ---------------- | ------------ | --------------------- |
| endpoint | string (URL) | não | Override do endpoint. |
| accessToken | string | não | Override do token. |
| includeDeprecated | boolean | não | Default true. |
Saída (texto JSON):
{
"endpoint": "https://storefront-api.fbits.net/graphql",
"fromCache": false,
"__schema": {
"queryType": { "name": "Query" },
"mutationType": null,
"subscriptionType": null,
"types": [
{
"name": "Query",
"kind": "OBJECT",
"fields": [
{ "name": "product", "type": { "name": "Product", "kind": "OBJECT" } }
]
}
]
}
}Dica: o payload pode ser grande em schemas extensos. Para varreduras pontuais por nome, prefira
wake_graphql_search. Para detalhes de um tipo específico, prefirawake_graphql_type.
wake_graphql_type
Mostra os detalhes completos de um tipo do schema: descrição, fields, args (com tipos formatados em notação GraphQL como [Product!]!), inputFields, enumValues e possibleTypes.
Input:
| Campo | Tipo | Obrigatório | Descrição |
| --------------------- | ---------------- | ------------ | --------------------------------------------- |
| typeName | string | sim | Nomeexato do tipo (case-sensitive). |
| endpoint | string (URL) | não | Override do endpoint. |
| accessToken | string | não | Override do token. |
| includeDeprecated | boolean | não | Default true. |
Exemplo (input):
{ "typeName": "Query" }Saída (texto JSON):
{
"endpoint": "https://storefront-api.fbits.net/graphql",
"type": {
"name": "Query",
"kind": "OBJECT",
"description": "Root query type",
"fields": [
{
"name": "product",
"description": "Busca um produto por id",
"isDeprecated": false,
"deprecationReason": null,
"type": "Product",
"args": [
{ "name": "id", "description": "Id do produto", "defaultValue": null, "type": "ID!" }
]
}
],
"inputFields": null,
"enumValues": null,
"possibleTypes": null
}
}Quando typeName não existe no schema, o retorno vem com isError: true e um details.hint recomendando wake_graphql_search.
wake_graphql_search
Busca substring (case-insensitive) nos nomes de tipos e campos via introspection. É a tool mais barata para se localizar antes de mergulhar em um tipo específico.
Input:
| Campo | Tipo | Obrigatório | Descrição |
| --------------------- | ---------------- | ------------ | ------------------------------------------------------------ |
| text | string | sim | Substring procurada (ex.:product, cart, menu). |
| limit | number | não | Máximo de matches retornados. Default 50, máx 200. |
| endpoint | string (URL) | não | Override do endpoint. |
| accessToken | string | não | Override do token. |
| includeDeprecated | boolean | não | Default true. |
Exemplo (input):
{ "text": "product", "limit": 30 }Saída (texto JSON):
{
"endpoint": "https://storefront-api.fbits.net/graphql",
"needle": "product",
"limit": 30,
"count": 4,
"matches": [
{ "kind": "type", "typeName": "Product", "typeKind": "OBJECT" },
{ "kind": "field", "typeName": "Query", "fieldName": "product", "fieldType": "Product" },
{ "kind": "field", "typeName": "Product", "fieldName": "productName", "fieldType": "String" }
]
}Tratamento de erros
| Cenário | Resposta |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Input não bate com o schema Zod (campo faltando, tipo errado, etc.) | isError: true, error: "Input inválido para a tool ...", details com o output do flatten() do Zod. |
| Tipo solicitado em wake_graphql_type não existe | isError: true, error: "Tipo não encontrado...", details.hint apontando wake_graphql_search. |
| HTTP não-2xx do endpoint GraphQL | isError: true, error: "Falha ao executar ...: Introspection falhou (HTTP 500)...". |
| Resposta GraphQL com errors[] (em query) | data e errors chegam ao cliente normalmente (não é tratado como isError, porque o agente normalmente quer ver os dois). |
| Body não-JSON (HTML de erro de gateway, etc.) | É devolvido como errors[0].message com um trecho do body. |
| Tool desconhecida em tools/call | isError: true, com details.availableTools. |
Troubleshooting
Recebo Introspection retornou errors: ... com mensagem de auth.
A Wake/FBITS exige TCS-Access-Token para esse endpoint. Configure accessToken (no arquivo, na env, ou no input da tool).
Mudei o schema na Wake e o MCP continua devolvendo a versão antiga.
O cache em memória respeita schemaCacheTtlMs. Reduza o TTL (ou reinicie o MCP) para forçar releitura. Cada combinação endpoint + includeDeprecated tem sua própria entrada de cache.
Header customizado para outro gateway.
Mude accessTokenHeader (ex.: Authorization). Se precisar incluir prefixo (Bearer ...), envie já formatado em accessToken.
Timeout em queries pesadas.
Aumente requestTimeoutMs.
O agente não está enxergando as tools.
Confirme que o servidor está rodando como command no mcp.json do seu cliente, e que ele consegue iniciar (por exemplo, rode npx -y wake-graphql-mcp num terminal separado e verifique se há erros em stderr).
O agente vê as tools mas as chamadas falham com "campo obrigatório <x>" mesmo com o input certo.
Isso costuma acontecer quando o cliente MCP está com um cache antigo de descritores apontando para um schema diferente. O servidor já gera um JSON Schema "minimalista" (type, description, properties, required, additionalProperties) compatível com a maioria dos clientes — toda validação fina (mínimos, formatos, limites) fica no Zod do servidor. Se ainda assim houver inconsistência, reinicie o servidor MCP no cliente para forçar a regeneração do cache.
Estrutura do código
src/
index.ts -> bootstrap: cria Server MCP, registra tools, conecta STDIO
config.ts -> loadConfig (arquivo + env + defaults, com precedência)
mcp/
define-tool.ts -> defineTool({...}), runTool, toListedTool (Zod -> JSON Schema)
result.ts -> jsonResult / errorResult (com isError correto)
graphql/
client.ts -> postGraphQL + buildAuthHeaders
introspection.ts -> getIntrospectionSchema (com cache), formatTypeRef, unwrapTypeRef
tools/
common.ts -> schemas Zod compartilhados (endpoint/token override) + resolvers
query.ts -> wake_graphql_query
introspect.ts -> wake_graphql_introspect
type.ts -> wake_graphql_type
search.ts -> wake_graphql_search
index.ts -> registro central (array `tools`)
tests/
helpers/ -> mockFetch, fixtures de schema, makeTestConfig
config.test.ts
graphql/ -> client + introspection (cache, formatação)
mcp/ -> result + define-tool
tools/ -> os 4 handlers ponta a pontaPrincípios:
- Cada tool é definida em um único arquivo (
name,title,description,inputSchemaZod ehandler). O JSON Schema da spec MCP é gerado a partir do Zod — sem duplicação. - Para adicionar uma tool nova, basta criar o módulo em
src/tools/, importar emsrc/tools/index.tse incluir no arraytools. runToolcuida dosafeParsee da conversão de exceções emerrorResult— handlers ficam enxutos.
Desenvolvimento (para contribuir no repositório)
npm run dev # inicia o MCP via tsx (sem build)
npm run build # compila TypeScript para dist/
npm run start # roda dist/index.js (precisa de build)
npm run typecheck # tsc --noEmit
npm test # node --test via tsx, executa tests/**/*.test.tsOs testes não fazem nenhuma chamada real — globalThis.fetch é trocado por um stub via tests/helpers/fetch-mock.ts, então rodam offline em milissegundos.
