Как подключиться к MCP-серверу Developer Knowledge с помощью SDK MCP

Официальные SDK-пакеты Model Context Protocol (MCP) позволяют вашим приложениям и ИИ-агентам подключаться к MCP-серверу Developer Knowledge программно. Используйте MCP SDK, если вы создаете собственного агента, бэкенд-сервис или MCP-сервер, которому нужно искать и получать официальную документацию для разработчиков Google Developers, а не настраивать существующую интегрированную среду разработки или помощь в программировании.

Из этого руководства вы узнаете, как:

  • Установите клиентский SDK MCP для Python или TypeScript.
  • Подключитесь к MCP-серверу Developer Knowledge с помощью ключа API или учетных данных по умолчанию для приложений (ADC).
  • Вызовите инструменты search_documents, get_documents и answer_query.
  • Обрабатывать ошибки аутентификации, квоты и инструментов.

Подготовка

Прежде чем начать, выполните действия, описанные в разделах ниже.

Как включить API и создать учетные данные

Включите Developer Knowledge API в проекте Google Cloud и создайте учетные данные для выбранного способа аутентификации. Пошаговые инструкции приведены в статье Выбор способа аутентификации.

В примерах в этом руководстве используется ключ API. Чтобы использовать ADC, ознакомьтесь со статьей Аутентификация с помощью Application Default Credentials.

Установите MCP SDK

Выберите язык программирования, чтобы установить клиентский SDK MCP:

Python

В этом руководстве используется версия 2 MCP Python SDK, для которой требуется Python 3.10 или более поздней версии. В версии 1.x SDK используются другие названия классов и функций, поэтому приведенные ниже примеры не будут работать.

pip install --upgrade "mcp>=2"

TypeScript

В этом руководстве используется MCP TypeScript SDK с Node.js 18 или более поздней версии.

npm install @modelcontextprotocol/sdk

Как задать ключ API

Чтобы не встраивать ключ API в исходный код, храните его в переменной среды. Замените YOUR_API_KEY своим ключом API:

export DEVELOPERKNOWLEDGE_API_KEY="YOUR_API_KEY"

Подключитесь к серверу

MCP-сервер Developer Knowledge использует транспорт Streamable HTTP в следующей конечной точке:

https://developerknowledge.googleapis.com/mcp

Чтобы выполнить аутентификацию, передавайте ключ API в HTTP-заголовке X-Goog-Api-Key при каждом запросе. Не передавайте ключ API в качестве параметра запроса URL.

В примере ниже показано, как подключиться к серверу и посмотреть список доступных инструментов:

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

Если подключение установлено, в выходных данных будут перечислены три инструмента:

Available tools: search_documents, answer_query, get_documents

Остальные примеры в этом руководстве выполняются в подключенном клиенте из этого раздела. В примерах TypeScript используется await верхнего уровня, поэтому запускайте их как модули ES (например, с помощью npx tsx index.ts).

Вызов инструментов

Каждый инструмент возвращает результат в виде структурированного контента, соответствующего схеме вывода инструмента, поэтому вы можете читать поля напрямую, а не анализировать текст. Полные схемы входных и выходных данных приведены в справочной документации по MCP.

Поиск по документации

Вызовите search_documents со строкой query, чтобы получить наиболее релевантные фрагменты документации. Каждый результат содержит фрагмент content и parent название ресурса документа, из которого он взят:

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

Получение полных документов

Если фрагмент не содержит достаточного контекста, передайте одно или несколько значений parent в get_documents, чтобы получить полное содержимое Markdown для каждой страницы. За один звонок можно запросить до 20 документов. Поскольку несколько фрагментов могут быть взяты из одного документа, сначала удалите повторяющиеся значения parent:

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

Полные документы могут быть большими, поэтому вызывайте get_documents, только если фрагментов поиска недостаточно. Подробнее о том, как оптимизировать окно контекста и использование токенов…

Как сгенерировать ответ

Вызовите answer_query, чтобы сгенерировать ответ на основе корпуса знаний для разработчиков. Результат содержит answerText и references, использованные для его создания:

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

Поле references содержит названия ресурсов документов, которые можно передать в get_documents. Один и тот же документ может появляться несколько раз, поэтому перед извлечением документов удалите дубликаты. Для инструмента answer_query установлена более низкая квота, чем для других инструментов. Подробнее о квотах и ограничениях…

Как выполнить аутентификацию с помощью Application Default Credentials

Вместо ключа API для аутентификации можно использовать Application Default Credentials (ADC). При локальной разработке ADC использует ваши учетные данные, а при запуске кода в Google Cloud – сервисные аккаунты.

При использовании ADC отправляйте в каждом запросе следующие заголовки:

  • Authorization – токен доступа OAuth 2.0 Bearer с областью действия https://www.googleapis.com/auth/cloud-platform.
  • X-Goog-User-Project – идентификатор проекта, в котором включен Developer Knowledge API и для которого оплачивается квота. У вашего аккаунта должно быть разрешение serviceusage.services.use для этого проекта.

Срок действия токенов доступа ограничен, поэтому клиенты, работающие в течение длительного времени, должны их обновлять. В примерах ниже показано, как с помощью библиотек аутентификации Google добавить текущий токен в каждый запрос.

  1. Настройте ADC для локальной разработки, следуя инструкциям на вкладке ADC в разделе Выберите тип учетных данных OAuth.

  2. Установите переменную среды GOOGLE_CLOUD_PROJECT для проекта, в котором включен Developer Knowledge API. В примерах этот идентификатор проекта отправляется в заголовке X-Goog-User-Project:

    export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
    
  3. Установите библиотеку аутентификации Google для вашего языка:

    Python

    pip install --upgrade google-auth requests
    

    TypeScript

    npm install google-auth-library
    
  4. Создайте клиента с помощью 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);
    

Обработка ошибок

Ошибки от MCP-сервера Developer Knowledge могут поступать в ваш код двумя способами:

  • Ошибки запросов. Ошибки аутентификации, разрешений и квот возвращаются с кодом статуса HTTP, например 400, 403 или 429. В SDK эти ошибки представлены как исключения: MCPError в Python и StreamableHTTPError в TypeScript. Перехватывайте эти исключения при вызовах инструментов.
  • Ошибки инструментов. Если инструмент запущен, но не может выполнить запрос, в результате будет указано значение is_error (Python) или isError (TypeScript) true, а в поле content будет текстовое описание проблемы. Проверяйте это поле перед чтением структурированного контента.

В следующем примере обрабатываются оба типа ошибок:

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

Если answer_query возвращает ошибку квоты (429 RESOURCE_EXHAUSTED), перейдите к search_documents, у которого квота выше. Стратегии повторных попыток, в том числе экспоненциальная выдержка, описаны в разделе Обработка ошибок и управление квотами. Распространенные причины ошибок аутентификации описаны в разделах Ошибки ключа API и Ошибки OAuth и ADC.

Дальнейшие действия