The official Model Context Protocol (MCP) SDKs let your own applications and AI agents connect to the Developer Knowledge MCP server programmatically. Use an MCP SDK when you're building a custom agent, a backend service, or your own MCP server that needs to search and retrieve official Google developer documentation, rather than configuring an existing IDE or coding assistant.
In this guide, you learn how to:
- Install the MCP client SDK for Python or TypeScript.
- Connect to the Developer Knowledge MCP server with an API key or Application Default Credentials (ADC).
- Call the
search_documents,get_documents, andanswer_querytools. - Handle authentication, quota, and tool errors.
Before you begin
Before you start, complete the following sections.
Enable the API and create credentials
Enable the Developer Knowledge API in your Google Cloud project and create the credentials for your authentication method. For step-by-step instructions, refer to Choose your authentication method.
The examples in this guide use an API key. To use ADC instead, refer to Authenticate with Application Default Credentials.
Install the MCP SDK
Select your programming language to install the MCP client SDK:
Python
This guide uses version 2 of the MCP Python SDK, which requires Python 3.10 or later. Version 1.x of the SDK uses different class and function names, so these examples don't work with it:
pip install --upgrade "mcp>=2"
TypeScript
This guide uses the MCP TypeScript SDK with Node.js 18 or later:
npm install @modelcontextprotocol/sdk
Set your API key
To avoid hardcoding your API key in source code, store it in an environment variable. Replace YOUR_API_KEY with your API key:
export DEVELOPERKNOWLEDGE_API_KEY="YOUR_API_KEY"
Connect to the server
The Developer Knowledge MCP server uses the Streamable HTTP transport at the following endpoint:
https://developerknowledge.googleapis.com/mcp
To authenticate, pass your API key in the X-Goog-Api-Key HTTP header on every
request. Don't pass the API key as a URL query parameter.
The following example connects to the server and lists the available tools:
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();
If the connection succeeds, the output lists the three tools:
Available tools: search_documents, answer_query, get_documents
The remaining examples in this guide run inside the connected client from this
section. The TypeScript examples use top-level await, so run them as ES
modules (for example, with npx tsx index.ts).
Call the tools
Each tool returns its result as structured content that matches the tool's output schema, so you can read fields directly instead of parsing text. For the full input and output schemas, refer to the MCP reference.
Search for documentation
Call search_documents with a query string to retrieve the most relevant
documentation chunks. Each result contains the chunk content and the parent
resource name of the document it came from:
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`);
}
Retrieve full documents
If a chunk doesn't contain enough context, pass one or more parent values to
get_documents to retrieve the full Markdown content of each page. You can
request up to 20 documents in a single call. Because several chunks can come
from the same document, remove duplicate parent values first:
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);
}
Full documents can be large, so call get_documents only when the search
chunks aren't sufficient. To learn more, refer to
Optimize context window and token usage.
Generate an answer
Call answer_query to generate an answer grounded in the
Developer Knowledge corpus. The result
contains the answerText and the references used to generate it:
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'));
The references field contains document resource names that you can pass to
get_documents. The same document can appear more than once, so remove
duplicates before you retrieve the documents. The answer_query tool has a
lower quota than the other tools. To learn more, refer to
Quota and limits.
Authenticate with Application Default Credentials
Instead of an API key, you can authenticate with Application Default Credentials (ADC). ADC works with your user credentials during local development and with service accounts when your code runs on Google Cloud.
When you use ADC, send the following headers on every request:
Authorization: aBearerOAuth 2.0 access token with thehttps://www.googleapis.com/auth/cloud-platformscope.X-Goog-User-Project: the ID of the project that has the Developer Knowledge API enabled and is billed for quota. Your account needs theserviceusage.services.usepermission on this project.
Access tokens expire, so long-running clients must refresh them. The following examples use the Google authentication libraries to add a current token to each request.
Set up ADC for local development by following the steps on the ADC tab in Choose your OAuth credential type.
Set the
GOOGLE_CLOUD_PROJECTenvironment variable to the project that has the Developer Knowledge API enabled. The examples send this project ID in theX-Goog-User-Projectheader:export GOOGLE_CLOUD_PROJECT="PROJECT_ID"Install the Google authentication library for your language:
Python
pip install --upgrade google-auth requestsTypeScript
npm install google-auth-libraryCreate the client with 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);
Handle errors
Errors from the Developer Knowledge MCP server reach your code in two ways:
- Request errors: authentication, permission, and quota errors are
returned with an HTTP error status, such as
400,403, or429. The SDKs raise these as exceptions:MCPErrorin Python andStreamableHTTPErrorin TypeScript. Catch these exceptions around your tool calls. - Tool errors: when a tool runs but can't complete the request, the
result has
is_error(Python) orisError(TypeScript) set totrue, and thecontentfield contains a text description of the problem. Check this field before reading the structured content.
The following example handles both error types:
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;
}
}
If answer_query returns a quota error (429 RESOURCE_EXHAUSTED), fall back
to search_documents, which has a higher quota. For retry strategies,
including exponential backoff, refer to
Error handling and quota management.
For common causes of authentication errors, refer to
API key errors and
OAuth and ADC errors.
What's next
- Explore the full tool schemas in the MCP reference.
- Learn which products are indexed in the Corpus reference.
- Call the Developer Knowledge API directly with the client libraries.