# Plan de migration détaillé : metoro-io/mcp-golang vers mark3labs/mcp-go Ce document présente un plan de migration détaillé pour remplacer la bibliothèque metoro-io/mcp-golang par mark3labs/mcp-go dans le projet LocalAGI. Le plan est divisé en phases avec des exemples de code concrets pour chaque étape critique. ## Phase 1 : Préparation et analyse ### Étape 1.1 : Audit du code existant ```bash # Identifier tous les fichiers qui utilisent la bibliothèque metoro-io/mcp-golang grep -r "github.com/metoro-io/mcp-golang" --include="*.go" . # Identifier les fonctionnalités spécifiques utilisées grep -r "mcp\.Client" --include="*.go" . grep -r "transport/http" --include="*.go" . grep -r "transport/stdio" --include="*.go" . ``` ### Étape 1.2 : Création d'un environnement de test ```bash # Créer une branche pour la migration git checkout -b mcp-migration # Installer la nouvelle bibliothèque go get github.com/mark3labs/mcp-go ``` ## Phase 2 : Modification des importations et structures ### Étape 2.1 : Mise à jour des importations ```go // Avant import ( mcp "github.com/metoro-io/mcp-golang" "github.com/metoro-io/mcp-golang/transport/http" stdioTransport "github.com/metoro-io/mcp-golang/transport/stdio" ) // Après import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) ``` ### Étape 2.2 : Adaptation des structures ```go // Avant type mcpAction struct { mcpClient *mcp.Client inputSchema ToolInputSchema toolName string toolDescription string } // Après type mcpAction struct { // Nous devrons déterminer la structure équivalente dans mark3labs/mcp-go // Basé sur la documentation, cela pourrait ressembler à: mcpClient *mcp.Client // ou une structure équivalente toolDefinition *mcp.Tool toolName string toolDescription string } // Avant type ToolInputSchema struct { Type string `json:"type"` Properties map[string]interface{} `json:"properties,omitempty"` Required []string `json:"required,omitempty"` } // Après // Nous utiliserons directement les structures de schéma fournies par mark3labs/mcp-go ``` ## Phase 3 : Migration des clients et transports ### Étape 3.1 : Clients HTTP ```go // Avant transport := http.NewHTTPClientTransport("/mcp") transport.WithBaseURL(mcpServer.URL) if mcpServer.Token != "" { transport.WithHeader("Authorization", "Bearer "+mcpServer.Token) } client := mcp.NewClient(transport) // Après // Basé sur les exemples disponibles, nous pourrions avoir besoin de créer un client HTTP personnalisé // Voici une approche possible: httpClient := &http.Client{} // Configurer un client HTTP pour se connecter au serveur MCP // Note: L'API exacte dépendra de la façon dont mark3labs/mcp-go implémente les clients ``` ### Étape 3.2 : Clients STDIO ```go // Avant client := stdio.NewClient(a.options.mcpBoxURL) p, err := client.CreateProcess(a.context, mcpStdioServer.Cmd, mcpStdioServer.Args, mcpStdioServer.Env, a.Character.Name) read, writer, err := client.GetProcessIO(p.ID) transport := stdioTransport.NewStdioServerTransportWithIO(read, writer) mcpClient := mcp.NewClient(transport) // Après // Basé sur les exemples, mark3labs/mcp-go utilise une approche différente pour STDIO // Nous devrons adapter notre code pour utiliser l'API de mark3labs/mcp-go // Exemple possible: cmd := exec.Command(mcpStdioServer.Cmd, mcpStdioServer.Args...) cmd.Env = append(os.Environ(), mcpStdioServer.Env...) // Configurer les pipes stdin/stdout // Créer un client qui utilise ces pipes ``` ## Phase 4 : Migration des outils et actions ### Étape 4.1 : Définition des outils ```go // Avant // Les outils sont définis implicitement via les réponses du serveur MCP var inputSchema ToolInputSchema err = json.Unmarshal(dat, &inputSchema) generatedActions = append(generatedActions, &mcpAction{ mcpClient: client, toolName: t.Name, inputSchema: inputSchema, toolDescription: desc, }) // Après // Avec mark3labs/mcp-go, nous pouvons définir les outils plus explicitement // Exemple basé sur la documentation: calculatorTool := mcp.NewTool("calculate", mcp.WithDescription("Perform basic arithmetic operations"), mcp.WithString("operation", mcp.Required(), mcp.Description("The operation to perform"), mcp.Enum("add", "subtract", "multiply", "divide"), ), mcp.WithNumber("x", mcp.Required(), mcp.Description("First number"), ), mcp.WithNumber("y", mcp.Required(), mcp.Description("Second number"), ), ) ``` ### Étape 4.2 : Appel des outils ```go // Avant func (m *mcpAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) { resp, err := m.mcpClient.CallTool(ctx, m.toolName, params) if err != nil { return types.ActionResult{}, err } textResult := "" for _, c := range resp.Content { switch c.Type { case mcp.ContentTypeText: textResult += c.TextContent.Text + "\n" // ... } } return types.ActionResult{ Result: textResult, }, nil } // Après // Basé sur la documentation, l'appel d'outil pourrait ressembler à: func (m *mcpAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) { // Convertir params en format attendu par mark3labs/mcp-go args := make(map[string]interface{}) if err := params.Unmarshal(&args); err != nil { return types.ActionResult{}, err } // Créer une requête d'appel d'outil request := mcp.CallToolRequest{ Params: mcp.CallToolParams{ Name: m.toolName, Arguments: args, }, } // Appeler l'outil // Note: L'API exacte dépendra de la façon dont mark3labs/mcp-go implémente les appels d'outils result, err := m.mcpClient.CallTool(ctx, request) if err != nil { return types.ActionResult{}, err } // Traiter le résultat textResult := "" // Extraire le texte du résultat selon le format de mark3labs/mcp-go return types.ActionResult{ Result: textResult, }, nil } ``` ## Phase 5 : Gestion des résultats ```go // Avant textResult := "" for _, c := range resp.Content { switch c.Type { case mcp.ContentTypeText: textResult += c.TextContent.Text + "\n" case mcp.ContentTypeImage: xlog.Error("Image content not supported yet") case mcp.ContentTypeEmbeddedResource: xlog.Error("Embedded resource content not supported yet") } } // Après // Basé sur la documentation, le traitement des résultats pourrait ressembler à: textResult := "" // Supposons que result est de type *mcp.CallToolResult if result.Error != nil { return types.ActionResult{}, fmt.Errorf("tool error: %s", result.Error) } // Traiter les différents types de contenu for _, content := range result.Content { switch content.Type { case "text": textContent, ok := content.Content.(mcp.TextContent) if ok { textResult += textContent.Text + "\n" } case "image": xlog.Error("Image content not supported yet") case "embedded_resource": xlog.Error("Embedded resource content not supported yet") } } ``` ## Phase 6 : Gestion des sessions ```go // Avant // La gestion des sessions est limitée dans la bibliothèque actuelle // Après // Implémentation d'une gestion de session plus avancée avec mark3labs/mcp-go type MCPSession struct { id string notifChannel chan mcp.JSONRPCNotification isInitialized bool } // Implémenter l'interface ClientSession func (s *MCPSession) SessionID() string { return s.id } func (s *MCPSession) NotificationChannel() chan<- mcp.JSONRPCNotification { return s.notifChannel } func (s *MCPSession) Initialize() { s.isInitialized = true } func (s *MCPSession) Initialized() bool { return s.isInitialized } // Utilisation dans le code session := &MCPSession{ id: mcpServer.SessionId, notifChannel: make(chan mcp.JSONRPCNotification, 10), } if err := mcpServer.RegisterSession(context.Background(), session); err != nil { xlog.Error("Failed to register session", "error", err.Error()) } ``` ## Phase 7 : Adaptation de la fonction initMCPActions ```go // Avant func (a *Agent) initMCPActions() error { a.mcpActions = nil var err error generatedActions := types.Actions{} // MCP HTTP Servers for _, mcpServer := range a.options.mcpServers { transport := http.NewHTTPClientTransport("/mcp") transport.WithBaseURL(mcpServer.URL) if mcpServer.Token != "" { transport.WithHeader("Authorization", "Bearer "+mcpServer.Token) } client := mcp.NewClient(transport) actions, err := a.addTools(client) if err != nil { xlog.Error("Failed to add tools for MCP server", "error", err.Error()) } generatedActions = append(generatedActions, actions...) } // MCP STDIO Servers // ... a.mcpActions = generatedActions return err } // Après func (a *Agent) initMCPActions() error { a.mcpActions = nil var err error generatedActions := types.Actions{} // MCP HTTP Servers for _, mcpServer := range a.options.mcpServers { // Créer un client HTTP pour se connecter au serveur MCP // Note: L'implémentation exacte dépendra de l'API de mark3labs/mcp-go httpClient := &http.Client{} // Configurer les headers, l'URL, etc. // Initialiser le client // ... // Lister et ajouter les outils actions, err := a.addTools(client, &mcpServer) if err != nil { xlog.Error("Failed to add tools for MCP server", "error", err.Error()) } generatedActions = append(generatedActions, actions...) } // MCP STDIO Servers // Adapter pour utiliser l'API STDIO de mark3labs/mcp-go // ... a.mcpActions = generatedActions return err } ``` ## Phase 8 : Tests et validation ### Étape 8.1 : Tests unitaires ```go // Créer des tests unitaires pour chaque composant migré func TestMCPClientInitialization(t *testing.T) { // Tester l'initialisation du client avec mark3labs/mcp-go } func TestToolDefinition(t *testing.T) { // Tester la définition des outils avec mark3labs/mcp-go } func TestToolExecution(t *testing.T) { // Tester l'exécution des outils avec mark3labs/mcp-go } ``` ### Étape 8.2 : Tests d'intégration ```go // Créer des tests d'intégration pour vérifier que tout fonctionne ensemble func TestMCPServerIntegration(t *testing.T) { // Tester l'intégration complète avec un serveur MCP } ``` ## Phase 9 : Déploiement progressif ### Étape 9.1 : Déploiement en environnement de test ```bash # Déployer la version migrée en environnement de test docker build -t localagi-mcp-migration:test . docker run -d --name localagi-test localagi-mcp-migration:test ``` ### Étape 9.2 : Surveillance et correction ```bash # Surveiller les logs pour détecter d'éventuels problèmes docker logs -f localagi-test # Corriger les problèmes identifiés # ... # Redéployer docker build -t localagi-mcp-migration:test-v2 . docker run -d --name localagi-test-v2 localagi-mcp-migration:test-v2 ``` ### Étape 9.3 : Déploiement en production ```bash # Une fois les tests validés, déployer en production docker build -t localagi:latest . # Déployer selon votre processus habituel ``` ## Considérations supplémentaires ### Compatibilité avec les serveurs MCP existants Il est important de vérifier que mark3labs/mcp-go est compatible avec les serveurs MCP existants auxquels votre application se connecte. Si des différences de protocole existent, des adaptations supplémentaires pourraient être nécessaires. ### Documentation Documenter tous les changements effectués et les différences de comportement entre les deux bibliothèques. Cela facilitera la maintenance future et aidera les développeurs à comprendre les choix de migration. ### Formation Prévoir une session de formation pour les développeurs afin de les familiariser avec la nouvelle bibliothèque et ses particularités. ## Diagramme de séquence de la migration ```mermaid sequenceDiagram participant Dev as Développeur participant Git as Système de contrôle de version participant Test as Environnement de test participant Prod as Production Dev->>Git: Créer branche de migration Dev->>Git: Modifier importations Dev->>Git: Adapter structures Dev->>Git: Migrer clients HTTP Dev->>Git: Migrer clients STDIO Dev->>Git: Migrer définition des outils Dev->>Git: Migrer appel des outils Dev->>Git: Migrer gestion des résultats Dev->>Git: Migrer gestion des sessions Dev->>Git: Écrire tests unitaires Dev->>Git: Écrire tests d'intégration Git->>Test: Déployer en test Test->>Dev: Retour d'erreurs Dev->>Git: Corrections Git->>Test: Redéployer en test Test->>Dev: Validation Git->>Prod: Déployer en production ``` ## Conclusion Ce plan de migration détaillé devrait vous guider efficacement à travers le processus de remplacement de metoro-io/mcp-golang par mark3labs/mcp-go. La migration nécessitera des modifications significatives du code existant, mais les avantages potentiels en termes de maintenance, de fonctionnalités et de robustesse justifient cet effort. Les principales difficultés résident dans les différences d'API et la façon dont les transports et les outils sont configurés et utilisés. Une approche progressive, avec des tests approfondis à chaque étape, est recommandée pour minimiser les risques. N'hésitez pas à adapter ce plan en fonction des spécificités de votre projet et des découvertes faites pendant la migration.