@expertcustom/funilaria-mcp
Enables AI assistants to interact with the Funilaria & Pintura portal through typed MCP tools, covering news publishing, supplier searches, stock and balance inquiries, and WhatsApp webhook operations.
README
@expertcustom/funilaria-mcp
Servidor MCP (Model Context Protocol) com as tools tipadas que a IA do Aurora usa para escrever e ler no portal Funilaria & Pintura.
Ele substitui o mcp-fetch montando requisição HTTP à mão com o segredo escrito no system prompt: aqui cada operação é uma tool com schema, descrição e erro em português.
IA do Aurora ──stdio──> npx @expertcustom/funilaria-mcp ──HTTPS──> backend NestJS
Pela ADR-001, este pacote é adaptador: nenhuma regra de negócio mora aqui. Toda tool chama um endpoint que já existe, e o serviço do backend continua sendo o dono da decisão.
Tools — quem define é o backend
Este pacote não sabe quais tools existem. Na subida ele busca GET /mcp/catalogo e publica o que vier; a execução vai por POST /mcp/executar, e o backend resolve o nome para o serviço.
subida ──> GET /mcp/catalogo → lista publicada em tools/list
chamada ──> POST /mcp/executar → { name, args }
O motivo é operacional: antes, tool nova custava editar este pacote, buildar, commitar, publicar e reinstalar o MCP no Aurora — cinco passos para expor um endpoint que já existia no backend. Agora é commit de um módulo só, em backend/src/mcp.
A lista corrente sai de GET /mcp/catalogo. Não há cópia dela aqui de propósito: cópia envelhece e passa a mentir.
Quando o catálogo não responde, o servidor publica uma única tool, funilaria_catalogo_indisponivel, cuja descrição explica o que verificar. Sem ela o sintoma seria "sumiram as tools" e o diagnóstico começaria pelo lugar errado.
O catálogo é buscado uma vez, na subida: o cliente MCP lê tools/list logo após conectar e não volta a perguntar. Tool adicionada no backend entra na próxima reinstalação do servidor no Aurora.
Autenticação
Credencial de serviço com shopId explícito é o caminho principal, tanto para escrever quanto para ler. Header x-aurora-secret, o mesmo valor de AURORA_WEBHOOK_SECRET no backend; ele não representa pessoa nenhuma, representa o serviço.
Uma IA que atende várias oficinas não tem sessão, então a oficina é parâmetro, nunca contexto implícito. Do lado do backend isso é o @AllowService() nas rotas de leitura de estoque: o JwtAuthGuard aceita o segredo no lugar do JWT e o ShopContextGuard passa a exigir o shopId — id inexistente responde 404 Oficina não encontrada, e não uma lista vazia que se confundiria com "oficina sem estoque".
Sessão de usuário (JWT de POST /auth/entrar) continua existindo para os comandos de CLI, mas não vale mais para as tools: POST /mcp/executar é sempre chamada de serviço, e a oficina é sempre parâmetro explícito. Uma IA que atende várias oficinas nunca teve sessão; manter os dois modos só criava um caminho em que shopId omitido significava coisas diferentes.
Configuração — env é o caminho principal
Em produção quem sobe este processo é o runtime do Aurora, que injeta as variáveis: não há terminal, e nenhum comando de login é executado. O servidor funciona com o disco totalmente vazio.
| Env | Apelido aceito | Para quê |
|---|---|---|
FUNILARIA_API_URL |
PUBLIC_API_URL |
Base da API |
FUNILARIA_SERVICE_SECRET |
AURORA_WEBHOOK_SECRET |
Segredo de serviço (x-aurora-secret) |
FUNILARIA_SIGNING_SECRET |
AURORA_WEBHOOK_SIGNING_SECRET |
Segredo da assinatura HMAC (opcional) |
FUNILARIA_SHOP_ID |
— | Oficina padrão de consultar_estoque |
FUNILARIA_TOKEN |
— | JWT de usuário, se houver (opcional) |
Os apelidos existem para o erro clássico de copiar o .env do backend e o segredo "sumir" por causa do prefixo diferente — AURORA_WEBHOOK_SECRET é exatamente o mesmo valor dos dois lados.
Segredo nunca é hardcoded nem lido de prompt. O arquivo ~/.config/funilaria-mcp/credentials.json (modo 0600) é conveniência de desenvolvimento local; a env sempre vence e nunca é gravada em disco.
No boot, o servidor escreve em stderr (stdout é do protocolo MCP) uma linha dizendo o que está configurado e de qual env veio cada coisa — nunca o valor. É o que aparece no log do Aurora quando alguém erra o nome da variável:
[funilaria-mcp] API: https://api.exemplo.com (FUNILARIA_API_URL) · Credencial de serviço: configurada via AURORA_WEBHOOK_SECRET · ...
[funilaria-mcp] Sem credencial de serviço: as tools de escrita vão recusar toda chamada. Defina FUNILARIA_SERVICE_SECRET no ambiente deste processo.
Assinatura HMAC
Quando FUNILARIA_SIGNING_SECRET existe, toda escrita leva também:
x-timestamp: <epoch em segundos>
x-signature: sha256=<HMAC-SHA256(`${timestamp}.${corpo}`)>
É a melhoria mapeada na ADR-001 (fecha replay e vazamento por log). O backend ainda não verifica — header desconhecido é ignorado, então dá para ligar o lado do servidor sem quebrar quem já está rodando.
Instalação
Na IA do Aurora (produção)
Registre o servidor com as variáveis no próprio cadastro do MCP — nada de login, nada de segredo no system prompt:
{
"command": "npx",
"args": ["-y", "@expertcustom/funilaria-mcp"],
"env": {
"FUNILARIA_API_URL": "https://<api-do-portal>",
"FUNILARIA_SERVICE_SECRET": "<mesmo valor de AURORA_WEBHOOK_SECRET>"
}
}
Local, para desenvolver
# opção A — env no shell (igual à produção)
FUNILARIA_API_URL=http://localhost:3334 FUNILARIA_SERVICE_SECRET=... npx @expertcustom/funilaria-mcp
# opção B — guardar em ~/.config para não exportar em todo shell
npx @expertcustom/funilaria-mcp login-servico
# sessão de usuário: só é necessária para consultar_estoque sem shopId
npx @expertcustom/funilaria-mcp login
# conferir o que está valendo e de onde veio (nunca imprime segredo)
npx @expertcustom/funilaria-mcp status
# registrar no Claude Code
claude mcp add funilaria --env FUNILARIA_API_URL=http://localhost:3334 -- npx -y @expertcustom/funilaria-mcp
Pendências no backend
As quatro pendências originais (webhook de estoque inalcançável, leitura sem credencial de serviço, segredo checado depois da validação, distância como código morto) foram corrigidas no backend e revalidadas contra localhost:3334. O que sobrou:
-
A IA não tem como descobrir o
shopId. É o único dado que ela precisa saber de cor, e hoje só chega porFUNILARIA_SHOP_ID— o que amarra um servidor a uma oficina e derruba o caso multi-oficina que motivou o desenho de serviço.O ponto mais barato de resolver é o
lancar_consumo: o backend já identificou funcionário e oficina pelo número do WhatsApp, mas devolve só o texto de confirmação. SeIntakeResultincluísseshopIdememberId, a conversa fluiria — "usei 100ml de verniz" → "quanto gastei esse mês?" seriaconsultar_balancetecom os dois ids em mãos. Sem isso, a segunda pergunta não tem resposta possível. -
GET /estoque/movimentosficou fora do@AllowService(). OshopIdestá declarado noListMovementsDto, mas a rota não aceita credencial de serviço — o parâmetro não tem como ser usado. Ou marca a rota, ou tira o campo do DTO para não sugerir capacidade que não existe. -
Assinatura HMAC ainda não é verificada. O cliente já envia
x-timestampex-signaturequando há segredo de assinatura (ver acima). Falta o lado do servidor para fechar replay e vazamento por log, como prevê a ADR-001.
Desenvolvimento
npm install
npm run build # tsc estrito, gera dist/
npm start # sobe o servidor MCP em stdio
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。