Skip to main content
Glama

MCP — Serveur documentaire

Un serveur Model Context Protocol complet, et les preuves qu'il fonctionne.

Tools · Resources · Prompts · Client · Tests · Guide 24 pages

Python MCP Tests Guide


Ce dépôt contient le projet fil rouge du cours Introduction to Model Context Protocol (Claude Academy), reconstruit, corrigé et documenté.

L'objectif n'est pas seulement d'avoir un serveur qui démarre : c'est de montrer comment on prouve qu'il fonctionne, sans modèle, sans clé API, et de documenter les pièges réels rencontrés en chemin.

📘 Le guide complet (24 pages, PDF) : docs/MCP-Guide.pdf — architecture, les trois primitives, construction pas à pas, les trois niveaux de test, étude de cas illustrée et 14 pièges documentés.


Sommaire


Related MCP server: local-docs-mcp

🧩 Ce que fait le serveur

Un mini gestionnaire de documents, avec les trois familles de capacités du protocole.

Élément

Type

Qui décide

Rôle

read_doc_contents

tool

le modèle

lire un document

edit_document

tool

le modèle

remplacer une chaîne (première occurrence)

search_docs

tool

le modèle

chercher un mot-clé, renvoyer des extraits

docs://documents

resource directe

l'application

liste des ids, en JSON — pour l'autocomplete @

docs://documents/{doc_id}

resource templatée

l'application

contenu d'un document, en texte brut

format

prompt

l'utilisateur

instructions de réécriture en markdown

Les documents sont stockés dans un dictionnaire en mémoire : le serveur repart de son état initial à chaque redémarrage.


🚀 Démarrage rapide

Linux / macOS

git clone https://github.com/thekiller-dev/mcp-server-course.git
cd mcp-server-course

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

Ou avec uv :

uv venv && uv pip install -r requirements.txt

Windows (PowerShell)

python -m venv .venv
.venv\Scripts\pip install -r requirements.txt

Fish (Linux)

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
# ou, pour tout enchaîner d'un coup :
fish setup.fish

⚠️ Version du SDK. Le cours utilise FastMCP. Depuis la 2.x, le SDK mcp l'a renommé MCPServer et a changé plusieurs signatures : tout le code ci-dessous casse avec No module named 'mcp.server.fastmcp'. requirements.txt épingle donc mcp[cli]<2.


🧪 Tester — les trois niveaux

Niveau 1 — sans clé API, sans navigateur (3 secondes)

.venv/bin/python test_server.py

Ce script lance le serveur en sous-processus et parle le protocole en stdio, exactement comme le ferait Claude Desktop. Il vérifie les tools et leurs schémas, appelle un tool, lit les deux resources, récupère le prompt.

✅ connecté à DocumentMCP v1.30.0

TOOLS : read_doc_contents, edit_document, search_docs
RESOURCES : [('docs://documents', 'application/json')]
RESOURCE TEMPLATES : [('docs://documents/{doc_id}', 'text/plain')]
PROMPTS : format

🎉 tous les tests passent

Niveau 2 — la boucle complète, racontée

.venv/bin/python demo_sans_cle.py

Rejoue ce que ferait un modèle, tool call après tool call, en affichant chaque étape : lecture, édition, vérification de la persistance, erreur volontaire (l'exception revient comme résultat, sans casser la session), lecture des resources, récupération du prompt.

Niveau 3 — l'inspecteur

.venv/bin/mcp dev mcp_server.py     # nécessite Node.js (npx)

Le terminal affiche une URL du type http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=…. Ouvrez l'URL complète — sans le jeton, la connexion est refusée.

À essayer dans l'interface :

Onglet

Valeur

Ce que ça prouve

Tools → read_doc_contents

{"document_id": "plan.md"}

schéma dérivé du code

Tools → edit_document

old 4. Ship it, new 4. Ship it to production

l'état persiste entre deux appels

Tools → edit_document

old ce texte n'existe pas

une erreur reste une réponse

Resources

docs://documents

sérialisation JSON automatique

Resource Templates

docs://documents/{doc_id} + report.pdf

parsing du gabarit d'URI

Prompts

format + email.md

prompt calculé côté serveur

Panneau de droite, onglet Protocol : chaque ligne est un message JSON-RPC réel.

Niveau 4 — un modèle aux commandes

export ANTHROPIC_API_KEY="sk-ant-..."     # PowerShell : $env:ANTHROPIC_API_KEY = "..."
.venv/bin/python mcp_client.py

Trois questions suffisent à valider le découpage :

Question

Ce qui doit se passer

Primitive

Quels documents parlent de revenue ?

Claude appelle search_docs seul

tool

@report.pdf résume les chiffres

aucun tool call, contenu injecté

resource

/format email.md

instructions récupérées puis envoyées

prompt

La deuxième ligne est la plus importante : un tool call là où une resource suffit signale une architecture mal découpée.


🧠 Les trois primitives expliquées

La différence n'est pas technique, elle tient à qui décide.

Ça lit des données                        → resource   (l'application décide)
Ça agit, ou ça peut échouer               → tool       (le modèle décide)
C'est une consigne destinée au modèle     → prompt     (l'utilisateur décide)

Un tool : le schéma vient du code

@mcp.tool(
    name="read_doc_contents",
    description="Read the contents of a document and return it as a string.",
)
def read_document(
    document_id: str = Field(description="Id of the document to read"),
) -> str:
    if document_id not in docs:
        raise ValueError(f"Doc with id {document_id} not found")
    return docs[document_id]
  • le type hint str devient "type": "string" dans le JSON Schema ;

  • Field(description=…) devient la description du paramètre — c'est du prompt engineering, pas de la décoration ;

  • raise ValueError devient un résultat d'erreur renvoyé au modèle, pas un crash.

Vous n'écrivez jamais de schéma JSON à la main : il ne peut donc pas dériver de l'implémentation.

Une resource : directe ou templatée

@mcp.resource("docs://documents", mime_type="application/json")
def list_docs() -> list[str]:
    return list(docs.keys())

@mcp.resource("docs://documents/{doc_id}", mime_type="text/plain")
def fetch_doc(doc_id: str) -> str:
    if doc_id not in docs:
        raise ValueError(f"Doc with id {doc_id} not found")
    return docs[doc_id]

Le préfixe d'URI est libre : ce n'est pas une URL réseau, c'est un espace de noms. Le SDK extrait {doc_id} et le passe en argument nommé.

Un prompt : la couche utilisateur

@mcp.prompt(name="format", description="Rewrite the document as clean markdown.")
def format_document(doc_id: str = Field(description="Id of the document")) -> str:
    return f"""Please rewrite the following document into clean markdown.
Do not invent information.

<document id="{doc_id}">
{docs.get(doc_id, "Document not found")}
</document>"""

📁 Structure du dépôt

mcp-server-course/
├── mcp_server.py            # le serveur : 3 tools, 2 resources, 1 prompt
├── mcp_client.py            # client + boucle agentique avec Claude (@mention, /format)
├── test_server.py           # test de protocole — aucune clé API requise
├── demo_sans_cle.py         # la boucle complète, rejouée et commentée
├── requirements.txt         # mcp[cli]<2, anthropic
├── pyproject.toml           # [tool.uv] package = false (voir « Pièges connus »)
├── setup.fish               # installation + test en une commande (fish)
└── docs/
    ├── MCP-Guide.pdf        # le guide de 24 pages
    └── screenshots/         # preuves d'exécution (inspecteur, JSON-RPC)

🔌 Brancher sur Claude Desktop / Claude Code

Claude Desktop — claude_desktop_config.json :

OS

Chemin

Linux

~/.config/Claude/claude_desktop_config.json

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

Windows

%APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "documents": {
      "command": "uv",
      "args": ["--no-project", "--with", "mcp", "mcp", "run",
               "/chemin/absolu/vers/mcp-server-course/mcp_server.py"]
    }
  }
}

Quittez complètement l'application puis relancez-la : la configuration n'est lue qu'au démarrage.

Claude Code :

claude mcp add documents -- python /chemin/absolu/vers/mcp_server.py

⚠️ Pièges connus

Ces erreurs sont documentées parce qu'elles ont réellement été rencontrées.

Symptôme

Cause

Solution

command not found: uv

binaire dans ~/.local/bin, absent du PATH

fish_add_path ~/.local/bin

syntax error: unexpected end of file

chemin abîmé par un copier-coller ([env.fish](http://…))

retaper la commande

No module named 'mcp'

Python du système au lieu du venv

.venv/bin/python test_server.py

No module named 'mcp.server.fastmcp'

SDK 2.x, FastMCP → MCPServer

pip install "mcp[cli]<2"

Unable to determine which files to ship inside the wheel

uv run tente de builder le dossier

[tool.uv] package = false, ou uv run --no-project …

terminal figé après mcp run

comportement normal du stdio

mcp dev pour un humain, mcp run pour un client

npx: command not found

Node.js absent

Node 20+ via NodeSource, pas le npm d'apt

nodejs : Conflicts: npm

nodejs NodeSource + npm d'apt

ne pas installer npm via apt

inspecteur « Disconnected »

URL sans le jeton

ouvrir le lien complet ?MCP_PROXY_AUTH_TOKEN=…

le modèle ignore l'outil

description trop vague

dire quand l'utiliser, pas seulement ce qu'il fait

La règle de tri : (1) le script de test répond-il ? (2) l'inspecteur exécute-t-il l'outil à la main ? (3) seulement ensuite, regarder les descriptions. 90 % des problèmes se règlent à l'étape 1.


🔭 Aller plus loin

  1. Resource de synthèse — stats://documents renvoyant en JSON le nombre de documents, le nombre total de mots et le document le plus long.

  2. Tool d'écriture complète — create_document(document_id, content), avec erreur explicite si l'identifiant existe déjà.

  3. Transport HTTP — mcp.run(transport="streamable-http"), connexion avec mcp.client.streamable_http, puis sortie du mono-utilisateur local.

  4. Persistance — remplacer le dictionnaire par des fichiers ou une base. La surface MCP ne bouge pas : c'est le signe d'une bonne séparation.


📚 Ressources


Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Provides tools and resources for managing in-memory documents, allowing users to read, edit, and list document contents via the Model Context Protocol. It includes features for formatting documents to Markdown and accessing document-specific resources.
    3
    -
  • F
    license
    A
    quality
    D
    maintenance
    Enables local document search and reading across formats like docx, pdf, md, and more, providing tools for listing, searching, and reading documents.
    3
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables managing documents on the filesystem through natural language, with tools for read, create, edit, delete, and commands for summarize, format, rewrite, and convert.
    5
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Exposes a document store over MCP tools, resources, and prompts for reading, editing, summarizing, and formatting documents in a chat interface.
    -