Skip to main content
Glama
laizaguedes

receitas-mcp-server

by laizaguedes
README.md
# receitas-mcp-server

Servidor **MCP (Model Context Protocol)** em **TypeScript + Node**, com a stack atual de mercado:

- [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) — SDK oficial
- **TypeScript** (ESM, `NodeNext`)
- **zod** para validação de schemas das tools
- transporte **stdio** (padrão para Claude Code, Cursor e Claude Desktop)

> ⚠️ **Importante:** um servidor MCP **não é chamado direto pelo frontend** (navegador). Ele é consumido por **assistentes de IA** (Claude Code, Cursor, Claude Desktop) **ou** por um backend que aja como cliente MCP — é o caso da API `receitas-api` (pasta irmã), que expõe esse MCP como REST para o frontend.

## 🗄️ Onde as receitas ficam guardadas

O storage é escolhido **em tempo de execução** (`src/repository.ts`):

- Se as variáveis `TRELLO_API_KEY`, `TRELLO_TOKEN` e `TRELLO_LIST_ID` estiverem definidas → grava/lê cada receita como um **card do Trello** (`src/trelloStore.ts`).
- Caso contrário → usa um **arquivo JSON local** `data/receitas.json` (`src/store.ts`), ótimo para desenvolvimento.

No Trello, cada receita vira um card na lista configurada: o nome do card é o nome da receita e a descrição guarda um bloco JSON (`<!--receita:...-->`) para reconstruir a receita fielmente. Configure as credenciais em `.env` (veja `.env.example`).

### Variáveis de ambiente (`.env`)

Crie um arquivo `.env` na raiz de `receitas-mcp-server` com estas três variáveis.
**Os valores abaixo são fictícios** — troque pelos seus.

```dotenv
# Chave de API do Trello — pegue em https://trello.com/app-key
# Formato: 32 caracteres hexadecimais.
TRELLO_API_KEY=a1b2c3d4e5f60718293a4b5c6d7e8f90

# Token do Trello — gere pelo link "Token" na mesma pagina do app-key.
# Formato: cadeia longa (~64+ caracteres).
TRELLO_TOKEN=ATTAa0000example1111token2222naoreal3333abcdef4444567890ghijkl

# ID da lista do Trello onde os cards de receita serao criados.
# Formato: 24 caracteres hexadecimais.
TRELLO_LIST_ID=6634f0a1b2c3d4e5f6a7b8c9
```

| Variável | O que é | Como obter |
|----------|---------|------------|
| `TRELLO_API_KEY` | Identifica seu app no Trello | https://trello.com/app-key |
| `TRELLO_TOKEN` | Autoriza acesso à sua conta | Link **Token** na página do app-key |
| `TRELLO_LIST_ID` | Lista onde as receitas viram cards | Abra o board com `.json` no fim da URL e procure o `id` da lista, ou `GET https://api.trello.com/1/boards/{boardId}/lists?key=SUA_KEY&token=SEU_TOKEN` |

> 🔒 As três são **obrigatórias juntas** para ativar o Trello. Se qualquer uma
> faltar, o servidor cai automaticamente no storage JSON local. O `.env` está no
> `.gitignore` — nunca comite suas credenciais reais.

---

## 📖 Índice

1. [O que é isso](#o-que-é-isso)
2. [Tools disponíveis](#tools-disponíveis)
3. [Como este MCP foi criado (passo a passo)](#como-este-mcp-foi-criado-passo-a-passo)
4. [Como usar (passo a passo)](#como-usar-passo-a-passo)
5. [Estrutura de pastas](#estrutura-de-pastas)

---

## O que é isso

MCP é um protocolo que permite a uma IA (Claude, Cursor, etc.) **chamar funções e ler dados** de uma fonte externa de forma padronizada. Aqui, a fonte externa é um **catálogo de receitas**. A IA conversa com este servidor por **stdio** (entrada/saída padrão), trocando mensagens no formato **JSON-RPC 2.0**.

---

## Tools disponíveis

| Tool | O que faz |
|------|-----------|
| `listar_receitas` | Lista receitas com filtros (categoria, dificuldade, ingrediente, busca) |
| `buscar_receita` | Detalhes completos de uma receita por `id` |
| `adicionar_receita` | Cadastra uma receita (persistida em `data/receitas.json`) |
| `remover_receita` | Remove uma receita por `id` |
| `sugerir_por_ingredientes` | Sugere receitas pelo que você tem em casa |

Também expõe um **resource** `receitas://catalogo` com o catálogo completo em JSON.

---

## Como este MCP foi criado (passo a passo)

Se você quiser recriar do zero (ou entender cada peça), foi exatamente esta a sequência:

### Passo 1 — Criar a pasta e o `package.json`

Projeto Node em **ESM** (`"type": "module"`), com scripts de build/start e as dependências certas:

```json
{
  "type": "module",
  "bin": { "receitas-mcp": "dist/index.js" },
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsx watch src/index.ts",
    "inspect": "npx @modelcontextprotocol/inspector node dist/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.19.1",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@types/node": "^24.7.0",
    "tsx": "^4.20.6",
    "typescript": "^5.9.3"
  }
}
```

- `@modelcontextprotocol/sdk` → o SDK oficial que implementa o protocolo.
- `zod` → valida os argumentos que a IA envia para cada tool.
- `tsx` → roda TypeScript direto em desenvolvimento (modo watch).

### Passo 2 — Configurar o TypeScript (`tsconfig.json`)

O ponto crítico é usar `module`/`moduleResolution` = **`NodeNext`**, porque o SDK é ESM e os imports precisam terminar em `.js`:

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "resolveJsonModule": true
  }
}
```

### Passo 3 — Definir os dados e os schemas (`src/types.ts`)

Uma única fonte de verdade com **zod**. O schema serve para **validar a entrada das tools** e, ao mesmo tempo, **gerar o tipo TypeScript** (`z.infer`):

```ts
export const receitaSchema = z.object({
  id: z.string().regex(/^[a-z0-9-]+$/),
  nome: z.string().min(1),
  categoria: z.string().min(1),
  tempoPreparoMin: z.number().int().positive(),
  porcoes: z.number().int().positive(),
  dificuldade: z.enum(["facil", "medio", "dificil"]),
  ingredientes: z.array(z.string()).min(1),
  passos: z.array(z.string()).min(1),
});
export type Receita = z.infer<typeof receitaSchema>;
```

### Passo 4 — Camada de dados (`src/store.ts`)

Um repositório simples que **lê e grava** o arquivo `data/receitas.json`. Isolar isso mantém o `index.ts` focado só no protocolo. Aqui ficam `listar`, `obter`, `adicionar`, `remover` e `sugerirPorIngredientes`.

### Passo 5 — O servidor MCP (`src/index.ts`)

O coração. Cria o servidor, registra cada **tool** com seu schema e handler, registra o **resource** e conecta no transporte stdio:

```ts
const server = new McpServer({ name: "receitas-mcp-server", version: "1.0.0" });

server.registerTool(
  "listar_receitas",
  { title: "Listar receitas", description: "...", inputSchema: { categoria: z.string().optional() } },
  async ({ categoria }) => {
    const lista = await store.listar({ categoria });
    return { content: [{ type: "text", text: "..." }], structuredContent: { receitas: lista } };
  },
);

const transport = new StdioServerTransport();
await server.connect(transport);
```

> 🔑 **Regra de ouro:** o `stdout` é **exclusivo do protocolo**. Qualquer log seu tem que ir para `stderr` (`console.error`), senão você corrompe a comunicação com a IA.

### Passo 6 — Instalar, compilar e testar

```bash
npm install     # baixa as dependências
npm run build   # compila src/ -> dist/
```

O teste de fumaça enviou 3 mensagens JSON-RPC pelo stdin (`initialize` → `notifications/initialized` → `tools/list` + uma `tools/call`) e confirmou que o servidor respondeu com as 5 tools e executou uma chamada real. ✅

---

## Como usar (passo a passo)

### 1. Preparar o servidor (uma vez)

```bash
cd receitas-mcp-server
npm install
npm run build
```

> Sempre rode `npm run build` de novo depois de editar qualquer arquivo em `src/`, pois a IA aponta para `dist/index.js`.

### 2. (Opcional) Testar sozinha com o Inspector

Abre uma interface web onde você vê e dispara as tools na mão:

```bash
npm run inspect
```

### 3. Conectar no **Claude Code**

Na pasta do frontend `receitas`, rode:

```bash
claude mcp add receitas -- node "C:/Users/laiza_g/Desktop/Laiza/cursos/cursos/aulaBOOTSTRAP4/receitas-mcp-server/dist/index.js"
```

Confira se conectou:

```bash
claude mcp list
```

### 4. Conectar no **Cursor** ou **Claude Desktop**

Adicione ao arquivo de configuração de MCP (`.cursor/mcp.json` no Cursor, ou `claude_desktop_config.json` no Claude Desktop):

```json
{
  "mcpServers": {
    "receitas": {
      "command": "node",
      "args": [
        "C:/Users/laiza_g/Desktop/Laiza/cursos/cursos/aulaBOOTSTRAP4/receitas-mcp-server/dist/index.js"
      ]
    }
  }
}
```

Depois **reinicie** o Cursor/Claude Desktop.

### 5. Usar no dia a dia

Com o MCP conectado, é só pedir em linguagem natural para a IA. Exemplos:

- *"Liste as receitas de sobremesa fáceis."* → chama `listar_receitas`
- *"Me mostra a receita do brigadeiro."* → chama `buscar_receita`
- *"Tenho tomate e manjericão, o que posso fazer?"* → chama `sugerir_por_ingredientes`
- *"Cadastra uma receita nova de bolo de cenoura."* → chama `adicionar_receita` (grava no JSON)

A IA escolhe a tool certa sozinha, preenche os argumentos e te devolve o resultado.

---

## Estrutura de pastas

```
receitas-mcp-server/
├── data/
│   └── receitas.json      # base local (fallback quando Trello nao configurado)
├── src/
│   ├── index.ts           # servidor MCP: tools + resources
│   ├── repository.ts      # interface + fabrica (escolhe Trello ou JSON)
│   ├── store.ts           # backend JSON local
│   ├── trelloStore.ts     # backend Trello (REST API)
│   ├── filtering.ts       # filtros e sugestao (funcoes puras compartilhadas)
│   └── types.ts           # schemas zod + tipos
├── .env.example           # credenciais do Trello
├── package.json
├── tsconfig.json
└── README.md
```

TDQS

A3.9/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clear and distinct purpose: listing, fetching details, adding, removing, and suggesting recipes. The overlap between listar and buscar is resolved by list returning a filtered collection while buscar returns a single full recipe.

Naming Consistency5/5

All tool names follow a consistent Portuguese verb_noun pattern: listar_receitas, buscar_receita, adicionar_receita, remover_receita, and sugerir_por_ingredientes. The pattern is uniform and predictable.

Tool Count5/5

With 5 tools, the server is well-scoped for a recipe management domain. Each tool covers a core operation without unnecessary redundancy.

Completeness4/5

The server covers list, get, create, and delete operations, but lacks an update tool for editing existing recipes. This is a minor gap that agents can work around by deleting and recreating, but it is not a fatal omission.

Maintenance

ActivitySlowing
ResponsivenessNo issues