Skip to main content
Glama
lucas-moont

mcp-lab-01-notes-server

by lucas-moont
README.md
# mcp-lab-01-notes-server

Nível 01 da trilha **MCP Lab**: primeiro servidor MCP construído com o **SDK oficial** (`mcp` no PyPI). Domínio: um gerenciador de notas e tarefas guardadas como arquivos markdown locais.

Termos técnicos seguem o glossário em [`../CONTEXT.md`](../CONTEXT.md).

## O que este Server faz

5 Tools sobre uma pasta de arquivos `.md`:

| Tool | O que faz |
|---|---|
| `create_note(title, content="", is_task=False)` | Cria uma nota; com `is_task=True` ela nasce como tarefa (`status: pending`) |
| `list_notes()` | Lista todas as notas com título e status |
| `read_note(slug)` | Devolve o corpo completo de uma nota |
| `mark_done(slug)` | Marca uma tarefa como concluída |
| `delete_note(slug)` | Apaga uma nota |

```mermaid
flowchart LR
    subgraph server.py [camada de protocolo]
        T[Tools do MCPServer]
    end
    subgraph note.py [domínio]
        N[Note, slugify, parse, render]
    end
    subgraph storage.py [armazenamento]
        S[NotesStorage: ler/escrever/apagar .md]
    end

    T -->|delega| N
    T -->|delega| S
    N -.->|não conhece| S
    S -.->|não conhece| N
```

`server.py` é a única camada que conhece as duas outras. `note.py` (regra de negócio) e `storage.py` (arquivos) não se conhecem entre si — isso é proposital: dá pra trocar onde as notas são guardadas (um banco de dados, por exemplo) sem tocar no que é uma Nota.

## Como rodar

```bash
uv sync
uv run pytest -q        # 33 testes
uv run ruff check .
uv run mypy
```

Por padrão as notas vão para `~/.mcp-lab/notes`. Pra usar outra pasta:

```bash
NOTES_SERVER_DIR=/caminho/qualquer uv run notes-server
```

### Usando de verdade no Claude Code

```bash
claude mcp add notes-server -- uv run --directory "$(pwd)" notes-server
```

Depois disso, numa conversa do Claude Code, peça pra ele criar uma nota ou listar suas tarefas — o modelo vai decidir sozinho quando chamar cada Tool.

## Estrutura do código

```
src/notes_server/
├── storage.py   → só sabe ler/escrever/apagar arquivos; barra path traversal
├── note.py      → o que é uma Note; slugify; frontmatter -> Note e Note -> frontmatter
└── server.py    → liga os Tools do MCP ao domínio; ToolError pros erros esperados
```

Um `.md` por camada em [`docs/`](./docs/), explicando o pra-quê/o-quê/como de cada uma:

- [`docs/01-armazenamento.md`](./docs/01-armazenamento.md)
- [`docs/02-dominio-nota.md`](./docs/02-dominio-nota.md)
- [`docs/03-tool-error-e-saida-estruturada.md`](./docs/03-tool-error-e-saida-estruturada.md)
- [`docs/04-injecao-de-dependencia.md`](./docs/04-injecao-de-dependencia.md)

## O que este nível deliberadamente NÃO faz

- Não expõe as notas como **Resources** nem tem **Prompts** prontos — isso é o Nível `02-resources-prompts`.
- Não valida concorrência (dois processos escrevendo a mesma nota ao mesmo tempo) — fora de escopo pra um projeto local de estudo.
- O frontmatter é um parser feito à mão, de propósito (ver `docs/02-dominio-nota.md`) — não é um formato geral de YAML.

## Referência oficial

[modelcontextprotocol.io](https://modelcontextprotocol.io) para a spec do protocolo. [github.com/modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk) para o código-fonte do SDK — o pacote `mcp` mudou de `FastMCP` para `MCPServer` na versão 2.x; se você ler isto muito depois, confira se a API ainda bate com o que está aqui.

TDQS

A3.6/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a clear primary action, and the CRUD operations are distinct. However, create_note doubles as a task creator via is_task, and mark_done applies only to tasks, which could cause slight ambiguity about whether notes also support status changes.

Naming Consistency4/5

Most tools follow a clear verb_noun pattern (create_note, list_notes, read_note, delete_note), but mark_done breaks the pattern by using verb_adjective instead of verb_noun. This is a minor inconsistency that still leaves the intent understandable.

Tool Count5/5

Five tools is appropriately scoped for a simple notes/tasks server. The set covers the essential operations without unnecessary bloat, making it easy for an agent to navigate.

Completeness3/5

The set lacks an update_note/edit_note operation, which is a notable gap for a notes domain. It also has no way to unmark a task or filter tasks from notes, limiting full lifecycle management for tasks.

Maintenance

ActivityMaintained
ResponsivenessNo issues