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"
|
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"
|
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"
|
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'
|
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'
|
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)"
|
description: "Learn about the core concepts and architecture of the Model Context Protocol (MCP)"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -22,10 +22,8 @@ The Model Context Protocol (MCP) is a standardized protocol that enables AI appl
|
||||||
</Card>
|
</Card>
|
||||||
</CardGroup>
|
</CardGroup>
|
||||||
|
|
||||||
# Core concepts
|
## Core concepts
|
||||||
|
|
||||||
MCP defines several key primitives that form the foundation of the protocol:
|
MCP defines several key primitives that form the foundation of the protocol:
|
||||||
|
|
||||||
<CardGroup cols={2}>
|
<CardGroup cols={2}>
|
||||||
<Card title="Resources" icon="book">
|
<Card title="Resources" icon="book">
|
||||||
Data that can be loaded as context for the AI model. Resources have URIs and can contain text or binary data.
|
Data that can be loaded as context for the AI model. Resources have URIs and can contain text or binary data.
|
||||||
|
|
@ -41,12 +39,10 @@ MCP defines several key primitives that form the foundation of the protocol:
|
||||||
</Card>
|
</Card>
|
||||||
</CardGroup>
|
</CardGroup>
|
||||||
|
|
||||||
# Protocol flow
|
## Protocol flow
|
||||||
|
|
||||||
## Connection and initialization
|
|
||||||
|
|
||||||
|
### Connection and initialization
|
||||||
When a client connects to an MCP server, they go through the following initialization sequence:
|
When a client connects to an MCP server, they go through the following initialization sequence:
|
||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Client connects">
|
<Step title="Client connects">
|
||||||
The client establishes a connection to the server using one of the supported transports.
|
The client establishes a connection to the server using one of the supported transports.
|
||||||
|
|
@ -64,10 +60,8 @@ When a client connects to an MCP server, they go through the following initializ
|
||||||
|
|
||||||
After initialization, the client can begin using the server's resources, tools, and other capabilities.
|
After initialization, the client can begin using the server's resources, tools, and other capabilities.
|
||||||
|
|
||||||
## Transport options
|
### Transport options
|
||||||
|
|
||||||
MCP supports multiple transport mechanisms for client-server communication:
|
MCP supports multiple transport mechanisms for client-server communication:
|
||||||
|
|
||||||
<AccordionGroup>
|
<AccordionGroup>
|
||||||
<Accordion title="Standard input/output (stdio)">
|
<Accordion title="Standard input/output (stdio)">
|
||||||
- Server process reads from stdin and writes to stdout
|
- Server process reads from stdin and writes to stdout
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
title: "Python Class Reference"
|
title: "Python class reference"
|
||||||
description: "Complete Python SDK class documentation"
|
description: "Complete Python SDK class documentation"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Server Class
|
## Server class
|
||||||
|
|
||||||
The main class for implementing MCP servers in Python.
|
The main class for implementing MCP servers in Python.
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ Creates a new MCP server instance.
|
||||||
|
|
||||||
### Decorators
|
### Decorators
|
||||||
|
|
||||||
#### Resource Handling
|
#### Resource handling
|
||||||
|
|
||||||
##### @server.list_resources()
|
##### @server.list_resources()
|
||||||
```python
|
```python
|
||||||
|
|
@ -72,7 +72,7 @@ async def unsubscribe_resource(uri: str) -> None:
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `uri` (str): Resource URI to unsubscribe from
|
- `uri` (str): Resource URI to unsubscribe from
|
||||||
|
|
||||||
#### Tool Support
|
#### Tool support
|
||||||
|
|
||||||
##### @server.list_tools()
|
##### @server.list_tools()
|
||||||
```python
|
```python
|
||||||
|
|
@ -99,7 +99,7 @@ async def call_tool(name: str, **kwargs) -> Any:
|
||||||
|
|
||||||
**Returns:** Tool execution result (any JSON-serializable value)
|
**Returns:** Tool execution result (any JSON-serializable value)
|
||||||
|
|
||||||
#### Prompt Management
|
#### Prompt management
|
||||||
|
|
||||||
##### @server.list_prompts()
|
##### @server.list_prompts()
|
||||||
```python
|
```python
|
||||||
|
|
@ -128,7 +128,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
|
||||||
- `messages` (List[Message]): List of prompt messages
|
- `messages` (List[Message]): List of prompt messages
|
||||||
- `description` (str, optional): Description of the prompt response
|
- `description` (str, optional): Description of the prompt response
|
||||||
|
|
||||||
### Session Methods
|
### Session methods
|
||||||
|
|
||||||
Methods available on the server session object:
|
Methods available on the server session object:
|
||||||
|
|
||||||
|
|
@ -158,7 +158,7 @@ async def send_log_message(
|
||||||
"""Sends log messages to clients."""
|
"""Sends log messages to clients."""
|
||||||
```
|
```
|
||||||
|
|
||||||
## Data Classes
|
## Data classes
|
||||||
|
|
||||||
### Resource
|
### Resource
|
||||||
```python
|
```python
|
||||||
|
|
@ -204,7 +204,7 @@ class PromptResponse:
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example Usage
|
## Example usage
|
||||||
|
|
||||||
Here's a complete example demonstrating the main features:
|
Here's a complete example demonstrating the main features:
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ if __name__ == "__main__":
|
||||||
anyio.run(main)
|
anyio.run(main)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Best Practices
|
## Best practices
|
||||||
|
|
||||||
1. **Error Handling**: Always implement proper error handling in your server methods:
|
1. **Error Handling**: Always implement proper error handling in your server methods:
|
||||||
```python
|
```python
|
||||||
|
|
@ -303,15 +303,15 @@ if __name__ == "__main__":
|
||||||
await session.send_resource_updated("example://resource1")
|
await session.send_resource_updated("example://resource1")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Transport Options
|
## Transport options
|
||||||
|
|
||||||
### stdio Transport
|
### Stdio transport
|
||||||
```python
|
```python
|
||||||
async with stdio_server() as (read_stream, write_stream):
|
async with stdio_server() as (read_stream, write_stream):
|
||||||
await server.run(read_stream, write_stream)
|
await server.run(read_stream, write_stream)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SSE Transport
|
### SSE transport
|
||||||
```python
|
```python
|
||||||
from mcp_python.transport import SSETransport
|
from mcp_python.transport import SSETransport
|
||||||
|
|
||||||
|
|
@ -327,7 +327,7 @@ async def message_endpoint(request: Request):
|
||||||
return await transport.handle_message(request)
|
return await transport.handle_message(request)
|
||||||
```
|
```
|
||||||
|
|
||||||
### WebSocket Transport
|
### WebSocket transport
|
||||||
```python
|
```python
|
||||||
from mcp_python.transport import WebSocketTransport
|
from mcp_python.transport import WebSocketTransport
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
title: "Python Type Hints"
|
title: "Python type hints"
|
||||||
description: "Python type system documentation"
|
description: "Python type system documentation"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Core Types
|
## Core types
|
||||||
|
|
||||||
### Resource Types
|
### Resource types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import TypedDict, Optional, Literal, Union, List
|
from typing import TypedDict, Optional, Literal, Union, List
|
||||||
|
|
@ -38,7 +38,7 @@ class BlobResourceContents(ResourceContents):
|
||||||
blob: bytes # Base64 encoded
|
blob: bytes # Base64 encoded
|
||||||
```
|
```
|
||||||
|
|
||||||
### Message Types
|
### Message types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class TextContent(TypedDict):
|
class TextContent(TypedDict):
|
||||||
|
|
@ -60,7 +60,7 @@ class Message(TypedDict):
|
||||||
content: MessageContent
|
content: MessageContent
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Types
|
### Tool types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ToolParameter(TypedDict):
|
class ToolParameter(TypedDict):
|
||||||
|
|
@ -82,7 +82,7 @@ class Tool(TypedDict):
|
||||||
inputSchema: ToolSchema
|
inputSchema: ToolSchema
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prompt Types
|
### Prompt types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class PromptArgument(TypedDict):
|
class PromptArgument(TypedDict):
|
||||||
|
|
@ -103,7 +103,7 @@ class PromptResponse(TypedDict):
|
||||||
messages: List[Message]
|
messages: List[Message]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Progress Types
|
### Progress types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Progress(TypedDict):
|
class Progress(TypedDict):
|
||||||
|
|
@ -112,7 +112,7 @@ class Progress(TypedDict):
|
||||||
total: Optional[int]
|
total: Optional[int]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Logging Types
|
### Logging types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
LogLevel = Literal["debug", "info", "warning", "error"]
|
LogLevel = Literal["debug", "info", "warning", "error"]
|
||||||
|
|
@ -124,9 +124,9 @@ class LogMessage(TypedDict):
|
||||||
data: Any # JSON-serializable value
|
data: Any # JSON-serializable value
|
||||||
```
|
```
|
||||||
|
|
||||||
## Request/Response Types
|
## Request/Response types
|
||||||
|
|
||||||
### Resource Requests
|
### Resource requests
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ListResourcesRequest(TypedDict):
|
class ListResourcesRequest(TypedDict):
|
||||||
|
|
@ -155,7 +155,7 @@ class UnsubscribeRequest(TypedDict):
|
||||||
uri: str
|
uri: str
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Requests
|
### Tool requests
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ListToolsRequest(TypedDict):
|
class ListToolsRequest(TypedDict):
|
||||||
|
|
@ -177,7 +177,7 @@ class CallToolResponse(TypedDict):
|
||||||
toolResult: Any # JSON-serializable value
|
toolResult: Any # JSON-serializable value
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prompt Requests
|
### Prompt requests
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ListPromptsRequest(TypedDict):
|
class ListPromptsRequest(TypedDict):
|
||||||
|
|
@ -195,7 +195,7 @@ class GetPromptRequest(TypedDict):
|
||||||
arguments: Optional[dict[str, str]]
|
arguments: Optional[dict[str, str]]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Protocol Types
|
## Protocol types
|
||||||
|
|
||||||
### Implementation Info
|
### Implementation Info
|
||||||
|
|
||||||
|
|
@ -231,9 +231,9 @@ class ServerCapabilities(TypedDict):
|
||||||
tools: Optional[ToolCapabilities]
|
tools: Optional[ToolCapabilities]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Transport Types
|
## Transport types
|
||||||
|
|
||||||
### Stream Types
|
### Stream types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ReadStream(Protocol):
|
class ReadStream(Protocol):
|
||||||
|
|
@ -245,7 +245,7 @@ class WriteStream(Protocol):
|
||||||
async def write(self, data: bytes) -> None: ...
|
async def write(self, data: bytes) -> None: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
### Session Types
|
### Session types
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class ServerSession(Protocol):
|
class ServerSession(Protocol):
|
||||||
|
|
@ -259,9 +259,9 @@ class ServerSession(Protocol):
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Usage examples
|
||||||
|
|
||||||
### Type Usage in Handlers
|
### Type usage in handlers
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from mcp_python.server import Server
|
from mcp_python.server import Server
|
||||||
|
|
@ -314,7 +314,7 @@ async def get_prompt(name: str, arguments: dict) -> PromptResponse:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Type Checking
|
### Type checking
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import TypeGuard
|
from typing import TypeGuard
|
||||||
|
|
@ -330,7 +330,7 @@ def process_message(message: Message) -> str:
|
||||||
return f"Image message with type: {content['mimeType']}"
|
return f"Image message with type: {content['mimeType']}"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Additional Notes
|
## Additional notes
|
||||||
|
|
||||||
- All types are compatible with standard Python type checkers (mypy, pyright)
|
- All types are compatible with standard Python type checkers (mypy, pyright)
|
||||||
- TypedDict is used extensively to ensure proper structure of JSON-like objects
|
- TypedDict is used extensively to ensure proper structure of JSON-like objects
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
title: "Event Handling"
|
title: "Event handling"
|
||||||
description: "Handle events and manage state in your MCP server"
|
description: "Handle events and manage state in your MCP server"
|
||||||
---
|
---
|
||||||
|
|
||||||
MCP servers process various events including requests, notifications, and connection lifecycle events. This guide explains how to implement event handlers effectively in your server.
|
MCP servers process various events including requests, notifications, and connection lifecycle events. This guide explains how to implement event handlers effectively in your server.
|
||||||
|
|
||||||
## Request handlers
|
## Request handling
|
||||||
|
|
||||||
Request handlers process incoming requests from clients and must return a response. Each handler is associated with a specific method name.
|
Request handlers process incoming requests from clients and must return a response. Each handler is associated with a specific method name.
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ async def handle_list_tools(request: ListToolsRequest) -> ListToolsResult:
|
||||||
```
|
```
|
||||||
</CodeGroup>
|
</CodeGroup>
|
||||||
|
|
||||||
## Notification handlers
|
## Notification handling
|
||||||
|
|
||||||
Notification handlers process one-way messages that don't require responses. They're useful for handling events like resource updates or logging messages.
|
Notification handlers process one-way messages that don't require responses. They're useful for handling events like resource updates or logging messages.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
title: "Resource Management"
|
title: "Resource management"
|
||||||
description: "How to implement resource management in your MCP server"
|
description: "How to implement resource management in your MCP server"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
title: "Tool Implementation"
|
title: "Tool implementation"
|
||||||
description: "Learn how to implement tools in your MCP server"
|
description: "Learn how to implement tools in your MCP server"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
---
|
---
|
||||||
title: "TypeScript Class Reference"
|
title: "TypeScript class reference"
|
||||||
description: "Complete TypeScript SDK class documentation"
|
description: "Complete TypeScript SDK class documentation"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Client Classes
|
## Client classes
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ getServerVersion(): Implementation | undefined
|
||||||
```
|
```
|
||||||
Returns the server's version information after connection.
|
Returns the server's version information after connection.
|
||||||
|
|
||||||
### Transport Classes
|
### Transport classes
|
||||||
|
|
||||||
#### StdioClientTransport
|
#### StdioClientTransport
|
||||||
```typescript
|
```typescript
|
||||||
|
|
@ -103,7 +103,7 @@ import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/webso
|
||||||
constructor(url: URL)
|
constructor(url: URL)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Server Classes
|
## Server classes
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
|
||||||
|
|
@ -173,7 +173,7 @@ getClientVersion(): Implementation | undefined
|
||||||
```
|
```
|
||||||
Returns the client's version information after connection.
|
Returns the client's version information after connection.
|
||||||
|
|
||||||
### Transport Classes
|
### Transport classes
|
||||||
|
|
||||||
#### StdioServerTransport
|
#### StdioServerTransport
|
||||||
```typescript
|
```typescript
|
||||||
|
|
@ -197,7 +197,7 @@ constructor(endpoint: string, res: ServerResponse)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Client Implementation
|
### Client implementation
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Client } from "@modelcontextprotocol/sdk/client";
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
||||||
|
|
@ -269,7 +269,7 @@ async function main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Server Implementation
|
### Server implementation
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Server } from "@modelcontextprotocol/sdk/server";
|
import { Server } from "@modelcontextprotocol/sdk/server";
|
||||||
|
|
@ -363,7 +363,7 @@ async function main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Best Practices
|
## Best practices
|
||||||
|
|
||||||
1. **Error Handling**
|
1. **Error Handling**
|
||||||
```typescript
|
```typescript
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
---
|
---
|
||||||
title: "TypeScript Type Definitions"
|
title: "TypeScript type definitions"
|
||||||
description: "TypeScript type system documentation"
|
description: "TypeScript type system documentation"
|
||||||
---
|
---
|
||||||
|
|
||||||
## Core Protocol Types
|
## Core protocol types
|
||||||
|
|
||||||
### JSON-RPC Types
|
### JSON-RPC types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export const JSONRPC_VERSION = "2.0";
|
export const JSONRPC_VERSION = "2.0";
|
||||||
|
|
@ -53,7 +53,7 @@ export type JSONRPCMessage =
|
||||||
| JSONRPCError;
|
| JSONRPCError;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Message Content Types
|
### Message content types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** Text provided to or from an LLM */
|
/** Text provided to or from an LLM */
|
||||||
|
|
@ -84,7 +84,7 @@ export interface Progress {
|
||||||
export type ProgressCallback = (progress: Progress) => void;
|
export type ProgressCallback = (progress: Progress) => void;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Resource Types
|
### Resource types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** The contents of a specific resource */
|
/** The contents of a specific resource */
|
||||||
|
|
@ -120,7 +120,7 @@ export interface ResourceTemplate {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Types
|
### Tool types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** Definition for a tool the client can call */
|
/** Definition for a tool the client can call */
|
||||||
|
|
@ -134,7 +134,7 @@ export interface Tool {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prompt Types
|
### Prompt types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** Describes an argument that a prompt can accept */
|
/** Describes an argument that a prompt can accept */
|
||||||
|
|
@ -152,9 +152,9 @@ export interface Prompt {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Request/Response Types
|
## Request/response types
|
||||||
|
|
||||||
### Resource Requests
|
### Resource requests
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ListResourcesRequest {
|
export interface ListResourcesRequest {
|
||||||
|
|
@ -195,7 +195,7 @@ export interface UnsubscribeRequest {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tool Requests
|
### Tool requests
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ListToolsRequest {
|
export interface ListToolsRequest {
|
||||||
|
|
@ -226,7 +226,7 @@ export interface CallToolResult {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prompt Requests
|
### Prompt requests
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ListPromptsRequest {
|
export interface ListPromptsRequest {
|
||||||
|
|
@ -255,9 +255,9 @@ export interface GetPromptResult {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Protocol Types
|
## Protocol types
|
||||||
|
|
||||||
### Implementation Info
|
### Implementation info
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface Implementation {
|
export interface Implementation {
|
||||||
|
|
@ -266,7 +266,7 @@ export interface Implementation {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Capability Types
|
### Capability types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ResourceCapabilities {
|
export interface ResourceCapabilities {
|
||||||
|
|
@ -296,7 +296,7 @@ export interface ClientCapabilities {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Notification Types
|
### Notification types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface ResourceUpdatedNotification {
|
export interface ResourceUpdatedNotification {
|
||||||
|
|
@ -328,7 +328,7 @@ export type ServerNotification =
|
||||||
| LogMessageNotification;
|
| LogMessageNotification;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Error Types
|
## Error types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export enum ErrorCode {
|
export enum ErrorCode {
|
||||||
|
|
@ -354,7 +354,7 @@ export class McpError extends Error {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Transport Types
|
## Transport types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export interface Transport {
|
export interface Transport {
|
||||||
|
|
@ -373,9 +373,9 @@ export interface StdioServerParameters {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Usage examples
|
||||||
|
|
||||||
### Type Guards
|
### Type guards
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function isTextContent(content:
|
function isTextContent(content:
|
||||||
|
|
@ -391,7 +391,7 @@ function isResourceUpdatedNotification(
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Type Assertions
|
### Type assertions
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function assertResource(data: unknown): asserts data is Resource {
|
function assertResource(data: unknown): asserts data is Resource {
|
||||||
|
|
@ -409,7 +409,7 @@ function assertResource(data: unknown): asserts data is Resource {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Generics
|
### Using generics
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
async function handleResourceContent<T extends ResourceContents>(
|
async function handleResourceContent<T extends ResourceContents>(
|
||||||
|
|
@ -425,7 +425,7 @@ async function handleResourceContent<T extends ResourceContents>(
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working with Union Types
|
### Working with union types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function processMessage(message: SamplingMessage): string {
|
function processMessage(message: SamplingMessage): string {
|
||||||
|
|
@ -442,7 +442,7 @@ function processMessage(message: SamplingMessage): string {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Type Utilities
|
## Type utilities
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** Helper type to extract request params from method name */
|
/** Helper type to extract request params from method name */
|
||||||
|
|
|
||||||
|
|
@ -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",
|
"name": "API Reference",
|
||||||
"url": "api-reference"
|
"url": "api-reference"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Specification",
|
|
||||||
"url": "specification"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"anchors": [
|
"anchors": [
|
||||||
|
|
@ -101,22 +97,6 @@
|
||||||
"api-reference/typescript/class-reference",
|
"api-reference/typescript/class-reference",
|
||||||
"api-reference/typescript/type-definitions"
|
"api-reference/typescript/type-definitions"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"group": "Specification",
|
|
||||||
"pages": [
|
|
||||||
"specification/overview",
|
|
||||||
"specification/jsonrpc",
|
|
||||||
"specification/lifecycle",
|
|
||||||
"specification/prompts",
|
|
||||||
"specification/resources",
|
|
||||||
"specification/cancellation",
|
|
||||||
"specification/logging",
|
|
||||||
"specification/tools",
|
|
||||||
"specification/completion",
|
|
||||||
"specification/sampling",
|
|
||||||
"specification/roots"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"footerSocials": {
|
"footerSocials": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue