Sécurité d'enveloppe
Anti-patterns de débordement pour les outils list_* de VantagePeers — fields=lite, plafond limit 200, anti-patterns à éviter, et pourquoi chaque outil list_* adopte par défaut une forme d'enveloppe sûre.
Sécurité d'enveloppe
Le serveur MCP VantagePeers applique un ensemble cohérent de protections sur chaque réponse list_* pour éviter que les payloads de réponse ne dépassent le budget de contexte de l'agent appelant. Cette page documente les protections, le système de projection fields=lite|full, le plafond strict de 200 lignes, et les anti-patterns ayant causé des incidents en production.
Les trois protections
Chaque outil list_* de VantagePeers applique trois couches de protection :
-
Plafond strict de lignes (200) : L'argument
limitest validé commez.number().int().min(1).max(200).optional(). Toute valeur supérieure à 200 est rejetée au niveau MCP avant d'atteindre Convex. La valeur par défaut quand aucunlimitn'est fourni est de 20 lignes. -
Projection
fields=lite: Tous les outilslist_*acceptentfields: "lite" | "full". La projectionliteretourne au maximum 6 champs par ligne, gardant les pages compactes même pour les documents avec un grand contenu texte (ex. mémoires avec un longcontent, briefings avec de longs tableauxdecisions). -
Limite douce de 50 Ko (
enforceEnvelopeCap) : Après projection des lignes, le serveur mesure la taille JSON sérialisée de l'enveloppe. Si le résultat dépasse 50 000 octets, le serveur divise le nombre de lignes de moitié et mesure à nouveau, en répétant jusqu'à ce que le payload soit dans les limites. Ce garde-fou existe en plus du plafond de lignes — il protège contre les lignes schéma complet avec du texte embarqué volumineux.
fields=lite vs fields=full
| Valeur | Champs retournés | Taille typique par ligne |
|---|---|---|
"lite" | _id, _creationTime, plus 2 à 4 champs d'affichage | ~200–400 octets |
"full" | Tous les champs du schéma incluant le contenu texte complet | ~2 000–20 000 octets |
La valeur par défaut est "full". Pour toute boucle traitant plus d'une page, toujours passer fields: "lite".
Exemple de projection lite pour list_tasks :
{
"_id": "k17abc...",
"_creationTime": 1751020800000,
"title": "Corriger la pagination list_memories",
"status": "done",
"assignedTo": "sigma",
"priority": "urgent"
}La même tâche en mode full inclut description (potentiellement des centaines de caractères), completionNote, blockers, dependsOn, missionId, orgId, createdBy, updatedAt, et tous les autres champs du schéma.
Comportement du plafonnement de limite
La fonction clampLimit dans mcp-server/src/paging.ts applique ces règles dans l'ordre :
- Si
limitest indéfini, retournerDEFAULT_LIMIT(20 pour la plupart des outils). - Si
limit < 1, retourner 1. - Si
limit > MAX_LIMIT(200), retourner 200. - Sinon retourner
limitinchangé.
Cela signifie qu'un appelant ne peut pas accidentellement demander un résultat non borné en passant une limit très grande. Le plafond de 200 lignes est appliqué quel que soit ce que l'appelant envoie.
Anti-patterns
Les motifs suivants ont causé des incidents en production vérifiés. Chacun est interdit dans toutes les implémentations de serveur MCP VantageOS.
Pourquoi chaque outil list_* adopte par défaut une forme d'enveloppe sûre
L'objectif de conception est qu'un appelant ne passant aucun argument reçoive quand même une réponse sûre. La combinaison par défaut limit: 20 et fields: "full" produit au maximum ~400 Ko pour les outils les plus riches en documents, bien dans le budget de contexte sûr pour tous les clients supportés (Claude.ai, Claude Code, ChatGPT, Codex).
Pour les boucles de parcours en production — balayage de toutes les tâches d'une BU, export d'un namespace complet, etc. — toujours surcharger avec limit: 200 et fields: "lite" pour maximiser le débit sans risque.
Référence des exports paging.ts
L'utilitaire partagé mcp-server/src/paging.ts centralise toute la logique de pagination. Ses exports clés :
| Export | Type | Description |
|---|---|---|
pagingArgsSchema | z.ZodObject | Schéma Zod partagé : { limit, cursor, fields } |
DEFAULT_LIMIT | 50 | Valeur de repli de clampLimit quand undefined est fourni |
MAX_LIMIT | 200 | Plafond strict appliqué par clampLimit |
ENVELOPE_TARGET_BYTES | 50 000 | Limite douce en octets pour enforceEnvelopeCap |
clampLimit | fonction | Plafonne limit à [1, MAX_LIMIT], par défaut DEFAULT_LIMIT |
encodeCursor | fonction | CursorPayload → chaîne base64url |
decodeCursor | fonction | `chaîne base64url → CursorPayload |
enforceEnvelopeCap | fonction | Divise les lignes de moitié jusqu'à rester sous ENVELOPE_TARGET_BYTES |
L'export DEFAULT_LIMIT de clampLimit est 50. Les outils individuels surchargent cela à 20 via DEFAULT_PAGING.limit = 20 dans applyPagingDefaults. Quand aucune limite n'est fournie à un outil liste spécifique, la valeur par défaut de l'outil de 20 s'applique — pas la constante DEFAULT_LIMIT.
Références croisées
- Pagination par curseur — contrat d'enveloppe, motif de boucle, matrice de couverture
- README du dépôt principal : vantageos-agency/vantage-peers
- npm du serveur MCP : vantage-peers-mcp
- Doctrine MCP Tools Standard : runbook VantageRegistry
kd750j7z7tqre6hxqmfsa8s9ed89erng - PR de correction Day-114 : #978
- PR de doctrine : #980