finished draft of quickstarts
This commit is contained in:
parent
2d987afeed
commit
e4dd2199fe
24 changed files with 2657 additions and 711 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: "Configuration"
|
||||
description: "Configure MCP servers for production"
|
||||
---
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
title: "Environment Setup"
|
||||
description: "Set up your production environment"
|
||||
---
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Monitoring"
|
||||
description: "Monitor your MCP servers in production"
|
||||
---
|
||||
|
||||
# Monitoring
|
||||
|
||||
Monitor your MCP servers in production
|
||||
235
docs/guides/claude.mdx
Normal file
235
docs/guides/claude.mdx
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
---
|
||||
title: "Connecting MCP to Claude"
|
||||
description: "Get started with MCP in less than 5 minutes"
|
||||
---
|
||||
|
||||
Give Claude superpowers by connecting it to your local computer! This guide will show you how to set up Model Context Protocol (MCP) and experience its magic in just 5 minutes.
|
||||
|
||||
<Note>
|
||||
MCP connects Claude to external data sources and tools. In this guide, we'll give Claude the ability to:
|
||||
- Take screenshots and analyze them
|
||||
- Control window arrangement
|
||||
- Execute local automation scripts
|
||||
|
||||
And it does this all securely - Claude can only access what you explicitly allow through MCP servers.
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- macOS (Windows/Linux guides coming soon)
|
||||
- Node.js v16 or higher (`node --version` to check)
|
||||
- Git (`git --version` to check)
|
||||
- [Claude desktop app](https://claude.ai/download) installed
|
||||
|
||||
<Accordion title="Need to install the prerequisites?">
|
||||
```bash
|
||||
# Using Homebrew
|
||||
brew install node git
|
||||
|
||||
# Or download directly:
|
||||
# Node.js: https://nodejs.org
|
||||
# Git: https://git-scm.com
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
## Installation
|
||||
|
||||
<Steps>
|
||||
<Step title="Install example servers">
|
||||
Let's start by getting some pre-built MCP servers that Claude can use:
|
||||
|
||||
```bash
|
||||
# Clone the example servers
|
||||
git clone https://github.com/modelcontextprotocol/example-servers
|
||||
cd example-servers
|
||||
|
||||
# Install dependencies and build
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Make servers available globally
|
||||
npm install -g
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure Claude">
|
||||
Open your Claude Desktop App configuration:
|
||||
|
||||
```bash
|
||||
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
||||
```
|
||||
|
||||
Add this configuration (replace YOUR_USERNAME with your actual username):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"osascript": {
|
||||
"command": "mcp-server-osascript",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Save and **restart Claude Desktop App**.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Test it out
|
||||
|
||||
Let's verify everything is working with a simple example. Try sending this prompt to Claude:
|
||||
|
||||
```
|
||||
Can you take a screenshot of my desktop and describe what you see?
|
||||
```
|
||||
|
||||
Claude will:
|
||||
|
||||
1. Request permission to take a screenshot
|
||||
2. Capture your screen through the MCP server
|
||||
3. Analyze and describe the screenshot
|
||||
|
||||
<Frame>
|
||||
<img src="/api/placeholder/800/400" alt="Example Claude conversation showing a screenshot analysis" />
|
||||
</Frame>
|
||||
<Note>
|
||||
The first time you use screenshot features, macOS will ask for permissions:
|
||||
- Screen Recording (for screenshots)
|
||||
- Automation (for window control)
|
||||
You'll need to grant these to Claude.app in System Settings.
|
||||
</Note>
|
||||
|
||||
## Try these examples
|
||||
|
||||
Now that MCP is working, try these increasingly powerful examples:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Basic Window Analysis" active>
|
||||
```
|
||||
Could you analyze my open windows and tell me:
|
||||
- How many windows I have open
|
||||
- Which apps are running
|
||||
- If any windows look cluttered
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="Window Organization">
|
||||
```
|
||||
Could you help organize my windows? I'd like:
|
||||
- Browser on the left half
|
||||
- VSCode on the right half
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="Create a Window Layout Script">
|
||||
```
|
||||
I often need this window layout for coding:
|
||||
- VSCode taking up the left 60%
|
||||
- Terminal in the top right
|
||||
- Browser in the bottom right
|
||||
Could you create an AppleScript to automate this?
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## What just happened?
|
||||
|
||||
Let's break down the magic:
|
||||
|
||||
1. When you installed the `osascript` server, you gave Claude a way to:
|
||||
- Take screenshots (see what you see)
|
||||
- Run AppleScript (control your windows)
|
||||
- Automate macOS tasks
|
||||
|
||||
2. The MCP protocol lets Claude:
|
||||
- Request these actions securely
|
||||
- Get results back in real-time
|
||||
- Chain actions together intelligently
|
||||
|
||||
3. All of this happens locally on your machine - no data leaves your computer!
|
||||
|
||||
## Add more capabilities
|
||||
|
||||
Want to give Claude even more superpowers? Add these servers to your configuration:
|
||||
<AccordionGroup>
|
||||
<Accordion title="File System Access" icon="folder-open">
|
||||
Add this to your config to let Claude read and analyze files:
|
||||
```json
|
||||
"tee": {
|
||||
"command": "mcp-server-tee",
|
||||
"args": ["tail", "-f", "/var/log/system.log"],
|
||||
"env": {
|
||||
"HOME": "/Users/YOUR_USERNAME"
|
||||
}
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Database Connection" icon="database">
|
||||
Connect Claude to your PostgreSQL database:
|
||||
```json
|
||||
"postgres": {
|
||||
"command": "mcp-server-postgres",
|
||||
"args": ["postgresql://localhost/mydb"],
|
||||
"env": {
|
||||
"HOME": "/Users/YOUR_USERNAME"
|
||||
}
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Web Automation" icon="globe">
|
||||
Enable web automation capabilities:
|
||||
```json
|
||||
"puppeteer": {
|
||||
"command": "mcp-server-puppeteer",
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Nothing showing up in Claude?">
|
||||
1. Check if MCP is enabled:
|
||||
- Click the 🔌 icon in Claude
|
||||
- You should see your configured servers
|
||||
|
||||
2. Verify your config:
|
||||
```bash
|
||||
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json
|
||||
```
|
||||
|
||||
3. Restart Claude completely:
|
||||
- Quit the app (not just close the window)
|
||||
- Start it again
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Permission errors?">
|
||||
Run this command to see Claude's logs:
|
||||
```bash
|
||||
tail -f ~/Claude.log
|
||||
```
|
||||
|
||||
Common fixes:
|
||||
- Check `HOME` env variable in your config
|
||||
- Grant missing permissions in System Settings
|
||||
- Try running example commands manually in Terminal
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Build Custom Servers" icon="code" href="/docs/guides/first-server-python">
|
||||
Create your own MCP integrations to give Claude new capabilities.
|
||||
</Card>
|
||||
|
||||
<Card title="Explore Examples" icon="microscope" href="https://github.com/modelcontextprotocol/example-servers">
|
||||
Browse our collection of example servers to see what's possible.
|
||||
</Card>
|
||||
|
||||
<Card title="Join Community" icon="users">
|
||||
Share your MCP creations and connect with other developers.
|
||||
[Join us →](/community)
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Your First MCP Server"
|
||||
description: "Build a complete MCP server from scratch"
|
||||
---
|
||||
|
||||
# Your First MCP Server
|
||||
|
||||
Build a complete MCP server from scratch
|
||||
422
docs/guides/first-server-python.mdx
Normal file
422
docs/guides/first-server-python.mdx
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
---
|
||||
title: "Your First MCP Server (Python)"
|
||||
description: "Create a simple MCP server in Python in 15 minutes"
|
||||
---
|
||||
|
||||
Let's build your first MCP server in Python! We'll create a weather server that provides current weather data as a resource and lets Claude fetch forecasts using tools.
|
||||
|
||||
<Note>
|
||||
This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Python">
|
||||
You'll need Python 3.8 or higher:
|
||||
|
||||
```bash
|
||||
python3 --version # Should be 3.8 or higher
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set up a virtual environment">
|
||||
```bash
|
||||
# Create and activate virtual environment
|
||||
python3 -m venv mcp-weather
|
||||
cd mcp-weather
|
||||
source bin/activate # On Windows: .\Scripts\activate
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Install MCP SDK">
|
||||
```bash
|
||||
pip install modelcontextprotocol-sdk requests
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Get API Key">
|
||||
1. Sign up at [OpenWeatherMap](https://openweathermap.org/api)
|
||||
2. Copy your API key
|
||||
3. Set it as an environment variable:
|
||||
```bash
|
||||
export OPENWEATHER_API_KEY='your-api-key'
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Create Your Server
|
||||
|
||||
<Steps>
|
||||
<Step title="Create project structure">
|
||||
```bash
|
||||
mkdir weather_server
|
||||
cd weather_server
|
||||
touch weather_server.py
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add the base code">
|
||||
Open `weather_server.py` and add this starter code:
|
||||
|
||||
```python
|
||||
from modelcontextprotocol.server import Server
|
||||
from modelcontextprotocol.server.stdio import StdioServerTransport
|
||||
from modelcontextprotocol.types import (
|
||||
ListResourcesRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
CallToolRequestSchema
|
||||
)
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
API_KEY = os.getenv('OPENWEATHER_API_KEY')
|
||||
BASE_URL = 'http://api.openweathermap.org/data/2.5'
|
||||
|
||||
class WeatherServer:
|
||||
def __init__(self):
|
||||
self.server = Server(
|
||||
name="example-weather-server",
|
||||
version="0.1.0"
|
||||
)
|
||||
self.default_city = "San Francisco"
|
||||
self.setup_handlers()
|
||||
|
||||
def setup_handlers(self):
|
||||
# We'll add handlers here
|
||||
pass
|
||||
|
||||
async def run(self):
|
||||
transport = StdioServerTransport()
|
||||
await self.server.connect(transport)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
server = WeatherServer()
|
||||
asyncio.run(server.run())
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add resource handlers">
|
||||
Let's add handlers to expose current weather as a resource:
|
||||
|
||||
```python
|
||||
def setup_handlers(self):
|
||||
self.server.set_request_handler(
|
||||
ListResourcesRequestSchema,
|
||||
self.handle_list_resources
|
||||
)
|
||||
self.server.set_request_handler(
|
||||
ReadResourceRequestSchema,
|
||||
self.handle_read_resource
|
||||
)
|
||||
|
||||
async def handle_list_resources(self, request):
|
||||
return {
|
||||
"resources": [{
|
||||
"uri": f"weather://{self.default_city}/current",
|
||||
"name": f"Current weather in {self.default_city}",
|
||||
"mimeType": "application/json"
|
||||
}]
|
||||
}
|
||||
|
||||
async def handle_read_resource(self, request):
|
||||
city = self.default_city
|
||||
if request.params.uri != f"weather://{city}/current":
|
||||
raise ValueError(f"Unknown resource: {request.params.uri}")
|
||||
|
||||
response = requests.get(
|
||||
f"{BASE_URL}/weather",
|
||||
params={
|
||||
"q": city,
|
||||
"appid": API_KEY,
|
||||
"units": "metric"
|
||||
}
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
return {
|
||||
"contents": [{
|
||||
"uri": request.params.uri,
|
||||
"mimeType": "application/json",
|
||||
"text": json.dumps({
|
||||
"temperature": data["main"]["temp"],
|
||||
"conditions": data["weather"][0]["description"],
|
||||
"humidity": data["main"]["humidity"],
|
||||
"wind_speed": data["wind"]["speed"],
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}, indent=2)
|
||||
}]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add tool handlers">
|
||||
Now let's add a tool to fetch weather forecasts:
|
||||
|
||||
```python
|
||||
def setup_handlers(self):
|
||||
# Add these lines to the existing method
|
||||
self.server.set_request_handler(
|
||||
ListToolsRequestSchema,
|
||||
self.handle_list_tools
|
||||
)
|
||||
self.server.set_request_handler(
|
||||
CallToolRequestSchema,
|
||||
self.handle_call_tool
|
||||
)
|
||||
|
||||
async def handle_list_tools(self, request):
|
||||
return {
|
||||
"tools": [{
|
||||
"name": "get_forecast",
|
||||
"description": "Get weather forecast for a city",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City name"
|
||||
},
|
||||
"days": {
|
||||
"type": "number",
|
||||
"description": "Number of days (1-5)"
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
async def handle_call_tool(self, request):
|
||||
if request.params.name != "get_forecast":
|
||||
raise ValueError(f"Unknown tool: {request.params.name}")
|
||||
|
||||
args = request.params.arguments
|
||||
city = args.get("city", self.default_city)
|
||||
days = min(int(args.get("days", 3)), 5)
|
||||
|
||||
response = requests.get(
|
||||
f"{BASE_URL}/forecast",
|
||||
params={
|
||||
"q": city,
|
||||
"appid": API_KEY,
|
||||
"units": "metric",
|
||||
"cnt": days * 8 # API returns 3-hour intervals
|
||||
}
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
# Process and return daily forecasts
|
||||
forecasts = []
|
||||
for i in range(0, len(data["list"]), 8): # One day = 8 intervals
|
||||
day_data = data["list"][i]
|
||||
forecasts.append({
|
||||
"date": day_data["dt_txt"].split()[0],
|
||||
"temperature": day_data["main"]["temp"],
|
||||
"conditions": day_data["weather"][0]["description"]
|
||||
})
|
||||
|
||||
return {"toolResult": forecasts}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Test your server">
|
||||
1. Save all changes
|
||||
2. Run your server:
|
||||
```bash
|
||||
python weather_server.py
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Connect to Claude
|
||||
|
||||
<Steps>
|
||||
<Step title="Install the server">
|
||||
```bash
|
||||
# From your project directory
|
||||
pip install -e .
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Update Claude config">
|
||||
Add this to your `claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"weather": {
|
||||
"command": "python",
|
||||
"args": ["-m", "weather_server"],
|
||||
"env": {
|
||||
"OPENWEATHER_API_KEY": "your-api-key",
|
||||
"HOME": "/Users/YOUR_USERNAME"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Restart Claude">
|
||||
1. Quit Claude completely
|
||||
2. Start Claude again
|
||||
3. Verify your weather server appears in the 🔌 menu
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Try It Out!
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Check Current Weather" active>
|
||||
Ask Claude:
|
||||
```
|
||||
What's the current weather in San Francisco? Can you analyze the conditions?
|
||||
```
|
||||
|
||||
Claude will:
|
||||
1. Access the weather resource
|
||||
2. Parse the JSON data
|
||||
3. Provide a natural language summary
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Get a Forecast">
|
||||
Ask Claude:
|
||||
```
|
||||
Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella?
|
||||
```
|
||||
|
||||
Claude will:
|
||||
1. Use the `get_forecast` tool
|
||||
2. Analyze the forecast data
|
||||
3. Give you packing advice
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Understanding the Code
|
||||
|
||||
Let's break down the key MCP concepts used in this server:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Resources">
|
||||
```python
|
||||
async def handle_list_resources(self, request):
|
||||
return {
|
||||
"resources": [{
|
||||
"uri": f"weather://{self.default_city}/current",
|
||||
"name": f"Current weather in {self.default_city}",
|
||||
"mimeType": "application/json"
|
||||
}]
|
||||
}
|
||||
```
|
||||
Resources provide data that Claude can access as context. In this case, we're exposing current weather data that Claude can read and analyze.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Tools">
|
||||
```python
|
||||
async def handle_list_tools(self, request):
|
||||
return {
|
||||
"tools": [{
|
||||
"name": "get_forecast",
|
||||
"description": "Get weather forecast for a city",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {"type": "string"},
|
||||
"days": {"type": "number"}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
Tools let Claude take actions through your server. The `inputSchema` defines what parameters Claude can provide.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Transport">
|
||||
```python
|
||||
async def run(self):
|
||||
transport = StdioServerTransport()
|
||||
await self.server.connect(transport)
|
||||
```
|
||||
The transport layer handles communication between Claude and your server. Here we're using stdio, but MCP also supports WebSocket and SSE.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've built your first MCP server, try these enhancements:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Add More Resources"
|
||||
icon="database"
|
||||
>
|
||||
- Air quality data
|
||||
- Weather alerts
|
||||
- Historical weather
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Enhance Tools"
|
||||
icon="wrench"
|
||||
>
|
||||
- Compare multiple cities
|
||||
- Get detailed hourly forecasts
|
||||
- Save favorite locations
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Improve Error Handling"
|
||||
icon="shield"
|
||||
>
|
||||
- Handle API errors gracefully
|
||||
- Add input validation
|
||||
- Rate limiting
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Add Subscriptions"
|
||||
icon="bell"
|
||||
>
|
||||
- Weather alerts
|
||||
- Temperature changes
|
||||
- Condition updates
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Import Errors">
|
||||
```bash
|
||||
pip install modelcontextprotocol-sdk --upgrade
|
||||
```
|
||||
Ensure you're using the latest SDK version.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="API Key Issues">
|
||||
1. Verify your API key is set:
|
||||
```bash
|
||||
echo $OPENWEATHER_API_KEY
|
||||
```
|
||||
2. Check the API response for error messages
|
||||
3. Ensure you're within free tier limits
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Connection Issues">
|
||||
1. Check Claude's logs:
|
||||
```bash
|
||||
tail -f ~/Claude.log
|
||||
```
|
||||
2. Verify your config JSON syntax
|
||||
3. Ensure Python path is correct in config
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Note>
|
||||
Remember: This is just the beginning! MCP servers can provide any type of data or functionality to Claude. Think about what unique capabilities you could add to Claude through MCP.
|
||||
</Note>
|
||||
533
docs/guides/first-server-ts.mdx
Normal file
533
docs/guides/first-server-ts.mdx
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
---
|
||||
title: "Your First MCP Server (TypeScript)"
|
||||
description: "Create a simple MCP server in TypeScript in 15 minutes"
|
||||
---
|
||||
|
||||
Let's build your first MCP server in TypeScript! We'll create a weather server that provides current weather data as a resource and lets Claude fetch forecasts using tools.
|
||||
|
||||
<Note>
|
||||
This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Steps>
|
||||
<Step title="Install Node.js">
|
||||
You'll need Node.js 16 or higher:
|
||||
|
||||
```bash
|
||||
node --version # Should be v16 or higher
|
||||
npm --version
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create a new project">
|
||||
```bash
|
||||
mkdir weather-server
|
||||
cd weather-server
|
||||
npm init -y
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Install dependencies">
|
||||
```bash
|
||||
npm install @modelcontextprotocol/sdk axios dotenv typescript @types/node
|
||||
npm install --save-dev ts-node
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Configure TypeScript">
|
||||
Create `tsconfig.json`:
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Set up environment">
|
||||
Create `.env`:
|
||||
```bash
|
||||
OPENWEATHER_API_KEY=your-api-key-here
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Create Your Server
|
||||
|
||||
<Steps>
|
||||
<Step title="Create project structure">
|
||||
```bash
|
||||
mkdir src
|
||||
touch src/index.ts
|
||||
touch src/types.ts
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Define types">
|
||||
In `src/types.ts`:
|
||||
|
||||
```typescript
|
||||
export interface WeatherData {
|
||||
temperature: number;
|
||||
conditions: string;
|
||||
humidity: number;
|
||||
wind_speed: number;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface ForecastDay {
|
||||
date: string;
|
||||
temperature: number;
|
||||
conditions: string;
|
||||
}
|
||||
|
||||
export interface GetForecastArgs {
|
||||
city: string;
|
||||
days?: number;
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add the base code">
|
||||
In `src/index.ts`:
|
||||
|
||||
```typescript
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import axios from "axios";
|
||||
import dotenv from "dotenv";
|
||||
import { WeatherData, ForecastDay, GetForecastArgs } from "./types.js";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const API_KEY = process.env.OPENWEATHER_API_KEY;
|
||||
const BASE_URL = 'http://api.openweathermap.org/data/2.5';
|
||||
const DEFAULT_CITY = 'San Francisco';
|
||||
|
||||
class WeatherServer {
|
||||
private server: Server;
|
||||
|
||||
constructor() {
|
||||
this.server = new Server({
|
||||
name: "example-weather-server",
|
||||
version: "0.1.0"
|
||||
});
|
||||
this.setupHandlers();
|
||||
}
|
||||
|
||||
private setupHandlers(): void {
|
||||
// We'll add handlers here
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const transport = new StdioServerTransport();
|
||||
await this.server.connect(transport);
|
||||
}
|
||||
}
|
||||
|
||||
const server = new WeatherServer();
|
||||
server.run().catch(console.error);
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add resource handlers">
|
||||
Add this to the `setupHandlers` method:
|
||||
|
||||
```typescript
|
||||
private setupHandlers(): void {
|
||||
this.server.setRequestHandler(
|
||||
ListResourcesRequestSchema,
|
||||
async () => ({
|
||||
resources: [{
|
||||
uri: `weather://${DEFAULT_CITY}/current`,
|
||||
name: `Current weather in ${DEFAULT_CITY}`,
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
})
|
||||
);
|
||||
|
||||
this.server.setRequestHandler(
|
||||
ReadResourceRequestSchema,
|
||||
async (request) => {
|
||||
const city = DEFAULT_CITY;
|
||||
if (request.params.uri !== `weather://${city}/current`) {
|
||||
throw new Error(`Unknown resource: ${request.params.uri}`);
|
||||
}
|
||||
|
||||
const response = await axios.get(`${BASE_URL}/weather`, {
|
||||
params: {
|
||||
q: city,
|
||||
appid: API_KEY,
|
||||
units: "metric"
|
||||
}
|
||||
});
|
||||
|
||||
const weatherData: WeatherData = {
|
||||
temperature: response.data.main.temp,
|
||||
conditions: response.data.weather[0].description,
|
||||
humidity: response.data.main.humidity,
|
||||
wind_speed: response.data.wind.speed,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: request.params.uri,
|
||||
mimeType: "application/json",
|
||||
text: JSON.stringify(weatherData, null, 2)
|
||||
}]
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Add tool handlers">
|
||||
Add these handlers to the `setupHandlers` method:
|
||||
|
||||
```typescript
|
||||
this.server.setRequestHandler(
|
||||
ListToolsRequestSchema,
|
||||
async () => ({
|
||||
tools: [{
|
||||
name: "get_forecast",
|
||||
description: "Get weather forecast for a city",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
city: {
|
||||
type: "string",
|
||||
description: "City name"
|
||||
},
|
||||
days: {
|
||||
type: "number",
|
||||
description: "Number of days (1-5)"
|
||||
}
|
||||
},
|
||||
required: ["city"]
|
||||
}
|
||||
}]
|
||||
})
|
||||
);
|
||||
|
||||
this.server.setRequestHandler(
|
||||
CallToolRequestSchema,
|
||||
async (request) => {
|
||||
if (request.params.name !== "get_forecast") {
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
}
|
||||
|
||||
const args = request.params.arguments as GetForecastArgs;
|
||||
const city = args.city || DEFAULT_CITY;
|
||||
const days = Math.min(args.days || 3, 5);
|
||||
|
||||
const response = await axios.get(`${BASE_URL}/forecast`, {
|
||||
params: {
|
||||
q: city,
|
||||
appid: API_KEY,
|
||||
units: "metric",
|
||||
cnt: days * 8 // API returns 3-hour intervals
|
||||
}
|
||||
});
|
||||
|
||||
const forecasts: ForecastDay[] = [];
|
||||
for (let i = 0; i < response.data.list.length; i += 8) {
|
||||
const dayData = response.data.list[i];
|
||||
forecasts.push({
|
||||
date: dayData.dt_txt.split(' ')[0],
|
||||
temperature: dayData.main.temp,
|
||||
conditions: dayData.weather[0].description
|
||||
});
|
||||
}
|
||||
|
||||
return { toolResult: forecasts };
|
||||
}
|
||||
);
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Build and test">
|
||||
Add these scripts to `package.json`:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "ts-node src/index.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Connect to Claude
|
||||
|
||||
<Steps>
|
||||
<Step title="Install globally">
|
||||
```bash
|
||||
npm install -g
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Update Claude config">
|
||||
Add to `claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"weather": {
|
||||
"command": "weather-server",
|
||||
"env": {
|
||||
"OPENWEATHER_API_KEY": "your-api-key",
|
||||
"HOME": "/Users/YOUR_USERNAME"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Restart Claude">
|
||||
1. Quit Claude completely
|
||||
2. Start Claude again
|
||||
3. Look for your weather server in the 🔌 menu
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Try It Out!
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Check Current Weather" active>
|
||||
Ask Claude:
|
||||
```
|
||||
What's the current weather in San Francisco? Can you analyze the conditions?
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Get a Forecast">
|
||||
Ask Claude:
|
||||
```
|
||||
Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella?
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Compare Weather">
|
||||
Ask Claude:
|
||||
```
|
||||
Can you analyze the forecast for both Tokyo and San Francisco and tell me which city will be warmer this week?
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Understanding the Code
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Type Safety">
|
||||
```typescript
|
||||
interface WeatherData {
|
||||
temperature: number;
|
||||
conditions: string;
|
||||
humidity: number;
|
||||
wind_speed: number;
|
||||
timestamp: string;
|
||||
}
|
||||
```
|
||||
TypeScript adds type safety to our MCP server, making it more reliable and easier to maintain.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Resources">
|
||||
```typescript
|
||||
this.server.setRequestHandler(
|
||||
ListResourcesRequestSchema,
|
||||
async () => ({
|
||||
resources: [{
|
||||
uri: `weather://${DEFAULT_CITY}/current`,
|
||||
name: `Current weather in ${DEFAULT_CITY}`,
|
||||
mimeType: "application/json"
|
||||
}]
|
||||
})
|
||||
);
|
||||
```
|
||||
Resources provide data that Claude can access as context.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Tools">
|
||||
```typescript
|
||||
{
|
||||
name: "get_forecast",
|
||||
description: "Get weather forecast for a city",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
city: { type: "string" },
|
||||
days: { type: "number" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Tools let Claude take actions through your server with type-safe inputs.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Best Practices
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Error Handling"
|
||||
icon="shield"
|
||||
>
|
||||
```typescript
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
throw new Error(`API error: ${error.response?.data.message}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Type Guards"
|
||||
icon="check"
|
||||
>
|
||||
```typescript
|
||||
function isValidForecastArgs(args: unknown): args is GetForecastArgs {
|
||||
return typeof args === "object" && args !== null &&
|
||||
"city" in args;
|
||||
}
|
||||
```
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Environment Variables"
|
||||
icon="gear"
|
||||
>
|
||||
```typescript
|
||||
if (!process.env.OPENWEATHER_API_KEY) {
|
||||
throw new Error("OPENWEATHER_API_KEY is required");
|
||||
}
|
||||
```
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Constants"
|
||||
icon="box"
|
||||
>
|
||||
```typescript
|
||||
const API_ENDPOINTS = {
|
||||
CURRENT: "weather",
|
||||
FORECAST: "forecast"
|
||||
} as const;
|
||||
```
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Enhancements
|
||||
|
||||
Try adding these features to your server:
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card
|
||||
title="Resource Templates"
|
||||
icon="square-terminal"
|
||||
>
|
||||
Add dynamic city resources:
|
||||
```typescript
|
||||
uriTemplate: "weather://{city}/current"
|
||||
```
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Caching"
|
||||
icon="database"
|
||||
>
|
||||
Cache API responses:
|
||||
```typescript
|
||||
import NodeCache from "node-cache"
|
||||
```
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Rate Limiting"
|
||||
icon="gauge"
|
||||
>
|
||||
Add API rate limiting:
|
||||
```typescript
|
||||
import rateLimit from "axios-rate-limit"
|
||||
```
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Build Errors">
|
||||
```bash
|
||||
# Check TypeScript version
|
||||
npx tsc --version
|
||||
|
||||
# Clean and rebuild
|
||||
rm -rf dist/
|
||||
npm run build
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Runtime Errors">
|
||||
Add better error logging:
|
||||
```typescript
|
||||
server.onerror = (error) => {
|
||||
console.error("[MCP Error]", error);
|
||||
};
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Type Errors">
|
||||
```bash
|
||||
# Check types without building
|
||||
npx tsc --noEmit
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Add WebSocket Transport"
|
||||
icon="bolt"
|
||||
href="/guides/websocket"
|
||||
>
|
||||
Switch to real-time updates with WebSocket transport
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Add Testing"
|
||||
icon="vial"
|
||||
href="/guides/testing"
|
||||
>
|
||||
Add Jest tests for your MCP server
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Note>
|
||||
Need help? Ask Claude! Since it has access to the MCP SDK documentation, it can help you debug issues and suggest improvements to your server.
|
||||
</Note>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Implementing Tools"
|
||||
description: "Create tools that LLMs can invoke"
|
||||
---
|
||||
|
||||
# Implementing Tools
|
||||
|
||||
Create tools that LLMs can invoke
|
||||
442
docs/guides/integrate-python.mdx
Normal file
442
docs/guides/integrate-python.mdx
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
---
|
||||
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/example-servers
|
||||
cd example-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>
|
||||
885
docs/guides/integrate-ts.mdx
Normal file
885
docs/guides/integrate-ts.mdx
Normal file
|
|
@ -0,0 +1,885 @@
|
|||
---
|
||||
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/example-servers
|
||||
cd example-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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Testing and Debugging"
|
||||
description: "Test and debug your MCP servers effectively"
|
||||
---
|
||||
|
||||
# Testing and Debugging
|
||||
|
||||
Test and debug your MCP servers effectively
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Working with Resources"
|
||||
description: "Learn how to expose and consume data through MCP"
|
||||
---
|
||||
|
||||
# Working with Resources
|
||||
|
||||
Learn how to expose and consume data through MCP
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
---
|
||||
title: "Installation"
|
||||
description: "Get started with Model Context Protocol (MCP) by installing the SDK for your preferred language"
|
||||
---
|
||||
|
||||
<Note>
|
||||
MCP supports both TypeScript and Python implementations. Choose the one that best fits your project.
|
||||
</Note>
|
||||
|
||||
<Steps>
|
||||
<Step title="Choose Your SDK">
|
||||
<Tabs>
|
||||
<Tab title="TypeScript">
|
||||
Install the TypeScript SDK using npm:
|
||||
```bash
|
||||
npm install @modelcontextprotocol/sdk
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Python">
|
||||
Install the Python SDK using pip:
|
||||
```bash
|
||||
pip install modelcontextprotocol
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Step>
|
||||
|
||||
<Step title="Verify Installation">
|
||||
Verify your installation by running a simple test:
|
||||
|
||||
<CodeGroup>
|
||||
```typescript typescript-test.ts
|
||||
import { Client } from "@modelcontextprotocol/sdk";
|
||||
|
||||
const client = new Client({
|
||||
name: "test-client",
|
||||
version: "0.1.0"
|
||||
});
|
||||
console.log("MCP SDK installed successfully!");
|
||||
```
|
||||
|
||||
```python python-test.py
|
||||
from modelcontextprotocol import Client
|
||||
|
||||
client = Client(
|
||||
name="test-client",
|
||||
version="0.1.0"
|
||||
)
|
||||
print("MCP SDK installed successfully!")
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Set Up Development Environment">
|
||||
<Info>
|
||||
For local development, you'll need Node.js 18+ for TypeScript or Python 3.8+ for Python.
|
||||
</Info>
|
||||
|
||||
Install the MCP Inspector for testing and debugging your implementations:
|
||||
```bash
|
||||
npm install -g @modelcontextprotocol/inspector
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## System Requirements
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="TypeScript Requirements" icon="js">
|
||||
- Node.js 18 or higher
|
||||
- npm 7 or higher
|
||||
- TypeScript 4.7 or higher (for TypeScript users)
|
||||
|
||||
Optional development tools:
|
||||
- VS Code with TypeScript plugin
|
||||
- ESLint for code quality
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Python Requirements" icon="python">
|
||||
- Python 3.8 or higher
|
||||
- pip 20.0 or higher
|
||||
- virtualenv (recommended)
|
||||
|
||||
Optional development tools:
|
||||
- VS Code with Python extension
|
||||
- pylint for code quality
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Operating System Support" icon="computer">
|
||||
MCP supports all major operating systems:
|
||||
- Windows 10/11
|
||||
- macOS 10.15+
|
||||
- Linux (major distributions)
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
<Frame>
|
||||
<img src="/images/mcp-architecture.png" />
|
||||
</Frame>
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[LLM Application] --> B[MCP Client]
|
||||
B --> C[MCP Server]
|
||||
C --> D[(External Resource)]
|
||||
|
||||
style A fill:#e0f4ff,stroke:#0077cc,stroke-width:2px
|
||||
style B fill:#fff4e0,stroke:#ff8c00,stroke-width:2px
|
||||
style C fill:#e0ffe0,stroke:#2d862d,stroke-width:2px
|
||||
style D fill:#ffe0e0,stroke:#cc0000,stroke-width:2px
|
||||
|
||||
classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px
|
||||
|
||||
## Next Steps
|
||||
<CardGroup>
|
||||
<Card title="Quick Start Guide" icon="play" href="/quickstart">
|
||||
Build your first MCP integration in under 5 minutes
|
||||
</Card>
|
||||
<Card title="Example Servers" icon="server" href="/example-servers">
|
||||
Explore pre-built MCP servers for common use cases
|
||||
</Card>
|
||||
<Card title="API Reference" icon="book" href="/api-reference">
|
||||
Dive into the complete API documentation
|
||||
</Card>
|
||||
</CardGroup>
|
||||
<Tip>
|
||||
Join our [Discord community](https://discord.gg/mcp) for help and discussions about MCP development.
|
||||
</Tip>
|
||||
|
||||
## Troubleshooting Common Issues
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Version Conflicts">
|
||||
If you encounter version conflicts, ensure all your dependencies are up to date:
|
||||
```bash
|
||||
# For TypeScript
|
||||
npm update @modelcontextprotocol/sdk
|
||||
Copy# For Python
|
||||
pip install --upgrade modelcontextprotocol
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="Connection Issues">
|
||||
If you're having trouble connecting to MCP servers:
|
||||
1. Check your network configuration
|
||||
2. Verify the server is running
|
||||
3. Ensure your firewall isn't blocking connections
|
||||
4. Check the server logs for errors
|
||||
</Accordion>
|
||||
<Accordion title="Build Errors">
|
||||
Common build errors and their solutions:
|
||||
- TypeScript type errors: Update your @types dependencies
|
||||
- Python import errors: Check your PYTHONPATH
|
||||
- Missing dependencies: Run package manager install commands
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
<Warning>
|
||||
Remember to keep your SDKs updated to the latest version for security patches and new features.
|
||||
</Warning>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "API Integration"
|
||||
description: "Wrap external APIs with MCP"
|
||||
---
|
||||
|
||||
# API Integration
|
||||
|
||||
Wrap external APIs with MCP
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Database Integration"
|
||||
description: "Connect databases to your LLM through MCP"
|
||||
---
|
||||
|
||||
# Database Integration
|
||||
|
||||
Connect databases to your LLM through MCP
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Local File Access"
|
||||
description: "Implement local file access in MCP"
|
||||
---
|
||||
|
||||
# Local File Access
|
||||
|
||||
Implement local file access in MCP
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
title: "Real-time Updates"
|
||||
description: "Handle live data updates in MCP"
|
||||
---
|
||||
|
||||
# Real-time Updates
|
||||
|
||||
Handle live data updates in MCP
|
||||
161
introduction.mdx
161
introduction.mdx
|
|
@ -1,63 +1,142 @@
|
|||
---
|
||||
title: Introduction
|
||||
description: 'Introduction to the Model Context Protocol'
|
||||
description: 'Get started with the Model Context Protocol (MCP)'
|
||||
---
|
||||
|
||||
The Model Context Protocol (MCP) is a protocol designed to enable LLM assistant surfaces to receive contextual information from specialized servers. Whether you’re building an IDE coding assistant, a chat interface, or any other LLM-powered application, MCP provides a standardized way to obtain and utilize relevant context.
|
||||
The Model Context Protocol (MCP) is an open protocol that enables seamless integration between LLM applications and external data sources and tools. Whether you're building an AI-powered IDE, enhancing a chat interface, or creating custom AI workflows, MCP provides a standardized way to connect LLMs with the context they need.
|
||||
|
||||
## Quickstart Guides
|
||||
|
||||
## Get started
|
||||
|
||||
The first step to world-class documentation is setting up your editing environments.
|
||||
Choose the path that best fits your needs:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Edit Your Docs"
|
||||
icon="pen-to-square"
|
||||
href="https://mintlify.com/docs/quickstart"
|
||||
title="Try MCP with Claude"
|
||||
icon="bolt"
|
||||
href="/docs/guides/claude"
|
||||
>
|
||||
Get your docs set up locally for easy development
|
||||
The fastest way to see MCP in action - connect example servers to Claude in minutes
|
||||
</Card>
|
||||
<Card
|
||||
title="Preview Changes"
|
||||
icon="image"
|
||||
href="https://mintlify.com/docs/development"
|
||||
>
|
||||
Preview your changes before you push to make sure they're perfect
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Make it yours
|
||||
|
||||
Update your docs to your brand and add valuable content for the best user conversion.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Customize Style"
|
||||
icon="palette"
|
||||
href="https://mintlify.com/docs/settings/global"
|
||||
>
|
||||
Customize your docs to your company's colors and brands
|
||||
</Card>
|
||||
<Card
|
||||
title="Reference APIs"
|
||||
title="Build Your First Server (TypeScript)"
|
||||
icon="code"
|
||||
href="https://mintlify.com/docs/api-playground/openapi"
|
||||
href="/docs/guides/first-server-ts"
|
||||
>
|
||||
Automatically generate endpoints from an OpenAPI spec
|
||||
Create a simple MCP server in TypeScript to understand the basics
|
||||
</Card>
|
||||
<Card
|
||||
title="Add Components"
|
||||
icon="screwdriver-wrench"
|
||||
href="https://mintlify.com/docs/components/accordion"
|
||||
title="Build Your First Server (Python)"
|
||||
icon="python"
|
||||
href="/docs/guides/first-server-python"
|
||||
>
|
||||
Build interactive features and designs to guide your users
|
||||
Create a simple MCP server in Python to understand the basics
|
||||
</Card>
|
||||
<Card
|
||||
title="Get Inspiration"
|
||||
icon="stars"
|
||||
href="https://mintlify.com/customers"
|
||||
title="Integrate MCP (TypeScript)"
|
||||
icon="plug"
|
||||
href="/docs/guides/integrate-ts"
|
||||
>
|
||||
Check out our showcase of our favorite documentation
|
||||
Add MCP support to your TypeScript/JavaScript LLM application
|
||||
</Card>
|
||||
<Card
|
||||
title="Integrate MCP (Python)"
|
||||
icon="plug"
|
||||
href="/docs/guides/integrate-python"
|
||||
>
|
||||
Add MCP support to your Python LLM application
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Explore MCP
|
||||
|
||||
Dive deeper into MCP's core concepts and capabilities:
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card
|
||||
title="Core Architecture"
|
||||
icon="sitemap"
|
||||
href="/core/architecture"
|
||||
>
|
||||
Understand how MCP connects clients, servers, and LLMs
|
||||
</Card>
|
||||
<Card
|
||||
title="Resources"
|
||||
icon="database"
|
||||
href="/core/resources"
|
||||
>
|
||||
Expose data and content from your servers to LLMs
|
||||
</Card>
|
||||
<Card
|
||||
title="Prompts"
|
||||
icon="message"
|
||||
href="/core/prompts"
|
||||
>
|
||||
Create reusable prompt templates and workflows
|
||||
</Card>
|
||||
<Card
|
||||
title="Tools"
|
||||
icon="wrench"
|
||||
href="/core/tools"
|
||||
>
|
||||
Enable LLMs to perform actions through your server
|
||||
</Card>
|
||||
<Card
|
||||
title="Sampling"
|
||||
icon="robot"
|
||||
href="/core/sampling"
|
||||
>
|
||||
Let your servers request completions from LLMs
|
||||
</Card>
|
||||
<Card
|
||||
title="Transport"
|
||||
icon="network-wired"
|
||||
href="/core/transport"
|
||||
>
|
||||
Learn about MCP's communication mechanisms
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Example Use Cases
|
||||
|
||||
See what you can build with MCP:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Custom Knowledge Base"
|
||||
icon="book"
|
||||
>
|
||||
Connect your documentation, wikis, and internal knowledge bases to LLMs
|
||||
</Card>
|
||||
<Card
|
||||
title="Database Integration"
|
||||
icon="database"
|
||||
>
|
||||
Query databases and analyze results with natural language
|
||||
</Card>
|
||||
<Card
|
||||
title="Local Development"
|
||||
icon="code"
|
||||
>
|
||||
Build AI-powered development tools with access to local files and git
|
||||
</Card>
|
||||
<Card
|
||||
title="Enterprise Systems"
|
||||
icon="building"
|
||||
>
|
||||
Securely connect enterprise tools and data to AI interfaces
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Security and Best Practices
|
||||
|
||||
MCP is designed with security in mind, but requires careful implementation:
|
||||
|
||||
<Card
|
||||
title="Security Guide"
|
||||
icon="shield"
|
||||
href="/security"
|
||||
>
|
||||
Learn about MCP's security model, best practices, and implementation guidelines
|
||||
</Card>
|
||||
|
||||
Want to contribute? Check out our [GitHub repository](https://github.com/modelcontextprotocol) or join our growing community of developers building with MCP.
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue