MCP — Model Context Protocol
Conecte agentes de IA (Claude, ChatGPT, copilotos internos) à sua operação Fhinck via o servidor MCP em integrations.fhinck.com/mcp.
key no body), o MCP usa JWT RS256 no header Authorization, com scopes por ferramenta e chaves rotacionáveis via JWKS. Os dois mundos coexistem — REST continua funcionando como antes.O que é o MCP
O Model Context Protocol é um padrão aberto (mantido pela Anthropic e comunidade) que define como agentes de IA descobrem e invocam ferramentas em sistemas externos. Em vez de programar cada integração à mão, um modelo (Claude, GPT, etc.) lê o catálogo de tools que seu servidor MCP publica e decide sozinho qual chamar para cumprir o pedido do usuário.
O servidor MCP da Fhinck expõe ferramentas de leitura e escrita sobre Master Data, eventos de ponto, classificação de aplicativos e diagnósticos operacionais. Cada chamada é autenticada, escopada por tenant e auditada em BigQuery.
Casos de uso
- Copiloto interno: agente que responde "quantos colaboradores ativos a empresa tem em São Paulo?" sem precisar de dashboard.
- Assistente de RH: chatbot que cria solicitação de extensão de jornada e busca o gestor responsável conversando em linguagem natural.
- Diagnóstico autônomo: agente de suporte que detecta colaborador sem dados há 24h, identifica a causa (transmissão, login, classificação) e abre ticket.
- Orquestração: pipelines N8N que substituem chamadas REST cruas por
tools/call, ganhando descoberta dinâmica e logs estruturados.
Endpoint
O servidor segue a especificação MCP 2025-03-26 (Streamable HTTP) com um endpoint único POST /mcp usando JSON-RPC 2.0. Subpaths utilitários complementam o endpoint canônico:
| Recurso | URL | Método |
|---|---|---|
| Endpoint canônico JSON-RPC | https://integrations.fhinck.com/mcp |
POST |
| SSE stream do servidor (notificações) | https://integrations.fhinck.com/mcp |
GET (Accept: text/event-stream) |
| Listar ferramentas (atalho REST) | https://integrations.fhinck.com/mcp/tools |
GET |
| Invocar ferramenta (atalho REST) | https://integrations.fhinck.com/mcp/tools/<nome> |
POST |
| Health check | https://integrations.fhinck.com/mcp/health |
GET |
| Readiness | https://integrations.fhinck.com/mcp/ready |
GET |
| JWKS público (chaves de verificação) | https://integrations.fhinck.com/.well-known/jwks.json |
GET |
POST /mcp. Os atalhos REST (/mcp/tools/<nome>) existem para integrações server-side simples (cURL, scripts, N8N HTTP Request) que preferem não montar JSON-RPC à mão — são equivalentes funcionais, com a mesma autenticação e os mesmos scopes.Autenticação — JWT RS256
Toda chamada autenticada ao MCP envia um JWT (JSON Web Token) assinado em RS256 no header Authorization:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjQyYTFi...
O servidor valida quatro coisas em cada token:
- Assinatura RS256 — verificada contra a chave pública publicada em
/.well-known/jwks.json. Você não precisa armazenar segredo nenhum para validar tokens; quem assina é o emissor Fhinck. - Audience — o claim
audprecisa ser exatamentefhinck-mcp. Tokens emitidos para a API REST tradicional (aud=gotadelimao) são automaticamente rejeitados. - Issuer — o claim
issprecisa estar na allowlist:fhinck-mcp-issuer(tokens de serviço via OAuth2 client_credentials) oufhinck-api-exchange(tokens trocados a partir de um ID token Firebase, usado pelo chatbot do dashboard). - Scopes — o claim
scopes(ouscope) precisa conter o escopo exigido pela ferramenta chamada. Sem o escopo, a resposta é HTTP 403 cominsufficient_scope.
key simples? O MCP foi desenhado para callers de IA que podem ter escopos diferentes (um chatbot do dashboard só lê do tenant do usuário logado; um worker N8N precisa cruzar tenants). JWTs permitem escopo granular, expiração curta (60 min), rotação de chave sem redeploy do cliente, e separação clara entre identidade humana (Firebase ID token) e identidade de serviço (OAuth2 client_credentials). É um modelo mais seguro do que um segredo único compartilhado.Como obter um token
Dois fluxos, dependendo de quem está chamando:
Fluxo de serviço — OAuth2 client_credentials
Para automações server-side (workflows N8N, agentes autônomos, ETLs, copilotos hospedados). Use as credenciais client_id + client_secret entregues pelo time Fhinck no onboarding do MCP.
curl -X POST https://us-central1-fhinck-api.cloudfunctions.net/oauthToken \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "SEU_CLIENT_ID",
"client_secret": "SEU_CLIENT_SECRET",
"scope": "read:masterdata:SUA_EMPRESA write:masterdata:SUA_EMPRESA"
}'
Resposta:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:masterdata:SUA_EMPRESA write:masterdata:SUA_EMPRESA"
}
Fluxo de chatbot — troca de Firebase ID token
Para copilotos rodando no contexto de um usuário autenticado (ex.: chat do dashboard). O frontend pega o Firebase ID token do usuário logado e troca por um token MCP com escopos derivados do tenant do usuário.
curl -X POST https://us-central1-fhinck-api.cloudfunctions.net/exchangeFirebaseToken \
-H "Content-Type: application/json" \
-d '{
"firebase_id_token": "FIREBASE_ID_TOKEN_DO_USUARIO_LOGADO"
}'
Modos de operação — service vs chatbot
O servidor resolve o mode de cada chamada para aplicar políticas diferentes:
| Modo | Quem usa | Característica |
|---|---|---|
service |
Workflows, agentes autônomos, ETLs | Pode usar scopes cross-tenant (read:tickets:*). Token via oauthToken. |
chatbot |
Copilotos no contexto de um usuário logado | Scopes restritos ao tenant do usuário. Token via exchangeFirebaseToken. Algumas ferramentas analíticas são exclusivas deste modo. |
Listar ferramentas disponíveis
O endpoint GET /mcp/tools retorna o catálogo de ferramentas que o servidor expõe. Não requer autenticação — é descoberta pública.
curl https://integrations.fhinck.com/mcp/tools
Resposta resumida (a lista real tem ~20 ferramentas):
{
"tools": [
{
"name": "searchEmployee",
"description": "Busca colaboradores por nome, login ou e-mail.",
"inputSchema": {
"type": "object",
"properties": {
"dataset": { "type": "string" },
"query": { "type": "string" },
"limit": { "type": "integer", "default": 10 }
},
"required": ["dataset", "query"]
}
},
{
"name": "whoIsManagerOf",
"description": "Retorna o gestor direto de um colaborador.",
"inputSchema": { "type": "object", "properties": { /* ... */ } }
}
/* ... demais ferramentas ... */
]
}
Endpoint canônico JSON-RPC (recomendado)
O endpoint canônico POST https://integrations.fhinck.com/mcp implementa a especificação MCP 2025-03-26 Streamable HTTP. Todo o protocolo passa por um único URL usando JSON-RPC 2.0. É o que clientes MCP padrão (Anthropic SDK, Claude Desktop, MCP Inspector) esperam.
Handshake — initialize
curl -X POST https://integrations.fhinck.com/mcp \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "meu-app", "version": "0.1.0" }
}
}'
Resposta:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-03-26",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": { "name": "fhinck-mcp", "version": "1.0.0" }
}
}
Listar ferramentas — tools/list
curl -X POST https://integrations.fhinck.com/mcp \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'
Invocar ferramenta — tools/call
curl -X POST https://integrations.fhinck.com/mcp \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "searchEmployee",
"arguments": {
"dataset": "SUA_EMPRESA",
"query": "joao silva",
"limit": 5
}
}
}'
Resposta (segue spec MCP — content + isError):
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"success\":true,\"data\":{\"matches\":[...]},\"humanSummary\":\"...\"}"
}
],
"isError": false,
"_meta": {
"humanSummary": "2 colaboradores encontrados.",
"durationMs": 142
}
}
}
Erros JSON-RPC
Erros seguem os códigos canônicos JSON-RPC 2.0:
| Código | Significado | Quando ocorre |
|---|---|---|
-32700 | Parse error | Body não é JSON válido |
-32600 | Invalid Request | Envelope sem jsonrpc:"2.0" ou method |
-32601 | Method not found | Método desconhecido (ex.: tools/foo) |
-32602 | Invalid params | tools/call sem params.name |
-32603 | Internal error | Erro inesperado no servidor |
-32000 | Tool dispatch failed | Erro durante execução da ferramenta |
Batch JSON-RPC
O endpoint aceita um array de requests JSON-RPC no body — útil pra pipeline N8N que precisa listar e chamar em uma única roundtrip. A resposta é um array na mesma ordem.
Streaming (SSE)
Para receber notificações de progresso de uma ferramenta longa, mande o header Accept: text/event-stream. O servidor responde com SSE — o último evento (event: result) contém o envelope JSON-RPC final.
Chamar uma ferramenta (atalhos REST)
Equivalente ao tools/call JSON-RPC, mas em rota REST direta. Útil para cURL e scripts simples.
curl -X POST https://integrations.fhinck.com/mcp/tools/searchEmployee \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dataset": "SUA_EMPRESA",
"query": "joao silva",
"limit": 5
}'
Shape da resposta
Toda ferramenta retorna o mesmo envelope, padronizado pela especificação MCP:
{
"success": true,
"data": {
"matches": [
{ "employee": "Joao Silva", "login": "jsilva", "department": "TI" },
{ "employee": "Joana Silva", "login": "joanas", "department": "RH" }
]
},
"humanSummary": "2 colaboradores encontrados.",
"warnings": [],
"meta": { "durationMs": 142, "apiCalls": 1 }
}
Em caso de erro:
{
"success": false,
"requiresHumanEscalation": false,
"escalationReason": "insufficient_scope",
"humanSummary": "Token sem permissao para read:masterdata:SUA_EMPRESA.",
"warnings": ["insufficient_scope: required one of read:masterdata:SUA_EMPRESA"],
"meta": { "durationMs": 8, "apiCalls": 0 }
}
Scopes por ferramenta
Cada ferramenta declara o escopo mínimo exigido. Em modo chatbot, o escopo é sempre tenant-scoped (ex.: read:masterdata:ACME). Em modo service, é possível usar wildcard (read:tickets:*) para callers cross-tenant.
| Família | Scope | Exemplo de ferramentas |
|---|---|---|
| Master Data — leitura | read:masterdata:<empresa> |
searchEmployee, whoIsManagerOf, getCompanyOverview, masterDataQuery |
| Master Data — escrita | write:masterdata:<empresa> |
masterDataMutate, categorizeURL, screenBlockToggle |
| Logs / transmissão | read:logs:<empresa> |
data-searchLogs, diagnose-transmission |
| Tickets de suporte | read:tickets:<empresa> ou read:tickets:* (service) |
lookupTicketContext, lookupExecutionStatus |
| Dashboard / analytics | read:dashboard:<empresa> / read:analytics:<empresa> |
data-dashboardChartQuery, analyticsQuery (chatbot only) |
| Administrativo | admin:* |
Bypass — concede todas as permissões. Reservado para automações internas Fhinck. |
Erros comuns
| Cenário | HTTP | Sintoma no envelope |
|---|---|---|
| Token ausente ou inválido | 401 | tokenError: "JsonWebTokenError: invalid signature" |
| Token expirado (60 min) | 401 | tokenError: "TokenExpiredError: jwt expired" |
| Audience errada | 401 | tokenError: "JsonWebTokenError: jwt audience invalid" |
| Escopo insuficiente | 400 | escalationReason: "insufficient_scope" |
| Ferramenta inexistente | 400 | escalationReason: "unknown_tool" |
| Tenant não autorizado para o token | 400 | escalationReason: "cross_tenant_blocked" |
Defesas adicionais do servidor
- Allowlist de
Origin: requisições de browser com headerOriginsó são aceitas se vierem dehttps://integrations.fhinck.com,https://apps.fhinck.com,https://admin.fhinck.com,https://fhinck.comouhttps://www.fhinck.com. Callers server-side (que não enviamOrigin) passam sem restrição. Mitiga DNS rebinding (spec MCP §Security Warning). X-MCP-Modeignorado quando há token: o modo (service/chatbot) vem exclusivamente das claims do JWT. Um caller com tokenchatbotnão consegue "se promover" mandando o header — defesa em camadas contra escalation lateral.- Catálogo público filtrado:
tools/listsem token oculta ferramentas que revelam clientes específicos pelo nome. Com token autenticado, o catálogo é exibido inteiro. - Rate limit: 30 req/min em modo
chatbot, 120 req/min em modoservice, poractor_id. Sliding window de 60s em Redis. - Audit imutável:
fhinckbackendnew.mcp_audit.tool_callspersiste 365 dias.
Rotação de chave (JWKS)
As chaves de assinatura RS256 do MCP são publicadas em https://integrations.fhinck.com/.well-known/jwks.json. Se você implementa um validador próprio do token (ex.: gateway que filtra antes de chamar o MCP), cache esse JWKS por no máximo 10 minutos e recarregue ao encontrar kid desconhecido. Durante uma janela de rotação, o JWKS publica a chave atual e a anterior em paralelo, permitindo que tokens emitidos antes da rotação continuem aceitos até expirarem.
Health checks
GET /mcp/health— sempre 200 OK enquanto o processo estiver vivo. Útil para load balancer.GET /mcp/ready— 200 OK só quando o container Inversify está pronto e o cliente BigQuery está acessível. Use para readiness probe.
Auditoria
Toda chamada de ferramenta — sucesso ou falha — é registrada em fhinckbackendnew.mcp_audit.tool_calls no BigQuery com: nome da ferramenta, modo (service/chatbot), actorId (claim sub do token), tenant, latência, status e hash do input (sem PII). Logs ficam disponíveis para investigação de incidentes e auditoria de conformidade. Solicite extração com seu contato comercial Fhinck.
Próximos passos
- Solicite as credenciais OAuth2 (
client_id/client_secret) ou habilite a troca de Firebase token em contato@fhinck.com. - Liste o catálogo:
curl https://integrations.fhinck.com/mcp/tools. - Faça uma chamada de teste com
searchEmployeeemSTRANGER_FHINCKERS(sandbox). - Se for integrar com Claude Desktop ou Anthropic SDK, escreva pra gente — temos um exemplo de configuração pronto.
