Se connecter au serveur MCP Developer Knowledge à l'aide des SDK MCP

Les SDK officiels du protocole MCP (Model Context Protocol) permettent à vos propres applications et agents IA de se connecter par programmation au serveur MCP Developer Knowledge. Utilisez un SDK MCP lorsque vous créez un agent personnalisé, un service de backend ou votre propre serveur MCP qui doit rechercher et récupérer la documentation officielle pour les développeurs Google, plutôt que de configurer un IDE ou un assistant de codage existant.

Avec ce guide, vous allez pouvoir viser plusieurs objectifs :

  • Installer le SDK client MCP pour Python ou TypeScript
  • Se connecter au serveur MCP Developer Knowledge avec une clé API ou les identifiants par défaut de l'application (ADC)
  • Appeler les outils search_documents, get_documents et answer_query
  • Gérer les erreurs d'authentification, de quota et d'outil

Avant de commencer

Avant de commencer, suivez les étapes décrites dans les sections ci-dessous.

Activer l'API et créer des identifiants

Activez l'API Developer Knowledge dans votre projet Google Cloud et créez les identifiants pour votre méthode d'authentification. Pour obtenir des instructions détaillées, consultez Choisir une méthode d'authentification.

Les exemples de ce guide utilisent une clé API. Pour utiliser plutôt les identifiants par défaut de l'application, consultez S'authentifier avec les identifiants par défaut de l'application.

Installer le SDK MCP

Sélectionnez votre langage de programmation pour installer le SDK client MCP :

Python

Ce guide utilise la version 2 du SDK MCP Python, qui nécessite Python 3.10 ou une version ultérieure. La version 1.x du SDK utilise des noms de classes et de fonctions différents. Ces exemples ne fonctionnent donc pas avec cette version :

pip install --upgrade "mcp>=2"

TypeScript

Ce guide utilise le SDK MCP TypeScript avec Node.js 18 ou une version ultérieure :

npm install @modelcontextprotocol/sdk

Définir votre clé API

Pour éviter de coder en dur votre clé API dans le code source, stockez-la dans une variable d'environnement. Remplacez YOUR_API_KEY par votre clé API :

export DEVELOPERKNOWLEDGE_API_KEY="YOUR_API_KEY"

Se connecter au serveur

Le serveur MCP Developer Knowledge utilise le transport HTTP en flux continu au point de terminaison suivant :

https://developerknowledge.googleapis.com/mcp

Pour vous authentifier, transmettez votre clé API dans l'en-tête HTTP X-Goog-Api-Key de chaque requête. Ne transmettez pas la clé API en tant que paramètre de requête d'URL.

L'exemple suivant se connecte au serveur et liste les outils disponibles :

Python

import asyncio
import os

from mcp import Client
from mcp.client.streamable_http import (
    create_mcp_http_client,
    streamable_http_client,
)

MCP_URL = "https://developerknowledge.googleapis.com/mcp"

async def main() -> None:
    headers = {"X-Goog-Api-Key": os.environ["DEVELOPERKNOWLEDGE_API_KEY"]}

    async with create_mcp_http_client(headers=headers) as http_client:
        transport = streamable_http_client(MCP_URL, http_client=http_client)
        async with Client(transport) as client:
            tools = await client.list_tools()
            names = ", ".join(tool.name for tool in tools.tools)
            print("Available tools:", names)

if __name__ == "__main__":
    asyncio.run(main())

TypeScript

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import {
  StreamableHTTPClientTransport,
} from '@modelcontextprotocol/sdk/client/streamableHttp.js';

const apiKey = process.env.DEVELOPERKNOWLEDGE_API_KEY;
if (!apiKey) {
  throw new Error('Set the DEVELOPERKNOWLEDGE_API_KEY variable.');
}

const transport = new StreamableHTTPClientTransport(
  new URL('https://developerknowledge.googleapis.com/mcp'),
  { requestInit: { headers: { 'X-Goog-Api-Key': apiKey } } },
);

const client = new Client({ name: 'my-docs-agent', version: '1.0.0' });
await client.connect(transport);

const { tools } = await client.listTools();
console.log('Available tools:', tools.map((tool) => tool.name).join(', '));

await client.close();

Si la connexion réussit, la sortie liste les trois outils :

Available tools: search_documents, answer_query, get_documents

Les exemples restants de ce guide s'exécutent dans le client connecté de cette section. Les exemples TypeScript utilisent await de premier niveau. Exécutez-les donc en tant que modules ES (par exemple, avec npx tsx index.ts).

Appeler les outils

Chaque outil renvoie son résultat sous forme de contenu structuré qui correspond au schéma de sortie de l'outil. Vous pouvez ainsi lire directement les champs au lieu d'analyser le texte. Pour obtenir les schémas d'entrée et de sortie complets, consultez la documentation de référence sur le protocole MCP.

Rechercher de la documentation

Appelez search_documents avec une chaîne query pour récupérer les blocs de documentation les plus pertinents. Chaque résultat contient le content du bloc et le nom de ressource parent du document dont il provient :

Python

search = await client.call_tool(
    "search_documents",
    {"query": "How do I create a Cloud Storage bucket?"},
)
results = search.structured_content["results"]
for chunk in results[:3]:
    print(f"{chunk['parent']}\n{chunk['content'][:200]}...\n")

TypeScript

const search = await client.callTool({
  name: 'search_documents',
  arguments: { query: 'How do I create a Cloud Storage bucket?' },
});
const { results } = search.structuredContent as {
  results: { parent: string; id: string; content: string }[];
};
for (const chunk of results.slice(0, 3)) {
  console.log(`${chunk.parent}\n${chunk.content.slice(0, 200)}...\n`);
}

Récupérer des documents complets

Si un bloc ne contient pas suffisamment de contexte, transmettez une ou plusieurs valeurs parent à get_documents pour récupérer le contenu Markdown complet de chaque page. Vous pouvez demander jusqu'à 20 documents en un seul appel. Comme plusieurs blocs peuvent provenir du même document, supprimez d'abord les valeurs parent en double :

Python

names = list(dict.fromkeys(chunk["parent"] for chunk in results[:3]))
get = await client.call_tool("get_documents", {"names": names})
for document in get.structured_content["documents"]:
    print(f"{document['title']} ({document['uri']})")
    print(document["content"])

TypeScript

const names = [...new Set(results.slice(0, 3).map((c) => c.parent))];
const get = await client.callTool({
  name: 'get_documents',
  arguments: { names },
});
const { documents } = get.structuredContent as {
  documents: {
    name: string;
    uri: string;
    title: string;
    content: string;
  }[];
};
for (const document of documents) {
  console.log(`${document.title} (${document.uri})`);
  console.log(document.content);
}

Les documents complets peuvent être volumineux. N'appelez donc get_documents que lorsque les blocs de recherche ne suffisent pas. Pour en savoir plus, consultez Optimiser la fenêtre de contexte et l'utilisation des jetons.

Générer une réponse

Appelez answer_query pour générer une réponse basée sur le corpus Developer Knowledge. Le résultat contient le answerText et les references utilisés pour le générer :

Python

answer = await client.call_tool(
    "answer_query",
    {"query": "How do I create a Cloud Storage bucket?"},
)
print(answer.structured_content["answerText"])
for reference in answer.structured_content["references"]:
    print(reference)

TypeScript

const answer = await client.callTool({
  name: 'answer_query',
  arguments: { query: 'How do I create a Cloud Storage bucket?' },
});
const { answerText, references } = answer.structuredContent as {
  answerText: string;
  references: string[];
};
console.log(answerText);
console.log(references.join('\n'));

Le champ references contient des noms de ressources de document que vous pouvez transmettre à get_documents. Le même document peut apparaître plusieurs fois. Supprimez donc les doublons avant de récupérer les documents. L'outil answer_query a un quota inférieur à celui des autres outils. Pour en savoir plus, consultez Quotas et limites.

S'authentifier avec les identifiants par défaut de l'application

Au lieu d'une clé API, vous pouvez vous authentifier avec les identifiants par défaut de l'application (ADC). Les identifiants par défaut de l'application fonctionnent avec vos identifiants utilisateur lors du développement local et avec les comptes de service lorsque votre code s'exécute sur Google Cloud.

Lorsque vous utilisez ADC, envoyez les en-têtes suivants dans chaque requête :

  • Authorization: jeton d'accès OAuth 2.0 Bearer avec le champ d'application https://www.googleapis.com/auth/cloud-platform.
  • X-Goog-User-Project: ID du projet pour lequel l'API Developer Knowledge est activée et qui est facturé pour le quota. Votre compte doit disposer de l'autorisation serviceusage.services.use sur ce projet.

Les jetons d'accès expirent. Les clients de longue durée doivent donc les actualiser. Les exemples suivants utilisent les bibliothèques d'authentification Google pour ajouter un jeton actuel à chaque requête.

  1. Configurez les identifiants par défaut de l'application pour le développement local en suivant les étapes de l' ADC dans Choisir votre type d'identifiants OAuth.

  2. Définissez la variable d'environnement GOOGLE_CLOUD_PROJECT sur le projet pour lequel l'API Developer Knowledge est activée. Les exemples envoient cet ID de projet dans l'en-tête X-Goog-User-Project :

    export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
    
  3. Installez la bibliothèque d'authentification Google pour votre langage :

    Python

    pip install --upgrade google-auth requests
    

    TypeScript

    npm install google-auth-library
    
  4. Créez le client avec les identifiants par défaut de l'application :

    Python

    import os
    
    import google.auth
    import google.auth.transport.requests
    import httpx2  # Installed automatically with mcp>=2
    from mcp import Client
    from mcp.client.streamable_http import (
        create_mcp_http_client,
        streamable_http_client,
    )
    
    MCP_URL = "https://developerknowledge.googleapis.com/mcp"
    
    class GoogleCredentialsAuth(httpx2.Auth):
        """Adds a current ADC access token and quota project to requests."""
    
        def __init__(self, project_id: str) -> None:
            self.credentials, _ = google.auth.default(
                scopes=["https://www.googleapis.com/auth/cloud-platform"]
            )
            self.project_id = project_id
    
        def auth_flow(self, request):
            if not self.credentials.valid:
                self.credentials.refresh(
                    google.auth.transport.requests.Request()
                )
            request.headers["Authorization"] = (
                f"Bearer {self.credentials.token}"
            )
            request.headers["X-Goog-User-Project"] = self.project_id
            yield request
    
    async def main() -> None:
        auth = GoogleCredentialsAuth(os.environ["GOOGLE_CLOUD_PROJECT"])
        async with create_mcp_http_client(auth=auth) as http_client:
            transport = streamable_http_client(
                MCP_URL, http_client=http_client
            )
            async with Client(transport) as client:
                ...
    

    TypeScript

    import { GoogleAuth } from 'google-auth-library';
    import { Client } from '@modelcontextprotocol/sdk/client/index.js';
    import {
      StreamableHTTPClientTransport,
    } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
    
    const auth = new GoogleAuth({
      scopes: 'https://www.googleapis.com/auth/cloud-platform',
    });
    const projectId = process.env.GOOGLE_CLOUD_PROJECT;
    if (!projectId) {
      throw new Error('Set the GOOGLE_CLOUD_PROJECT variable.');
    }
    
    const transport = new StreamableHTTPClientTransport(
      new URL('https://developerknowledge.googleapis.com/mcp'),
      {
        // Add a current access token and the quota project to each request.
        fetch: async (url, init) => {
          const headers = new Headers(init?.headers);
          for (const [name, value] of await auth.getRequestHeaders()) {
            headers.set(name, value);
          }
          headers.set('X-Goog-User-Project', projectId);
          return fetch(url, { ...init, headers });
        },
      },
    );
    
    const client = new Client({ name: 'my-docs-agent', version: '1.0.0' });
    await client.connect(transport);
    

Gérer les erreurs

Les erreurs du serveur MCP Developer Knowledge atteignent votre code de deux manières :

  • Erreurs de requête : les erreurs d'authentification, d'autorisation et de quota sont renvoyées avec un état d'erreur HTTP, tel que 400, 403, ou 429. Les SDK les génèrent en tant qu'exceptions : MCPError en Python et StreamableHTTPError en TypeScript. Interceptez ces exceptions autour de vos appels d'outils.
  • Erreurs d'outil : lorsqu'un outil s'exécute, mais ne peut pas terminer la requête, le résultat est défini sur is_error (Python) ou isError (TypeScript) sur true, et le champ content contient une description textuelle du problème. Vérifiez ce champ avant de lire le contenu structuré.

L'exemple suivant gère les deux types d'erreurs :

Python

from mcp import MCPError

try:
    result = await client.call_tool(
        "search_documents", {"query": "Cloud Storage buckets"}
    )
except MCPError as error:
    print(f"Request failed ({error.code}): {error.message}")
else:
    if result.is_error:
        print("Tool error:", result.content)
    else:
        results = result.structured_content["results"]

TypeScript

import {
  StreamableHTTPError,
} from '@modelcontextprotocol/sdk/client/streamableHttp.js';

try {
  const result = await client.callTool({
    name: 'search_documents',
    arguments: { query: 'Cloud Storage buckets' },
  });
  if (result.isError) {
    console.error('Tool error:', result.content);
  } else {
    const { results } = result.structuredContent as {
      results: { parent: string; id: string; content: string }[];
    };
  }
} catch (error) {
  if (error instanceof StreamableHTTPError) {
    console.error(`Request failed (${error.code}): ${error.message}`);
  } else {
    throw error;
  }
}

Si answer_query renvoie une erreur de quota (429 RESOURCE_EXHAUSTED), revenez à search_documents, qui a un quota plus élevé. Pour connaître les stratégies de nouvelle tentative, y compris la temporisation de retransmission, consultez Gestion des erreurs et des quotas. Pour connaître les causes courantes des erreurs d'authentification, consultez Erreurs de clé API et Erreurs OAuth et ADC.

Étape suivante