This commit is contained in:
Zack Lee 2024-11-20 12:24:08 -05:00
commit ba7d5b866d
No known key found for this signature in database
16 changed files with 79 additions and 1432 deletions

View file

@ -1,5 +1,5 @@
--- ---
title: "Connection Management" title: "Connection management"
description: "Learn how to establish and manage MCP client connections" description: "Learn how to establish and manage MCP client connections"
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: "Resource Consumption" title: "Resource consumption"
description: "Learn how to consume resources from MCP servers" description: "Learn how to consume resources from MCP servers"
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: "Tool Invocation" title: "Tool invocation"
description: "Learn how to invoke tools through the MCP client API" description: "Learn how to invoke tools through the MCP client API"
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: 'Error Handling' title: 'Error handling'
description: 'How to handle and respond to errors in the Model Context Protocol' description: 'How to handle and respond to errors in the Model Context Protocol'
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: 'Message Types' title: 'Message types'
description: 'Understanding the different types of messages in the Model Context Protocol' description: 'Understanding the different types of messages in the Model Context Protocol'
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: "Protocol Overview" title: "Protocol overview"
description: "Learn about the core concepts and architecture of the Model Context Protocol (MCP)" description: "Learn about the core concepts and architecture of the Model Context Protocol (MCP)"
--- ---
@ -22,10 +22,8 @@ The Model Context Protocol (MCP) is a standardized protocol that enables AI appl
</Card> </Card>
</CardGroup> </CardGroup>
# Core concepts ## Core concepts
MCP defines several key primitives that form the foundation of the protocol: MCP defines several key primitives that form the foundation of the protocol:
<CardGroup cols={2}> <CardGroup cols={2}>
<Card title="Resources" icon="book"> <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. Data that can be loaded as context for the AI model. Resources have URIs and can contain text or binary data.
@ -41,12 +39,10 @@ MCP defines several key primitives that form the foundation of the protocol:
</Card> </Card>
</CardGroup> </CardGroup>
# Protocol flow ## Protocol flow
## Connection and initialization
### Connection and initialization
When a client connects to an MCP server, they go through the following initialization sequence: When a client connects to an MCP server, they go through the following initialization sequence:
<Steps> <Steps>
<Step title="Client connects"> <Step title="Client connects">
The client establishes a connection to the server using one of the supported transports. The client establishes a connection to the server using one of the supported transports.
@ -64,10 +60,8 @@ When a client connects to an MCP server, they go through the following initializ
After initialization, the client can begin using the server's resources, tools, and other capabilities. After initialization, the client can begin using the server's resources, tools, and other capabilities.
## Transport options ### Transport options
MCP supports multiple transport mechanisms for client-server communication: MCP supports multiple transport mechanisms for client-server communication:
<AccordionGroup> <AccordionGroup>
<Accordion title="Standard input/output (stdio)"> <Accordion title="Standard input/output (stdio)">
- Server process reads from stdin and writes to stdout - Server process reads from stdin and writes to stdout

View file

@ -1,9 +1,9 @@
--- ---
title: "Python Class Reference" title: "Python class reference"
description: "Complete Python SDK class documentation" description: "Complete Python SDK class documentation"
--- ---
## Server Class ## Server class
The main class for implementing MCP servers in Python. The main class for implementing MCP servers in Python.
@ -25,7 +25,7 @@ Creates a new MCP server instance.
### Decorators ### Decorators
#### Resource Handling #### Resource handling
##### @server.list_resources() ##### @server.list_resources()
```python ```python
@ -72,7 +72,7 @@ async def unsubscribe_resource(uri: str) -> None:
**Parameters:** **Parameters:**
- `uri` (str): Resource URI to unsubscribe from - `uri` (str): Resource URI to unsubscribe from
#### Tool Support #### Tool support
##### @server.list_tools() ##### @server.list_tools()
```python ```python
@ -99,7 +99,7 @@ async def call_tool(name: str, **kwargs) -> Any:
**Returns:** Tool execution result (any JSON-serializable value) **Returns:** Tool execution result (any JSON-serializable value)
#### Prompt Management #### Prompt management
##### @server.list_prompts() ##### @server.list_prompts()
```python ```python
@ -128,7 +128,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
- `messages` (List[Message]): List of prompt messages - `messages` (List[Message]): List of prompt messages
- `description` (str, optional): Description of the prompt response - `description` (str, optional): Description of the prompt response
### Session Methods ### Session methods
Methods available on the server session object: Methods available on the server session object:
@ -158,7 +158,7 @@ async def send_log_message(
"""Sends log messages to clients.""" """Sends log messages to clients."""
``` ```
## Data Classes ## Data classes
### Resource ### Resource
```python ```python
@ -204,7 +204,7 @@ class PromptResponse:
description: Optional[str] = None description: Optional[str] = None
``` ```
## Example Usage ## Example usage
Here's a complete example demonstrating the main features: Here's a complete example demonstrating the main features:
@ -263,7 +263,7 @@ if __name__ == "__main__":
anyio.run(main) anyio.run(main)
``` ```
## Best Practices ## Best practices
1. **Error Handling**: Always implement proper error handling in your server methods: 1. **Error Handling**: Always implement proper error handling in your server methods:
```python ```python
@ -303,15 +303,15 @@ if __name__ == "__main__":
await session.send_resource_updated("example://resource1") await session.send_resource_updated("example://resource1")
``` ```
## Transport Options ## Transport options
### stdio Transport ### Stdio transport
```python ```python
async with stdio_server() as (read_stream, write_stream): async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream) await server.run(read_stream, write_stream)
``` ```
### SSE Transport ### SSE transport
```python ```python
from mcp_python.transport import SSETransport from mcp_python.transport import SSETransport
@ -327,7 +327,7 @@ async def message_endpoint(request: Request):
return await transport.handle_message(request) return await transport.handle_message(request)
``` ```
### WebSocket Transport ### WebSocket transport
```python ```python
from mcp_python.transport import WebSocketTransport from mcp_python.transport import WebSocketTransport

View file

@ -1,11 +1,11 @@
--- ---
title: "Python Type Hints" title: "Python type hints"
description: "Python type system documentation" description: "Python type system documentation"
--- ---
## Core Types ## Core types
### Resource Types ### Resource types
```python ```python
from typing import TypedDict, Optional, Literal, Union, List from typing import TypedDict, Optional, Literal, Union, List
@ -38,7 +38,7 @@ class BlobResourceContents(ResourceContents):
blob: bytes # Base64 encoded blob: bytes # Base64 encoded
``` ```
### Message Types ### Message types
```python ```python
class TextContent(TypedDict): class TextContent(TypedDict):
@ -60,7 +60,7 @@ class Message(TypedDict):
content: MessageContent content: MessageContent
``` ```
### Tool Types ### Tool types
```python ```python
class ToolParameter(TypedDict): class ToolParameter(TypedDict):
@ -82,7 +82,7 @@ class Tool(TypedDict):
inputSchema: ToolSchema inputSchema: ToolSchema
``` ```
### Prompt Types ### Prompt types
```python ```python
class PromptArgument(TypedDict): class PromptArgument(TypedDict):
@ -103,7 +103,7 @@ class PromptResponse(TypedDict):
messages: List[Message] messages: List[Message]
``` ```
### Progress Types ### Progress types
```python ```python
class Progress(TypedDict): class Progress(TypedDict):
@ -112,7 +112,7 @@ class Progress(TypedDict):
total: Optional[int] total: Optional[int]
``` ```
### Logging Types ### Logging types
```python ```python
LogLevel = Literal["debug", "info", "warning", "error"] LogLevel = Literal["debug", "info", "warning", "error"]
@ -124,9 +124,9 @@ class LogMessage(TypedDict):
data: Any # JSON-serializable value data: Any # JSON-serializable value
``` ```
## Request/Response Types ## Request/Response types
### Resource Requests ### Resource requests
```python ```python
class ListResourcesRequest(TypedDict): class ListResourcesRequest(TypedDict):
@ -155,7 +155,7 @@ class UnsubscribeRequest(TypedDict):
uri: str uri: str
``` ```
### Tool Requests ### Tool requests
```python ```python
class ListToolsRequest(TypedDict): class ListToolsRequest(TypedDict):
@ -177,7 +177,7 @@ class CallToolResponse(TypedDict):
toolResult: Any # JSON-serializable value toolResult: Any # JSON-serializable value
``` ```
### Prompt Requests ### Prompt requests
```python ```python
class ListPromptsRequest(TypedDict): class ListPromptsRequest(TypedDict):
@ -195,7 +195,7 @@ class GetPromptRequest(TypedDict):
arguments: Optional[dict[str, str]] arguments: Optional[dict[str, str]]
``` ```
## Protocol Types ## Protocol types
### Implementation Info ### Implementation Info
@ -231,9 +231,9 @@ class ServerCapabilities(TypedDict):
tools: Optional[ToolCapabilities] tools: Optional[ToolCapabilities]
``` ```
## Transport Types ## Transport types
### Stream Types ### Stream types
```python ```python
class ReadStream(Protocol): class ReadStream(Protocol):
@ -245,7 +245,7 @@ class WriteStream(Protocol):
async def write(self, data: bytes) -> None: ... async def write(self, data: bytes) -> None: ...
``` ```
### Session Types ### Session types
```python ```python
class ServerSession(Protocol): class ServerSession(Protocol):
@ -259,9 +259,9 @@ class ServerSession(Protocol):
) -> None: ... ) -> None: ...
``` ```
## Usage Examples ## Usage examples
### Type Usage in Handlers ### Type usage in handlers
```python ```python
from mcp_python.server import Server from mcp_python.server import Server
@ -314,7 +314,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
} }
``` ```
### Type Checking ### Type checking
```python ```python
from typing import TypeGuard from typing import TypeGuard
@ -330,7 +330,7 @@ def process_message(message: Message) -> str:
return f"Image message with type: {content['mimeType']}" return f"Image message with type: {content['mimeType']}"
``` ```
## Additional Notes ## Additional notes
- All types are compatible with standard Python type checkers (mypy, pyright) - All types are compatible with standard Python type checkers (mypy, pyright)
- TypedDict is used extensively to ensure proper structure of JSON-like objects - TypedDict is used extensively to ensure proper structure of JSON-like objects

View file

@ -1,11 +1,11 @@
--- ---
title: "Event Handling" title: "Event handling"
description: "Handle events and manage state in your MCP server" 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. 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 handlers ## Request handling
Request handlers process incoming requests from clients and must return a response. Each handler is associated with a specific method name. Request handlers process incoming requests from clients and must return a response. Each handler is associated with a specific method name.
@ -62,7 +62,7 @@ async def handle_list_tools(request: ListToolsRequest) -> ListToolsResult:
``` ```
</CodeGroup> </CodeGroup>
## Notification handlers ## 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. Notification handlers process one-way messages that don't require responses. They're useful for handling events like resource updates or logging messages.

View file

@ -1,5 +1,5 @@
--- ---
title: "Resource Management" title: "Resource management"
description: "How to implement resource management in your MCP server" description: "How to implement resource management in your MCP server"
--- ---

View file

@ -1,5 +1,5 @@
--- ---
title: "Tool Implementation" title: "Tool implementation"
description: "Learn how to implement tools in your MCP server" description: "Learn how to implement tools in your MCP server"
--- ---

View file

@ -1,9 +1,9 @@
--- ---
title: "TypeScript Class Reference" title: "TypeScript class reference"
description: "Complete TypeScript SDK class documentation" description: "Complete TypeScript SDK class documentation"
--- ---
## Client Classes ## Client classes
### Client ### Client
@ -65,7 +65,7 @@ getServerVersion(): Implementation | undefined
``` ```
Returns the server's version information after connection. Returns the server's version information after connection.
### Transport Classes ### Transport classes
#### StdioClientTransport #### StdioClientTransport
```typescript ```typescript
@ -103,7 +103,7 @@ import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/webso
constructor(url: URL) constructor(url: URL)
``` ```
## Server Classes ## Server classes
### Server ### Server
@ -173,7 +173,7 @@ getClientVersion(): Implementation | undefined
``` ```
Returns the client's version information after connection. Returns the client's version information after connection.
### Transport Classes ### Transport classes
#### StdioServerTransport #### StdioServerTransport
```typescript ```typescript
@ -197,7 +197,7 @@ constructor(endpoint: string, res: ServerResponse)
## Examples ## Examples
### Client Implementation ### Client implementation
```typescript ```typescript
import { Client } from "@modelcontextprotocol/sdk/client"; import { Client } from "@modelcontextprotocol/sdk/client";
@ -269,7 +269,7 @@ async function main() {
} }
``` ```
### Server Implementation ### Server implementation
```typescript ```typescript
import { Server } from "@modelcontextprotocol/sdk/server"; import { Server } from "@modelcontextprotocol/sdk/server";
@ -363,7 +363,7 @@ async function main() {
} }
``` ```
## Best Practices ## Best practices
1. **Error Handling** 1. **Error Handling**
```typescript ```typescript

View file

@ -1,11 +1,11 @@
--- ---
title: "TypeScript Type Definitions" title: "TypeScript type definitions"
description: "TypeScript type system documentation" description: "TypeScript type system documentation"
--- ---
## Core Protocol Types ## Core protocol types
### JSON-RPC Types ### JSON-RPC types
```typescript ```typescript
export const JSONRPC_VERSION = "2.0"; export const JSONRPC_VERSION = "2.0";
@ -53,7 +53,7 @@ export type JSONRPCMessage =
| JSONRPCError; | JSONRPCError;
``` ```
### Message Content Types ### Message content types
```typescript ```typescript
/** Text provided to or from an LLM */ /** Text provided to or from an LLM */
@ -84,7 +84,7 @@ export interface Progress {
export type ProgressCallback = (progress: Progress) => void; export type ProgressCallback = (progress: Progress) => void;
``` ```
### Resource Types ### Resource types
```typescript ```typescript
/** The contents of a specific resource */ /** The contents of a specific resource */
@ -120,7 +120,7 @@ export interface ResourceTemplate {
} }
``` ```
### Tool Types ### Tool types
```typescript ```typescript
/** Definition for a tool the client can call */ /** Definition for a tool the client can call */
@ -134,7 +134,7 @@ export interface Tool {
} }
``` ```
### Prompt Types ### Prompt types
```typescript ```typescript
/** Describes an argument that a prompt can accept */ /** Describes an argument that a prompt can accept */
@ -152,9 +152,9 @@ export interface Prompt {
} }
``` ```
## Request/Response Types ## Request/response types
### Resource Requests ### Resource requests
```typescript ```typescript
export interface ListResourcesRequest { export interface ListResourcesRequest {
@ -195,7 +195,7 @@ export interface UnsubscribeRequest {
} }
``` ```
### Tool Requests ### Tool requests
```typescript ```typescript
export interface ListToolsRequest { export interface ListToolsRequest {
@ -226,7 +226,7 @@ export interface CallToolResult {
} }
``` ```
### Prompt Requests ### Prompt requests
```typescript ```typescript
export interface ListPromptsRequest { export interface ListPromptsRequest {
@ -255,9 +255,9 @@ export interface GetPromptResult {
} }
``` ```
## Protocol Types ## Protocol types
### Implementation Info ### Implementation info
```typescript ```typescript
export interface Implementation { export interface Implementation {
@ -266,7 +266,7 @@ export interface Implementation {
} }
``` ```
### Capability Types ### Capability types
```typescript ```typescript
export interface ResourceCapabilities { export interface ResourceCapabilities {
@ -296,7 +296,7 @@ export interface ClientCapabilities {
} }
``` ```
### Notification Types ### Notification types
```typescript ```typescript
export interface ResourceUpdatedNotification { export interface ResourceUpdatedNotification {
@ -328,7 +328,7 @@ export type ServerNotification =
| LogMessageNotification; | LogMessageNotification;
``` ```
## Error Types ## Error types
```typescript ```typescript
export enum ErrorCode { export enum ErrorCode {
@ -354,7 +354,7 @@ export class McpError extends Error {
} }
``` ```
## Transport Types ## Transport types
```typescript ```typescript
export interface Transport { export interface Transport {
@ -373,9 +373,9 @@ export interface StdioServerParameters {
} }
``` ```
## Usage Examples ## Usage examples
### Type Guards ### Type guards
```typescript ```typescript
function isTextContent(content: function isTextContent(content:
@ -391,7 +391,7 @@ function isResourceUpdatedNotification(
} }
``` ```
### Type Assertions ### Type assertions
```typescript ```typescript
function assertResource(data: unknown): asserts data is Resource { function assertResource(data: unknown): asserts data is Resource {
@ -409,7 +409,7 @@ function assertResource(data: unknown): asserts data is Resource {
} }
``` ```
### Using Generics ### Using generics
```typescript ```typescript
async function handleResourceContent<T extends ResourceContents>( async function handleResourceContent<T extends ResourceContents>(
@ -425,7 +425,7 @@ async function handleResourceContent<T extends ResourceContents>(
} }
``` ```
### Working with Union Types ### Working with union types
```typescript ```typescript
function processMessage(message: SamplingMessage): string { function processMessage(message: SamplingMessage): string {
@ -442,7 +442,7 @@ function processMessage(message: SamplingMessage): string {
} }
``` ```
## Type Utilities ## Type utilities
```typescript ```typescript
/** Helper type to extract request params from method name */ /** Helper type to extract request params from method name */

View file

@ -1,442 +0,0 @@
---
title: "Integrate MCP into Your Python App"
description: "Add MCP support to your LLM application in Python"
---
Learn how to integrate MCP into your Python LLM application. We'll build a simple web analyzer that uses Claude to analyze websites, enhanced with MCP's web automation capabilities.
<Note>
This guide uses an existing MCP server ([puppeteer](/servers/puppeteer)) rather than building one from scratch. This lets us focus on the integration patterns.
</Note>
## The example app
We'll build an "AI Web Analyzer" that:
1. Takes a URL from the user
2. Captures the webpage using MCP
3. Has the LLM analyze the page's content, design, and accessibility
<Frame>
<img src="/api/placeholder/800/400" alt="Screenshot of the Web Analyzer CLI interface" />
</Frame>
## Prerequisites
<Steps>
<Step title="Install dependencies">
```bash
pip install modelcontextprotocol-sdk anthropic click rich
```
</Step>
<Step title="Set up puppeteer server">
```bash
# Install example MCP servers
git clone https://github.com/modelcontextprotocol/servers
cd servers
npm install
npm run build
npm install -g
```
</Step>
<Step title="Get API key">
```bash
# Set your Anthropic API key
export ANTHROPIC_API_KEY='your-key-here'
```
</Step>
</Steps>
## Building the base app
First, let's create a basic version without MCP:
<Steps>
<Step title="Create project structure">
```bash
mkdir web-analyzer
cd web-analyzer
touch analyzer.py
```
</Step>
<Step title="Add base implementation">
```python
# analyzer.py
import click
import anthropic
from rich.console import Console
from rich.panel import Panel
from rich import print as rprint
console = Console()
client = anthropic.Client()
def analyze_url(url: str) -> str:
messages = [{
"role": "user",
"content": f"Please analyze this website: {url}\n\n"
f"I'd like to know about:\n"
f"1. Content quality and organization\n"
f"2. Visual design (based on the URL/description)\n"
f"3. Potential improvements"
}]
response = client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
messages=messages
)
return response.content[0].text
@click.command()
@click.argument('url')
def main(url: str):
with console.status("[bold green]Analyzing website..."):
analysis = analyze_url(url)
rprint(Panel.fit(
analysis,
title="Website Analysis",
border_style="blue"
))
if __name__ == '__main__':
main()
```
</Step>
<Step title="Test the base app">
```bash
python analyzer.py https://example.com
```
</Step>
</Steps>
## Adding MCP support
Now let's enhance the app with MCP capabilities:
<Steps>
<Step title="Create MCP client">
```python
# At the top of analyzer.py
from modelcontextprotocol.client import Client
from modelcontextprotocol.client.stdio import StdioClientTransport
import asyncio
import json
from typing import Optional
class MCPWebClient:
def __init__(self):
self.client = Client(
client_info={
"name": "web-analyzer",
"version": "0.1.0"
}
)
self.transport = None
async def connect(self):
self.transport = StdioClientTransport(
server={
"command": "mcp-server-puppeteer",
}
)
await self.client.connect(self.transport)
async def navigate(self, url: str) -> Optional[str]:
try:
result = await self.client.request(
{
"method": "tools/call",
"params": {
"name": "navigate",
"arguments": {"url": url}
}
},
schema=CallToolResultSchema
)
return result.get("toolResult")
except Exception as e:
console.print(f"[red]Error navigating to URL: {e}")
return None
async def get_console_logs(self) -> str:
result = await self.client.request(
{
"method": "resources/read",
"params": {"uri": "console://logs"}
},
schema=ReadResourceResultSchema
)
return result["contents"][0]["text"]
async def close(self):
if self.transport:
await self.client.close()
```
</Step>
<Step title="Update the analyzer">
```python
async def analyze_url_with_mcp(url: str) -> str:
# Create and connect MCP client
mcp = MCPWebClient()
await mcp.connect()
# Navigate to the URL
await mcp.navigate(url)
# Get console logs (includes errors, warnings, etc.)
console_logs = await mcp.get_console_logs()
# Close the connection
await mcp.close()
# Analyze with Claude
messages = [{
"role": "user",
"content": (
f"Please analyze this website: {url}\n\n"
f"Here are the browser console logs:\n{console_logs}\n\n"
f"Please analyze:\n"
f"1. Content quality and organization\n"
f"2. Visual design\n"
f"3. Technical issues (based on console logs)\n"
f"4. Potential improvements"
)
}]
response = client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
messages=messages
)
return response.content[0].text
@click.command()
@click.argument('url')
def main(url: str):
with console.status("[bold green]Analyzing website..."):
analysis = asyncio.run(analyze_url_with_mcp(url))
rprint(Panel.fit(
analysis,
title="Website Analysis",
border_style="blue"
))
```
</Step>
<Step title="Run the enhanced version">
```bash
python analyzer.py https://example.com
```
</Step>
</Steps>
## Understanding MCP integration
Let's break down the key components of MCP integration:
<Tabs>
<Tab title="Client Setup">
```python
class MCPWebClient:
def __init__(self):
self.client = Client(
client_info={
"name": "web-analyzer",
"version": "0.1.0"
}
)
```
The MCP client identifies your application and manages the connection to MCP servers.
</Tab>
<Tab title="Transport">
```python
self.transport = StdioClientTransport(
server={
"command": "mcp-server-puppeteer",
}
)
```
The transport layer handles communication with the MCP server. Here we're using stdio to talk to the puppeteer server.
</Tab>
<Tab title="Tools">
```python
result = await self.client.request(
{
"method": "tools/call",
"params": {
"name": "navigate",
"arguments": {"url": url}
}
},
schema=CallToolResultSchema
)
```
Tools let you take actions through MCP servers. Here we're using puppeteer's navigate tool.
</Tab>
<Tab title="Resources">
```python
result = await self.client.request(
{
"method": "resources/read",
"params": {"uri": "console://logs"}
},
schema=ReadResourceResultSchema
)
```
Resources provide data from MCP servers. Here we're reading console logs that puppeteer collected.
</Tab>
</Tabs>
## Enhancement ideas
Now that you have MCP working, here are some ways to enhance the analyzer:
<CardGroup cols={2}>
<Card
title="Visual Analysis"
icon="image"
>
```python
# Take screenshots with puppeteer
await client.request({
"method": "tools/call",
"params": {
"name": "screenshot",
"arguments": {...}
}
})
```
</Card>
<Card
title="Multiple Pages"
icon="layer-group">
```python
# Analyze multiple pages in sequence
for url in urls:
await navigate(url)
await analyze()
```
</Card>
<Card
title="Interactive Elements"
icon="mouse-pointer">
```python
# Test interactive features
await client.request({
"method": "tools/call",
"params": {
"name": "click",
"arguments": {"selector": "button"}
}
})
```
</Card>
</CardGroup>
Common Patterns
Here are some patterns you'll often use when integrating MCP:
<AccordionGroup>
<Accordion title="Resource Polling" active>
When you need to wait for resource updates:
```python
async def wait_for_resource(uri: str, timeout: int = 30):
start = time.time()
while time.time() - start < timeout:
result = await client.request(
{
"method": "resources/read",
"params": {"uri": uri}
},
schema=ReadResourceResultSchema
)
if some_condition(result):
return result
await asyncio.sleep(1)
raise TimeoutError()
```
</Accordion>
<Accordion title="Error Handling">
Robust error handling for MCP operations:
```python
try:
await client.request(...)
except MCPError as e:
if e.code == ErrorCode.ResourceNotFound:
# Handle missing resource
elif e.code == ErrorCode.InvalidRequest:
# Handle invalid parameters
else:
# Handle other errors
```
</Accordion>
<Accordion title="Resource Subscriptions">
Subscribe to resource updates:
```python
await client.request(
{
"method": "resources/subscribe",
"params": {"uri": "console://logs"}
},
schema=EmptyResultSchema
)
# Now you'll get notifications when logs change
```
</Accordion>
</AccordionGroup>
## Troubleshooting
<AccordionGroup>
<Accordion title="Connection Issues">
```python
# Enable debug logging
import logging
logging.basicConfig(level=logging.DEBUG)
```
Watch for connection errors and MCP protocol messages.
</Accordion>
<Accordion title="Resource Errors">
1. Check if the resource exists:
```python
resources = await client.request(
{"method": "resources/list"},
schema=ListResourcesResultSchema
)
print(resources)
```
2. Verify URI format
3. Check server logs
</Accordion>
<Accordion title="Tool Errors">
1. List available tools:
```python
tools = await client.request(
{"method": "tools/list"},
schema=ListToolsResultSchema
)
print(tools)
```
2. Check argument schema
3. Verify server capabilities
</Accordion>
</AccordionGroup>
## Next steps
<CardGroup cols={2}>
<Card
title="Add More Servers"
icon="plus"
href="/servers"
>
Connect to additional MCP servers for more capabilities
</Card>
<Card
title="Build Custom Server"
icon="code"
href="/docs/guides/first-server-python">
Create your own MCP server for custom functionality
</Card>
</CardGroup>

View file

@ -1,885 +0,0 @@
---
title: "Integrate MCP into Your TypeScript App"
description: "Add MCP support to your LLM application in TypeScript"
---
Learn how to integrate MCP into your TypeScript/React application. We'll build an AI Web Analyzer that uses Claude to analyze websites, enhanced with MCP's web automation capabilities.
<Note>
This guide uses an existing MCP server ([puppeteer](/servers/puppeteer)) rather than building one from scratch. This lets us focus on the integration patterns.
</Note>
## The example app
We'll build an "AI Web Analyzer" that:
1. Takes a URL from the user
2. Captures the webpage using MCP
3. Has Claude analyze the page's content, design, and accessibility
<Frame>
<img src="/api/placeholder/800/400" alt="Screenshot of the Web Analyzer interface" />
</Frame>
## Prerequisites
<Steps>
<Step title="Create React project">
```bash
# Create new Next.js project with TypeScript
npx create-next-app@latest web-analyzer --typescript --tailwind
cd web-analyzer
```
</Step>
<Step title="Install dependencies">
```bash
npm install @modelcontextprotocol/sdk @anthropic-ai/sdk
```
</Step>
<Step title="Set up puppeteer server">
```bash
# Install example MCP servers
git clone https://github.com/modelcontextprotocol/servers
cd servers
npm install
npm run build
npm install -g
```
</Step>
</Steps>
## Building the base app
First, let's create a basic version without MCP:
<Steps>
<Step title="Create components">
Create `components/WebAnalyzer.tsx`:
```tsx
import { useState } from 'react';
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic({
apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY
});
export default function WebAnalyzer() {
const [url, setUrl] = useState('');
const [analysis, setAnalysis] = useState('');
const [loading, setLoading] = useState(false);
const analyzeUrl = async () => {
setLoading(true);
try {
const response = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
max_tokens: 1000,
messages: [{
role: 'user',
content: `Please analyze this website: ${url}\n\n`
+ `I'd like to know about:\n`
+ `1. Content quality and organization\n`
+ `2. Visual design (based on URL/description)\n`
+ `3. Potential improvements`
}]
});
setAnalysis(response.content[0].text);
} catch (error) {
console.error('Error:', error);
setAnalysis('Error analyzing website');
}
setLoading(false);
};
return (
<div className="max-w-2xl mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">
AI Web Analyzer
</h1>
<div className="flex gap-2 mb-4">
<input
type="url"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="Enter website URL"
className="flex-1 p-2 border rounded"
/>
<button
onClick={analyzeUrl}
disabled={loading}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Analyze
</button>
</div>
{loading && (
<div className="animate-pulse text-gray-500">
Analyzing website...
</div>
)}
{analysis && (
<div className="mt-4 p-4 border rounded bg-gray-50">
<pre className="whitespace-pre-wrap">{analysis}</pre>
</div>
)}
</div>
);
}
```
</Step>
<Step title="Update app page">
Update `app/page.tsx`:
```tsx
import WebAnalyzer from '@/components/WebAnalyzer';
export default function Home() {
return (
<main>
<WebAnalyzer />
</main>
);
}
```
</Step>
<Step title="Add environment variables">
Create `.env.local`:
```bash
NEXT_PUBLIC_ANTHROPIC_API_KEY=your-key-here
```
</Step>
</Steps>
## Adding MCP support
Now let's enhance the app with MCP capabilities:
<Steps>
<Step title="Create MCP client">
Create `lib/mcp.ts`:
```typescript
import { Client } from '@modelcontextprotocol/sdk/client';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio';
import {
CallToolResultSchema,
ReadResourceResultSchema
} from '@modelcontextprotocol/sdk/types';
export class MCPWebClient {
private client: Client;
private transport: StdioClientTransport | null = null;
constructor() {
this.client = new Client({
name: 'web-analyzer',
version: '0.1.0'
});
}
async connect() {
this.transport = new StdioClientTransport({
command: 'mcp-server-puppeteer'
});
await this.client.connect(this.transport);
}
async navigate(url: string): Promise<string | null> {
try {
const result = await this.client.request(
{
method: 'tools/call',
params: {
name: 'navigate',
arguments: { url }
}
},
CallToolResultSchema
);
return result.toolResult as string;
} catch (error) {
console.error('Error navigating:', error);
return null;
}
}
async getConsoleLogs(): Promise<string> {
const result = await this.client.request(
{
method: 'resources/read',
params: { uri: 'console://logs' }
},
ReadResourceResultSchema
);
return result.contents[0].text;
}
async close() {
if (this.transport) {
await this.client.close();
}
}
}
```
</Step>
<Step title="Create MCP context">
Create `contexts/MCPContext.tsx`:
```typescript
import { createContext, useContext, useEffect, useRef } from 'react';
import { MCPWebClient } from '@/lib/mcp';
const MCPContext = createContext<MCPWebClient | null>(null);
export function MCPProvider({ children }: { children: React.ReactNode }) {
const clientRef = useRef<MCPWebClient | null>(null);
useEffect(() => {
const initMCP = async () => {
clientRef.current = new MCPWebClient();
await clientRef.current.connect();
};
initMCP();
return () => {
if (clientRef.current) {
clientRef.current.close();
}
};
}, []);
return (
<MCPContext.Provider value={clientRef.current}>
{children}
</MCPContext.Provider>
);
}
export function useMCP() {
const context = useContext(MCPContext);
if (!context) {
throw new Error('useMCP must be used within MCPProvider');
}
return context;
}
```
</Step>
<Step title="Update the analyzer component">
Update `components/WebAnalyzer.tsx`:
```typescript
import { useState } from 'react';
import Anthropic from '@anthropic-ai/sdk';
import { useMCP } from '@/contexts/MCPContext';
const anthropic = new Anthropic({
apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY
});
export default function WebAnalyzer() {
const mcp = useMCP();
const [url, setUrl] = useState('');
const [analysis, setAnalysis] = useState('');
const [loading, setLoading] = useState(false);
const analyzeUrl = async () => {
setLoading(true);
try {
// Navigate to the URL with MCP
await mcp.navigate(url);
// Get console logs
const consoleLogs = await mcp.getConsoleLogs();
// Analyze with Claude
const response = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
max_tokens: 1000,
messages: [{
role: 'user',
content: `Please analyze this website: ${url}\n\n`
+ `Here are the browser console logs:\n${consoleLogs}\n\n`
+ `Please analyze:\n`
+ `1. Content quality and organization\n`
+ `2. Visual design\n`
+ `3. Technical issues (based on console logs)\n`
+ `4. Potential improvements`
}]
});
setAnalysis(response.content[0].text);
} catch (error) {
console.error('Error:', error);
setAnalysis('Error analyzing website');
}
setLoading(false);
};
// ... rest of the component remains the same
}
```
</Step>
<Step title="Add the provider">
Update `app/layout.tsx`:
```typescript
import { MCPProvider } from '@/contexts/MCPContext';
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<MCPProvider>
{children}
</MCPProvider>
</body>
</html>
);
}
```
</Step>
</Steps>
## Understanding MCP integration
Let's break down the key components:
<Tabs>
<Tab title="Client Setup">
```typescript
export class MCPWebClient {
private client: Client;
constructor() {
this.client = new Client({
name: 'web-analyzer',
version: '0.1.0'
});
}
}
```
The MCP client manages the connection to MCP servers and handles requests.
</Tab>
<Tab title="Context Provider">
```typescript
export function MCPProvider({ children }: { children: React.ReactNode }) {
const clientRef = useRef<MCPWebClient | null>(null);
useEffect(() => {
const initMCP = async () => {
clientRef.current = new MCPWebClient();
await clientRef.current.connect();
};
initMCP();
// ... cleanup
}, []);
}
```
The context provider manages the MCP client lifecycle.
</Tab>
<Tab title="Tools">
```typescript
async navigate(url: string): Promise<string | null> {
const result = await this.client.request(
{
method: 'tools/call',
params: {
name: 'navigate',
arguments: { url }
}
},
CallToolResultSchema
);
return result.toolResult as string;
}
```
Tools let you take actions through MCP servers.
</Tab>
<Tab title="Resources">
```typescript
async getConsoleLogs(): Promise<string> {
const result = await this.client.request(
{
method: 'resources/read',
params: { uri: 'console://logs' }
},
ReadResourceResultSchema
);
return result.contents[0].text;
}
```
Resources provide data from MCP servers.
</Tab>
</Tabs>
## Enhancement ideas
Here are some ways to enhance the analyzer:
<CardGroup cols={2}>
<Card
title="Visual Snapshots"
icon="image"
>
```typescript
// Add screenshot capability
async function captureScreenshot() {
const result = await mcp.client.request({
method: 'tools/call',
params: {
name: 'screenshot',
arguments: { /* ... */ }
}
});
}
```
</Card>
<Card
title="Batch Analysis"
icon="layer-group"
>
```typescript
// Analyze multiple pages
async function analyzeBatch(urls: string[]) {
const results = [];
for (const url of urls) {
await mcp.navigate(url);
// ... analyze
}
}
```
</Card>
<Card
title="Interactive Testing"
icon="mouse-pointer"
>
```typescript
// Test interactive elements
async function testInteraction() {
await mcp.client.request({
method: 'tools/call',
params: {
name: 'click',
arguments: { selector: 'button' }
}
});
}
```
</Card>
<Card
title="Performance Analysis"
icon="gauge"
>
```typescript
// Add performance metrics
async function getPerformance() {
const metrics = await mcp.client.request({
method: 'resources/read',
params: { uri: 'metrics://performance' }
});
}
```
</Card>
</CardGroup>
## Common patterns
Here are some patterns you'll often use with MCP in React:
<AccordionGroup>
<Accordion title="Resource Polling" active>
```typescript
function useResourcePolling(uri: string, interval = 1000) {
const [data, setData] = useState(null);
useEffect(() => {
let mounted = true;
async function poll() {
while (mounted) {
const result = await mcp.client.request({
method: 'resources/read',
params: { uri }
});
if (mounted) {
setData(result);
await new Promise(r => setTimeout(r, interval));
}
}
}
poll();
return () => { mounted = false; };
}, [uri, interval]);
return data;
}
```
</Accordion>
<Accordion title="Error Boundaries">
```typescript
class MCPErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
if (error instanceof MCPError) {
// Handle MCP-specific errors
}
}
render() {
if (this.state.hasError) {
return <ErrorDisplay />;
}
return this.props.children;
}
}
```
</Accordion>
<Accordion title="Resource Subscriptions">
```typescript
function useResourceSubscription(uri: string) {
useEffect(() => {
mcp.client.request({
method: 'resources/subscribe',
params: { uri }
});
return () => {
mcp.client.request({
method: 'resources/unsubscribe',
params: { uri }
});
};
}, [uri]);
}
```
</Accordion>
</AccordionGroup>
## Troubleshooting
<AccordionGroup>
<Accordion title="Connection Issues">
```typescript
// Enable debug logging
const initMCP = async () => {
const client = new MCPWebClient({
debug: true, // Enable debug logging
onError: (error) => {
console.error('MCP Error:', error);
}
});
await client.connect();
};
```
Watch the browser console for connection errors and protocol messages.
</Accordion>
<Accordion title="React Component Lifecycle">
Common issues and solutions:
```typescript
function WebAnalyzer() {
// Don't create client on every render
const mcpRef = useRef<MCPWebClient | null>(null);
// Initialize in useEffect
useEffect(() => {
const init = async () => {
mcpRef.current = new MCPWebClient();
await mcpRef.current.connect();
};
init();
// Clean up properly
return () => {
if (mcpRef.current) {
mcpRef.current.close();
}
};
}, []);
}
```
</Accordion>
<Accordion title="Type Safety">
Use TypeScript to catch MCP issues early:
```typescript
// Define expected response types
interface ToolResponse {
toolResult: {
screenshot?: string;
logs?: string[];
error?: string;
};
}
// Use with request
const result = await client.request<ToolResponse>({
method: 'tools/call',
params: {
name: 'screenshot',
arguments: { /* ... */ }
}
});
// TypeScript will catch missing properties
console.log(result.toolResult.screenshot);
```
</Accordion>
</AccordionGroup>
## Performance optimization
<CardGroup cols={2}>
<Card
title="Caching Resources"
icon="database"
>
```typescript
function useCachedResource(uri: string) {
const [data, setData] = useState<string | null>(null);
const cache = useRef(new Map<string, string>());
useEffect(() => {
async function fetchResource() {
if (cache.current.has(uri)) {
setData(cache.current.get(uri)!);
return;
}
const result = await mcp.client.request({
method: 'resources/read',
params: { uri }
});
cache.current.set(uri, result.contents[0].text);
setData(result.contents[0].text);
}
fetchResource();
}, [uri]);
return data;
}
```
</Card>
<Card
title="Batching Requests"
icon="layer-group"
>
```typescript
class BatchedMCPClient extends MCPWebClient {
private batchQueue: Map<string, Promise<any>>;
async request(method: string, params: any) {
const key = JSON.stringify({ method, params });
if (!this.batchQueue.has(key)) {
this.batchQueue.set(
key,
super.request(method, params)
);
// Clear after resolution
this.batchQueue.get(key)!.finally(() => {
this.batchQueue.delete(key);
});
}
return this.batchQueue.get(key);
}
}
```
</Card>
</CardGroup>
## Building for production
<Steps>
<Step title="Error handling">
Add proper error boundaries:
```typescript
import { ErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div className="p-4 border border-red-500 rounded">
<h2 className="text-red-500">Something went wrong:</h2>
<pre>{error.message}</pre>
<button
onClick={resetErrorBoundary}
className="mt-2 px-4 py-2 bg-red-500 text-white rounded"
>
Try again
</button>
</div>
);
}
export default function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => {
// Reset application state
}}
>
<WebAnalyzer />
</ErrorBoundary>
);
}
```
</Step>
<Step title="Loading states">
Add proper loading indicators:
```typescript
function WebAnalyzer() {
const [state, setState] = useState<{
status: 'idle' | 'loading' | 'success' | 'error';
error?: Error;
data?: string;
}>({
status: 'idle'
});
return (
<div>
{state.status === 'loading' && (
<div className="animate-pulse">
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
<div className="space-y-3 mt-4">
<div className="h-4 bg-gray-200 rounded"></div>
<div className="h-4 bg-gray-200 rounded w-5/6"></div>
</div>
</div>
)}
{state.status === 'error' && (
<div className="text-red-500">
{state.error?.message}
</div>
)}
{state.status === 'success' && (
<div>{state.data}</div>
)}
</div>
);
}
```
</Step>
<Step title="Environment configuration">
Set up proper environment variables:
```typescript
// next.config.js
module.exports = {
env: {
NEXT_PUBLIC_ANTHROPIC_API_KEY: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY,
MCP_DEBUG: process.env.NODE_ENV === 'development'
}
};
// Usage in code
const mcpClient = new MCPWebClient({
debug: process.env.MCP_DEBUG === 'true'
});
```
</Step>
</Steps>
## Security considerations
<Warning>
Always validate and sanitize URLs before passing them to MCP servers. The puppeteer server has access to execute JavaScript and interact with web pages.
</Warning>
```typescript
function validateUrl(url: string): boolean {
try {
const parsed = new URL(url);
// Add your validation rules
return parsed.protocol === 'https:';
} catch {
return false;
}
}
function WebAnalyzer() {
const analyzeUrl = async () => {
if (!validateUrl(url)) {
setError('Please enter a valid HTTPS URL');
return;
}
// ... rest of the analysis code
};
}
```
## Next steps
<CardGroup cols={2}>
<Card
title="Add Authentication"
icon="lock"
href="/guides/auth"
>
Learn how to handle authenticated web pages with MCP
</Card>
<Card
title="Custom MCP Server"
icon="server"
href="/quickstarts/first-server-typescript">
Build your own MCP server for custom functionality
</Card>
<Card
title="Testing"
icon="vial"
href="/guides/testing">
Learn how to test MCP integrations
</Card>
<Card
title="Production Setup"
icon="rocket"
href="/guides/production">
Deploy your MCP-enabled app to production
</Card>
</CardGroup>

View file

@ -21,10 +21,6 @@
{ {
"name": "API Reference", "name": "API Reference",
"url": "api-reference" "url": "api-reference"
},
{
"name": "Specification",
"url": "specification"
} }
], ],
"anchors": [ "anchors": [
@ -101,22 +97,6 @@
"api-reference/typescript/class-reference", "api-reference/typescript/class-reference",
"api-reference/typescript/type-definitions" "api-reference/typescript/type-definitions"
] ]
},
{
"group": "Specification",
"pages": [
"specification/overview",
"specification/jsonrpc",
"specification/lifecycle",
"specification/prompts",
"specification/resources",
"specification/cancellation",
"specification/logging",
"specification/tools",
"specification/completion",
"specification/sampling",
"specification/roots"
]
} }
], ],
"footerSocials": { "footerSocials": {