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"
---

View file

@ -1,5 +1,5 @@
---
title: "Resource Consumption"
title: "Resource consumption"
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"
---

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

View file

@ -1,5 +1,5 @@
---
title: 'Message Types'
title: 'Message types'
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)"
---
@ -22,10 +22,8 @@ The Model Context Protocol (MCP) is a standardized protocol that enables AI appl
</Card>
</CardGroup>
# Core concepts
## 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.
@ -41,12 +39,10 @@ MCP defines several key primitives that form the foundation of the protocol:
</Card>
</CardGroup>
# Protocol flow
## Connection and initialization
## 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.
@ -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.
## Transport options
### 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

View file

@ -1,9 +1,9 @@
---
title: "Python Class Reference"
title: "Python class reference"
description: "Complete Python SDK class documentation"
---
## Server Class
## Server class
The main class for implementing MCP servers in Python.
@ -25,7 +25,7 @@ Creates a new MCP server instance.
### Decorators
#### Resource Handling
#### Resource handling
##### @server.list_resources()
```python
@ -72,7 +72,7 @@ async def unsubscribe_resource(uri: str) -> None:
**Parameters:**
- `uri` (str): Resource URI to unsubscribe from
#### Tool Support
#### Tool support
##### @server.list_tools()
```python
@ -99,7 +99,7 @@ async def call_tool(name: str, **kwargs) -> Any:
**Returns:** Tool execution result (any JSON-serializable value)
#### Prompt Management
#### Prompt management
##### @server.list_prompts()
```python
@ -128,7 +128,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
- `messages` (List[Message]): List of prompt messages
- `description` (str, optional): Description of the prompt response
### Session Methods
### Session methods
Methods available on the server session object:
@ -158,7 +158,7 @@ async def send_log_message(
"""Sends log messages to clients."""
```
## Data Classes
## Data classes
### Resource
```python
@ -204,7 +204,7 @@ class PromptResponse:
description: Optional[str] = None
```
## Example Usage
## Example usage
Here's a complete example demonstrating the main features:
@ -263,7 +263,7 @@ if __name__ == "__main__":
anyio.run(main)
```
## Best Practices
## Best practices
1. **Error Handling**: Always implement proper error handling in your server methods:
```python
@ -303,15 +303,15 @@ if __name__ == "__main__":
await session.send_resource_updated("example://resource1")
```
## Transport Options
## Transport options
### stdio Transport
### Stdio transport
```python
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
```
### SSE Transport
### SSE transport
```python
from mcp_python.transport import SSETransport
@ -327,7 +327,7 @@ async def message_endpoint(request: Request):
return await transport.handle_message(request)
```
### WebSocket Transport
### WebSocket transport
```python
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"
---
## Core Types
## Core types
### Resource Types
### Resource types
```python
from typing import TypedDict, Optional, Literal, Union, List
@ -38,7 +38,7 @@ class BlobResourceContents(ResourceContents):
blob: bytes # Base64 encoded
```
### Message Types
### Message types
```python
class TextContent(TypedDict):
@ -60,7 +60,7 @@ class Message(TypedDict):
content: MessageContent
```
### Tool Types
### Tool types
```python
class ToolParameter(TypedDict):
@ -82,7 +82,7 @@ class Tool(TypedDict):
inputSchema: ToolSchema
```
### Prompt Types
### Prompt types
```python
class PromptArgument(TypedDict):
@ -103,7 +103,7 @@ class PromptResponse(TypedDict):
messages: List[Message]
```
### Progress Types
### Progress types
```python
class Progress(TypedDict):
@ -112,7 +112,7 @@ class Progress(TypedDict):
total: Optional[int]
```
### Logging Types
### Logging types
```python
LogLevel = Literal["debug", "info", "warning", "error"]
@ -124,9 +124,9 @@ class LogMessage(TypedDict):
data: Any # JSON-serializable value
```
## Request/Response Types
## Request/Response types
### Resource Requests
### Resource requests
```python
class ListResourcesRequest(TypedDict):
@ -155,7 +155,7 @@ class UnsubscribeRequest(TypedDict):
uri: str
```
### Tool Requests
### Tool requests
```python
class ListToolsRequest(TypedDict):
@ -177,7 +177,7 @@ class CallToolResponse(TypedDict):
toolResult: Any # JSON-serializable value
```
### Prompt Requests
### Prompt requests
```python
class ListPromptsRequest(TypedDict):
@ -195,7 +195,7 @@ class GetPromptRequest(TypedDict):
arguments: Optional[dict[str, str]]
```
## Protocol Types
## Protocol types
### Implementation Info
@ -231,9 +231,9 @@ class ServerCapabilities(TypedDict):
tools: Optional[ToolCapabilities]
```
## Transport Types
## Transport types
### Stream Types
### Stream types
```python
class ReadStream(Protocol):
@ -245,7 +245,7 @@ class WriteStream(Protocol):
async def write(self, data: bytes) -> None: ...
```
### Session Types
### Session types
```python
class ServerSession(Protocol):
@ -259,9 +259,9 @@ class ServerSession(Protocol):
) -> None: ...
```
## Usage Examples
## Usage examples
### Type Usage in Handlers
### Type usage in handlers
```python
from mcp_python.server import Server
@ -314,7 +314,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
}
```
### Type Checking
### Type checking
```python
from typing import TypeGuard
@ -330,7 +330,7 @@ def process_message(message: Message) -> str:
return f"Image message with type: {content['mimeType']}"
```
## Additional Notes
## 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

View file

@ -1,11 +1,11 @@
---
title: "Event Handling"
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 handlers
## Request handling
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>
## 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.

View file

@ -1,5 +1,5 @@
---
title: "Resource Management"
title: "Resource management"
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"
---

View file

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

View file

@ -1,11 +1,11 @@
---
title: "TypeScript Type Definitions"
title: "TypeScript type definitions"
description: "TypeScript type system documentation"
---
## Core Protocol Types
## Core protocol types
### JSON-RPC Types
### JSON-RPC types
```typescript
export const JSONRPC_VERSION = "2.0";
@ -53,7 +53,7 @@ export type JSONRPCMessage =
| JSONRPCError;
```
### Message Content Types
### Message content types
```typescript
/** Text provided to or from an LLM */
@ -84,7 +84,7 @@ export interface Progress {
export type ProgressCallback = (progress: Progress) => void;
```
### Resource Types
### Resource types
```typescript
/** The contents of a specific resource */
@ -120,7 +120,7 @@ export interface ResourceTemplate {
}
```
### Tool Types
### Tool types
```typescript
/** Definition for a tool the client can call */
@ -134,7 +134,7 @@ export interface Tool {
}
```
### Prompt Types
### Prompt types
```typescript
/** 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
export interface ListResourcesRequest {
@ -195,7 +195,7 @@ export interface UnsubscribeRequest {
}
```
### Tool Requests
### Tool requests
```typescript
export interface ListToolsRequest {
@ -226,7 +226,7 @@ export interface CallToolResult {
}
```
### Prompt Requests
### Prompt requests
```typescript
export interface ListPromptsRequest {
@ -255,9 +255,9 @@ export interface GetPromptResult {
}
```
## Protocol Types
## Protocol types
### Implementation Info
### Implementation info
```typescript
export interface Implementation {
@ -266,7 +266,7 @@ export interface Implementation {
}
```
### Capability Types
### Capability types
```typescript
export interface ResourceCapabilities {
@ -296,7 +296,7 @@ export interface ClientCapabilities {
}
```
### Notification Types
### Notification types
```typescript
export interface ResourceUpdatedNotification {
@ -328,7 +328,7 @@ export type ServerNotification =
| LogMessageNotification;
```
## Error Types
## Error types
```typescript
export enum ErrorCode {
@ -354,7 +354,7 @@ export class McpError extends Error {
}
```
## Transport Types
## Transport types
```typescript
export interface Transport {
@ -373,9 +373,9 @@ export interface StdioServerParameters {
}
```
## Usage Examples
## Usage examples
### Type Guards
### Type guards
```typescript
function isTextContent(content:
@ -391,7 +391,7 @@ function isResourceUpdatedNotification(
}
```
### Type Assertions
### Type assertions
```typescript
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
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
function processMessage(message: SamplingMessage): string {
@ -442,7 +442,7 @@ function processMessage(message: SamplingMessage): string {
}
```
## Type Utilities
## Type utilities
```typescript
/** 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",
"url": "api-reference"
},
{
"name": "Specification",
"url": "specification"
}
],
"anchors": [
@ -101,22 +97,6 @@
"api-reference/typescript/class-reference",
"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": {