- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docs | ||
| docs_mcp | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
docs-mcp
Serveur MCP distant (Streamable HTTP + OAuth 2.1) pour La Suite Docs : recherche, lecture en Markdown et création de documents, avec les droits de l'utilisateur connecté. Compatible avec tout client MCP récent (Hermes, Claude Desktop/Code, VS Code, Cursor…).
Conception : docs/DESIGN.md. Sur YunoHost, docs-mcp s'installe comme composant optionnel du paquet lasuite-docs_ynh.
Outils
| Outil | Rôle |
|---|---|
search_documents |
recherche plein texte (titres + contenus) dans les documents accessibles |
list_documents |
documents de premier niveau |
get_document_tree |
arborescence (complète ou sous un document) |
read_document |
contenu Markdown d'un document |
create_document |
crée un document ou sous-document depuis du Markdown |
append_to_document |
ajoute du Markdown à la fin d'un document |
replace_document_content |
réécrit tout le contenu (paragraphes inchangés conservés ; restauration par le panneau Versions) |
rename_document |
change le titre |
Les modifications se fusionnent avec les frappes des personnes qui éditent en même temps et sont
attribuées à l'utilisateur connecté. Elles demandent l'action edit-content de Docs, absente de Docs
d'origine : patch 0004 du paquet lasuite-docs_ynh. Aucun outil ne supprime de document.
Prérequis côté Docs et fournisseur OIDC
- Docs ≥ 4 avec l'API externe activée en mode resource server
(
OIDC_RESOURCE_SERVER_ENABLED=True,EXTERNAL_APIouvrant au minimumdocuments:list, retrieve, create, children, formatted_content, plusedit_content, partial_updatepour modifier), etCONVERSION_UPLOAD_ENABLEDavec.mdautorisé pour la création. - Un client OIDC pour docs-mcp, avec l'URL de retour
<PUBLIC_URL>/auth/callbacket le scopeoffline_accessautorisé. Docs doit accepter les jetons de ce client (OIDC_RS_ALLOWED_AUDIENCES). - Avec Dex : Docs a besoin d'un backend d'introspection adapté (Dex ne renvoie pas
scope) ; le paquet YunoHost le fournit.
Installation autonome
uv sync --no-dev # ou : pip install .
docs-mcp # écoute sur HOST:PORT (127.0.0.1:8790 par défaut)
| Variable | Obligatoire | Description |
|---|---|---|
DOCS_URL |
oui | URL de Docs, ex. https://docs.example.org |
OIDC_CONFIG_URL |
oui | https://<idp>/.well-known/openid-configuration |
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET |
oui | client OIDC de docs-mcp |
PUBLIC_URL |
oui | URL publique du MCP, ex. https://docs.example.org/mcp |
JWT_SIGNING_KEY |
oui | ≥ 32 caractères aléatoires ; signe les jetons remis aux clients et chiffre le stockage |
DATA_DIR |
non | clients enregistrés et jetons (chiffrés) ; à sauvegarder |
HOST / PORT |
non | 127.0.0.1 / 8790 |
OIDC_SCOPES |
non | openid email profile offline_access |
nginx (MCP sous /mcp d'un domaine existant)
Les clients cherchent les métadonnées OAuth à la racine du domaine : il faut aussi relayer les
deux URL /.well-known/…/mcp.
location = /mcp { proxy_pass http://127.0.0.1:8790/; include mcp_proxy.conf; }
location ^~ /mcp/ { proxy_pass http://127.0.0.1:8790/; include mcp_proxy.conf; }
location ^~ /.well-known/oauth-protected-resource/mcp { proxy_pass http://127.0.0.1:8790; include mcp_proxy.conf; }
location ^~ /.well-known/oauth-authorization-server/mcp {
proxy_pass http://127.0.0.1:8790/.well-known/oauth-authorization-server; include mcp_proxy.conf;
}
# mcp_proxy.conf
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 300s;
Contrôle : POST https://<domaine>/mcp/ → 401 avec un en-tête www-authenticate ;
GET https://<domaine>/.well-known/oauth-authorization-server/mcp → 200.
Connecter un client
URL du serveur : https://<domaine>/mcp/. À la première connexion, le client ouvre une page
d'autorisation (« Allow Access »), puis la connexion habituelle du SSO. L'assistant agit ensuite
avec les droits de ce compte : il peut modifier tout document que ce compte peut modifier.
Claude Code
Pour tous les projets (portée user) :
claude mcp add --transport http --scope user docs https://<domaine>/mcp/
Puis, dans Claude Code : /mcp → docs → Authenticate.
- Sans
--scope user, le serveur n'est inscrit que pour le dossier courant (portéelocal), et une entrée locale de même nom l'emporte sur l'entrée globale. Pour garder une instance de test à côté, utiliser un autre nom (ex.docs-dev), ou retirer l'entrée locale :claude mcp remove docs -s local. - Vérification :
claude mcp list→docs: https://<domaine>/mcp/ (HTTP) - ✔ Connected.
Hermes
Sur la machine où tourne Hermes (-p <profil> si besoin, ex. -p dev) :
hermes mcp add docs --url https://<domaine>/mcp/ --auth oauth
- Hermes affiche un lien d'autorisation : l'ouvrir dans le navigateur de son poste et se connecter.
- Le navigateur finit sur
http://127.0.0.1:<port>/callback?code=…avec une page « Ce site est inaccessible » : c'est normal, ce port est sur la machine d'Hermes, pas sur le poste. Copier l'adresse complète depuis la barre d'adresse et la coller dans le terminal. Pour éviter cette page : avant d'ouvrir le lien, rediriger le port affiché depuis le poste (ssh -N -L <port>:127.0.0.1:<port> <utilisateur>@<machine-hermes>). - À « Enable all N tools? », répondre
y. - Contrôle :
hermes mcp test docsliste les outils. - Dans une conversation déjà ouverte (Telegram…) :
/reload-mcpcharge les outils sans redémarrer la passerelle.
Si les outils renvoient une erreur d'authentification plus tard : hermes mcp reauth docs.
Pour retirer un outil, par exemple replace_document_content : hermes mcp configure docs.
Autres clients
- Claude Desktop / claude.ai : Réglages → Connecteurs → Ajouter un connecteur personnalisé.
- VS Code :
.vscode/mcp.json→{"servers": {"docs": {"type": "http", "url": "https://<domaine>/mcp/"}}}. - Clients stdio uniquement :
npx mcp-remote https://<domaine>/mcp/.
En cas d'échec
« Docs authentication failed: reconnect this MCP server » alors que la connexion réussit : Docs
refuse le jeton. Dans le journal de Docs, Failed to validate token's claims indique un
OIDC_OP_URL différent de l'issuer annoncé par le fournisseur OIDC (attention à la /
finale : Dex sous un chemin, ex. https://exemple.org/dex, n'en a pas).
Le contenu lu par l'assistant est transmis au fournisseur du modèle utilisé par le client.
Développement
uv sync
uv run pytest
Licence : MIT.