Conception des connecteurs MCP
Ce chapitre décrit comment un service externe devient un ensemble
d'outils MCP dans Chatbotaurus. Le moteur est le crate forge-mcp. À la fin, vous saurez
écrire le manifeste d'un connecteur et ce que le contrôle de conformité UE en refuse.
Deux types de connecteurs
1. Connecteur déclaratif YAML (cas général)
Un fichier connectors/<nom>.yaml décrit le service et ses outils. Au
démarrage, forge-api lit le dossier désigné par la variable
CONNECTOR_CATALOGUE_DIR (par défaut ./connectors). Il enregistre
chaque connecteur dans le registre. Le fichier
connectors/TEMPLATE.yaml est un modèle à copier. Pas à pas : Créer votre premier
connecteur MCP. Le dossier n'est lu qu'au
démarrage : redémarrez forge-api après chaque modification (voir
Fichiers de configuration).
Exemple tiré de connectors/matomo.yaml, abrégé (l'URL par défaut y est remplacée par une adresse d'exemple) :
id: matomo
display_name: "Matomo Analytics"
base_url: "${MATOMO_URL:-https://matomo.exemple.eu}"
base_url_env: MATOMO_URL
auth:
type: query_token
param: token_auth
token_env: MATOMO_API_KEY
compliance:
data_residency: self-hosted
self_hosted: true
gdpr_compliant: true
license: "GPL-3.0"
gaia_x: true
timeout_ms: 30000
tools:
- name: get_visits_summary
description: "Matomo Reporting API VisitsSummary.get"
method: GET
path: "/index.php"
param_location: query
input_schema:
type: object
properties:
module: { type: string, default: "API" }
method: { type: string, default: "VisitsSummary.get" }
format: { type: string, default: "JSON" }
Champs principaux (structure HttpConnectorConfig,
crates/forge-mcp/src/connector/http.rs) :
| Champ | Rôle |
|---|---|
id, display_name | Identifiant unique et nom lisible |
base_url | URL de base ; ${VAR:-défaut} est résolu depuis l'environnement au démarrage |
base_url_env | Variable portant l'URL propre à un locataire (instance auto-hébergée par client) |
auth | Méthode d'authentification, discriminée par type |
compliance | Métadonnées de conformité UE, contrôlées à l'enregistrement |
timeout_ms | Délai de la requête (30 000 par défaut) |
cache_ttl_s | Cache de lecture des GET, désactivé à 0 (défaut) ; jamais actif dans un contexte locataire |
rate_limit_per_min | Plafond publié par l'amont, vérifié avant l'appel |
tools[] | name, description, method (GET, POST, PUT, PATCH, DELETE), path ({param} est remplacé par un argument), param_location (query, body ou path), input_schema (JSON Schema) |
Types d'authentification : none, bearer, api_key, basic,
query_token, jwt_exchange, oauth2, login_token, checksum, json_rpc_session. Les
fichiers YAML ne portent jamais de secret : ils nomment la variable
d'environnement qui le contient (token_env, key_env, entre autres).
Les outils sont exposés avec le préfixe de leur connecteur :
l'outil get_visits_summary du connecteur matomo s'appelle
matomo.get_visits_summary.
2. Connecteur natif Rust
Pour un protocole qui n'est pas du REST (par exemple l'XML-RPC d'Odoo,
crates/forge-mcp/src/connector/odoo_xmlrpc_client.rs) ou une
transformation lourde, on implémente le trait McpConnector
(crates/forge-mcp/src/connector/mod.rs) :
#[async_trait::async_trait]
pub trait McpConnector: Send + Sync + 'static {
fn id(&self) -> &str;
fn display_name(&self) -> &str;
fn compliance(&self) -> &EuCompliance;
async fn list_tools(&self) -> ForgeResult<Vec<ToolDefinition>>;
async fn execute(
&self,
tool_name: &str,
arguments: serde_json::Value,
) -> ForgeResult<Vec<ContentBlock>>;
async fn health_check(&self) -> ForgeResult<ConnectorHealth>;
// ... plus des méthodes avec valeur par défaut (voir le fichier)
}
Un connecteur natif est enregistré dans le ConnectorRegistry au même
titre qu'un connecteur YAML.
Contrôle de conformité UE
ConnectorRegistry::register appelle EuCompliance::validate. Un
connecteur dont gdpr_compliant vaut false, ou dont la résidence des
données n'est pas européenne (ou self-hosted), est rejeté au démarrage
et journalisé. La classification de la résidence est centralisée dans
crates/forge-mcp/src/connector/residence.rs. Côté exécution, chaque
appel de serveur repasse par la fonction unique
forge_core::compliance::is_server_allowed.
Cycle de vie
- Enregistrement : au démarrage, le
CatalogueLoadercharge les YAML et le registre reçoit aussi les connecteurs natifs. - Découverte : le client MCP appelle
tools/listsurPOST /api/v1/mcp. Le catalogue se consulte aussi parGET /api/v1/mcp/catalogue. - Exécution : le client appelle
tools/callsur la même route. - Résultat : le connecteur renvoie des blocs de contenu MCP
(
ContentBlock).
Figure 3 : du connecteur à l'outil MCP, avec le contrôle de conformité UE à l'enregistrement et à chaque appel.
Identifiants et secrets
- Les identifiants tiers d'un locataire sont chiffrés en AES-256-GCM
avant stockage. Au démarrage,
crates/forge-api/src/connector_credential_env.rsles déchiffre et les publie dans les variables d'environnement que lisent les connecteurs. Les locataires réglementés peuvent utiliser une couche OpenBao. - À chaque requête, les secrets du seul locataire appelant sont
installés pour la durée de l'appel. Avec
FORGE_MULTI_TENANT_STRICT=1, le chargement global au démarrage est sauté et aucun connecteur ne retombe sur les identifiants globaux du déploiement.
Sécurité
- SSRF : une URL de base fournie par un locataire (
base_url_env) est contrôlée en deux temps avant tout appel réseau. Premier temps : analyse de l'URL (schéma, adresse, hôtes internes). Second temps : résolution DNS avec refus des adresses privées. Une violation renvoieForbiddenavec le motifSSRF_BLOCKED. Ce contrôle ne s'applique qu'aux URL fournies par un locataire : l'URL du YAML ou de l'environnement de l'opérateur n'y est pas soumise. Aucune option d'exploitation ne le désactive ; seule la compilation des tests le lève. - Actions irréversibles : un outil irréversible ne s'exécute qu'après
une approbation humaine explicite, limitée au nom exact de l'outil
(
crates/forge-mcp/src/connector/human_authorization.rs). Un outil destructif n'est jamais autorisable par cette voie. - Un connecteur peut être limité à la lecture : le connecteur Matomo, par exemple, ne publie que des outils de rapport.
Bonnes pratiques
- Connexions : un seul client
reqwestréutilisé par connecteur. - Limites amont : déclarez
rate_limit_per_minquand l'API publie un plafond ; une réponse 429 est renvoyée enRATE_LIMITEDavec sonRetry-After. - Cache :
cache_ttl_sconvient aux données publiques en lecture seule ; laissez-le à 0 pour tout le reste. - Données publiques : le champ
groundedfait accompagner chaque réponse de sa source (source_url,retrieved_at).
Voir aussi
- Créer votre premier connecteur MCP : écrire, valider et tester un manifeste pas à pas
- Connecteurs MCP : ce qui est mesuré et comment un connecteur est chargé
- Routes MCP (Streamable HTTP) : découverte et appel des outils, catalogue consultable par l'API
- Gestion des erreurs : codes renvoyés par un connecteur : délai, limite amont, SSRF
- Fichiers de configuration : où vivent les manifestes et comment l'environnement y est interpolé