---
contentId: 5326cb9f-fd51-4d43-bff8-2cee2a995d89
title: "Un serveur Model Context Protocol (MCP) pour mon site web"
description: "Explorer le potentiel du Model Context Protocol (MCP) en l'intégrant dans mon flux de travail et en optimisant les opérations backend de mon site web."
date: 2025-05-10
---

**Les Modèles de Langage de Grande Taille** (LLMs) sont omniprésents ces jours-ci. Le rythme des avancées est stupéfiant, et il est difficile de suivre les mises à jour constantes, c'est tout simplement fou !

Au milieu de cette avalanche d'informations, j'ai trouvé le concept d'un **agent**, particulièrement avec le [**Model Context Protocol**](https://modelcontextprotocol.io/introduction) (MCP), particulièrement intrigant et prometteur. J'ai donc décidé d'expérimenter avec cela et de voir comment cela pourrait améliorer mon flux de travail.

> [!NOTE]
> Vous préférez regarder une vidéo ? Consultez la version vidéo de cet article sur [YouTube](https://www.youtube.com/watch?v=NnLIYresumQ).

## Le défi des identifiants

Actuellement, mon site web se compose de deux composants clés :

- Le **frontend**, construit avec [**VitePress**](https://vitepress.dev), où chaque page est un fichier Markdown.
- Le **backend**, une application [**Laravel**](https://laravel.com) qui ajoute des fonctionnalités supplémentaires.

Pour garantir que le bon contenu est servi et stocké pour chaque page frontend, je dois partager un identifiant entre ces composants. Chaque fichier Markdown a un identifiant unique dans son frontmatter.

```md [src/posts/a-simple-markdown-file.md]
---
id: 1
title:
description:
---
```

Cet identifiant récupère le contenu correspondant du backend lors du chargement de la page. Pour que tout fonctionne sans accroc, le backend doit également stocker cet identifiant dans la base de données. Sans cela, il est impossible de maintenir une base de données relationnelle fonctionnelle, car ma base de données comprend une table `posts`.

Pour obtenir ces identifiants, le backend récupère régulièrement un fichier JSON généré au moment de la construction par **VitePress**. Ce fichier contient tous les fichiers Markdown et leur frontmatter. Cette approche fonctionne bien, mais il y a un hic.

Lorsque j'écris un nouveau fichier Markdown, je dois accéder à la page d'administration du backend, trier la table `posts` par la colonne `id`, et trouver le dernier identifiant utilisé. Ensuite, j'écris cet identifiant, incrémenté de un, dans le fichier sur lequel je travaille. C'est une tâche fastidieuse qui n'apporte aucune réelle valeur et consomme du temps, un processus que je déteste profondément.

Simultanément, j'utilise fréquemment les **LLMs** pour améliorer le contenu technique de mes articles, y compris le **SEO**, la grammaire et l'orthographe. Cela m'a amené à me demander : **Puis-je intégrer un agent dans le processus LLM actuel pour m'assurer que l'identifiant est toujours correct ?**

_Oui !_

## Mise en place d'une nouvelle route backend

Les serveurs MCP ne sont pas mystiques ; ils fournissent un moyen pour les LLMs d'interagir avec des sources de données. Ainsi, je dois créer une route API backend pour renvoyer le prochain identifiant de publication. Cette route sera accessible par le serveur MCP via la capacité d'outils.

Créer cette route API dans mon application **Laravel** et configurer un contrôleur invocable est assez simple :

```php [routes/api.php]
use App\Http\Controllers\NextPostIdController;
use Illuminate\Support\Facades\Route;

Route::get('posts/next-id', NextPostIdController::class)
    ->name('posts.next-id');
```

```php [app/Http/Controllers/NextPostIdController.php]
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\JsonResponse;

class NextPostIdController extends Controller
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(): JsonResponse
    {
        $nextPostId = Post::max('id') + 1;

        return response()->json(['next_post_id' => $nextPostId]);
    }
}
```

Cette configuration, bien que simple, est cruciale pour un serveur MCP efficace.

## Configuration du serveur MCP

Pour le serveur MCP, j'utilise le [**SDK TypeScript**](https://github.com/modelcontextprotocol/typescript-sdk) officiel. C'est simple et très efficace.

```ts [src/index.ts]
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import {
  CallToolRequestSchema,
  ListToolsRequestSchema
} from '@modelcontextprotocol/sdk/types.js'
import { ofetch } from 'ofetch'
import { z } from 'zod'
import { zodToJsonSchema } from 'zod-to-json-schema'

const server = new Server(
  {
    name: 'mcp.soubiran.dev',
    version: '0.0.0'
  },
  {
    capabilities: {
      tools: {}
    }
  }
)

const GetNextId = z.object({})

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'next_post_id',
        description: 'Obtenir le prochain ID de publication pour un post sur soubiran.dev',
        inputSchema: zodToJsonSchema(GetNextId),
      },
    ]
  }
})

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === 'next_post_id') {
    try {
      const data = await ofetch<{ next_post_id: number }>('http://localhost:8000/api/posts/next-id')

      return {
        content: [{
          type: 'text',
          text: data.next_post_id
        }]
      }
    }
    catch (error) {
      throw new Error('Erreur lors de la récupération du prochain ID de post')
    }
  }

  throw new Error('Outil inconnu')
})

const transport = new StdioServerTransport()
await server.connect(transport)
```

Ce code établit un serveur MCP STDIO avec deux gestionnaires de requêtes clés :

1. Le gestionnaire `ListToolsRequest` renvoie les outils disponibles à l'agent. Actuellement, il y a un outil : `next_post_id`.
2. Le gestionnaire `CallToolRequest` est activé lorsque l'agent utilise l'outil. Il appelle la route API backend pour récupérer le prochain ID de post.

Le processus d'appel d'outil est simple ; il récupère le prochain ID de post depuis la route API backend que j'ai définie, en utilisant la bibliothèque `ofetch` pour plus de facilité. L'ID de publication est ensuite renvoyé sous forme de nombre.

Par conséquent, tout agent invoquant cet outil recevra le prochain ID de publication en réponse dans son contexte. Cela me permet de rédiger des fichiers Markdown sans me soucier des IDs de post, l'agent s'en occupe parfaitement !

> [!NOTE]
> Pour le code complet, regardez la [vidéo sur YouTube](https://www.youtube.com/watch?v=NnLIYresumQ).

## Ça fonctionne ?

Oui, cela fonctionne parfaitement ! Voyez-le en action :

<figure>
  <video autoplay loop muted playsinline>
    <source src="https://images.soubiran.dev/posts/a-model-context-protocol-mcp-server-for-my-website/working-mcp-soubiran-dev.mp4" type="video/mp4">
  </video>
  <figcaption>Demande à l'agent d'améliorer un fichier et d'insérer automatiquement l'ID correct en utilisant le prochain ID de publication du serveur MCP.</figcaption>
</figure>

Avec ce **serveur MCP** opérationnel, je peux désormais interagir avec mes fichiers Markdown tout en fournissant un contexte à l'agent. Cela rationalise mon flux de travail, me permettant de me concentrer sur le contenu plutôt que sur les détails techniques. Mon objectif ultime est d'accélérer mon processus d'écriture, le rendant plus efficace et agréable, et ce logiciel est une étape vers cet objectif.

Je suis impressionné par la facilité d'utilisation du SDK MCP et son intégration avec **VS Code**. Il permet de créer rapidement de nouveaux agents et d'incorporer facilement le flux de travail.

Je suis impatient d'explorer les possibilités que cela ouvre. L'avenir des agents est prometteur, et je recommande vivement d'expérimenter avec eux !
