Introduction aux Model Context Protocols (MCP)

2024-11-15

AIArchitectureProtocols

Introduction

Les Large Language Models (LLMs) ont révolutionné notre façon d’interagir avec l’intelligence artificielle, mais leur utilité reste limitée sans accès aux données et outils du monde réel. Les Model Context Protocols (MCP) émergent comme une solution standardisée pour connecter les LLMs à des sources de données externes, des APIs et des outils de manière sécurisée et structurée.

Dans cet article, nous allons explorer ce que sont les MCP, pourquoi ils sont importants, et comment ils transforment l’architecture des applications basées sur les LLMs.

Qu’est-ce qu’un Model Context Protocol ?

Définition

Un Model Context Protocol est un standard de communication qui permet aux LLMs d’interagir avec des sources de données et des outils externes de manière structurée. Il définit :

  • Format de communication : Comment les requêtes et réponses sont structurées
  • Authentification : Comment sécuriser l’accès aux ressources
  • Capabilities : Quelles fonctionnalités sont disponibles
  • Error handling : Comment gérer les erreurs et exceptions

Le problème qu’ils résolvent

Avant les MCP, chaque intégration était unique :

// Approche non standardisée
async function askLLMWithDatabase(prompt: string) {
  const dbData = await fetchFromDatabase();
  const weatherData = await fetchWeatherAPI();
  const filesData = await readLocalFiles();

  // Format custom pour chaque source
  const context = `
    Database: ${JSON.stringify(dbData)}
    Weather: ${JSON.stringify(weatherData)}
    Files: ${JSON.stringify(filesData)}

    User question: ${prompt}
  `;

  return await llm.complete(context);
}

Avec MCP, l’approche devient standardisée :

// Approche standardisée avec MCP
async function askLLMWithMCP(prompt: string) {
  const mcpClient = new MCPClient([
    new DatabaseMCP(),
    new WeatherMCP(),
    new FileSystemMCP(),
  ]);

  return await llm.complete(prompt, {
    context: mcpClient.getContext(),
    tools: mcpClient.getTools(),
  });
}

Architecture MCP

Structure de base

interface MCPServer {
  // Métadonnées du serveur
  info: {
    name: string;
    version: string;
    description: string;
  };

  // Capacités disponibles
  capabilities: {
    resources?: boolean;
    tools?: boolean;
    prompts?: boolean;
  };

  // Méthodes d'interaction
  listResources(): Promise<Resource[]>;
  readResource(uri: string): Promise<ResourceContent>;
  listTools(): Promise<Tool[]>;
  callTool(name: string, args: any): Promise<ToolResult>;
}

Exemple d’implémentation

class DatabaseMCP implements MCPServer {
  info = {
    name: 'postgresql-database',
    version: '1.0.0',
    description: 'PostgreSQL database access',
  };

  capabilities = {
    resources: true,
    tools: true,
  };

  async listResources() {
    return [
      { uri: 'db://users', name: 'Users table', type: 'database' },
      { uri: 'db://orders', name: 'Orders table', type: 'database' },
    ];
  }

  async readResource(uri: string) {
    const table = uri.replace('db://', '');
    const data = await this.query(`SELECT * FROM ${table} LIMIT 100`);
    return {
      uri,
      mimeType: 'application/json',
      text: JSON.stringify(data),
    };
  }

  async listTools() {
    return [
      {
        name: 'execute_query',
        description: 'Execute a SQL query',
        inputSchema: {
          type: 'object',
          properties: {
            query: { type: 'string' },
          },
          required: ['query'],
        },
      },
    ];
  }

  async callTool(name: string, args: any) {
    if (name === 'execute_query') {
      const result = await this.query(args.query);
      return {
        content: [{ type: 'text', text: JSON.stringify(result) }],
      };
    }
    throw new Error(`Unknown tool: ${name}`);
  }

  private async query(sql: string) {
    // Implémentation de la requête
  }
}

Types de ressources MCP

Resources

Les ressources sont des données accessibles en lecture :

interface Resource {
  uri: string;          // db://users, file://config.json
  name: string;         // Nom lisible
  description?: string; // Description optionnelle
  mimeType?: string;    // Type MIME du contenu
}

Tools

Les tools sont des fonctions exécutables :

interface Tool {
  name: string;
  description: string;
  inputSchema: JSONSchema; // JSON Schema pour validation
}

Prompts

Les prompts sont des templates réutilisables :

interface Prompt {
  name: string;
  description: string;
  arguments: Array<{
    name: string;
    description: string;
    required: boolean;
  }>;
}

Cas d’usage concrets

1. Assistant de développement

const devAssistant = new MCPClient([
  new GitHubMCP({ token: process.env.GITHUB_TOKEN }),
  new FileSystemMCP({ root: './src' }),
  new JiraMCP({ apiKey: process.env.JIRA_KEY }),
]);

// Le LLM peut maintenant :
// - Lire et créer des issues GitHub
// - Parcourir et modifier le code source
// - Créer et mettre à jour des tickets Jira

2. Analyse de données business

const businessAnalyst = new MCPClient([
  new PostgreSQLMCP({ connection: dbConfig }),
  new GoogleSheetsMCP({ credentials: googleCreds }),
  new SlackMCP({ token: slackToken }),
]);

// Le LLM peut :
// - Interroger la base de données
// - Lire et écrire dans Google Sheets
// - Poster des résumés dans Slack

3. Automatisation DevOps

const devopsAgent = new MCPClient([
  new KubernetesMCP({ kubeconfig: k8sConfig }),
  new DatadogMCP({ apiKey: datadogKey }),
  new PagerDutyMCP({ token: pdToken }),
]);

// Le LLM peut :
// - Monitorer les pods Kubernetes
// - Analyser les métriques Datadog
// - Créer des incidents PagerDuty

Sécurité et bonnes pratiques

Principe de moindre privilège

const mcp = new FileSystemMCP({
  root: './data',           // Restreindre au répertoire data
  readOnly: true,           // Lecture seule
  allowedExtensions: ['.txt', '.json'], // Fichiers autorisés
});

Validation des entrées

async callTool(name: string, args: any) {
  // Valider les arguments
  const schema = this.getToolSchema(name);
  const validation = validate(args, schema);

  if (!validation.valid) {
    throw new Error('Invalid arguments');
  }

  // Sanitize les inputs
  const sanitized = sanitizeInput(args);

  return await this.executeTool(name, sanitized);
}

Rate limiting

class RateLimitedMCP implements MCPServer {
  private limiter = new RateLimiter({
    tokensPerInterval: 10,
    interval: 'minute',
  });

  async callTool(name: string, args: any) {
    await this.limiter.removeTokens(1);
    return await this.executeToolInternal(name, args);
  }
}

L’écosystème MCP

Serveurs MCP populaires

  • @modelcontextprotocol/server-filesystem : Accès au système de fichiers
  • @modelcontextprotocol/server-postgres : Base de données PostgreSQL
  • @modelcontextprotocol/server-github : API GitHub
  • @modelcontextprotocol/server-slack : Intégration Slack

Clients MCP

  • Claude Desktop : Support natif des MCP
  • Custom implementations : Via les SDKs TypeScript/Python

Créer son propre serveur

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new Server({
  name: 'my-custom-mcp',
  version: '1.0.0',
}, {
  capabilities: {
    resources: {},
    tools: {},
  },
});

// Définir les ressources
server.setRequestHandler('resources/list', async () => ({
  resources: [
    { uri: 'custom://resource', name: 'My Resource' },
  ],
}));

// Définir les tools
server.setRequestHandler('tools/list', async () => ({
  tools: [
    { name: 'my_tool', description: 'Does something' },
  ],
}));

// Lancer le serveur
const transport = new StdioServerTransport();
await server.connect(transport);

Conclusion

Les Model Context Protocols représentent une évolution majeure dans l’architecture des applications AI. En standardisant la façon dont les LLMs accèdent aux données et outils externes, ils ouvrent la voie à des intégrations plus robustes, sécurisées et maintenables.

L’adoption des MCP permet de :

  • Réduire la complexité d’intégration avec des sources multiples
  • Améliorer la sécurité via des abstractions standardisées
  • Faciliter la réutilisation de serveurs MCP à travers différents projets
  • Accélérer le développement en s’appuyant sur un écosystème croissant

Si vous construisez des applications basées sur les LLMs, explorer les MCP devrait être une priorité. Le standard est encore jeune, mais son potentiel est immense et l’écosystème se développe rapidement.

Pour aller plus loin :