finished draft of quickstarts

This commit is contained in:
Zack Lee 2024-11-18 08:48:20 -05:00
commit e4dd2199fe
No known key found for this signature in database
18 changed files with 2657 additions and 711 deletions

View file

@ -1,5 +0,0 @@
---
title: "Configuration"
description: "Configure MCP servers for production"
---

View file

@ -1,4 +0,0 @@
---
title: "Environment Setup"
description: "Set up your production environment"
---

View file

@ -1,8 +0,0 @@
---
title: "Monitoring"
description: "Monitor your MCP servers in production"
---
# Monitoring
Monitor your MCP servers in production

View file

235
docs/guides/claude.mdx Normal file
View 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>

View file

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

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

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

View file

@ -1,8 +0,0 @@
---
title: "Implementing Tools"
description: "Create tools that LLMs can invoke"
---
# Implementing Tools
Create tools that LLMs can invoke

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

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

View file

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

View file

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

View file

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

View file

@ -1,8 +0,0 @@
---
title: "API Integration"
description: "Wrap external APIs with MCP"
---
# API Integration
Wrap external APIs with MCP

View file

@ -1,8 +0,0 @@
---
title: "Database Integration"
description: "Connect databases to your LLM through MCP"
---
# Database Integration
Connect databases to your LLM through MCP

View file

@ -1,8 +0,0 @@
---
title: "Local File Access"
description: "Implement local file access in MCP"
---
# Local File Access
Implement local file access in MCP

View file

@ -1,8 +0,0 @@
---
title: "Real-time Updates"
description: "Handle live data updates in MCP"
---
# Real-time Updates
Handle live data updates in MCP