grammar
This commit is contained in:
parent
6cac5a1cde
commit
ba7d5b866d
16 changed files with 79 additions and 1432 deletions
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "Connection Management"
|
||||
title: "Connection management"
|
||||
description: "Learn how to establish and manage MCP client connections"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "Resource Consumption"
|
||||
title: "Resource consumption"
|
||||
description: "Learn how to consume resources from MCP servers"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "Tool Invocation"
|
||||
title: "Tool invocation"
|
||||
description: "Learn how to invoke tools through the MCP client API"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: 'Error Handling'
|
||||
title: 'Error handling'
|
||||
description: 'How to handle and respond to errors in the Model Context Protocol'
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: 'Message Types'
|
||||
title: 'Message types'
|
||||
description: 'Understanding the different types of messages in the Model Context Protocol'
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "Resource Management"
|
||||
title: "Resource management"
|
||||
description: "How to implement resource management in your MCP server"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "Tool Implementation"
|
||||
title: "Tool implementation"
|
||||
description: "Learn how to implement tools in your MCP server"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
20
mint.json
20
mint.json
|
|
@ -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": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue