Conéctate al servidor de MCP de Developer Knowledge con los SDKs de MCP

Los SDKs oficiales del Protocolo de contexto del modelo (MCP) permiten que tus propias aplicaciones y agentes de IA se conecten de forma programática al servidor de MCP de Developer Knowledge. Usa un SDK de MCP cuando compiles un agente personalizado, un servicio de backend o tu propio servidor de MCP que necesite buscar y recuperar documentación oficial para desarrolladores de Google, en lugar de configurar un IDE existente o un asistente de codificación.

En esta guía, aprenderás a hacer lo siguiente:

  • Instalar el SDK de cliente de MCP para Python o TypeScript
  • Conectarte al servidor de MCP de Developer Knowledge con una clave de API o credenciales predeterminadas de la aplicación (ADC)
  • Llamar a las herramientas search_documents, get_documents y answer_query
  • Solucionar errores de autenticación, cuota y herramientas

Antes de comenzar

Antes de comenzar, completa las siguientes secciones.

Habilita la API y crea credenciales

Habilita la API de Developer Knowledge en tu proyecto de Google Cloud y crea las credenciales para tu método de autenticación. Para obtener instrucciones paso a paso, consulta Elige tu método de autenticación.

En los ejemplos de esta guía, se usa una clave de API. Para usar ADC en su lugar, consulta Autentica con credenciales predeterminadas de la aplicación.

Instala el SDK de MCP

Selecciona tu lenguaje de programación para instalar el SDK de cliente de MCP:

Python

En esta guía, se usa la versión 2 del SDK de MCP para Python, que requiere Python 3.10 o versiones posteriores. La versión 1.x del SDK usa diferentes nombres de clase y función, por lo que estos ejemplos no funcionan con ella:

pip install --upgrade "mcp>=2"

TypeScript

En esta guía, se usa el SDK de MCP para TypeScript con Node.js 18 o versiones posteriores:

npm install @modelcontextprotocol/sdk

Establece tu clave de API

Para evitar codificar de forma rígida tu clave de API en el código fuente, almacénala en una variable de entorno. Reemplaza YOUR_API_KEY por tu clave de API:

export DEVELOPERKNOWLEDGE_API_KEY="YOUR_API_KEY"

Conéctate al servidor

El servidor de MCP de Developer Knowledge usa el transporte HTTP transmisible en el siguiente extremo:

https://developerknowledge.googleapis.com/mcp

Para autenticarte, pasa tu clave de API en el encabezado HTTP X-Goog-Api-Key en cada solicitud. No pases la clave de API como un parámetro de consulta de URL.

En el siguiente ejemplo, se conecta al servidor y se enumeran las herramientas 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 conexión se realiza correctamente, el resultado muestra las tres herramientas:

Available tools: search_documents, answer_query, get_documents

Los ejemplos restantes de esta guía se ejecutan dentro del cliente conectado de esta sección. Los ejemplos de TypeScript usan await de nivel superior, por lo que debes ejecutarlos como módulos ES (por ejemplo, con npx tsx index.ts).

Llama a las herramientas

Cada herramienta muestra su resultado como contenido estructurado que coincide con el esquema de salida de la herramienta, por lo que puedes leer los campos directamente en lugar de analizar el texto. Para obtener los esquemas completos de entrada y salida, consulta la referencia de MCP.

Busca documentación

Llama a search_documents con una cadena query para recuperar los fragmentos de documentación más relevantes. Cada resultado contiene el fragmento content y el nombre del recurso parent del documento del que proviene:

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`);
}

Recupera documentos completos

Si un fragmento no contiene suficiente contexto, pasa uno o más valores parent a get_documents para recuperar el contenido completo de Markdown de cada página. Puedes solicitar hasta 20 documentos en una sola llamada. Debido a que varios fragmentos pueden provenir del mismo documento, primero quita los valores parent duplicados:

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);
}

Los documentos completos pueden ser grandes, por lo que debes llamar a get_documents solo cuando los fragmentos de búsqueda no sean suficientes. Para obtener más información, consulta Optimiza la ventana de contexto y el uso de tokens.

Genera una respuesta

Llama a answer_query para generar una respuesta basada en el corpus de Developer Knowledge. El resultado contiene el answerText y las references que se usaron para generarlo:

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'));

El campo references contiene nombres de recursos de documentos que puedes pasar a get_documents. El mismo documento puede aparecer más de una vez, por lo que debes quitar los duplicados antes de recuperar los documentos. La herramienta answer_query tiene una cuota más baja que las otras herramientas. Para obtener más información, consulta Cuotas y límites.

Autentica con credenciales predeterminadas de la aplicación

En lugar de una clave de API, puedes autenticarte con credenciales predeterminadas de la aplicación (ADC). ADC funciona con tus credenciales de usuario durante el desarrollo local y con cuentas de servicio cuando tu código se ejecuta en Google Cloud.

Cuando usas ADC, envía los siguientes encabezados en cada solicitud:

  • Authorization: Un token de acceso Bearer de OAuth 2.0 con el alcance https://www.googleapis.com/auth/cloud-platform.
  • X-Goog-User-Project: El ID del proyecto que tiene habilitada la API de Developer Knowledge y al que se le factura la cuota. Tu cuenta necesita el permiso serviceusage.services.use en este proyecto.

Los tokens de acceso vencen, por lo que los clientes de larga duración deben actualizarlos. En los siguientes ejemplos, se usan las bibliotecas de autenticación de Google para agregar un token actual a cada solicitud.

  1. Para configurar ADC para el desarrollo local, sigue los pasos de la pestaña ADC en Elige tu tipo de credencial de OAuth.

  2. Establece la variable de entorno GOOGLE_CLOUD_PROJECT en el proyecto que tiene habilitada la API de Developer Knowledge. En los ejemplos, se envía este ID del proyecto en el encabezado X-Goog-User-Project:

    export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
    
  3. Instala la biblioteca de autenticación de Google para tu lenguaje:

    Python

    pip install --upgrade google-auth requests
    

    TypeScript

    npm install google-auth-library
    
  4. Crea el cliente con ADC:

    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);
    

Soluciona errores

Los errores del servidor de MCP de Developer Knowledge llegan a tu código de dos maneras:

  • Errores de solicitud: Los errores de autenticación, permiso y cuota se muestran con un estado de error de HTTP, como 400, 403, o 429. Los SDKs los generan como excepciones: MCPError en Python y StreamableHTTPError en TypeScript. Detecta estas excepciones en tus llamadas a herramientas.
  • Errores de herramientas: cuando una herramienta se ejecuta, pero no puede completar la solicitud, el resultado tiene is_error (Python) o isError (TypeScript) establecido en true, y el campo content contiene una descripción de texto del problema. Verifica este campo antes de leer el contenido estructurado.

En el siguiente ejemplo, se controlan ambos tipos de errores:

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 muestra un error de cuota (429 RESOURCE_EXHAUSTED), vuelve a search_documents, que tiene una cuota más alta. Para obtener estrategias de reintento, incluida la retirada exponencial, consulta Manejo de errores y administración de cuotas. Para conocer las causas comunes de los errores de autenticación, consulta Errores de clave de API y Errores de OAuth y ADC.

¿Qué sigue?