Trackily Docs

MCP — Le protocole

Le Model Context Protocol est un standard JSON-RPC 2.0 publié par Anthropic en 2024. Il décrit comment un client LLM (Claude Desktop, Cursor, etc.) découvre et exécute des tools, lit des resources, et instancie des prompts exposés par un serveur tiers. Trackily implémente le transport "streamable HTTP" sur /mcp.

Pourquoi un protocole standardisé

Avant MCP, chaque agent LLM avait son propre format pour exposer des capabilities :

  • OpenAI : "function calling" JSON-Schema spécifique
  • Anthropic : "tool use" Anthropic-flavored
  • Google : "function declarations" Gemini-style
  • LangChain : structured tools avec décorateurs Python
  • Cursor / Zed / etc : intégrations ad-hoc

Conséquence : si tu écrivais un outil pour Cursor, tu devais le réécrire pour Claude Desktop, pour ton script Python, pour Zed… MCP unifie ça. Tu écris un serveur une fois, et tous les clients qui parlent MCP peuvent s'y connecter sans modification.

Côté serveur, MCP est explicite sur trois concepts :

  • Resources — données read-only adressées par URI (trackily://stats/dashboard, trackily://campaign/42). Le client peut les lire sans paramètre, comme un GET sur un fichier.
  • Tools — fonctions appelables, identifiées par un nom, avec un JSON-Schema décrivant les arguments. Peuvent muter l'état.
  • Prompts — templates de conversation paramétrables, exposés comme des "slash commands" côté client (ex: /brief, /scale-winners).

JSON-RPC 2.0 — les bases

JSON-RPC est un protocole RPC minimaliste sur JSON. Une requête :

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "list_campaigns",
    "arguments": { "limit": 5, "is_active": true }
  }
}

Une réponse réussie :

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "content": [
      { "type": "text", "text": "{ \"campaigns\": [...] }" }
    ],
    "isError": false
  }
}

Une réponse en erreur :

{
  "jsonrpc": "2.0",
  "id": 42,
  "error": {
    "code": -32602,
    "message": "Missing tool name"
  }
}

Codes d'erreur utilisés par Trackily :

Code Sens
-32700 Parse error (JSON invalide)
-32600 Invalid request (pas du JSON-RPC 2.0)
-32601 Method not found (méthode inconnue OU tool/resource inconnue)
-32602 Invalid params (paramètres manquants / mal typés)
-32603 Internal error (exception non gérée côté serveur)
-32001 Unauthorized (token manquant / invalide / expiré)
-32002 Forbidden — missing scope (le tool nécessite un scope que le token n'a pas)
-32003 Rate limited

Transport

Deux transports MCP existent :

  • stdio — le client lance le serveur comme un sous-process et communique sur stdin/stdout. Pratique pour les serveurs locaux (filesystem, calculatrice…).
  • streamable HTTP — le client POST sur un endpoint HTTP, le serveur répond en JSON. Optionnellement Server-Sent Events pour le streaming.

Trackily implémente streamable HTTP : ton instance est de toute façon déjà accessible sur le réseau, et tu ne veux pas que Claude Desktop spawn un sous-process pour t'y connecter.

Endpoint : POST /mcp sur ton domaine Trackily (ex: https://trackily.online/mcp).

Header d'auth : Authorization: Bearer tly_ap_<your_token>. Alternativement, ?token=tly_ap_… en query string (utile pour les clients qui ne savent pas set des headers en transport streamable).

Handshake initial

Le client commence toujours par initialize :

// Client → Server
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {},
    "clientInfo": { "name": "claude-desktop", "version": "1.4.2" }
  }
}

// Server → Client
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "resources": { "subscribe": false, "listChanged": false },
      "tools": { "listChanged": false },
      "prompts": { "listChanged": false },
      "logging": {}
    },
    "serverInfo": {
      "name": "Trackily Autopilot",
      "version": "1.0.0"
    },
    "instructions": "Trackily Autopilot — AI copilot for a self-hosted affiliate marketing tracker.\nOperator is French-speaking (reply in French unless asked otherwise).\n\nQUICK ROUTING — When the operator says...\n  \"mes stats\", \"KPIs\", \"dashboard\"          → read resource trackily://stats/dashboard\n  ..."
  }
}

Le champ instructions est important : c'est un grand bloc de texte que le serveur envoie au client, qui le injecte directement dans le system prompt du LLM. C'est là que Trackily explique au LLM les patterns courants ("quand l'opérateur dit X, appelle Y"), le contexte (operateur francophone, Tier-2, etc.). Tu peux le voir dans autopilot.js autour de la ligne 600.

Puis le client envoie la notification initialized (pas de réponse attendue) :

{ "jsonrpc": "2.0", "method": "notifications/initialized" }

À partir de là, le client peut appeler les méthodes du protocole.

Méthodes du protocole

Resources

// List
{ "jsonrpc": "2.0", "id": 2, "method": "resources/list" }

// Read
{ "jsonrpc": "2.0", "id": 3, "method": "resources/read",
  "params": { "uri": "trackily://stats/dashboard" } }

Les resources Trackily disponibles (chaque token voit seulement celles dont il a le scope) :

  • trackily://stats/dashboard — KPIs globaux
  • trackily://campaign/<id> — détail campagne
  • trackily://offer/<id> — détail offre
  • trackily://landing/<id> — détail landing
  • trackily://flow/<id> — détail flow
  • trackily://settings — config publique
  • et d'autres listées dans autopilot-resources.js

Tools

// List
{ "jsonrpc": "2.0", "id": 4, "method": "tools/list" }

// Call
{ "jsonrpc": "2.0", "id": 5, "method": "tools/call",
  "params": {
    "name": "list_campaigns",
    "arguments": { "limit": 5 }
  }
}

tools/list retourne les 181 tools (filtrés par scope du token), chacun avec son name, description, inputSchema. Le LLM utilise ces métadonnées pour décider quel tool appeler en fonction de ce que dit l'utilisateur.

Prompts

// List
{ "jsonrpc": "2.0", "id": 6, "method": "prompts/list" }

// Get (instancie le prompt avec des arguments → retourne un dialogue à injecter)
{ "jsonrpc": "2.0", "id": 7, "method": "prompts/get",
  "params": {
    "name": "brief",
    "arguments": { "window_hours": 24 }
  }
}

Trackily expose ~12 prompts, vus comme des slash commands côté Claude Desktop : /brief, /check, /pause-losers, /scale-winners, etc. Chacun chaîne plusieurs tools avec les bons defaults pour un workflow opérationnel donné.

Batched requests

JSON-RPC supporte les batches (array de requests). Trackily les gère :

[
  { "jsonrpc": "2.0", "id": 1, "method": "tools/call",
    "params": { "name": "list_campaigns", "arguments": {} } },
  { "jsonrpc": "2.0", "id": 2, "method": "tools/call",
    "params": { "name": "list_offers", "arguments": {} } }
]

Réponse : array dans le même ordre. Utile pour réduire le RTT quand un client a plusieurs reads indépendants à faire d'un coup.

Probing l'endpoint

Un GET /mcp (sans le POST JSON-RPC) retourne un payload de santé :

{
  "name": "Trackily Autopilot",
  "version": "1.0.0",
  "protocolVersion": "2025-06-18",
  "status": "ok",
  "docs": "/admin#autopilot"
}

Utile pour curl https://trackily.online/mcp et vérifier que l'endpoint est joignable, sans avoir besoin d'un token.

Différences entre MCP et REST classique

Aspect REST MCP
Découverte OpenAPI spec à parser séparément tools/list retourne tout en JSON-Schema
Auth varié (bearer, JWT, OAuth, etc.) bearer simple, géré par le client
Erreurs HTTP status + body custom codes JSON-RPC unifiés
Streaming SSE / WebSocket / poll streamable HTTP natif
Composition client compose à la main LLM compose grâce aux descriptions
Confirmation géré côté client Tier-2 codifié dans le contrat

MCP n'est pas "mieux" que REST en général — il est mieux pour les agents LLM. Trackily expose les deux : MCP pour les agents, REST/HTTP pour les intégrations classiques (cf. API).

Voir aussi