removed api reference

This commit is contained in:
Zack Lee 2024-11-21 11:24:39 -05:00
commit ea5fe6d115
No known key found for this signature in database
17 changed files with 7 additions and 4522 deletions

View file

@ -1,355 +0,0 @@
---
title: "Connection management"
description: "Learn how to establish and manage MCP client connections"
---
## Overview
The MCP client API provides flexible connection management options with support for different transport types. This guide covers establishing connections, handling connection events, and managing connection lifecycles.
## Creating a client
First, create an MCP client instance with your application's information.
<CodeGroup>
```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk";
const client = new Client({
name: "my-application",
version: "1.0.0"
});
```
```python Python
from mcp import Client
client = Client(
name="my-application",
version="1.0.0"
)
```
</CodeGroup>
## Transport types
MCP supports multiple transport types for different use cases. Choose the appropriate transport based on your needs.
### WebSocket transport
Use WebSocket transport for real-time bidirectional communication.
<CodeGroup>
```typescript TypeScript
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk";
const transport = new WebSocketClientTransport(
new URL("ws://localhost:3000")
);
await client.connect(transport);
```
```python Python
from mcp.transports import WebSocketTransport
transport = WebSocketTransport(
url="ws://localhost:3000"
)
await client.connect(transport)
```
</CodeGroup>
### SSE transport
Server-Sent Events transport is suitable for scenarios where the server pushes data to the client.
<CodeGroup>
```typescript TypeScript
import { SSEClientTransport } from "@modelcontextprotocol/sdk";
const transport = new SSEClientTransport(
new URL("http://localhost:3000/events")
);
await client.connect(transport);
```
```python Python
from mcp.transports import SSETransport
transport = SSETransport(
url="http://localhost:3000/events"
)
await client.connect(transport)
```
</CodeGroup>
### Stdio transport
For local server processes, use the stdio transport to communicate via standard input/output.
<CodeGroup>
```typescript TypeScript
import { StdioClientTransport } from "@modelcontextprotocol/sdk";
const transport = new StdioClientTransport({
command: "/path/to/server",
args: ["--arg1", "--arg2"],
env: { "KEY": "value" }
});
await client.connect(transport);
```
```python Python
from mcp.transports import StdioTransport
transport = StdioTransport(
command="/path/to/server",
args=["--arg1", "--arg2"],
env={"KEY": "value"}
)
await client.connect(transport)
```
</CodeGroup>
## Connection lifecycle
### Event handling
Set up event handlers to manage the connection lifecycle.
<CodeGroup>
```typescript TypeScript
client.onclose = () => {
console.log("Connection closed");
};
client.onerror = (error) => {
console.error("Connection error:", error);
};
// Transport-specific events
transport.onclose = () => {
console.log("Transport closed");
};
transport.onerror = (error) => {
console.error("Transport error:", error);
};
```
```python Python
@client.on_close
async def handle_close():
print("Connection closed")
@client.on_error
async def handle_error(error):
print(f"Connection error: {error}")
# Transport-specific events
@transport.on_close
async def handle_transport_close():
print("Transport closed")
@transport.on_error
async def handle_transport_error(error):
print(f"Transport error: {error}")
```
</CodeGroup>
### Connection states
Monitor and manage connection states throughout your application's lifecycle.
<CodeGroup>
```typescript TypeScript
// Check if connected
if (client.transport) {
console.log("Client is connected");
}
// Get server capabilities after connection
const capabilities = client.getServerCapabilities();
const serverVersion = client.getServerVersion();
// Clean up connection
await client.close();
```
```python Python
# Check if connected
if client.transport:
print("Client is connected")
# Get server capabilities after connection
capabilities = client.get_server_capabilities()
server_version = client.get_server_version()
# Clean up connection
await client.close()
```
</CodeGroup>
## Error handling
Implement robust error handling for connection-related issues.
<CodeGroup>
```typescript TypeScript
try {
await client.connect(transport);
} catch (error) {
if (error.code === ErrorCode.ConnectionClosed) {
// Handle connection closure
} else if (error.code === ErrorCode.InvalidRequest) {
// Handle invalid request
} else {
// Handle other errors
}
}
```
```python Python
try:
await client.connect(transport)
except ConnectionClosedError:
# Handle connection closure
pass
except InvalidRequestError:
# Handle invalid request
pass
except McpError as e:
# Handle other errors
pass
```
</CodeGroup>
## Best practices
<CardGroup cols={2}>
<Card title="Connection management" icon="plug">
Always close connections when they're no longer needed to free up resources
</Card>
<Card title="Error handling" icon="shield-check">
Implement comprehensive error handling for all connection states
</Card>
<Card title="Event handling" icon="bell">
Set up appropriate event handlers before establishing connections
</Card>
<Card title="Resource cleanup" icon="broom">
Use try/finally blocks to ensure proper cleanup of resources
</Card>
</CardGroup>
## Connection examples
Here are some common connection patterns:
<AccordionGroup>
<Accordion title="Basic connection with retry">
<CodeGroup>
```typescript TypeScript
async function connectWithRetry(
client: Client,
transport: Transport,
maxAttempts = 3
) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
await client.connect(transport);
return;
} catch (error) {
if (attempt === maxAttempts) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
```
```python Python
async def connect_with_retry(
client: Client,
transport: Transport,
max_attempts: int = 3
):
for attempt in range(max_attempts):
try:
await client.connect(transport)
return
except Exception as e:
if attempt == max_attempts - 1:
raise
await asyncio.sleep(attempt + 1)
```
</CodeGroup>
</Accordion>
<Accordion title="Connection with timeout">
<CodeGroup>
```typescript TypeScript
async function connectWithTimeout(
client: Client,
transport: Transport,
timeoutMs = 5000
) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Connection timeout")), timeoutMs);
});
await Promise.race([
client.connect(transport),
timeoutPromise
]);
}
```
```python Python
async def connect_with_timeout(
client: Client,
transport: Transport,
timeout: float = 5.0
):
async with asyncio.timeout(timeout):
await client.connect(transport)
```
</CodeGroup>
</Accordion>
</AccordionGroup>
## Troubleshooting
<AccordionGroup>
<Accordion title="Connection refused">
- Verify the server is running and accessible
- Check if the port is correct and available
- Ensure firewalls aren't blocking the connection
</Accordion>
<Accordion title="Authentication failures">
- Verify credentials if required
- Check if environment variables are properly set
- Ensure transport configuration is correct
</Accordion>
<Accordion title="Connection drops">
- Implement reconnection logic
- Check network stability
- Monitor server health
</Accordion>
</AccordionGroup>
## Transport selection guide
Choose the appropriate transport based on your use case:
| Transport | Use Case | Advantages | Considerations |
|-----------|----------|------------|----------------|
| WebSocket | Real-time bidirectional | Full-duplex, low latency | Requires WebSocket server |
| SSE | Server push updates | Simple, firewall-friendly | One-way server push |
| Stdio | Local process communication | Simple, reliable | Limited to local processes |

View file

@ -1,418 +0,0 @@
---
title: "Resource consumption"
description: "Learn how to consume resources from MCP servers"
---
MCP servers can expose resources that clients can access. This guide explains how to list available resources, read their contents, and subscribe to resource updates using both Python and TypeScript.
## Listing resources
To get a list of available resources from an MCP server:
<CodeGroup>
```typescript list_resources.ts
import { Client } from "@modelcontextprotocol/sdk";
const client = new Client({
name: "my-client",
version: "1.0.0",
});
// Connect to the server
await client.connect(transport);
// List available resources
const result = await client.request(
{
method: "resources/list"
},
ListResourcesResultSchema
);
// Available resources
for (const resource of result.resources) {
console.log(`Found resource: ${resource.name} (${resource.uri})`);
}
```
```python list_resources.py
from modelcontextprotocol.client import Client
client = Client(
name="my-client",
version="1.0.0"
)
# Connect to the server
await client.connect(transport)
# List available resources
result = await client.request({
"method": "resources/list"
})
# Available resources
for resource in result["resources"]:
print(f"Found resource: {resource['name']} ({resource['uri']})")
```
</CodeGroup>
## Reading resources
Once you have a resource URI, you can read its contents:
<CodeGroup>
```typescript read_resource.ts
// Read a specific resource
const result = await client.request(
{
method: "resources/read",
params: {
uri: "file:///example.txt"
}
},
ReadResourceResultSchema
);
// Process the contents
for (const content of result.contents) {
if ("text" in content) {
console.log("Text content:", content.text);
} else if ("blob" in content) {
// Handle binary data (base64 encoded)
const binaryData = Buffer.from(content.blob, "base64");
console.log("Binary content length:", binaryData.length);
}
}
```
```python read_resource.py
# Read a specific resource
result = await client.request({
"method": "resources/read",
"params": {
"uri": "file:///example.txt"
}
})
# Process the contents
for content in result["contents"]:
if "text" in content:
print("Text content:", content["text"])
elif "blob" in content:
# Handle binary data (base64 encoded)
import base64
binary_data = base64.b64decode(content["blob"])
print("Binary content length:", len(binary_data))
```
</CodeGroup>
## Resource templates
Some servers provide resource templates that can be used to construct resource URIs dynamically:
<CodeGroup>
```typescript list_templates.ts
const result = await client.request(
{
method: "resources/templates/list"
},
ListResourceTemplatesResultSchema
);
for (const template of result.resourceTemplates) {
console.log(`Template: ${template.name}`);
console.log(`URI template: ${template.uriTemplate}`);
}
```
```python list_templates.py
result = await client.request({
"method": "resources/templates/list"
})
for template in result["resourceTemplates"]:
print(f"Template: {template['name']}")
print(f"URI template: {template['uriTemplate']}")
```
</CodeGroup>
## Subscribing to updates
You can subscribe to receive notifications when resources change:
<CodeGroup>
```typescript subscribe_resource.ts
// Subscribe to changes
await client.request(
{
method: "resources/subscribe",
params: {
uri: "file:///example.txt"
}
},
EmptyResultSchema
);
// Set up notification handler
client.setNotificationHandler(
ResourceUpdatedNotificationSchema,
async (notification) => {
console.log(`Resource updated: ${notification.params.uri}`);
// Re-read the resource
const result = await client.request(
{
method: "resources/read",
params: {
uri: notification.params.uri
}
},
ReadResourceResultSchema
);
// Process updated contents...
}
);
// Later, unsubscribe when done
await client.request(
{
method: "resources/unsubscribe",
params: {
uri: "file:///example.txt"
}
},
EmptyResultSchema
);
```
```python subscribe_resource.py
# Subscribe to changes
await client.request({
"method": "resources/subscribe",
"params": {
"uri": "file:///example.txt"
}
})
# Set up notification handler
@client.notification_handler("notifications/resources/updated")
async def handle_update(notification):
print(f"Resource updated: {notification['params']['uri']}")
# Re-read the resource
result = await client.request({
"method": "resources/read",
"params": {
"uri": notification["params"]["uri"]
}
})
# Process updated contents...
# Later, unsubscribe when done
await client.request({
"method": "resources/unsubscribe",
"params": {
"uri": "file:///example.txt"
}
})
```
</CodeGroup>
## Handling pagination
When listing resources, servers may paginate results. Here's how to handle pagination:
<CodeGroup>
```typescript pagination.ts
let cursor: string | undefined = undefined;
do {
const result = await client.request(
{
method: "resources/list",
params: { cursor }
},
ListResourcesResultSchema
);
// Process current page of resources
for (const resource of result.resources) {
console.log(`Resource: ${resource.name}`);
}
// Update cursor for next page
cursor = result.nextCursor;
} while (cursor !== undefined);
```
```python pagination.py
cursor = None
while True:
result = await client.request({
"method": "resources/list",
"params": { "cursor": cursor }
})
# Process current page of resources
for resource in result["resources"]:
print(f"Resource: {resource['name']}")
# Update cursor for next page
cursor = result.get("nextCursor")
if cursor is None:
break
```
</CodeGroup>
## Error handling
When working with resources, handle potential errors appropriately:
<CodeGroup>
```typescript error_handling.ts
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk";
try {
const result = await client.request(
{
method: "resources/read",
params: {
uri: "file:///nonexistent.txt"
}
},
ReadResourceResultSchema
);
} catch (error) {
if (error instanceof McpError) {
switch (error.code) {
case ErrorCode.InvalidRequest:
console.error("Invalid resource URI");
break;
case ErrorCode.MethodNotFound:
console.error("Server doesn't support resource reading");
break;
default:
console.error(`Resource error: ${error.message}`);
}
}
}
```
```python error_handling.py
from modelcontextprotocol.errors import McpError, ErrorCode
try:
result = await client.request({
"method": "resources/read",
"params": {
"uri": "file:///nonexistent.txt"
}
})
except McpError as error:
if error.code == ErrorCode.INVALID_REQUEST:
print("Invalid resource URI")
elif error.code == ErrorCode.METHOD_NOT_FOUND:
print("Server doesn't support resource reading")
else:
print(f"Resource error: {error.message}")
```
</CodeGroup>
## Best practices
When consuming resources from MCP servers:
<CardGroup cols={2}>
<Card title="Resource cleanup" icon="broom">
Always unsubscribe from resources when you're done with them
</Card>
<Card title="Error handling" icon="shield">
Implement proper error handling for all resource operations
</Card>
<Card title="Content types" icon="file">
Check MIME types before processing resource contents
</Card>
<Card title="Pagination" icon="list">
Always handle pagination when listing resources
</Card>
</CardGroup>
## Type safety
To ensure type safety when working with resources:
<CodeGroup>
```typescript type_safety.ts
import {
Resource,
ResourceContents,
TextResourceContents,
BlobResourceContents
} from "@modelcontextprotocol/sdk";
function isTextContent(
content: ResourceContents
): content is TextResourceContents {
return "text" in content;
}
function isBlobContent(
content: ResourceContents
): content is BlobResourceContents {
return "blob" in content;
}
// Use type guards when processing contents
for (const content of result.contents) {
if (isTextContent(content)) {
// TypeScript knows this is text content
const text: string = content.text;
} else if (isBlobContent(content)) {
// TypeScript knows this is binary content
const blob: string = content.blob;
}
}
```
```python type_safety.py
from typing import TypedDict, Union, Literal
class TextContent(TypedDict):
type: Literal["text"]
text: str
uri: str
mimeType: str
class BlobContent(TypedDict):
type: Literal["blob"]
blob: str
uri: str
mimeType: str
ResourceContent = Union[TextContent, BlobContent]
def process_content(content: ResourceContent) -> None:
if content["type"] == "text":
text: str = content["text"]
else:
blob: str = content["blob"]
```
</CodeGroup>

View file

@ -1,329 +0,0 @@
---
title: "Tool invocation"
description: "Learn how to invoke tools through the MCP client API"
---
MCP allows clients to invoke tools exposed by servers. Tools are discrete operations that servers can perform on behalf of clients, similar to function calls.
## Getting available tools
Before invoking tools, you'll need to get a list of available tools from the server.
<CodeGroup>
```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk/client";
import { ListToolsResultSchema } from "@modelcontextprotocol/sdk/types";
// Assuming client is already connected
const result = await client.request(
{
method: "tools/list"
},
ListToolsResultSchema
);
// Tools are now available in result.tools
for (const tool of result.tools) {
console.log(`Found tool: ${tool.name}`);
console.log(`Description: ${tool.description}`);
}
```
```python Python
from mcp.client import Client
from mcp.types import ListToolsRequest
# Assuming client is already connected
result = await client.request(
ListToolsRequest(method="tools/list"),
ListToolsResultSchema
)
# Tools are now available in result.tools
for tool in result.tools:
print(f"Found tool: {tool.name}")
print(f"Description: {tool.description}")
```
</CodeGroup>
## Tool invocation
To invoke a tool, you'll use the `tools/call` method with the tool name and any required arguments.
<CodeGroup>
```typescript TypeScript
import { CallToolRequest, CallToolResultSchema } from "@modelcontextprotocol/sdk/types";
const result = await client.request(
{
method: "tools/call",
params: {
name: "example_tool",
arguments: {
param1: "value1",
param2: 42
}
}
},
CallToolResultSchema
);
// Tool result is available in result.toolResult
console.log("Tool result:", result.toolResult);
```
```python Python
from mcp.types import CallToolRequest, CallToolResult
result = await client.request(
CallToolRequest(
method="tools/call",
params={
"name": "example_tool",
"arguments": {
"param1": "value1",
"param2": 42
}
}
),
CallToolResult
)
# Tool result is available in result.tool_result
print("Tool result:", result.tool_result)
```
</CodeGroup>
## Progress tracking
For long-running tools, you can track progress using progress notifications.
<CodeGroup>
```typescript TypeScript
const result = await client.request(
{
method: "tools/call",
params: {
name: "long_running_tool",
arguments: {
duration: 10
}
}
},
CallToolResultSchema,
(progress) => {
console.log(`Progress: ${progress.progress}/${progress.total ?? '?'}`);
}
);
```
```python Python
def progress_callback(progress):
print(f"Progress: {progress.progress}/{progress.total or '?'}")
result = await client.request(
CallToolRequest(
method="tools/call",
params={
"name": "long_running_tool",
"arguments": {
"duration": 10
}
}
),
CallToolResult,
on_progress=progress_callback
)
```
</CodeGroup>
## Error handling
Tool invocations may fail for various reasons. Always handle potential errors appropriately.
<CodeGroup>
```typescript TypeScript
try {
const result = await client.request(
{
method: "tools/call",
params: {
name: "risky_tool",
arguments: {
important_param: "value"
}
}
},
CallToolResultSchema
);
} catch (error) {
if (error instanceof McpError) {
console.error(`Tool error (${error.code}): ${error.message}`);
if (error.data) {
console.error("Additional error data:", error.data);
}
} else {
console.error("Unexpected error:", error);
}
}
```
```python Python
from mcp.errors import McpError
try:
result = await client.request(
CallToolRequest(
method="tools/call",
params={
"name": "risky_tool",
"arguments": {
"important_param": "value"
}
}
),
CallToolResult
)
except McpError as e:
print(f"Tool error ({e.code}): {e.message}")
if e.data:
print("Additional error data:", e.data)
except Exception as e:
print("Unexpected error:", e)
```
</CodeGroup>
## Complete example
Here's a complete example showing how to discover and use tools with proper error handling.
<CodeGroup>
```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk/client";
import {
ListToolsResultSchema,
CallToolResultSchema,
McpError
} from "@modelcontextprotocol/sdk/types";
async function invokeTools(client: Client) {
try {
// Get available tools
const toolsList = await client.request(
{ method: "tools/list" },
ListToolsResultSchema
);
// Find a specific tool
const tool = toolsList.tools.find(t => t.name === "example_tool");
if (!tool) {
console.error("Tool not found");
return;
}
// Invoke the tool with progress tracking
const result = await client.request(
{
method: "tools/call",
params: {
name: tool.name,
arguments: {
// Tool-specific arguments
param1: "value1"
}
}
},
CallToolResultSchema,
(progress) => {
console.log(
`Progress: ${progress.progress}/${progress.total ?? '?'}`
);
}
);
console.log("Tool result:", result.toolResult);
} catch (error) {
if (error instanceof McpError) {
console.error(`Tool error (${error.code}): ${error.message}`);
} else {
console.error("Unexpected error:", error);
}
}
}
```
```python Python
from mcp.client import Client
from mcp.types import ListToolsRequest, CallToolRequest
from mcp.errors import McpError
async def invoke_tools(client: Client):
try:
# Get available tools
tools_list = await client.request(
ListToolsRequest(method="tools/list"),
ListToolsResultSchema
)
# Find a specific tool
tool = next(
(t for t in tools_list.tools if t.name == "example_tool"),
None
)
if not tool:
print("Tool not found")
return
# Invoke the tool with progress tracking
result = await client.request(
CallToolRequest(
method="tools/call",
params={
"name": tool.name,
"arguments": {
# Tool-specific arguments
"param1": "value1"
}
}
),
CallToolResult,
on_progress=lambda p: print(
f"Progress: {p.progress}/{p.total or '?'}"
)
)
print("Tool result:", result.tool_result)
except McpError as e:
print(f"Tool error ({e.code}): {e.message}")
except Exception as e:
print("Unexpected error:", e)
```
</CodeGroup>
## Best practices
When working with tools:
<CardGroup cols={2}>
<Card title="Validation" icon="check-circle">
Always check tool availability before invoking
</Card>
<Card title="Error handling" icon="shield-check">
Implement comprehensive error handling
</Card>
<Card title="Progress" icon="bars-progress">
Use progress callbacks for long-running operations
</Card>
<Card title="Arguments" icon="input-text">
Validate arguments against the tool's input schema
</Card>
</CardGroup>
## Common errors
| Error Code | Description | Resolution |
|------------|-------------|------------|
| -32601 | Method not found | Verify the tool name exists |
| -32602 | Invalid params | Check the tool's input schema |
| -32603 | Internal error | Server-side error, check server logs |
| -1 | Connection closed | Check connection status |

View file

@ -1,241 +0,0 @@
---
title: 'Error handling'
description: 'How to handle and respond to errors in the Model Context Protocol'
---
MCP follows JSON-RPC 2.0's error handling patterns while adding specific error codes and best practices for MCP implementations.
## Error response structure
When an error occurs, servers must respond with an error object instead of a result:
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32601,
"message": "Method not found",
"data": {
// Optional additional error details
}
}
}
```
### Required fields
<CardGroup cols={3}>
<Card title="code" icon="hashtag">
A number indicating the error type
</Card>
<Card title="message" icon="message-dots">
A concise, single-sentence description
</Card>
<Card title="data" icon="circle-info">
Optional object with additional details
</Card>
</CardGroup>
## Standard error codes
MCP uses both standard JSON-RPC error codes and MCP-specific codes.
### JSON-RPC standard codes
| Code | Name | Description | Example |
|------|------|-------------|----------|
| -32700 | Parse error | Invalid JSON received | Malformed JSON in request |
| -32600 | Invalid request | Request object invalid | Missing required fields |
| -32601 | Method not found | Method doesn't exist | Calling undefined endpoint |
| -32602 | Invalid params | Invalid method parameters | Wrong parameter types |
| -32603 | Internal error | Internal JSON-RPC error | Unexpected server error |
### MCP-specific codes
| Code | Name | Description |
|------|------|-------------|
| -1 | Connection closed | Connection was terminated |
| Additional codes TBD | | |
## Common error scenarios
<AccordionGroup>
<Accordion title="Initialization errors">
Errors that can occur during the connection initialization phase:
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Unsupported protocol version",
"data": {
"requestedVersion": "2023-01-01",
"supportedVersions": ["2024-10-07"]
}
}
}
```
</Accordion>
<Accordion title="Resource errors">
Errors when accessing resources:
```json
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32601,
"message": "Resource not found",
"data": {
"uri": "file:///nonexistent.txt"
}
}
}
```
</Accordion>
<Accordion title="Tool invocation errors">
Errors during tool execution:
```json
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "Invalid tool parameters",
"data": {
"tool": "query",
"invalidParams": ["sql"]
}
}
}
```
</Accordion>
</AccordionGroup>
## Error handling best practices
<Steps>
<Step title="Use appropriate error codes">
Choose the most specific error code that applies to the situation. Prefer standard JSON-RPC codes when applicable.
</Step>
<Step title="Write clear messages">
Error messages should be:
- Concise (single sentence)
- Descriptive
- Action-oriented when possible
</Step>
<Step title="Include helpful data">
Add relevant details in the `data` field to help diagnose and resolve the issue:
```json
{
"error": {
"code": -32602,
"message": "Invalid resource URI format",
"data": {
"uri": "invalid://uri",
"expectedFormat": "file:///path/to/resource",
"validSchemes": ["file", "http", "https"]
}
}
}
```
</Step>
<Step title="Handle connection errors">
Implement proper cleanup and recovery for connection-related errors:
```typescript
try {
await client.connect(transport);
} catch (error) {
if (error.code === -1) {
// Handle connection closed
await cleanup();
await reconnect();
}
}
```
</Step>
</Steps>
## Client-side error handling
Recommendations for MCP clients:
<CardGroup cols={2}>
<Card title="Request timeout handling">
Implement timeouts for requests and handle them gracefully:
```typescript
const response = await Promise.race([
client.request(request),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
)
]);
```
</Card>
<Card title="Reconnection logic">
Implement exponential backoff for reconnection attempts:
```typescript
async function reconnect(attempts = 0) {
try {
await client.connect(transport);
} catch (error) {
if (attempts < maxAttempts) {
await delay(Math.min(1000 * Math.pow(2, attempts), 30000));
await reconnect(attempts + 1);
}
}
}
```
</Card>
</CardGroup>
## Server-side error handling
Best practices for MCP servers:
<CardGroup cols={2}>
<Card title="Graceful degradation">
When possible, continue operating with reduced functionality rather than failing completely
</Card>
<Card title="Resource cleanup">
Always clean up resources when errors occur, especially for long-running operations
</Card>
<Card title="Error logging">
Log errors with appropriate context for debugging while keeping sensitive information secure
</Card>
<Card title="Rate limiting">
Implement rate limiting and return appropriate error responses when limits are exceeded
</Card>
</CardGroup>
## Type-safe error handling
When using TypeScript with MCP:
```typescript
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk";
try {
await server.handleRequest(request);
} catch (error) {
if (error instanceof McpError) {
switch (error.code) {
case ErrorCode.ConnectionClosed:
// Handle connection closed
break;
case ErrorCode.MethodNotFound:
// Handle unknown method
break;
default:
// Handle other MCP errors
}
} else {
// Handle unexpected errors
}
}
```

View file

@ -1,267 +0,0 @@
---
title: 'Message types'
description: 'Understanding the different types of messages in the Model Context Protocol'
---
The Model Context Protocol (MCP) uses JSON-RPC 2.0 as its base protocol and defines several message types for communication between clients and servers.
## Core message types
MCP uses three core types of messages for communication:
<CardGroup cols={3}>
<Card title="Requests" icon="arrow-right">
Messages that expect a response, identified by a unique ID
</Card>
<Card title="Responses" icon="arrow-left">
Messages sent in reply to requests, containing results or errors
</Card>
<Card title="Notifications" icon="bell">
One-way messages that don't expect a response
</Card>
</CardGroup>
## Message structure
All messages in MCP follow the JSON-RPC 2.0 specification and include specific required fields.
<AccordionGroup>
<Accordion title="Request structure">
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/list",
"params": {
// Optional method parameters
}
}
```
Required fields:
- `jsonrpc`: Must be "2.0"
- `id`: A unique identifier for the request
- `method`: The name of the method to invoke
</Accordion>
<Accordion title="Response structure">
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
// Method-specific result data
}
}
```
Required fields:
- `jsonrpc`: Must be "2.0"
- `id`: The same ID as the corresponding request
- `result`: The result data (or `error` for error responses)
</Accordion>
<Accordion title="Notification structure">
```json
{
"jsonrpc": "2.0",
"method": "notifications/initialized",
"params": {
// Optional notification parameters
}
}
```
Required fields:
- `jsonrpc`: Must be "2.0"
- `method`: The name of the notification
</Accordion>
</AccordionGroup>
## Error handling
When a request cannot be fulfilled, the server responds with an error object instead of a result.
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32601,
"message": "Method not found",
"data": {
// Optional additional error information
}
}
}
```
### Standard error codes
| Code | Message | Description |
|------|---------|-------------|
| -32700 | Parse error | Invalid JSON received |
| -32600 | Invalid request | Request object invalid |
| -32601 | Method not found | Requested method doesn't exist |
| -32602 | Invalid params | Method parameters invalid |
| -32603 | Internal error | Internal JSON-RPC error |
## Progress tracking
MCP supports progress tracking for long-running operations through a combination of request parameters and notifications.
<Steps>
<Step title="Include progress token">
Add a progress token in the request:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"_meta": {
"progressToken": "abc123"
}
}
}
```
</Step>
<Step title="Receive progress notifications">
The server sends progress updates as notifications:
```json
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "abc123",
"progress": 50,
"total": 100
}
}
```
</Step>
</Steps>
## Message content types
MCP supports different content types for messages exchanged between the client and server.
<CodeGroup>
```json Text content
{
"type": "text",
"text": "This is a text message"
}
```
```json Image content
{
"type": "image",
"data": "base64-encoded-image-data",
"mimeType": "image/png"
}
```
</CodeGroup>
## Special considerations
When implementing MCP message handling, keep in mind:
- All messages must be encoded in UTF-8
- Binary data must be base64 encoded
- Message IDs should be unique within a session
- Error messages should be concise and single-sentence
- Progress notifications are optional and may not be supported by all servers
## Message flow examples
Here are some common message flow patterns in MCP:
<AccordionGroup>
<Accordion title="Resource listing">
1. Client sends request:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/list"
}
```
2. Server responds with resources:
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resources": [
{
"uri": "file:///example.txt",
"name": "Example File",
"mimeType": "text/plain"
}
]
}
}
```
</Accordion>
<Accordion title="Tool invocation with progress">
1. Client sends tool request:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "longRunningTool",
"_meta": {
"progressToken": "token123"
}
}
}
```
2. Server sends progress notifications:
```json
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "token123",
"progress": 50,
"total": 100
}
}
```
3. Server sends final response:
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"toolResult": "Operation completed successfully"
}
}
```
</Accordion>
</AccordionGroup>
## Best practices
When working with MCP messages:
<CardGroup cols={2}>
<Card title="Error handling" icon="shield-check">
Always include appropriate error codes and meaningful error messages
</Card>
<Card title="Progress updates" icon="bars-progress">
Send regular progress updates for long-running operations
</Card>
<Card title="Content validation" icon="check-double">
Validate message content against the appropriate schemas
</Card>
<Card title="Resource management" icon="database">
Clean up resources when connections are closed
</Card>
</CardGroup>

View file

@ -1,86 +0,0 @@
---
title: "Protocol overview"
description: "Learn about the core concepts and architecture of the Model Context Protocol (MCP)"
---
The Model Context Protocol (MCP) is a standardized protocol that enables AI applications to securely access external data sources and tools. MCP follows a client-server architecture where AI applications act as clients that can connect to one or more MCP servers.
## Key features
<CardGroup cols={2}>
<Card title="Flexible integration" icon="puzzle-piece">
Connect AI models to any data source or tool through a unified protocol
</Card>
<Card title="Secure access" icon="shield-check">
Control what data and capabilities are exposed to AI systems
</Card>
<Card title="Composable design" icon="cubes">
Combine multiple servers together for enhanced functionality
</Card>
<Card title="Standard interface" icon="code">
Build integrations that work consistently across AI applications
</Card>
</CardGroup>
## Core concepts
MCP defines several key primitives that form the foundation of the protocol:
<CardGroup cols={2}>
<Card title="Resources" icon="book">
Data that can be loaded as context for the AI model. Resources have URIs and can contain text or binary data.
</Card>
<Card title="Tools" icon="screwdriver-wrench">
Functions that the AI can invoke to perform actions, like writing files or calling APIs.
</Card>
<Card title="Prompts" icon="message">
Pre-defined prompt templates that help guide AI interactions in specific ways.
</Card>
<Card title="Sampling" icon="rotate">
Allows servers to request completions from the AI model through the client.
</Card>
</CardGroup>
## Protocol flow
### Connection and initialization
When a client connects to an MCP server, they go through the following initialization sequence:
<Steps>
<Step title="Client connects">
The client establishes a connection to the server using one of the supported transports.
</Step>
<Step title="Initialize request">
The client sends an initialize request containing its capabilities and protocol version.
</Step>
<Step title="Server response">
The server responds with its own capabilities and supported protocol version.
</Step>
<Step title="Initialized notification">
The client sends an initialized notification to indicate setup is complete.
</Step>
</Steps>
After initialization, the client can begin using the server's resources, tools, and other capabilities.
### Transport options
MCP supports multiple transport mechanisms for client-server communication:
<AccordionGroup>
<Accordion title="Standard input/output (stdio)">
- Server process reads from stdin and writes to stdout
- Messages are newline-terminated JSON
- Client manages server process lifetime
- State is lost when process exits
</Accordion>
<Accordion title="WebSocket">
- Bidirectional communication over WebSocket protocol
- Client and server negotiate using 'mcp' subprotocol
- Can connect to remote servers
- State persists until disconnect
</Accordion>
<Accordion title="Server-Sent Events (SSE)">
- Server pushes messages via SSE
- Client sends messages via HTTP POST
- Supports cross-origin restrictions
- State persists until SSE connection closes
</Accordion>
</AccordionGroup>

View file

@ -1,340 +0,0 @@
---
title: "Python class reference"
description: "Complete Python SDK class documentation"
---
## Server class
The main class for implementing MCP servers in Python.
```python
from mcp_python.server import Server
```
### Constructor
```python
Server(name: str, version: str = "1.0.0")
```
Creates a new MCP server instance.
**Parameters:**
- `name` (str): Name of the server
- `version` (str, optional): Version of the server. Defaults to "1.0.0"
### Decorators
#### Resource handling
##### @server.list_resources()
```python
@server.list_resources()
async def list_resources() -> List[Resource]:
"""Lists available resources."""
```
**Returns:** List of `Resource` objects containing:
- `uri` (str): Resource identifier
- `name` (str): Human-readable name
- `description` (str, optional): Resource description
- `mimeType` (str, optional): MIME type of the resource
##### @server.read_resource()
```python
@server.read_resource()
async def read_resource(uri: str) -> Union[str, bytes]:
"""Reads content of a specific resource."""
```
**Parameters:**
- `uri` (str): Resource URI to read
**Returns:** Content of the resource as either string or bytes
##### @server.subscribe_resource()
```python
@server.subscribe_resource()
async def subscribe_resource(uri: str) -> None:
"""Handles resource subscription requests."""
```
**Parameters:**
- `uri` (str): Resource URI to subscribe to
##### @server.unsubscribe_resource()
```python
@server.unsubscribe_resource()
async def unsubscribe_resource(uri: str) -> None:
"""Handles resource unsubscribe requests."""
```
**Parameters:**
- `uri` (str): Resource URI to unsubscribe from
#### Tool support
##### @server.list_tools()
```python
@server.list_tools()
async def list_tools() -> List[Tool]:
"""Lists available tools."""
```
**Returns:** List of `Tool` objects containing:
- `name` (str): Tool identifier
- `description` (str): Human-readable description
- `parameters` (dict): JSON Schema defining tool parameters
##### @server.call_tool()
```python
@server.call_tool()
async def call_tool(name: str, **kwargs) -> Any:
"""Handles tool execution requests."""
```
**Parameters:**
- `name` (str): Tool identifier
- `**kwargs`: Tool-specific parameters
**Returns:** Tool execution result (any JSON-serializable value)
#### Prompt management
##### @server.list_prompts()
```python
@server.list_prompts()
async def list_prompts() -> List[Prompt]:
"""Lists available prompts."""
```
**Returns:** List of `Prompt` objects containing:
- `name` (str): Prompt identifier
- `description` (str, optional): Human-readable description
- `parameters` (dict, optional): JSON Schema defining prompt parameters
##### @server.get_prompt()
```python
@server.get_prompt()
async def get_prompt(name: str, arguments: dict) -> PromptResponse:
"""Retrieves specific prompt templates."""
```
**Parameters:**
- `name` (str): Prompt identifier
- `arguments` (dict): Prompt parameters
**Returns:** `PromptResponse` object containing:
- `messages` (List[Message]): List of prompt messages
- `description` (str, optional): Description of the prompt response
### Session methods
Methods available on the server session object:
#### send_resource_updated()
```python
async def send_resource_updated(uri: str) -> None:
"""Notifies clients that a resource has been updated."""
```
#### send_progress_notification()
```python
async def send_progress_notification(
token: str,
progress: int,
total: Optional[int] = None
) -> None:
"""Sends progress updates for long-running operations."""
```
#### send_log_message()
```python
async def send_log_message(
level: str,
data: Any,
logger: Optional[str] = None
) -> None:
"""Sends log messages to clients."""
```
## Data classes
### Resource
```python
@dataclass
class Resource:
uri: str
name: str
description: Optional[str] = None
mimeType: Optional[str] = None
```
### Tool
```python
@dataclass
class Tool:
name: str
description: str
parameters: dict
```
### Prompt
```python
@dataclass
class Prompt:
name: str
description: Optional[str] = None
parameters: Optional[dict] = None
```
### Message
```python
@dataclass
class Message:
role: Literal["user", "assistant"]
content: Union[TextContent, ImageContent]
```
### PromptResponse
```python
@dataclass
class PromptResponse:
messages: List[Message]
description: Optional[str] = None
```
## Example usage
Here's a complete example demonstrating the main features:
```python
from mcp_python.server import Server
import anyio
server = Server("example-server")
@server.list_resources()
async def list_resources():
return [
{
"uri": "example://resource1",
"name": "Example Resource 1",
"description": "An example resource"
}
]
@server.read_resource()
async def read_resource(uri):
if uri == "example://resource1":
return "Example resource content"
raise ValueError(f"Unknown resource: {uri}")
@server.list_tools()
async def list_tools():
return [
{
"name": "example-tool",
"description": "An example tool",
"parameters": {
"type": "object",
"properties": {
"param1": {"type": "string"}
}
}
}
]
@server.call_tool()
async def call_tool(name, **kwargs):
if name == "example-tool":
return f"Tool executed with params: {kwargs}"
raise ValueError(f"Unknown tool: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
anyio.run(main)
```
## Best practices
1. **Error Handling**: Always implement proper error handling in your server methods:
```python
@server.read_resource()
async def read_resource(uri):
try:
return await fetch_resource(uri)
except ResourceNotFoundError as e:
raise ValueError(f"Resource not found: {uri}") from e
```
2. **Type Hints**: Use typing hints for better code clarity:
```python
@server.list_resources()
async def list_resources() -> List[Resource]:
resources: List[Resource] = []
return resources
```
3. **Progress Updates**: For long-running operations, send progress updates:
```python
@server.call_tool()
async def call_tool(name: str, session: ServerSession, **kwargs):
for i in range(100):
await session.send_progress_notification(
"operation-1",
progress=i,
total=100
)
```
4. **Resource Updates**: Notify clients when resources change:
```python
@server.call_tool()
async def call_tool(name: str, session: ServerSession, **kwargs):
# ... perform update ...
await session.send_resource_updated("example://resource1")
```
## Transport options
### Stdio transport
```python
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
```
### SSE transport
```python
from mcp_python.transport import SSETransport
app = FastAPI()
transport = SSETransport()
@app.get("/sse")
async def sse_endpoint():
return await transport.handle_sse()
@app.post("/message")
async def message_endpoint(request: Request):
return await transport.handle_message(request)
```
### WebSocket transport
```python
from mcp_python.transport import WebSocketTransport
app = FastAPI()
transport = WebSocketTransport()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await transport.handle_websocket(websocket)
```

View file

@ -1,359 +0,0 @@
---
title: "Python type hints"
description: "Python type system documentation"
---
## Core types
### Resource types
```python
from typing import TypedDict, Optional, Literal, Union, List
class Resource(TypedDict):
"""Represents a resource that can be accessed through MCP."""
uri: str
name: str
description: Optional[str]
mimeType: Optional[str]
class ResourceTemplate(TypedDict):
"""Template for constructing resource URIs."""
uriTemplate: str
name: str
description: Optional[str]
mimeType: Optional[str]
class ResourceContents(TypedDict):
"""Contents of a specific resource."""
uri: str
mimeType: Optional[str]
class TextResourceContents(ResourceContents):
"""Resource contents in text format."""
text: str
class BlobResourceContents(ResourceContents):
"""Resource contents in binary format."""
blob: bytes # Base64 encoded
```
### Message types
```python
class TextContent(TypedDict):
"""Text content in a message."""
type: Literal["text"]
text: str
class ImageContent(TypedDict):
"""Image content in a message."""
type: Literal["image"]
data: str # Base64 encoded
mimeType: str
MessageContent = Union[TextContent, ImageContent]
class Message(TypedDict):
"""A message in an LLM conversation."""
role: Literal["user", "assistant"]
content: MessageContent
```
### Tool types
```python
class ToolParameter(TypedDict):
"""Parameter definition for a tool."""
type: str
description: Optional[str]
required: Optional[bool]
class ToolSchema(TypedDict):
"""JSON Schema for tool parameters."""
type: Literal["object"]
properties: dict[str, ToolParameter]
required: Optional[List[str]]
class Tool(TypedDict):
"""Definition of a tool that can be called through MCP."""
name: str
description: str
inputSchema: ToolSchema
```
### Prompt types
```python
class PromptArgument(TypedDict):
"""Argument definition for a prompt template."""
name: str
description: Optional[str]
required: Optional[bool]
class Prompt(TypedDict):
"""A prompt template that can be used through MCP."""
name: str
description: Optional[str]
arguments: Optional[List[PromptArgument]]
class PromptResponse(TypedDict):
"""Response to a prompt request."""
description: Optional[str]
messages: List[Message]
```
### Progress types
```python
class Progress(TypedDict):
"""Progress information for long-running operations."""
progress: int
total: Optional[int]
```
### Logging types
```python
LogLevel = Literal["debug", "info", "warning", "error"]
class LogMessage(TypedDict):
"""A log message sent through MCP."""
level: LogLevel
logger: Optional[str]
data: Any # JSON-serializable value
```
## Request/Response types
### Resource requests
```python
class ListResourcesRequest(TypedDict):
"""Request to list available resources."""
cursor: Optional[str]
class ListResourcesResponse(TypedDict):
"""Response containing available resources."""
resources: List[Resource]
nextCursor: Optional[str]
class ReadResourceRequest(TypedDict):
"""Request to read a specific resource."""
uri: str
class ReadResourceResponse(TypedDict):
"""Response containing resource contents."""
contents: List[Union[TextResourceContents, BlobResourceContents]]
class SubscribeRequest(TypedDict):
"""Request to subscribe to resource updates."""
uri: str
class UnsubscribeRequest(TypedDict):
"""Request to unsubscribe from resource updates."""
uri: str
```
### Tool requests
```python
class ListToolsRequest(TypedDict):
"""Request to list available tools."""
cursor: Optional[str]
class ListToolsResponse(TypedDict):
"""Response containing available tools."""
tools: List[Tool]
nextCursor: Optional[str]
class CallToolRequest(TypedDict):
"""Request to call a specific tool."""
name: str
arguments: Optional[dict]
class CallToolResponse(TypedDict):
"""Response from a tool call."""
toolResult: Any # JSON-serializable value
```
### Prompt requests
```python
class ListPromptsRequest(TypedDict):
"""Request to list available prompts."""
cursor: Optional[str]
class ListPromptsResponse(TypedDict):
"""Response containing available prompts."""
prompts: List[Prompt]
nextCursor: Optional[str]
class GetPromptRequest(TypedDict):
"""Request to get a specific prompt."""
name: str
arguments: Optional[dict[str, str]]
```
## Protocol types
### Implementation Info
```python
class Implementation(TypedDict):
"""Information about an MCP implementation."""
name: str
version: str
```
### Capabilities
```python
class ResourceCapabilities(TypedDict):
"""Capabilities related to resources."""
subscribe: Optional[bool]
listChanged: Optional[bool]
class PromptCapabilities(TypedDict):
"""Capabilities related to prompts."""
listChanged: Optional[bool]
class ToolCapabilities(TypedDict):
"""Capabilities related to tools."""
listChanged: Optional[bool]
class ServerCapabilities(TypedDict):
"""Complete set of server capabilities."""
experimental: Optional[dict]
logging: Optional[dict]
prompts: Optional[PromptCapabilities]
resources: Optional[ResourceCapabilities]
tools: Optional[ToolCapabilities]
```
## Transport types
### Stream types
```python
class ReadStream(Protocol):
"""Protocol for reading from a transport."""
async def read(self) -> bytes: ...
class WriteStream(Protocol):
"""Protocol for writing to a transport."""
async def write(self, data: bytes) -> None: ...
```
### Session types
```python
class ServerSession(Protocol):
"""Protocol for server-side session operations."""
async def send_resource_updated(self, uri: str) -> None: ...
async def send_progress_notification(
self, token: str, progress: int, total: Optional[int] = None
) -> None: ...
async def send_log_message(
self, level: LogLevel, data: Any, logger: Optional[str] = None
) -> None: ...
```
## Usage examples
### Type usage in handlers
```python
from mcp_python.server import Server
from mcp_python.types import Resource, Tool, PromptResponse, Message
server = Server("example")
@server.list_resources()
async def list_resources() -> List[Resource]:
return [
{
"uri": "example://test",
"name": "Test Resource",
"description": "A test resource",
"mimeType": "text/plain"
}
]
@server.list_tools()
async def list_tools() -> List[Tool]:
return [
{
"name": "test-tool",
"description": "A test tool",
"inputSchema": {
"type": "object",
"properties": {
"param": {
"type": "string",
"description": "A parameter"
}
}
}
}
]
@server.get_prompt()
async def get_prompt(name: str, arguments: dict) -> PromptResponse:
return {
"description": "A test prompt",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": f"Test prompt with args: {arguments}"
}
}
]
}
```
### Type checking
```python
from typing import TypeGuard
def is_text_content(content: MessageContent) -> TypeGuard[TextContent]:
"""Type guard for text content."""
return content["type"] == "text"
def process_message(message: Message) -> str:
content = message["content"]
if is_text_content(content):
return content["text"]
return f"Image message with type: {content['mimeType']}"
```
## Additional notes
- All types are compatible with standard Python type checkers (mypy, pyright)
- TypedDict is used extensively to ensure proper structure of JSON-like objects
- Literal types are used to restrict string values to specific options
- Optional fields use the Optional type hint to indicate nullable values
- Protocol classes define interface contracts for pluggable components
For runtime type checking, you can use the following pattern:
```python
from typing import cast
from typing_extensions import assert_type
def validate_resource(data: dict) -> Resource:
"""Validate and convert a dict to a Resource type."""
required_fields = {"uri", "name"}
if not all(field in data for field in required_fields):
raise ValueError("Missing required fields")
return cast(Resource, {
"uri": str(data["uri"]),
"name": str(data["name"]),
"description": str(data.get("description")) if "description" in data else None,
"mimeType": str(data.get("mimeType")) if "mimeType" in data else None
})
```

View file

@ -1,330 +0,0 @@
---
title: "Event handling"
description: "Handle events and manage state in your MCP server"
---
MCP servers process various events including requests, notifications, and connection lifecycle events. This guide explains how to implement event handlers effectively in your server.
## Request handling
Request handlers process incoming requests from clients and must return a response. Each handler is associated with a specific method name.
<CodeGroup>
```typescript server.ts
import { Server } from "@modelcontextprotocol/sdk/server";
import { ListToolsRequestSchema, ListToolsResultSchema } from "@modelcontextprotocol/sdk/types";
const server = new Server({
name: "example-server",
version: "1.0.0",
});
server.setRequestHandler(ListToolsRequestSchema, async (request) => {
return {
tools: [
{
name: "example-tool",
description: "An example tool",
inputSchema: {
type: "object",
properties: {
message: { type: "string" },
},
},
},
],
};
});
```
```python server.py
from mcp import Server
from mcp.types import ListToolsRequest, ListToolsResult, Tool
server = Server(name="example-server", version="1.0.0")
@server.request_handler("tools/list")
async def handle_list_tools(request: ListToolsRequest) -> ListToolsResult:
return ListToolsResult(
tools=[
Tool(
name="example-tool",
description="An example tool",
input_schema={
"type": "object",
"properties": {
"message": {"type": "string"}
}
}
)
]
)
```
</CodeGroup>
## Notification handling
Notification handlers process one-way messages that don't require responses. They're useful for handling events like resource updates or logging messages.
<CodeGroup>
```typescript notifications.ts
import { ResourceUpdatedNotificationSchema } from "@modelcontextprotocol/sdk/types";
server.setNotificationHandler(ResourceUpdatedNotificationSchema, async (notification) => {
const { uri } = notification.params;
console.log(`Resource updated: ${uri}`);
});
```
```python notifications.py
from mcp.types import ResourceUpdatedNotification
@server.notification_handler("notifications/resources/updated")
async def handle_resource_updated(notification: ResourceUpdatedNotification):
uri = notification.params.uri
print(f"Resource updated: {uri}")
```
</CodeGroup>
## Connection lifecycle
Your server can handle connection lifecycle events through callbacks. This is useful for setup and cleanup operations.
<CodeGroup>
```typescript lifecycle.ts
const server = new Server({
name: "example-server",
version: "1.0.0",
});
server.oninitialized = () => {
console.log("Client has completed initialization");
};
server.onclose = () => {
console.log("Connection closed");
// Perform cleanup
};
```
```python lifecycle.py
server = Server(name="example-server", version="1.0.0")
@server.on_initialized
async def handle_initialized():
print("Client has completed initialization")
@server.on_close
async def handle_close():
print("Connection closed")
# Perform cleanup
```
</CodeGroup>
## Error handling
Properly handle errors in your event handlers to provide meaningful feedback to clients.
<CodeGroup>
```typescript errors.ts
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types";
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// Attempt to call tool
const result = await callTool(request.params);
return { toolResult: result };
} catch (error) {
throw new McpError(
ErrorCode.InvalidParams,
"Failed to execute tool",
{ details: error.message }
);
}
});
```
```python errors.py
from mcp.types import CallToolRequest, McpError, ErrorCode
@server.request_handler("tools/call")
async def handle_call_tool(request: CallToolRequest):
try:
# Attempt to call tool
result = await call_tool(request.params)
return {"toolResult": result}
except Exception as e:
raise McpError(
code=ErrorCode.INVALID_PARAMS,
message="Failed to execute tool",
data={"details": str(e)}
)
```
</CodeGroup>
## Progress reporting
For long-running operations, you can report progress back to the client.
<CodeGroup>
```typescript progress.ts
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const progressToken = request.params._meta?.progressToken;
if (progressToken) {
await server.notification({
method: "notifications/progress",
params: {
progressToken,
progress: 50,
total: 100
}
});
}
// Complete the operation
return { toolResult: "Operation completed" };
});
```
```python progress.py
@server.request_handler("tools/call")
async def handle_call_tool(request: CallToolRequest):
progress_token = request.params._meta.progress_token if request.params._meta else None
if progress_token:
await server.notify(
"notifications/progress",
{
"progressToken": progress_token,
"progress": 50,
"total": 100
}
)
# Complete the operation
return {"toolResult": "Operation completed"}
```
</CodeGroup>
## State management
While MCP servers are generally stateless, you might need to maintain some state between requests. Here's how to manage state safely:
<CodeGroup>
```typescript state.ts
class ExampleServer {
private subscriptions: Set<string> = new Set();
private server: Server;
constructor() {
this.server = new Server({
name: "example-server",
version: "1.0.0",
});
this.server.setRequestHandler(SubscribeRequestSchema, async (request) => {
const { uri } = request.params;
this.subscriptions.add(uri);
return {};
});
this.server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
const { uri } = request.params;
this.subscriptions.delete(uri);
return {};
});
this.server.onclose = () => {
this.subscriptions.clear();
};
}
}
```
```python state.py
class ExampleServer:
def __init__(self):
self.subscriptions = set()
self.server = Server(name="example-server", version="1.0.0")
@self.server.request_handler("resources/subscribe")
async def handle_subscribe(request: SubscribeRequest):
self.subscriptions.add(request.params.uri)
return {}
@self.server.request_handler("resources/unsubscribe")
async def handle_unsubscribe(request: UnsubscribeRequest):
self.subscriptions.remove(request.params.uri)
return {}
@self.server.on_close
async def handle_close():
self.subscriptions.clear()
```
</CodeGroup>
## Best practices
When implementing event handlers in your MCP server:
<CardGroup cols={2}>
<Card title="Validation" icon="shield-check">
Always validate request parameters before processing
</Card>
<Card title="Error handling" icon="triangle-exclamation">
Use appropriate error codes and provide helpful error messages
</Card>
<Card title="Async operations" icon="spinner">
Handle long-running operations asynchronously and report progress
</Card>
<Card title="Resource cleanup" icon="broom">
Clean up resources and state when connections are closed
</Card>
</CardGroup>
## Debugging tips
To help debug your event handlers:
1. Enable logging in your server:
<CodeGroup>
```typescript logging.ts
server.setRequestHandler(SetLevelRequestSchema, async (request) => {
const { level } = request.params;
server.notification({
method: "notifications/message",
params: {
level: "debug",
data: `Setting log level to: ${level}`
}
});
return {};
});
```
```python logging.py
@server.request_handler("logging/setLevel")
async def handle_set_level(request: SetLevelRequest):
level = request.params.level
await server.notify(
"notifications/message",
{
"level": "debug",
"data": f"Setting log level to: {level}"
}
)
return {}
```
</CodeGroup>
2. Use the progress reporting mechanism to debug long-running operations
3. Implement comprehensive error handling with detailed error messages
4. Add request/response logging for debugging complex interactions
Remember that logging and debugging information should be appropriate for the execution environment and should never expose sensitive information.

View file

@ -1,385 +0,0 @@
---
title: "Resource management"
description: "How to implement resource management in your MCP server"
---
Resources in MCP are any type of content that can be loaded as context for an LLM. This guide explains how to implement resource management in your MCP server.
## Overview
Resources are identified by URIs and can represent:
- Files on the local filesystem
- Remote data (e.g., database records, API responses)
- Generated content
- Dynamic system state
## Basic resource implementation
To implement resources in your MCP server, you need to handle two main requests:
- `resources/list`: Lists available resources
- `resources/read`: Reads the content of a specific resource
<CodeGroup>
```typescript server.ts
import { Server } from "@modelcontextprotocol/sdk/server";
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema
} from "@modelcontextprotocol/sdk/types";
const server = new Server({
name: "example-server",
version: "1.0.0",
});
// Handle resource listing
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "file:///example.txt",
name: "Example File",
mimeType: "text/plain",
description: "An example text file resource"
}
]
};
});
// Handle resource reading
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
// Read and return the resource content
return {
contents: [
{
uri: uri,
mimeType: "text/plain",
text: "Example content"
}
]
};
});
```
```python server.py
from mcp import Server
from mcp.types import Resource, ResourceContents
server = Server(
name="example-server",
version="1.0.0"
)
# Handle resource listing
@server.request_handler("resources/list")
async def list_resources(request):
return {
"resources": [
{
"uri": "file:///example.txt",
"name": "Example File",
"mimeType": "text/plain",
"description": "An example text file resource"
}
]
}
# Handle resource reading
@server.request_handler("resources/read")
async def read_resource(request):
uri = request.params["uri"]
# Read and return the resource content
return {
"contents": [
{
"uri": uri,
"mimeType": "text/plain",
"text": "Example content"
}
]
}
```
</CodeGroup>
## Resource content types
MCP supports two types of resource contents:
- Text content: For plain text and other text-based formats
- Binary content: For images and other binary data (encoded as base64)
<CodeGroup>
```typescript content-types.ts
// Text content example
const textContent = {
uri: "file:///document.txt",
mimeType: "text/plain",
text: "This is the text content"
};
// Binary content example
const binaryContent = {
uri: "file:///image.png",
mimeType: "image/png",
blob: Buffer.from("...").toString("base64")
};
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
return {
contents: [
// Return either text or binary content based on the resource
request.params.uri.endsWith(".txt") ? textContent : binaryContent
]
};
});
```
```python content-types.py
import base64
# Text content example
text_content = {
"uri": "file:///document.txt",
"mimeType": "text/plain",
"text": "This is the text content"
}
# Binary content example
binary_content = {
"uri": "file:///image.png",
"mimeType": "image/png",
"blob": base64.b64encode(b"...").decode()
}
@server.request_handler("resources/read")
async def read_resource(request):
return {
"contents": [
# Return either text or binary content based on the resource
text_content if request.params["uri"].endswith(".txt") else binary_content
]
}
```
</CodeGroup>
## Resource templates
Resource templates allow servers to define patterns for dynamic resources using URI templates (RFC 6570).
<CodeGroup>
```typescript templates.ts
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
// Static resources
{
uri: "file:///static.txt",
name: "Static File"
}
],
resourceTemplates: [
// Dynamic resources
{
uriTemplate: "user://{userId}/profile",
name: "User Profile",
description: "Access user profile data",
mimeType: "application/json"
}
]
};
});
```
```python templates.py
@server.request_handler("resources/list")
async def list_resources(request):
return {
"resources": [
# Static resources
{
"uri": "file:///static.txt",
"name": "Static File"
}
],
"resourceTemplates": [
# Dynamic resources
{
"uriTemplate": "user://{userId}/profile",
"name": "User Profile",
"description": "Access user profile data",
"mimeType": "application/json"
}
]
}
```
</CodeGroup>
## Resource updates
MCP supports notifying clients about resource changes through subscriptions and notifications.
<CodeGroup>
```typescript updates.ts
import { SubscribeRequestSchema, UnsubscribeRequestSchema } from "@modelcontextprotocol/sdk/types";
// Track subscribed resources
const subscriptions = new Set<string>();
// Handle subscription requests
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
const uri = request.params.uri;
subscriptions.add(uri);
return {};
});
// Handle unsubscribe requests
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
const uri = request.params.uri;
subscriptions.delete(uri);
return {};
});
// Notify about resource updates
function notifyResourceUpdate(uri: string) {
if (subscriptions.has(uri)) {
server.notification({
method: "notifications/resources/updated",
params: { uri }
});
}
}
```
```python updates.py
# Track subscribed resources
subscriptions = set()
# Handle subscription requests
@server.request_handler("resources/subscribe")
async def subscribe(request):
uri = request.params["uri"]
subscriptions.add(uri)
return {}
# Handle unsubscribe requests
@server.request_handler("resources/unsubscribe")
async def unsubscribe(request):
uri = request.params["uri"]
subscriptions.remove(uri)
return {}
# Notify about resource updates
async def notify_resource_update(uri: str):
if uri in subscriptions:
await server.notification(
method="notifications/resources/updated",
params={"uri": uri}
)
```
</CodeGroup>
## Pagination
For servers with many resources, MCP supports pagination using cursors.
<CodeGroup>
```typescript pagination.ts
const PAGE_SIZE = 10;
server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
const cursor = request.params?.cursor;
let startIndex = 0;
if (cursor) {
startIndex = parseInt(Buffer.from(cursor, 'base64').toString());
}
const resources = getAllResources();
const pageResources = resources.slice(startIndex, startIndex + PAGE_SIZE);
// Calculate next cursor if there are more resources
const nextCursor = startIndex + PAGE_SIZE < resources.length
? Buffer.from(String(startIndex + PAGE_SIZE)).toString('base64')
: undefined;
return {
resources: pageResources,
nextCursor
};
});
```
```python pagination.py
PAGE_SIZE = 10
@server.request_handler("resources/list")
async def list_resources(request):
cursor = request.params.get("cursor")
start_index = 0
if cursor:
start_index = int(base64.b64decode(cursor))
resources = get_all_resources()
page_resources = resources[start_index:start_index + PAGE_SIZE]
# Calculate next cursor if there are more resources
next_cursor = (base64.b64encode(str(start_index + PAGE_SIZE).encode()).decode()
if start_index + PAGE_SIZE < len(resources) else None)
return {
"resources": page_resources,
"nextCursor": next_cursor
}
```
</CodeGroup>
## Best practices
When implementing resource management:
<CardGroup cols={2}>
<Card title="URI design" icon="link">
Use meaningful URI schemes and hierarchical paths for resource organization
</Card>
<Card title="Error handling" icon="triangle-exclamation">
Return appropriate error codes for missing or inaccessible resources
</Card>
<Card title="Content types" icon="file-code">
Always specify accurate MIME types for resource contents
</Card>
<Card title="Resource cleanup" icon="broom">
Implement proper cleanup for subscriptions when connections close
</Card>
</CardGroup>
## Resource security
When exposing resources:
- Validate all URI parameters and resource paths
- Implement appropriate access controls
- Sanitize and validate all resource content
- Consider rate limiting for resource-intensive operations
- Use secure transport mechanisms (e.g., HTTPS) for remote resources
## Common pitfalls
- Failing to handle URI encoding/decoding properly
- Not cleaning up subscriptions when connections close
- Returning inconsistent MIME types
- Missing error handling for invalid resource requests
- Not implementing pagination for large resource collections
- Memory leaks from unmanaged resource subscriptions

View file

@ -1,462 +0,0 @@
---
title: "Tool implementation"
description: "Learn how to implement tools in your MCP server"
---
Tools are one of the core features of MCP, allowing servers to expose functionality that can be invoked by clients or AI models. This guide explains how to implement tools in your MCP server.
## Tool definition
Tools are defined by implementing the `Tool` interface, which describes the tool's name, description, and input schema.
<CodeGroup>
```typescript Tool interface in TypeScript
interface Tool {
// The name of the tool
name: string;
// A human-readable description
description?: string;
// JSON Schema defining the expected parameters
inputSchema: {
type: "object";
properties?: Record<string, unknown>;
};
}
```
```python Tool interface in Python
@dataclass
class Tool:
# The name of the tool
name: str
# A human-readable description
description: Optional[str] = None
# JSON Schema defining the expected parameters
input_schema: Dict[str, Any] = field(default_factory=lambda: {
"type": "object",
"properties": {}
})
```
</CodeGroup>
## Basic implementation
Here's a simple example of implementing a tool that adds two numbers:
<CodeGroup>
```typescript calculator.ts
import { Server } from "@modelcontextprotocol/sdk/server";
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types";
const server = new Server({
name: "calculator-server",
version: "1.0.0",
});
// Define and register available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "add",
description: "Add two numbers together",
inputSchema: {
type: "object",
properties: {
a: { type: "number", description: "First number" },
b: { type: "number", description: "Second number" }
},
required: ["a", "b"]
}
}
]
};
});
// Implement tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "add") {
const a = request.params.arguments?.a as number;
const b = request.params.arguments?.b as number;
return {
toolResult: a + b
};
}
throw new Error("Tool not found");
});
```
```python calculator.py
from dataclasses import dataclass
from typing import Dict, Any
from mcp_sdk import Server, Tool
server = Server(
name="calculator-server",
version="1.0.0"
)
# Define the tool
add_tool = Tool(
name="add",
description="Add two numbers together",
input_schema={
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"}
},
"required": ["a", "b"]
}
)
@server.handle_list_tools
async def handle_list_tools(request):
return {
"tools": [add_tool]
}
@server.handle_call_tool
async def handle_call_tool(request):
if request.params.name == "add":
a = request.params.arguments["a"]
b = request.params.arguments["b"]
return {
"toolResult": a + b
}
raise ValueError("Tool not found")
```
</CodeGroup>
## Progress reporting
For long-running operations, tools can report progress back to the client:
<CodeGroup>
```typescript long-operation.ts
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "longOperation",
description: "A time-consuming operation with progress updates",
inputSchema: {
type: "object",
properties: {
duration: {
type: "number",
description: "Duration in seconds"
}
}
}
}
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "longOperation") {
const duration = request.params.arguments?.duration as number ?? 10;
const steps = 10;
const stepDuration = duration / steps;
const progressToken = request.params._meta?.progressToken;
for (let i = 1; i <= steps; i++) {
await new Promise(resolve => setTimeout(resolve, stepDuration * 1000));
if (progressToken) {
server.notification({
method: "notifications/progress",
params: {
progress: i,
total: steps,
progressToken
}
});
}
}
return { toolResult: "Operation completed" };
}
throw new Error("Tool not found");
});
```
```python long_operation.py
import asyncio
from mcp_sdk import Server, Tool
long_operation_tool = Tool(
name="longOperation",
description="A time-consuming operation with progress updates",
input_schema={
"type": "object",
"properties": {
"duration": {
"type": "number",
"description": "Duration in seconds"
}
}
}
)
@server.handle_list_tools
async def handle_list_tools(request):
return {
"tools": [long_operation_tool]
}
@server.handle_call_tool
async def handle_call_tool(request):
if request.params.name == "longOperation":
duration = request.params.arguments.get("duration", 10)
steps = 10
step_duration = duration / steps
progress_token = request.params._meta.get("progressToken")
for i in range(1, steps + 1):
await asyncio.sleep(step_duration)
if progress_token:
await server.notification({
"method": "notifications/progress",
"params": {
"progress": i,
"total": steps,
"progressToken": progress_token
}
})
return {"toolResult": "Operation completed"}
raise ValueError("Tool not found")
```
</CodeGroup>
## Error handling
Tools should handle errors gracefully and return appropriate error information:
<CodeGroup>
```typescript error-handling.ts
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "riskyOperation") {
try {
// Attempt the operation
const result = await performRiskyOperation(request.params.arguments);
return { toolResult: result };
} catch (error) {
if (error instanceof ValidationError) {
throw new McpError(
ErrorCode.InvalidParams,
"Invalid parameters provided",
error.details
);
}
if (error instanceof OperationError) {
throw new McpError(
ErrorCode.InternalError,
"Operation failed",
{
reason: error.message,
retryable: error.isRetryable
}
);
}
throw error;
}
}
});
```
```python error_handling.py
from mcp_sdk import McpError, ErrorCode
@server.handle_call_tool
async def handle_call_tool(request):
if request.params.name == "riskyOperation":
try:
# Attempt the operation
result = await perform_risky_operation(request.params.arguments)
return {"toolResult": result}
except ValidationError as e:
raise McpError(
code=ErrorCode.INVALID_PARAMS,
message="Invalid parameters provided",
data=e.details
)
except OperationError as e:
raise McpError(
code=ErrorCode.INTERNAL_ERROR,
message="Operation failed",
data={
"reason": str(e),
"retryable": e.is_retryable
}
)
```
</CodeGroup>
## Best practices
When implementing tools, follow these guidelines:
<CardGroup cols={2}>
<Card title="Clear descriptions" icon="book">
Provide detailed descriptions that help AI models understand when and how to use the tool
</Card>
<Card title="Input validation" icon="shield-check">
Use JSON Schema to define and validate input parameters thoroughly
</Card>
<Card title="Progress updates" icon="bars-progress">
Send regular progress updates for operations that take more than a few seconds
</Card>
<Card title="Error handling" icon="triangle-exclamation">
Return specific error codes and helpful error messages
</Card>
</CardGroup>
### Tool naming conventions
- Use camelCase for tool names in TypeScript/JavaScript
- Use snake_case for tool names in Python
- Keep names concise but descriptive
- Use verbs for action-oriented tools (e.g., `convertCurrency`, `fetchWeather`)
- Use nouns for data-oriented tools (e.g., `userProfile`, `systemStatus`)
### Input schema best practices
- Be explicit about required vs optional parameters
- Include descriptions for all parameters
- Use appropriate JSON Schema types and formats
- Consider adding validation constraints (min, max, pattern, etc.)
Example of a well-defined input schema:
<CodeGroup>
```typescript schema-example.ts
const toolSchema = {
type: "object",
properties: {
query: {
type: "string",
description: "Search query string",
minLength: 1,
maxLength: 100
},
limit: {
type: "integer",
description: "Maximum number of results",
minimum: 1,
maximum: 100,
default: 10
},
includeArchived: {
type: "boolean",
description: "Include archived items in results",
default: false
}
},
required: ["query"]
};
```
```python schema_example.py
tool_schema = {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query string",
"minLength": 1,
"maxLength": 100
},
"limit": {
"type": "integer",
"description": "Maximum number of results",
"minimum": 1,
"maximum": 100,
"default": 10
},
"include_archived": {
"type": "boolean",
"description": "Include archived items in results",
"default": False
}
},
"required": ["query"]
}
```
</CodeGroup>
## Testing tools
Here's how to test your tool implementations:
<CodeGroup>
```typescript tool-test.ts
import { TestServer } from "@modelcontextprotocol/sdk/testing";
describe("Calculator tools", () => {
let server: TestServer;
beforeEach(() => {
server = new TestServer();
// Initialize your tools
});
it("should add two numbers", async () => {
const response = await server.callTool("add", {
a: 5,
b: 3
});
expect(response.toolResult).toBe(8);
});
it("should handle invalid inputs", async () => {
await expect(
server.callTool("add", {
a: "not a number",
b: 3
})
).rejects.toThrow();
});
});
```
```python tool_test.py
import pytest
from mcp_sdk.testing import TestServer
@pytest.fixture
async def server():
server = TestServer()
# Initialize your tools
return server
async def test_add_numbers(server):
response = await server.call_tool("add", {
"a": 5,
"b": 3
})
assert response.tool_result == 8
async def test_invalid_input(server):
with pytest.raises(ValueError):
await server.call_tool("add", {
"a": "not a number",
"b": 3
})
```
</CodeGroup>

View file

@ -1,418 +0,0 @@
---
title: "TypeScript class reference"
description: "Complete TypeScript SDK class documentation"
---
## Client classes
### Client
The main class for implementing MCP clients in TypeScript.
```typescript
import { Client } from "@modelcontextprotocol/sdk/client";
```
#### Constructor
```typescript
constructor(clientInfo: Implementation)
```
**Parameters:**
- `clientInfo`: Implementation object containing:
- `name`: string - Name of the client
- `version`: string - Version of the client
#### Methods
##### connect()
```typescript
async connect(transport: Transport): Promise<void>
```
Connects to a server using the provided transport.
##### request()
```typescript
async request<T extends AnyZodObject>(
request: ClientRequest,
resultSchema: T,
onprogress?: ProgressCallback
): Promise<z.infer<T>>
```
Sends a request to the server and waits for a response.
##### notification()
```typescript
async notification(notification: ClientNotification): Promise<void>
```
Sends a one-way notification to the server.
##### close()
```typescript
async close(): Promise<void>
```
Closes the connection to the server.
##### getServerCapabilities()
```typescript
getServerCapabilities(): ServerCapabilities | undefined
```
Returns the server's capabilities after connection.
##### getServerVersion()
```typescript
getServerVersion(): Implementation | undefined
```
Returns the server's version information after connection.
### Transport classes
#### StdioClientTransport
```typescript
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio";
```
##### Constructor
```typescript
constructor(params: StdioServerParameters)
```
**Parameters:**
- `params`: Object containing:
- `command`: string - Command to execute
- `args?`: string[] - Command arguments
- `env?`: object - Environment variables
#### SSEClientTransport
```typescript
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse";
```
##### Constructor
```typescript
constructor(url: URL)
```
#### WebSocketClientTransport
```typescript
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket";
```
##### Constructor
```typescript
constructor(url: URL)
```
## Server classes
### Server
The main class for implementing MCP servers in TypeScript.
```typescript
import { Server } from "@modelcontextprotocol/sdk/server";
```
#### Constructor
```typescript
constructor(serverInfo: Implementation)
```
**Parameters:**
- `serverInfo`: Implementation object containing:
- `name`: string - Name of the server
- `version`: string - Version of the server
#### Methods
##### connect()
```typescript
async connect(transport: Transport): Promise<void>
```
Starts listening for client connections.
##### setRequestHandler()
```typescript
setRequestHandler<T extends ZodObject<{method: ZodLiteral<string>}>>(
requestSchema: T,
handler: (request: z.infer<T>) => ServerResult | Promise<ServerResult>
): void
```
Registers a handler for specific request types.
##### setNotificationHandler()
```typescript
setNotificationHandler<T extends ZodObject<{method: ZodLiteral<string>}>>(
notificationSchema: T,
handler: (notification: z.infer<T>) => void | Promise<void>
): void
```
Registers a handler for specific notification types.
##### notification()
```typescript
async notification(notification: ServerNotification): Promise<void>
```
Sends a notification to the client.
##### close()
```typescript
async close(): Promise<void>
```
Closes all connections.
##### getClientCapabilities()
```typescript
getClientCapabilities(): ClientCapabilities | undefined
```
Returns the client's capabilities after connection.
##### getClientVersion()
```typescript
getClientVersion(): Implementation | undefined
```
Returns the client's version information after connection.
### Transport classes
#### StdioServerTransport
```typescript
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
```
##### Constructor
```typescript
constructor(stdin?: Readable, stdout?: Writable)
```
#### SSEServerTransport
```typescript
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse";
```
##### Constructor
```typescript
constructor(endpoint: string, res: ServerResponse)
```
## Examples
### Client implementation
```typescript
import { Client } from "@modelcontextprotocol/sdk/client";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio";
import {
ListResourcesResultSchema,
ReadResourceResultSchema,
ListToolsResultSchema,
CallToolResultSchema
} from "@modelcontextprotocol/sdk/types";
async function main() {
// Create client
const client = new Client({
name: "example-client",
version: "1.0.0"
});
// Connect to server
const transport = new StdioClientTransport({
command: "./server",
args: ["--config", "config.json"]
});
await client.connect(transport);
try {
// List resources
const resources = await client.request(
{ method: "resources/list" },
ListResourcesResultSchema
);
console.log("Available resources:", resources);
// Read resource
const content = await client.request(
{
method: "resources/read",
params: { uri: "example://resource" }
},
ReadResourceResultSchema
);
console.log("Resource content:", content);
// List tools
const tools = await client.request(
{ method: "tools/list" },
ListToolsResultSchema
);
console.log("Available tools:", tools);
// Call tool with progress
const result = await client.request(
{
method: "tools/call",
params: {
name: "example-tool",
arguments: { param1: "value1" }
}
},
CallToolResultSchema,
(progress) => {
console.log(`Progress: ${progress.progress}/${progress.total}`);
}
);
console.log("Tool result:", result);
} finally {
await client.close();
}
}
```
### Server implementation
```typescript
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import {
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListToolsRequestSchema,
CallToolRequestSchema
} from "@modelcontextprotocol/sdk/types";
async function main() {
// Create server
const server = new Server({
name: "example-server",
version: "1.0.0"
});
// Handle resource listing
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "example://resource",
name: "Example Resource",
description: "An example resource"
}
]
};
});
// Handle resource reading
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri === "example://resource") {
return {
contents: [
{
uri: request.params.uri,
mimeType: "text/plain",
text: "Example content"
}
]
};
}
throw new Error("Resource not found");
});
// Handle tool listing
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "example-tool",
description: "An example tool",
inputSchema: {
type: "object",
properties: {
param1: { type: "string" }
}
}
}
]
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
// Send progress updates
for (let i = 0; i < 5; i++) {
await server.notification({
method: "notifications/progress",
params: {
progress: i + 1,
total: 5,
progressToken: request.params._meta?.progressToken
}
});
await new Promise(resolve => setTimeout(resolve, 1000));
}
return {
toolResult: `Executed ${name} with args: ${JSON.stringify(args)}`
};
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
}
```
## Best practices
1. **Error Handling**
```typescript
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
try {
const content = await readResource(request.params.uri);
return { contents: [content] };
} catch (error) {
if (error instanceof ResourceNotFoundError) {
throw new McpError(404, `Resource not found: ${request.params.uri}`);
}
throw error;
}
});
```
2. **Progress Updates**
```typescript
async function longRunningOperation(
progressToken?: string | number
): Promise<void> {
for (let i = 0; i < total; i++) {
await server.notification({
method: "notifications/progress",
params: {
progress: i,
total,
progressToken
}
});
}
}
```
3. **Resource Updates**
```typescript
async function updateResource(uri: string): Promise<void> {
// Update resource
await server.notification({
method: "notifications/resources/updated",
params: { uri }
});
}
```
4. **Cleanup**
```typescript
process.on("SIGINT", async () => {
await server.close();
process.exit(0);
});
```

View file

@ -1,461 +0,0 @@
---
title: "TypeScript type definitions"
description: "TypeScript type system documentation"
---
## Core protocol types
### JSON-RPC types
```typescript
export const JSONRPC_VERSION = "2.0";
/** A uniquely identifying ID for a request in JSON-RPC */
export type RequestId = string | number;
/** A request that expects a response */
export interface JSONRPCRequest {
jsonrpc: typeof JSONRPC_VERSION;
id: RequestId;
method: string;
params?: Record<string, unknown>;
}
/** A notification which does not expect a response */
export interface JSONRPCNotification {
jsonrpc: typeof JSONRPC_VERSION;
method: string;
params?: Record<string, unknown>;
}
/** A successful (non-error) response to a request */
export interface JSONRPCResponse {
jsonrpc: typeof JSONRPC_VERSION;
id: RequestId;
result: unknown;
}
/** A response to a request that indicates an error occurred */
export interface JSONRPCError {
jsonrpc: typeof JSONRPC_VERSION;
id: RequestId;
error: {
code: number;
message: string;
data?: unknown;
};
}
export type JSONRPCMessage =
| JSONRPCRequest
| JSONRPCNotification
| JSONRPCResponse
| JSONRPCError;
```
### Message content types
```typescript
/** Text provided to or from an LLM */
export interface TextContent {
type: "text";
text: string;
}
/** An image provided to or from an LLM */
export interface ImageContent {
type: "image";
data: string; // Base64-encoded
mimeType: string;
}
/** Describes a message issued to or received from an LLM API */
export interface SamplingMessage {
role: "user" | "assistant";
content: TextContent | ImageContent;
}
/** Progress information for long-running operations */
export interface Progress {
progress: number;
total?: number;
}
export type ProgressCallback = (progress: Progress) => void;
```
### Resource types
```typescript
/** The contents of a specific resource */
export interface ResourceContents {
uri: string;
mimeType?: string;
}
/** Text-based resource contents */
export interface TextResourceContents extends ResourceContents {
text: string;
}
/** Binary resource contents */
export interface BlobResourceContents extends ResourceContents {
blob: string; // Base64-encoded
}
/** A known resource that the server is capable of reading */
export interface Resource {
uri: string;
name: string;
description?: string;
mimeType?: string;
}
/** A template description for resources available on the server */
export interface ResourceTemplate {
uriTemplate: string;
name: string;
description?: string;
mimeType?: string;
}
```
### Tool types
```typescript
/** Definition for a tool the client can call */
export interface Tool {
name: string;
description?: string;
inputSchema: {
type: "object";
properties?: Record<string, unknown>;
};
}
```
### Prompt types
```typescript
/** Describes an argument that a prompt can accept */
export interface PromptArgument {
name: string;
description?: string;
required?: boolean;
}
/** A prompt or prompt template that the server offers */
export interface Prompt {
name: string;
description?: string;
arguments?: PromptArgument[];
}
```
## Request/response types
### Resource requests
```typescript
export interface ListResourcesRequest {
method: "resources/list";
params?: {
cursor?: string;
};
}
export interface ListResourcesResult {
resources: Resource[];
nextCursor?: string;
}
export interface ReadResourceRequest {
method: "resources/read";
params: {
uri: string;
};
}
export interface ReadResourceResult {
contents: Array<TextResourceContents | BlobResourceContents>;
}
export interface SubscribeRequest {
method: "resources/subscribe";
params: {
uri: string;
};
}
export interface UnsubscribeRequest {
method: "resources/unsubscribe";
params: {
uri: string;
};
}
```
### Tool requests
```typescript
export interface ListToolsRequest {
method: "tools/list";
params?: {
cursor?: string;
};
}
export interface ListToolsResult {
tools: Tool[];
nextCursor?: string;
}
export interface CallToolRequest {
method: "tools/call";
params: {
name: string;
arguments?: Record<string, unknown>;
_meta?: {
progressToken?: string | number;
};
};
}
export interface CallToolResult {
toolResult: unknown;
}
```
### Prompt requests
```typescript
export interface ListPromptsRequest {
method: "prompts/list";
params?: {
cursor?: string;
};
}
export interface ListPromptsResult {
prompts: Prompt[];
nextCursor?: string;
}
export interface GetPromptRequest {
method: "prompts/get";
params: {
name: string;
arguments?: Record<string, string>;
};
}
export interface GetPromptResult {
description?: string;
messages: SamplingMessage[];
}
```
## Protocol types
### Implementation info
```typescript
export interface Implementation {
name: string;
version: string;
}
```
### Capability types
```typescript
export interface ResourceCapabilities {
subscribe?: boolean;
listChanged?: boolean;
}
export interface PromptCapabilities {
listChanged?: boolean;
}
export interface ToolCapabilities {
listChanged?: boolean;
}
export interface ServerCapabilities {
experimental?: Record<string, unknown>;
logging?: Record<string, unknown>;
prompts?: PromptCapabilities;
resources?: ResourceCapabilities;
tools?: ToolCapabilities;
}
export interface ClientCapabilities {
experimental?: Record<string, unknown>;
sampling?: Record<string, unknown>;
}
```
### Notification types
```typescript
export interface ResourceUpdatedNotification {
method: "notifications/resources/updated";
params: {
uri: string;
};
}
export interface ProgressNotification {
method: "notifications/progress";
params: Progress & {
progressToken: string | number;
};
}
export interface LogMessageNotification {
method: "notifications/message";
params: {
level: "debug" | "info" | "warning" | "error";
logger?: string;
data: unknown;
};
}
export type ServerNotification =
| ResourceUpdatedNotification
| ProgressNotification
| LogMessageNotification;
```
## Error types
```typescript
export enum ErrorCode {
// SDK error codes
ConnectionClosed = -1,
// Standard JSON-RPC error codes
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
}
export class McpError extends Error {
constructor(
public readonly code: number,
message: string,
public readonly data?: unknown
) {
super(`MCP error ${code}: ${message}`);
}
}
```
## Transport types
```typescript
export interface Transport {
start(): Promise<void>;
send(message: JSONRPCMessage): Promise<void>;
close(): Promise<void>;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
}
export interface StdioServerParameters {
command: string;
args?: string[];
env?: Record<string, string>;
}
```
## Usage examples
### Type guards
```typescript
function isTextContent(content:
TextContent | ImageContent
): content is TextContent {
return content.type === "text";
}
function isResourceUpdatedNotification(
notification: ServerNotification
): notification is ResourceUpdatedNotification {
return notification.method === "notifications/resources/updated";
}
```
### Type assertions
```typescript
function assertResource(data: unknown): asserts data is Resource {
if (typeof data !== "object" || data === null) {
throw new TypeError("Expected object");
}
const resource = data as Partial<Resource>;
if (typeof resource.uri !== "string") {
throw new TypeError("Expected string uri");
}
if (typeof resource.name !== "string") {
throw new TypeError("Expected string name");
}
}
```
### Using generics
```typescript
async function handleResourceContent<T extends ResourceContents>(
content: T
): Promise<string> {
if ("text" in content) {
return content.text;
}
if ("blob" in content) {
return atob(content.blob);
}
throw new Error("Invalid resource content");
}
```
### Working with union types
```typescript
function processMessage(message: SamplingMessage): string {
const { content } = message;
switch (content.type) {
case "text":
return content.text;
case "image":
return `Image: ${content.mimeType}`;
default:
const _exhaustiveCheck: never = content;
throw new Error("Unknown content type");
}
}
```
## Type utilities
```typescript
/** Helper type to extract request params from method name */
type RequestParams<T extends string> = Extract<
ClientRequest,
{ method: T }
>["params"];
/** Helper type to extract result type from schema */
type SchemaType<T extends ZodType> = z.infer<T>;
/** Helper type for request handlers */
type RequestHandler<T extends ClientRequest> = (
request: T
) => Promise<SchemaType<typeof ResultSchemas[T["method"]]>>;
```

View file

@ -22,6 +22,10 @@ npx @modelcontextprotocol/inspector path/to/server.js arg1 arg2
## Feature overview
<Frame caption="The MCP Inspector interface">
<img src="/images/mcp-inspector.png" />
</Frame>
The Inspector provides several features for interacting with your MCP server:
### Server connection pane

BIN
images/mcp-inspector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

View file

@ -17,12 +17,6 @@
"name": "GitHub",
"url": "https://github.com/modelcontextprotocol"
},
"tabs": [
{
"name": "API Reference",
"url": "api-reference"
}
],
"anchors": [
{
"name": "Python SDK",
@ -43,24 +37,15 @@
"navigation": [
{
"group": "Get Started",
"pages": [
"introduction",
"quickstart"
]
"pages": ["introduction", "quickstart"]
},
{
"group": "Your First MCP Server",
"pages": [
"docs/first-server/python",
"docs/first-server/typescript"
]
"pages": ["docs/first-server/python", "docs/first-server/typescript"]
},
{
"group": "Development Tools",
"pages": [
"docs/tools/debugging",
"docs/tools/inspector"
]
"pages": ["docs/tools/debugging", "docs/tools/inspector"]
},
{
"group": "Concepts",
@ -72,44 +57,6 @@
"docs/concepts/sampling",
"docs/concepts/transports"
]
},
{
"group": "API Reference",
"pages": [
"api-reference/protocol-overview",
"api-reference/message-types",
"api-reference/error-handling"
]
},
{
"group": "Server APIs",
"pages": [
"api-reference/server-api/resource-management",
"api-reference/server-api/tool-implementation",
"api-reference/server-api/event-handling"
]
},
{
"group": "Client APIs",
"pages": [
"api-reference/client-api/connection-management",
"api-reference/client-api/resource-consumption",
"api-reference/client-api/tool-invocation"
]
},
{
"group": "Python SDK",
"pages": [
"api-reference/python/class-reference",
"api-reference/python/type-hints"
]
},
{
"group": "TypeScript SDK",
"pages": [
"api-reference/typescript/class-reference",
"api-reference/typescript/type-definitions"
]
}
],
"footerSocials": {

View file

@ -1,15 +0,0 @@
.stroke-path {
stroke: black;
stroke-width: 12;
stroke-linecap: round;
}
@media (prefers-color-scheme: dark) {
.stroke-path {
stroke: white;
}
#clip0_19_13 rect {
fill: transparent;
}
}