Skip to main content
Glama
adventureandre

@expertcustom/funilaria-mcp

@expertcustom/funilaria-mcp

Сервер MCP (Model Context Protocol) с типизированными инструментами, которые ИИ Aurora использует для записи и чтения на портале Funilaria & Pintura.

Он заменяет mcp-fetch, вручную собирая HTTP-запрос с секретом, записанным в системном промпте: здесь каждая операция — это инструмент со схемой, описанием и ошибкой на португальском.

IA do Aurora ──stdio──> npx @expertcustom/funilaria-mcp ──HTTPS──> backend NestJS

Согласно ADR-001, этот пакет является адаптером: никакие бизнес-правила здесь не живут. Каждый инструмент вызывает уже существующую конечную точку, а серверная часть остаётся владельцем решения.

Инструменты — кто определяет, так это бэкенд

Этот пакет не знает, какие инструменты существуют. При запуске он запрашивает GET /mcp/catalogo и публикует то, что приходит; выполнение идёт через POST /mcp/executar, и бэкенд сопоставляет имя с сервисом.

subida  ──> GET  /mcp/catalogo   → lista publicada em tools/list
chamada ──> POST /mcp/executar   → { name, args }

Причина операционная: раньше новый инструмент стоил правки этого пакета, сборки, коммита, публикации и переустановки MCP в Aurora — пять шагов, чтобы выставить конечную точку, которая уже существовала в бэкенде. Теперь это коммит одного модуля в backend/src/mcp.

Текущий список берётся из GET /mcp/catalogo. Здесь намеренно нет его копии: копия устаревает и начинает лгать.

Когда каталог не отвечает, сервер публикует единственный инструмент funilaria_catalogo_indisponivel, описание которого объясняет, что проверить. Без него симптомом было бы «инструменты исчезли», и диагностика началась бы не с того места.

Каталог запрашивается один раз, при запуске: клиент MCP читает tools/list сразу после подключения и больше не спрашивает. Инструмент, добавленный в бэкенд, попадает при следующей переустановке сервера в Aurora.

Related MCP server: Telegram Bot MCP Server

Аутентификация

Сервисное учётное данное с явным shopId — основной путь как для записи, так и для чтения. Заголовок x-aurora-secret, то же значение, что и AURORA_WEBHOOK_SECRET в бэкенде; он не представляет никакого человека, он представляет сервис.

ИИ, обслуживающий несколько мастерских, не имеет сессии, поэтому мастерская — это параметр, а не неявный контекст. На стороне бэкенда это @AllowService() в маршрутах чтения запасов: JwtAuthGuard принимает секрет вместо JWT, а ShopContextGuard начинает требовать shopId — несуществующий id отвечает 404 Oficina não encontrada, а не пустым списком, который можно было бы спутать с «мастерская без запасов».

Сессия пользователя (JWT от POST /auth/entrar) по-прежнему существует для команд CLI, но больше не действует для инструментов: POST /mcp/executar — это всегда вызов сервиса, и мастерская всегда является явным параметром. ИИ, обслуживающий несколько мастерских, никогда не имел сессии; сохранение обоих режимов создавало бы путь, где опущенный shopId означал бы разные вещи.

Конфигурация — env является основным путём

В продакшене этот процесс запускает рантайм Aurora, который внедряет переменные: нет терминала, и никакая команда входа не выполняется. Сервер работает с полностью пустым диском.

Env

Принятый псевдоним

Для чего

FUNILARIA_API_URL

PUBLIC_API_URL

База API

FUNILARIA_SERVICE_SECRET

AURORA_WEBHOOK_SECRET

Сервисный секрет (x-aurora-secret)

FUNILARIA_SIGNING_SECRET

AURORA_WEBHOOK_SIGNING_SECRET

Секрет подписи HMAC (необязательно)

FUNILARIA_SHOP_ID

—

Мастерская по умолчанию для consultar_estoque

FUNILARIA_TOKEN

—

JWT пользователя, если есть (необязательно)

Псевдонимы существуют из-за классической ошибки копирования .env из бэкенда, когда секрет «исчезает» из-за другого префикса — AURORA_WEBHOOK_SECRET — это ровно то же значение с обеих сторон.

Секрет никогда не захардкожен и не читается из промпта. Файл ~/.config/funilaria-mcp/credentials.json (режим 0600) — это удобство для локальной разработки; env всегда побеждает и никогда не записывается на диск.

При загрузке сервер пишет в stderr (stdout принадлежит протоколу MCP) строку о том, что настроено и из какого env что пришло — никогда значение. Это то, что появляется в логе Aurora, когда кто-то ошибается в имени переменной:

[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.

Подпись HMAC

Когда существует FUNILARIA_SIGNING_SECRET, каждая запись также несёт:

x-timestamp: <epoch em segundos>
x-signature: sha256=<HMAC-SHA256(`${timestamp}.${corpo}`)>

Это улучшение, описанное в ADR-001 (закрывает повтор и утечку через логи). Бэкенд пока не проверяет — неизвестный заголовок игнорируется, так что можно включить сторону сервера, не ломая тех, кто уже работает.

Установка

В ИИ Aurora (продакшен)

Зарегистрируйте сервер с переменными в самой записи MCP — никакого входа, никакого секрета в системном промпте:

{
  "command": "npx",
  "args": ["-y", "@expertcustom/funilaria-mcp"],
  "env": {
    "FUNILARIA_API_URL": "https://<api-do-portal>",
    "FUNILARIA_SERVICE_SECRET": "<mesmo valor de AURORA_WEBHOOK_SECRET>"
  }
}

Локально, для разработки

# 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

Остающиеся задачи в бэкенде

Четыре исходные задачи (недостижимый вебхук запасов, чтение без сервисного учётного данного, секрет, проверяемый после валидации, расстояние как мёртвый код) были исправлены в бэкенде и повторно проверены против localhost:3334. Что осталось:

  1. ИИ не может узнать shopId. Это единственные данные, которые ему нужно знать наизусть, и сегодня они приходят только через FUNILARIA_SHOP_ID — что привязывает сервер к одной мастерской и рушит сценарий с несколькими мастерскими, ради которого и был спроектирован сервис.

    Самое дешёвое место для решения — lancar_consumo: бэкенд уже идентифицировал сотрудника и мастерскую по номеру WhatsApp, но возвращает только текст подтверждения. Если бы IntakeResult включал shopId и memberId, разговор бы шёл — «я использовал 100 мл лака» → «сколько я потратил в этом месяце?» было бы consultar_balancete с обоими id на руках. Без этого на второй вопрос нет возможного ответа.

  2. GET /estoque/movimentos остался вне @AllowService(). shopId объявлен в ListMovementsDto, но маршрут не принимает сервисное учётное данное — параметр невозможно использовать. Либо пометить маршрут, либо убрать поле из DTO, чтобы не предполагать возможность, которой нет.

  3. Подпись HMAC ещё не проверяется. Клиент уже отправляет x-timestamp и x-signature, когда есть секрет подписи (см. выше). Не хватает стороны сервера, чтобы закрыть повтор и утечку через логи, как предусмотрено в ADR-001.

Разработка

npm install
npm run build     # tsc estrito, gera dist/
npm start         # sobe o servidor MCP em stdio

Available Tools

1 tool
funilaria_catalogo_indisponivelCatálogo do Funilaria indisponívelA

O backend do Funilaria não respondeu GET /mcp/catalogo, então NENHUMA tool do portal está disponível nesta sessão — não é que elas não existam. Verifique se FUNILARIA_API_URL aponta para o backend certo e se FUNILARIA_SERVICE_SECRET (ou AURORA_WEBHOOK_SECRET) está definido no processo deste MCP; o motivo exato saiu no stderr do servidor. Não tente cumprir a tarefa por outro caminho: não monte requisição HTTP à mão, não invente URL nem segredo. Avise quem pediu que a integração com o portal está fora do ar.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains that the tool is not a functional operation but a signal that the catalog is down, that no portal tools are available, and that the exact cause is in the server's stderr. It also discloses the expected fallback behavior (informing the requester) and explicitly forbids bypass attempts. This fully discloses the tool's non-functional nature and the reasoning behind it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, dense paragraph that front-loads the core message (backend down, no tools available) and then provides corrective actions and prohibitions. Every sentence contributes essential information: the root cause, the implication, troubleshooting steps, and explicit instructions. There is no fluff or redundancy, making it both concise and structurally sound.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there is no output schema and the tool is essentially a status indicator, the description is complete. It specifies what happened, why, what to check, what not to do, and what to tell the requester. All necessary operational context is provided, and because the tool has zero parameters and no output expectations, the description fully covers what an agent needs to handle this situation correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema is empty with 0 parameters, so the baseline is 4. The description does not need to add parameter details, but it explains why the tool takes no arguments (it is a placeholder for an unavailable catalog). It also provides environment variable checks (FUNILARIA_API_URL, FUNILARIA_SERVICE_SECRET) as context, which indirectly explains the setup. This exceeds the baseline by giving operational context beyond the mere absence of parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool indicates the backend did not respond to GET /mcp/catalogo, making the entire portal's tools unavailable in this session. It does not use a classic verb+resource phrasing, but its purpose as an unavailability signal is unambiguous and distinct from any normal tool. Since there are no siblings, the distinguishing aspect is not relevant, but the description still clearly explains what it represents.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs when to use this tool (when it appears, treat it as a session-wide unavailability) and what NOT to do: do not attempt to fulfill the task by other means, do not craft HTTP requests manually, do not invent URLs or secrets. It also tells the agent to inform the requester. This is direct, actionable context with explicit exclusions, covering both usage and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observedfunilaria_catalogo_indisponivel

TDQS

A4.1/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of tool confusion. The tool's purpose—to report that the catalog is unavailable—is uniquely clear.

Naming Consistency5/5

The single tool name is descriptive and domain-specific, following a clear pattern. With no other tools, there is no inconsistency to penalize.

Tool Count1/5

A single tool that serves only as an error placeholder is far below the expected scope for a catalog server. This is an extreme mismatch with the apparent purpose.

Completeness1/5

The server provides no actual catalog operations; the only tool explicitly states that all functional tools are unavailable. The surface is severely incomplete and unusable.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers