diff --git a/docs/core/architecture.mdx b/docs/concepts/architecture.mdx
similarity index 100%
rename from docs/core/architecture.mdx
rename to docs/concepts/architecture.mdx
diff --git a/docs/core/prompts.mdx b/docs/concepts/prompts.mdx
similarity index 100%
rename from docs/core/prompts.mdx
rename to docs/concepts/prompts.mdx
diff --git a/docs/core/resources.mdx b/docs/concepts/resources.mdx
similarity index 100%
rename from docs/core/resources.mdx
rename to docs/concepts/resources.mdx
diff --git a/docs/core/sampling.mdx b/docs/concepts/sampling.mdx
similarity index 100%
rename from docs/core/sampling.mdx
rename to docs/concepts/sampling.mdx
diff --git a/docs/core/tools.mdx b/docs/concepts/tools.mdx
similarity index 100%
rename from docs/core/tools.mdx
rename to docs/concepts/tools.mdx
diff --git a/docs/core/transport.mdx b/docs/concepts/transport.mdx
similarity index 100%
rename from docs/core/transport.mdx
rename to docs/concepts/transport.mdx
diff --git a/docs/first-server/python.mdx b/docs/first-server/python.mdx
new file mode 100644
index 0000000..a551d5f
--- /dev/null
+++ b/docs/first-server/python.mdx
@@ -0,0 +1,750 @@
+---
+title: "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.
+
+
+This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
+
+
+## Prerequisites
+
+
+
+ You'll need Python 3.9 or higher:
+
+ ```bash
+ python --version # Should be 3.9 or higher
+ pip --version
+ ```
+
+
+
+ ```bash
+ mkdir weather-server
+ cd weather-server
+ python -m venv venv
+ source venv/bin/activate # On Windows use: venv\Scripts\activate
+ ```
+
+
+
+ ```bash
+ pip install modelcontextprotocol requests python-dotenv
+ ```
+
+
+
+ Create `.env`:
+ ```bash
+ OPENWEATHER_API_KEY=your-api-key-here
+ ```
+
+
+
+## Create your server
+
+
+
+ ```bash
+ touch weather_server.py
+ ```
+
+
+
+ In `weather_server.py`:
+
+ ```python
+ import os
+ import json
+ from datetime import datetime
+ from typing import Any, Dict, List, Optional
+
+ import requests
+ from dotenv import load_dotenv
+ from modelcontextprotocol import Server, StdioServerTransport
+ from modelcontextprotocol.types import (
+ ListResourcesRequest,
+ ReadResourceRequest,
+ ListToolsRequest,
+ CallToolRequest,
+ ErrorCode,
+ McpError
+ )
+
+ load_dotenv()
+
+ API_KEY = os.getenv("OPENWEATHER_API_KEY")
+ if not API_KEY:
+ raise ValueError("OPENWEATHER_API_KEY environment variable is required")
+
+ API_CONFIG = {
+ "BASE_URL": "http://api.openweathermap.org/data/2.5",
+ "DEFAULT_CITY": "San Francisco",
+ "ENDPOINTS": {
+ "CURRENT": "weather",
+ "FORECAST": "forecast"
+ }
+ }
+
+ class WeatherServer:
+ def __init__(self):
+ self.server = Server(
+ name="example-weather-server",
+ version="0.1.0"
+ )
+
+ self.session = requests.Session()
+ self.session.params = {
+ "appid": API_KEY,
+ "units": "metric"
+ }
+
+ self.setup_handlers()
+ self.setup_error_handling()
+
+ def setup_error_handling(self) -> None:
+ def on_error(error: Exception) -> None:
+ print("[MCP Error]", error, flush=True)
+
+ self.server.onerror = on_error
+
+ def setup_handlers(self) -> None:
+ self.server.set_request_handler(
+ ListResourcesRequest, self.handle_list_resources)
+ self.server.set_request_handler(
+ ReadResourceRequest, self.handle_read_resource)
+ self.server.set_request_handler(
+ ListToolsRequest, self.handle_list_tools)
+ self.server.set_request_handler(
+ CallToolRequest, self.handle_call_tool)
+
+ async def run(self) -> None:
+ transport = StdioServerTransport()
+ await self.server.connect(transport)
+ print("Weather MCP server running on stdio", flush=True)
+
+ # Handler implementations will continue in next sections
+```
+
+
+
+ Add these methods to the `WeatherServer` class:
+
+ ```python
+ async def handle_list_resources(
+ self,
+ request: ListResourcesRequest
+ ) -> Dict[str, Any]:
+ return {
+ "resources": [{
+ "uri": f"weather://{API_CONFIG['DEFAULT_CITY']}/current",
+ "name": f"Current weather in {API_CONFIG['DEFAULT_CITY']}",
+ "mimeType": "application/json",
+ "description": "Real-time weather data including temperature, conditions, humidity, and wind speed"
+ }]
+ }
+
+ async def handle_read_resource(
+ self,
+ request: ReadResourceRequest
+ ) -> Dict[str, Any]:
+ city = API_CONFIG["DEFAULT_CITY"]
+ if request.params.uri != f"weather://{city}/current":
+ raise McpError(
+ ErrorCode.INVALID_REQUEST,
+ f"Unknown resource: {request.params.uri}"
+ )
+
+ try:
+ response = self.session.get(
+ f"{API_CONFIG['BASE_URL']}/{API_CONFIG['ENDPOINTS']['CURRENT']}",
+ params={"q": city}
+ )
+ response.raise_for_status()
+ data = response.json()
+
+ weather_data = {
+ "temperature": data["main"]["temp"],
+ "conditions": data["weather"][0]["description"],
+ "humidity": data["main"]["humidity"],
+ "wind_speed": data["wind"]["speed"],
+ "timestamp": datetime.now().isoformat()
+ }
+
+ return {
+ "contents": [{
+ "uri": request.params.uri,
+ "mimeType": "application/json",
+ "text": json.dumps(weather_data, indent=2)
+ }]
+ }
+ except requests.RequestException as e:
+ raise McpError(
+ ErrorCode.INTERNAL_ERROR,
+ f"Weather API error: {str(e)}"
+ )
+ ```
+
+
+
+ Add these methods to the `WeatherServer` class:
+
+ ```python
+ async def handle_list_tools(
+ self,
+ request: ListToolsRequest
+ ) -> Dict[str, Any]:
+ 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)",
+ "minimum": 1,
+ "maximum": 5
+ }
+ },
+ "required": ["city"]
+ }
+ }]
+ }
+
+ async def handle_call_tool(
+ self,
+ request: CallToolRequest
+ ) -> Dict[str, Any]:
+ if request.params.name != "get_forecast":
+ raise McpError(
+ ErrorCode.METHOD_NOT_FOUND,
+ f"Unknown tool: {request.params.name}"
+ )
+
+ args = request.params.arguments
+ if not isinstance(args, dict) or "city" not in args:
+ raise McpError(
+ ErrorCode.INVALID_PARAMS,
+ "Invalid forecast arguments"
+ )
+
+ city = args["city"]
+ days = min(int(args.get("days", 3)), 5)
+
+ try:
+ response = self.session.get(
+ f"{API_CONFIG['BASE_URL']}/{API_CONFIG['ENDPOINTS']['FORECAST']}",
+ params={
+ "q": city,
+ "cnt": days * 8 # API returns 3-hour intervals
+ }
+ )
+ response.raise_for_status()
+ data = response.json()
+
+ forecasts = []
+ for i in range(0, len(data["list"]), 8):
+ 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}
+ except requests.RequestException as e:
+ raise McpError(
+ ErrorCode.INTERNAL_ERROR,
+ f"Weather API error: {str(e)}"
+ )
+ ```
+
+
+
+ Add this to the end of `weather_server.py`:
+
+ ```python
+ if __name__ == "__main__":
+ import asyncio
+ import signal
+
+ async def main():
+ server = WeatherServer()
+
+ def signal_handler(sig, frame):
+ print("Shutting down...", flush=True)
+ asyncio.create_task(server.server.close())
+
+ signal.signal(signal.SIGINT, signal_handler)
+ await server.run()
+
+ asyncio.run(main())
+ ```
+
+
+
+ ```bash
+ chmod +x weather_server.py
+ pip install -e .
+ ```
+
+ Create `setup.py`:
+ ```python
+ from setuptools import setup
+
+ setup(
+ name="weather-server",
+ version="0.1.0",
+ py_modules=["weather_server"],
+ entry_points={
+ "console_scripts": [
+ "weather-server=weather_server:main",
+ ],
+ },
+ install_requires=[
+ "modelcontextprotocol",
+ "requests",
+ "python-dotenv"
+ ],
+ )
+ ```
+
+
+
+## Understanding the code
+
+
+
+ ```python
+ async def handle_read_resource(
+ self,
+ request: ReadResourceRequest
+ ) -> Dict[str, Any]:
+ # ...
+ ```
+ Python type hints help catch errors early and improve code maintainability.
+
+
+
+ ```python
+ async def handle_list_resources(
+ self,
+ request: ListResourcesRequest
+ ) -> Dict[str, Any]:
+ return {
+ "resources": [{
+ "uri": f"weather://{DEFAULT_CITY}/current",
+ "name": f"Current weather in {DEFAULT_CITY}",
+ "mimeType": "application/json"
+ }]
+ }
+ ```
+ Resources provide data that Claude can access as context.
+
+
+
+ ```python
+ {
+ "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 validated inputs.
+
+
+
+## Best practices
+
+
+
+ ```python
+ try:
+ response = self.session.get(...)
+ response.raise_for_status()
+ except requests.RequestException as e:
+ raise McpError(
+ ErrorCode.INTERNAL_ERROR,
+ f"API error: {str(e)}"
+ )
+ ```
+
+
+
+ ```python
+ if not isinstance(args, dict) or "city" not in args:
+ raise McpError(
+ ErrorCode.INVALID_PARAMS,
+ "Invalid forecast arguments"
+ )
+ ```
+
+
+
+ ```python
+ if not API_KEY:
+ raise ValueError("OPENWEATHER_API_KEY is required")
+ ```
+
+
+
+ ```python
+ API_CONFIG = {
+ "BASE_URL": "...",
+ "ENDPOINTS": {
+ "CURRENT": "weather",
+ "FORECAST": "forecast"
+ }
+ }
+ ```
+
+
+
+## Available Transports
+
+While this guide uses stdio transport, MCP supports multiple transport options:
+
+### WebSocket
+```python
+from modelcontextprotocol import WebSocketServerTransport
+transport = WebSocketServerTransport()
+```
+
+### SSE (Server-Sent Events)
+```python
+from modelcontextprotocol import SSEServerTransport
+transport = SSEServerTransport("/events", response)
+```
+
+## Troubleshooting
+
+### Installation Issues
+```bash
+# Check Python version
+python --version
+
+# Reinstall dependencies
+pip uninstall -r requirements.txt
+pip install -r requirements.txt
+```
+
+### Runtime Errors
+```bash
+# Enable debug logging
+export MCP_LOG_LEVEL=DEBUG
+python weather_server.py
+```
+
+### Type Checking
+```bash
+# Install mypy
+pip install mypy
+
+# Run type checker
+mypy weather_server.py
+```
+
+## Connect to Claude Desktop
+
+
+
+ Add to `claude_desktop_config.json`:
+
+ ```json
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "weather-server",
+ "env": {
+ "OPENWEATHER_API_KEY": "your-api-key",
+ }
+ }
+ }
+ }
+ ```
+
+
+
+ 1. Quit Claude completely
+ 2. Start Claude again
+ 3. Look for your weather server in the 🔌 menu
+
+
+
+## Try it out!
+
+
+
+ Ask Claude:
+ ```
+ What's the current weather in San Francisco? Can you analyze the conditions and tell me if it's a good day for outdoor activities?
+ ```
+
+
+
+ Ask Claude:
+ ```
+ Can you get me a 5-day forecast for Tokyo and help me plan what clothes to pack for my trip?
+ ```
+
+
+
+ Ask Claude:
+ ```
+ Can you analyze the forecast for both Tokyo and San Francisco and tell me which city would be better for outdoor photography this week?
+ ```
+
+
+
+## Advanced Features
+
+
+
+ ```python
+ from functools import lru_cache
+ from datetime import datetime, timedelta
+
+ class WeatherServer:
+ def __init__(self):
+ self._cache_timeout = timedelta(minutes=15)
+ self._last_cache_time = None
+ self._cached_weather = None
+
+ @lru_cache(maxsize=32)
+ async def _fetch_weather(self, city: str) -> Dict[str, Any]:
+ # Cache expires after 15 minutes
+ now = datetime.now()
+ if (self._cached_weather is None or
+ self._last_cache_time is None or
+ now - self._last_cache_time > self._cache_timeout):
+
+ response = self.session.get(...)
+ self._cached_weather = response.json()
+ self._last_cache_time = now
+
+ return self._cached_weather
+ ```
+
+
+
+ ```python
+ async def handle_call_tool(
+ self,
+ request: CallToolRequest
+ ) -> Dict[str, Any]:
+ if progress_token := request.params._meta.get("progressToken"):
+ # Send progress notifications
+ await self.server.notification({
+ "method": "notifications/progress",
+ "params": {
+ "progress": 1,
+ "total": 2,
+ "progressToken": progress_token
+ }
+ })
+
+ # Fetch data...
+
+ await self.server.notification({
+ "method": "notifications/progress",
+ "params": {
+ "progress": 2,
+ "total": 2,
+ "progressToken": progress_token
+ }
+ })
+ ```
+
+
+
+ ```python
+ import logging
+
+ class WeatherServer:
+ def __init__(self):
+ self.logger = logging.getLogger("weather-server")
+ self.logger.setLevel(logging.INFO)
+
+ # Set up logging handler
+ self.server.set_request_handler(
+ SetLevelRequest,
+ self.handle_set_log_level
+ )
+
+ async def handle_set_log_level(
+ self,
+ request: SetLevelRequest
+ ) -> Dict[str, Any]:
+ level = request.params.level.upper()
+ self.logger.setLevel(getattr(logging, level))
+
+ await self.server.notification({
+ "method": "notifications/message",
+ "params": {
+ "level": "info",
+ "logger": "weather-server",
+ "data": f"Log level set to {level}"
+ }
+ })
+ return {}
+ ```
+
+
+
+ ```python
+ async def handle_list_resources(
+ self,
+ request: ListResourcesRequest
+ ) -> Dict[str, Any]:
+ return {
+ "resources": [...],
+ "resourceTemplates": [{
+ "uriTemplate": "weather://{city}/current",
+ "name": "Current weather for any city",
+ "mimeType": "application/json"
+ }]
+ }
+ ```
+
+
+
+## Testing
+
+
+
+ Create `test_weather_server.py`:
+
+ ```python
+ import pytest
+ from unittest.mock import Mock, patch
+ from weather_server import WeatherServer
+
+ @pytest.fixture
+ async def server():
+ server = WeatherServer()
+ yield server
+ await server.server.close()
+
+ @pytest.mark.asyncio
+ async def test_list_resources(server):
+ request = Mock()
+ result = await server.handle_list_resources(request)
+ assert len(result["resources"]) > 0
+ assert result["resources"][0]["mimeType"] == "application/json"
+
+ @pytest.mark.asyncio
+ async def test_get_forecast():
+ with patch("requests.Session") as mock_session:
+ mock_session.return_value.get.return_value.json.return_value = {
+ "list": [{
+ "dt_txt": "2024-01-01 12:00:00",
+ "main": {"temp": 20},
+ "weather": [{"description": "sunny"}]
+ }]
+ }
+
+ server = WeatherServer()
+ request = Mock()
+ request.params.name = "get_forecast"
+ request.params.arguments = {"city": "Tokyo", "days": 1}
+
+ result = await server.handle_call_tool(request)
+ assert len(result["toolResult"]) == 1
+ assert result["toolResult"][0]["temperature"] == 20
+ ```
+
+
+
+ ```bash
+ pip install pytest pytest-asyncio
+ pytest test_weather_server.py -v
+ ```
+
+
+
+## Deployment
+
+
+
+ ```dockerfile
+ FROM python:3.11-slim
+
+ WORKDIR /app
+ COPY requirements.txt .
+ RUN pip install -r requirements.txt
+
+ COPY . .
+
+ CMD ["python", "weather_server.py"]
+ ```
+
+
+
+ ```ini
+ [Unit]
+ Description=Weather MCP Server
+ After=network.target
+
+ [Service]
+ ExecStart=/path/to/venv/bin/python /path/to/weather_server.py
+ Environment=OPENWEATHER_API_KEY=your-key-here
+ Restart=always
+
+ [Install]
+ WantedBy=multi-user.target
+ ```
+
+
+
+## Next steps
+
+
+
+ Learn more about the MCP architecture
+
+
+
+ Read more about the Python SDK
+
+
\ No newline at end of file
diff --git a/docs/first-server/typescript.mdx b/docs/first-server/typescript.mdx
new file mode 100644
index 0000000..ecd06d8
--- /dev/null
+++ b/docs/first-server/typescript.mdx
@@ -0,0 +1,631 @@
+---
+title: "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.
+
+
+This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
+
+
+## Prerequisites
+
+
+
+ You'll need Node.js 18 or higher:
+
+ ```bash
+ node --version # Should be v18 or higher
+ npm --version
+ ```
+
+
+
+ ```bash
+ mkdir weather-server
+ cd weather-server
+ npm init -y
+ ```
+
+
+
+ ```bash
+ npm install @modelcontextprotocol/sdk axios dotenv typescript @types/node
+ npm install --save-dev ts-node
+ ```
+
+
+
+ Create `tsconfig.json`:
+ ```json
+ {
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ES2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true
+ },
+ "include": ["src/**/*"]
+ }
+ ```
+
+
+
+ Create `.env`:
+ ```bash
+ OPENWEATHER_API_KEY=your-api-key-here
+ ```
+
+
+
+## Create your server
+
+
+
+ ```bash
+ mkdir src
+ touch src/index.ts
+ touch src/types.ts
+ ```
+
+
+
+ In `src/types.ts`:
+
+ ```typescript
+ export interface OpenWeatherResponse {
+ main: {
+ temp: number;
+ humidity: number;
+ };
+ weather: Array<{
+ description: string;
+ }>;
+ wind: {
+ speed: number;
+ };
+ dt_txt?: string;
+ }
+
+ 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;
+ }
+
+ // Type guard for forecast arguments
+ export function isValidForecastArgs(args: unknown): args is GetForecastArgs {
+ return (
+ typeof args === "object" &&
+ args !== null &&
+ "city" in args &&
+ typeof args.city === "string" &&
+ (args.days === undefined || typeof args.days === "number")
+ );
+ }
+ ```
+
+
+
+ In `src/index.ts`:
+
+ ```typescript
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+ import {
+ ListResourcesRequestSchema,
+ ReadResourceRequestSchema,
+ ListToolsRequestSchema,
+ CallToolRequestSchema,
+ ErrorCode,
+ McpError
+ } from "@modelcontextprotocol/sdk/types.js";
+ import axios from "axios";
+ import dotenv from "dotenv";
+ import {
+ WeatherData,
+ ForecastDay,
+ GetForecastArgs,
+ OpenWeatherResponse,
+ isValidForecastArgs
+ } from "./types.js";
+
+ dotenv.config();
+
+ const API_KEY = process.env.OPENWEATHER_API_KEY;
+ if (!API_KEY) {
+ throw new Error("OPENWEATHER_API_KEY environment variable is required");
+ }
+
+ const API_CONFIG = {
+ BASE_URL: 'http://api.openweathermap.org/data/2.5',
+ DEFAULT_CITY: 'San Francisco',
+ ENDPOINTS: {
+ CURRENT: 'weather',
+ FORECAST: 'forecast'
+ }
+ } as const;
+
+ class WeatherServer {
+ private server: Server;
+ private axiosInstance;
+
+ constructor() {
+ this.server = new Server({
+ name: "example-weather-server",
+ version: "0.1.0"
+ });
+
+ // Configure axios with defaults
+ this.axiosInstance = axios.create({
+ baseURL: API_CONFIG.BASE_URL,
+ params: {
+ appid: API_KEY,
+ units: "metric"
+ }
+ });
+
+ this.setupHandlers();
+ this.setupErrorHandling();
+ }
+
+ private setupErrorHandling(): void {
+ this.server.onerror = (error) => {
+ console.error("[MCP Error]", error);
+ };
+
+ process.on('SIGINT', async () => {
+ await this.server.close();
+ process.exit(0);
+ });
+ }
+
+ private setupHandlers(): void {
+ this.setupResourceHandlers();
+ this.setupToolHandlers();
+ }
+
+ private setupResourceHandlers(): void {
+ // Implementation continues in next section
+ }
+
+ private setupToolHandlers(): void {
+ // Implementation continues in next section
+ }
+
+ async run(): Promise {
+ const transport = new StdioServerTransport();
+ await this.server.connect(transport);
+ console.log("Weather MCP server running on stdio");
+ }
+ }
+
+ const server = new WeatherServer();
+ server.run().catch(console.error);
+ ```
+
+
+
+ Add this to the `setupHandlers` method:
+
+ ```typescript
+ private setupResourceHandlers(): void {
+ this.server.setRequestHandler(
+ ListResourcesRequestSchema,
+ async () => ({
+ resources: [{
+ uri: `weather://${API_CONFIG.DEFAULT_CITY}/current`,
+ name: `Current weather in ${API_CONFIG.DEFAULT_CITY}`,
+ mimeType: "application/json",
+ description: "Real-time weather data including temperature, conditions, humidity, and wind speed"
+ }]
+ })
+ );
+
+ this.server.setRequestHandler(
+ ReadResourceRequestSchema,
+ async (request) => {
+ const city = API_CONFIG.DEFAULT_CITY;
+ if (request.params.uri !== `weather://${city}/current`) {
+ throw new McpError(
+ ErrorCode.InvalidRequest,
+ `Unknown resource: ${request.params.uri}`
+ );
+ }
+
+ try {
+ const response = await this.axiosInstance.get(
+ API_CONFIG.ENDPOINTS.CURRENT,
+ {
+ params: { q: city }
+ }
+ );
+
+ 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)
+ }]
+ };
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ throw new McpError(
+ ErrorCode.InternalError,
+ `Weather API error: ${error.response?.data.message ?? error.message}`
+ );
+ }
+ throw error;
+ }
+ }
+ );
+ }
+ ```
+
+
+
+ Add these handlers to the `setupHandlers` method:
+
+ ```typescript
+ private setupToolHandlers(): void {
+ 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)",
+ minimum: 1,
+ maximum: 5
+ }
+ },
+ required: ["city"]
+ }
+ }]
+ })
+ );
+
+ this.server.setRequestHandler(
+ CallToolRequestSchema,
+ async (request) => {
+ if (request.params.name !== "get_forecast") {
+ throw new McpError(
+ ErrorCode.MethodNotFound,
+ `Unknown tool: ${request.params.name}`
+ );
+ }
+
+ if (!isValidForecastArgs(request.params.arguments)) {
+ throw new McpError(
+ ErrorCode.InvalidParams,
+ "Invalid forecast arguments"
+ );
+ }
+
+ const city = request.params.arguments.city;
+ const days = Math.min(request.params.arguments.days || 3, 5);
+
+ try {
+ const response = await this.axiosInstance.get<{
+ list: OpenWeatherResponse[]
+ }>(API_CONFIG.ENDPOINTS.FORECAST, {
+ params: {
+ q: city,
+ 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] ?? new Date().toISOString().split('T')[0],
+ temperature: dayData.main.temp,
+ conditions: dayData.weather[0].description
+ });
+ }
+
+ return { toolResult: forecasts };
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ throw new McpError(
+ ErrorCode.InternalError,
+ `Weather API error: ${error.response?.data.message ?? error.message}`
+ );
+ }
+ throw error;
+ }
+ }
+ );
+ }
+ ```
+
+
+
+ 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 install -g .
+ ```
+
+
+
+## Connect to Claude Desktop
+
+
+
+ Add to `claude_desktop_config.json`:
+
+ ```json
+ {
+ "mcpServers": {
+ "weather": {
+ "command": "weather-server",
+ "env": {
+ "OPENWEATHER_API_KEY": "your-api-key",
+ }
+ }
+ }
+ }
+ ```
+
+
+
+ 1. Quit Claude completely
+ 2. Start Claude again
+ 3. Look for your weather server in the 🔌 menu
+
+
+
+## Try it out!
+
+
+
+ Ask Claude:
+ ```
+ What's the current weather in San Francisco? Can you analyze the conditions?
+ ```
+
+
+
+ Ask Claude:
+ ```
+ Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella?
+ ```
+
+
+
+ Ask Claude:
+ ```
+ Can you analyze the forecast for both Tokyo and San Francisco and tell me which city will be warmer this week?
+ ```
+
+
+
+## Understanding the code
+
+
+
+ ```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.
+
+
+
+ ```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.
+
+
+
+ ```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.
+
+
+
+## Best practices
+
+
+
+ ```typescript
+ try {
+ const response = await this.axiosInstance.get(...);
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ throw new McpError(
+ ErrorCode.InternalError,
+ `API error: ${error.response?.data.message}`
+ );
+ }
+ throw error;
+ }
+ ```
+
+
+
+ ```typescript
+ function isValidForecastArgs(args: unknown): args is GetForecastArgs {
+ return (
+ typeof args === "object" &&
+ args !== null &&
+ "city" in args &&
+ typeof args.city === "string"
+ );
+ }
+ ```
+
+
+
+ ```typescript
+ if (!process.env.OPENWEATHER_API_KEY) {
+ throw new Error("OPENWEATHER_API_KEY is required");
+ }
+ ```
+
+
+
+ ```typescript
+ const API_CONFIG = {
+ BASE_URL: '...',
+ ENDPOINTS: {
+ CURRENT: 'weather',
+ FORECAST: 'forecast'
+ }
+ } as const;
+ ```
+
+
+
+## Available Transports
+
+While this guide uses stdio transport, MCP supports multiple transport options:
+
+### WebSocket
+```typescript
+import { WebSocketServerTransport } from "@modelcontextprotocol/sdk/server/websocket.js";
+const transport = new WebSocketServerTransport();
+```
+
+### SSE (Server-Sent Events)
+```typescript
+import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
+const transport = new SSEServerTransport("/events", response);
+```
+
+## Troubleshooting
+
+### Build Errors
+```bash
+# Check TypeScript version
+npx tsc --version
+
+# Clean and rebuild
+rm -rf dist/
+npm run build
+```
+
+### Runtime Errors
+Look for detailed error messages in the Claude app logs:
+```bash
+# Launch Claude with logging
+open /Applications/Claude.app --stdout ~/Claude.log --stderr ~/Claude.log
+
+# Monitor logs
+tail -f ~/Claude.log
+```
+
+### Type Errors
+```bash
+# Check types without building
+npx tsc --noEmit
+```
+
+## Next steps
+
+
+
+ Learn more about the MCP architecture
+
+
+
+ Read more about the TypeScript SDK
+
+
+
+
+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.
+
\ No newline at end of file
diff --git a/docs/guides/first-server-python.mdx b/docs/guides/first-server-python.mdx
deleted file mode 100644
index 3068ccb..0000000
--- a/docs/guides/first-server-python.mdx
+++ /dev/null
@@ -1,422 +0,0 @@
----
-title: "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.
-
-
-This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
-
-
-## Prerequisites
-
-
-
- You'll need Python 3.8 or higher:
-
- ```bash
- python3 --version # Should be 3.8 or higher
- ```
-
-
-
- ```bash
- # Create and activate virtual environment
- python3 -m venv mcp-weather
- cd mcp-weather
- source bin/activate # On Windows: .\Scripts\activate
- ```
-
-
-
- ```bash
- pip install modelcontextprotocol-sdk requests
- ```
-
-
-
- 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'
- ```
-
-
-
-## Create your server
-
-
-
- ```bash
- mkdir weather_server
- cd weather_server
- touch weather_server.py
- ```
-
-
-
- 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())
- ```
-
-
-
- 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)
- }]
- }
- ```
-
-
-
- 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}
- ```
-
-
-
- 1. Save all changes
- 2. Run your server:
- ```bash
- python weather_server.py
- ```
-
-
-
-## Connect to Claude
-
-
-
- ```bash
- # From your project directory
- pip install -e .
- ```
-
-
-
- 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"
- }
- }
- }
- }
- ```
-
-
-
- 1. Quit Claude completely
- 2. Start Claude again
- 3. Verify your weather server appears in the 🔌 menu
-
-
-
-## Try it out!
-
-
-
- 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
-
-
-
- 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
-
-
-
-## Understanding the code
-
-Let's break down the key MCP concepts used in this server:
-
-
-
- ```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.
-
-
-
- ```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.
-
-
-
- ```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.
-
-
-
-## Next steps
-
-Now that you've built your first MCP server, try these enhancements:
-
-
-
- - Air quality data
- - Weather alerts
- - Historical weather
-
-
-
- - Compare multiple cities
- - Get detailed hourly forecasts
- - Save favorite locations
-
-
-
- - Handle API errors gracefully
- - Add input validation
- - Rate limiting
-
-
-
- - Weather alerts
- - Temperature changes
- - Condition updates
-
-
-
-## Troubleshooting
-
-
-
- ```bash
- pip install modelcontextprotocol-sdk --upgrade
- ```
- Ensure you're using the latest SDK version.
-
-
-
- 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
-
-
-
- 1. Check Claude's logs:
- ```bash
- tail -f ~/Claude.log
- ```
- 2. Verify your config JSON syntax
- 3. Ensure Python path is correct in config
-
-
-
-
-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.
-
\ No newline at end of file
diff --git a/docs/guides/first-server-ts.mdx b/docs/guides/first-server-ts.mdx
deleted file mode 100644
index 2615856..0000000
--- a/docs/guides/first-server-ts.mdx
+++ /dev/null
@@ -1,533 +0,0 @@
----
-title: "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.
-
-
-This guide uses the OpenWeatherMap API. You'll need a free API key from [OpenWeatherMap](https://openweathermap.org/api) to follow along.
-
-
-## Prerequisites
-
-
-
- You'll need Node.js 16 or higher:
-
- ```bash
- node --version # Should be v16 or higher
- npm --version
- ```
-
-
-
- ```bash
- mkdir weather-server
- cd weather-server
- npm init -y
- ```
-
-
-
- ```bash
- npm install @modelcontextprotocol/sdk axios dotenv typescript @types/node
- npm install --save-dev ts-node
- ```
-
-
-
- Create `tsconfig.json`:
- ```json
- {
- "compilerOptions": {
- "target": "ES2020",
- "module": "ES2020",
- "moduleResolution": "node",
- "esModuleInterop": true,
- "outDir": "./dist",
- "rootDir": "./src",
- "strict": true
- },
- "include": ["src/**/*"]
- }
- ```
-
-
-
- Create `.env`:
- ```bash
- OPENWEATHER_API_KEY=your-api-key-here
- ```
-
-
-
-## Create your server
-
-
-
- ```bash
- mkdir src
- touch src/index.ts
- touch src/types.ts
- ```
-
-
-
- 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;
- }
- ```
-
-
-
- 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 {
- const transport = new StdioServerTransport();
- await this.server.connect(transport);
- }
- }
-
- const server = new WeatherServer();
- server.run().catch(console.error);
- ```
-
-
-
- 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)
- }]
- };
- }
- );
- }
- ```
-
-
-
- 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 };
- }
- );
- ```
-
-
-
- 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
- ```
-
-
-
-## Connect to Claude
-
-
-
- ```bash
- npm install -g
- ```
-
-
-
- Add to `claude_desktop_config.json`:
-
- ```json
- {
- "mcpServers": {
- "weather": {
- "command": "weather-server",
- "env": {
- "OPENWEATHER_API_KEY": "your-api-key",
- "HOME": "/Users/YOUR_USERNAME"
- }
- }
- }
- }
- ```
-
-
-
- 1. Quit Claude completely
- 2. Start Claude again
- 3. Look for your weather server in the 🔌 menu
-
-
-
-## Try it out!
-
-
-
- Ask Claude:
- ```
- What's the current weather in San Francisco? Can you analyze the conditions?
- ```
-
-
-
- Ask Claude:
- ```
- Can you get me a 5-day forecast for Tokyo and tell me if I should pack an umbrella?
- ```
-
-
-
- Ask Claude:
- ```
- Can you analyze the forecast for both Tokyo and San Francisco and tell me which city will be warmer this week?
- ```
-
-
-
-## Understanding the code
-
-
-
- ```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.
-
-
-
- ```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.
-
-
-
- ```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.
-
-
-
-## Best practices
-
-
-
- ```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;
- }
- ```
-
-
-
- ```typescript
- function isValidForecastArgs(args: unknown): args is GetForecastArgs {
- return typeof args === "object" && args !== null &&
- "city" in args;
- }
- ```
-
-
-
- ```typescript
- if (!process.env.OPENWEATHER_API_KEY) {
- throw new Error("OPENWEATHER_API_KEY is required");
- }
- ```
-
-
-
- ```typescript
- const API_ENDPOINTS = {
- CURRENT: "weather",
- FORECAST: "forecast"
- } as const;
- ```
-
-
-
-## Enhancements
-
-Try adding these features to your server:
-
-
-
- Add dynamic city resources:
- ```typescript
- uriTemplate: "weather://{city}/current"
- ```
-
-
-
- Cache API responses:
- ```typescript
- import NodeCache from "node-cache"
- ```
-
-
-
- Add API rate limiting:
- ```typescript
- import rateLimit from "axios-rate-limit"
- ```
-
-
-
-## Troubleshooting
-
-
-
- ```bash
- # Check TypeScript version
- npx tsc --version
-
- # Clean and rebuild
- rm -rf dist/
- npm run build
- ```
-
-
-
- Add better error logging:
- ```typescript
- server.onerror = (error) => {
- console.error("[MCP Error]", error);
- };
- ```
-
-
-
- ```bash
- # Check types without building
- npx tsc --noEmit
- ```
-
-
-
-## Next steps
-
-
-
- Switch to real-time updates with WebSocket transport
-
-
-
- Add Jest tests for your MCP server
-
-
-
-
-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.
-
\ No newline at end of file
diff --git a/docs/guides/integrating-with-llm.mdx b/docs/guides/integrating-with-llm.mdx
deleted file mode 100644
index a801e53..0000000
--- a/docs/guides/integrating-with-llm.mdx
+++ /dev/null
@@ -1,385 +0,0 @@
----
-title: "Integrating MCP into Your LLM Application"
-description: 'Learn how to integrate the Model Context Protocol (MCP) into your LLM-powered applications'
----
-
-The Model Context Protocol (MCP) enables seamless integration between LLM applications and various data sources and tools. This guide will walk you through integrating MCP into your own LLM-powered chatbot application.
-
-## Our Example Chatbot
-
-For this guide, we'll be working with a hypothetical customer service chatbot for a software company. Our chatbot currently:
-
-- Uses an LLM API (like Anthropic's Claude API) to generate responses
-- Maintains conversation history in memory
-- Has basic error handling and retry logic
-- Runs as a web service that customers interact with through a REST API
-
-However, our chatbot faces some limitations:
-- It can't access real-time product documentation or knowledge base articles
-- It can't look up customer information or ticket history
-- It can't perform actions like creating tickets or updating customer records
-- It doesn't stay up-to-date with product changes and new features
-
-By integrating MCP, we'll enhance our chatbot to:
-- Access documentation and knowledge base articles as contextual resources
-- Look up customer information through a CRM integration
-- Create and update support tickets through a ticketing system integration
-- Get real-time updates when documentation or product information changes
-
-Let's get started!
-
-## Prerequisites
-
-1. Clone the example MCP servers:
-```bash
-git clone https://github.com/modelcontextprotocol/example-servers.git
-cd example-servers
-npm install
-```
-
-2. Install the MCP SDK in your chatbot project:
-```bash
-npm install @modelcontextprotocol/sdk
-```
-
-## Starting Point: Our Basic Chatbot
-
-Here's our starting chatbot implementation that we'll enhance with MCP:
-
-```typescript
-interface Message {
- role: 'user' | 'assistant';
- content: string;
-}
-
-class CustomerServiceBot {
- private conversation: Message[] = [];
- private llmClient: LLMClient; // Your LLM API client
-
- constructor(llmClient: LLMClient) {
- this.llmClient = llmClient;
- }
-
- async handleMessage(message: string): Promise {
- // Add user message to conversation
- this.conversation.push({ role: 'user', content: message });
-
- // Get LLM response
- const response = await this.llmClient.complete({
- messages: this.conversation,
- maxTokens: 1000
- });
-
- // Add assistant response to conversation
- this.conversation.push({ role: 'assistant', content: response });
-
- return response;
- }
-}
-```
-
-## Step 1: Adding Documentation Context
-
-First, let's enhance our chatbot to incorporate product documentation. We'll use the example PostgreSQL server which can store and serve our docs.
-
-```typescript
-import { Client } from "@modelcontextprotocol/sdk/client";
-import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio";
-import {
- ListResourcesResultSchema,
- ReadResourceResultSchema
-} from "@modelcontextprotocol/sdk/types";
-
-class EnhancedCustomerServiceBot {
- private conversation: Message[] = [];
- private llmClient: LLMClient;
- private mcpClient: Client;
-
- constructor(llmClient: LLMClient) {
- this.llmClient = llmClient;
-
- // Initialize MCP client
- this.mcpClient = new Client({
- name: "customer-service-bot",
- version: "1.0.0"
- });
- }
-
- async initialize() {
- // Connect to PostgreSQL server for documentation
- const transport = new StdioClientTransport({
- command: "./example-servers/postgres/index.js",
- args: ["postgres://localhost/docs"] // Your docs database
- });
- await this.mcpClient.connect(transport);
- }
-
- async getRelevantDocs(message: string): Promise {
- // List available documentation resources
- const { resources } = await this.mcpClient.request(
- { method: "resources/list" },
- ListResourcesResultSchema
- );
-
- // Read each documentation resource
- const docs = await Promise.all(
- resources.map(async (resource) => {
- const { contents } = await this.mcpClient.request(
- {
- method: "resources/read",
- params: { uri: resource.uri }
- },
- ReadResourceResultSchema
- );
- return contents[0].text;
- })
- );
-
- return docs.join("\n\n");
- }
-
- async handleMessage(message: string): Promise {
- // Get relevant documentation
- const docs = await this.getRelevantDocs(message);
-
- // Build prompt with documentation context
- const prompt = `
- Here is relevant documentation about our product:
- ${docs}
-
- Please use this information to help answer the customer's question.
-
- Customer: ${message}
- `;
-
- // Add user message to conversation
- this.conversation.push({ role: 'user', content: message });
-
- // Get LLM response with documentation context
- const response = await this.llmClient.complete({
- messages: [...this.conversation, { role: 'user', content: prompt }],
- maxTokens: 1000
- });
-
- // Add assistant response to conversation
- this.conversation.push({ role: 'assistant', content: response });
-
- return response;
- }
-}
-```
-
-## Step 2: Adding Ticket Management
-
-Now let's add the ability to create and update support tickets. We'll use the example tools server for this:
-
-```typescript
-import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types";
-
-interface Ticket {
- id: string;
- subject: string;
- description: string;
- status: 'open' | 'closed';
-}
-
-class EnhancedCustomerServiceBot {
- // ... previous code ...
-
- async createTicket(subject: string, description: string): Promise {
- const result = await this.mcpClient.request(
- {
- method: "tools/call",
- params: {
- name: "create_ticket",
- arguments: {
- subject,
- description
- }
- }
- },
- CallToolResultSchema
- );
-
- return result.toolResult as Ticket;
- }
-
- async handleMessage(message: string): Promise {
- // Get relevant documentation
- const docs = await this.getRelevantDocs(message);
-
- // Build prompt with documentation context and ticket creation ability
- const prompt = `
- Here is relevant documentation about our product:
- ${docs}
-
- You can create support tickets when needed using the createTicket function.
- Only create tickets for actual technical issues that need follow-up.
-
- Customer: ${message}
- `;
-
- // Get LLM response
- const response = await this.llmClient.complete({
- messages: [...this.conversation, { role: 'user', content: prompt }],
- maxTokens: 1000,
- tools: [{
- name: 'createTicket',
- description: 'Create a support ticket for technical issues',
- parameters: {
- subject: 'string',
- description: 'string'
- }
- }]
- });
-
- // Check if the LLM wants to create a ticket
- if (response.toolCalls?.length > 0) {
- const call = response.toolCalls[0];
- const ticket = await this.createTicket(
- call.arguments.subject,
- call.arguments.description
- );
-
- // Add ticket creation to conversation
- this.conversation.push({
- role: 'system',
- content: `Created ticket #${ticket.id}: ${ticket.subject}`
- });
- }
-
- // Add messages to conversation
- this.conversation.push({ role: 'user', content: message });
- this.conversation.push({ role: 'assistant', content: response.content });
-
- return response.content;
- }
-}
-```
-
-## Step 3: Real-time Documentation Updates
-
-Finally, let's make our chatbot aware of documentation changes in real-time:
-
-```typescript
-class EnhancedCustomerServiceBot {
- // ... previous code ...
-
- async initialize() {
- // Connect to PostgreSQL server
- const transport = new StdioClientTransport({
- command: "./example-servers/postgres/index.js",
- args: ["postgres://localhost/docs"]
- });
- await this.mcpClient.connect(transport);
-
- // Subscribe to documentation updates
- const { resources } = await this.mcpClient.request(
- { method: "resources/list" },
- ListResourcesResultSchema
- );
-
- for (const resource of resources) {
- await this.mcpClient.request(
- {
- method: "resources/subscribe",
- params: { uri: resource.uri }
- },
- EmptyResultSchema
- );
- }
-
- // Handle update notifications
- this.mcpClient.setNotificationHandler(
- ResourceUpdatedNotificationSchema,
- async (notification) => {
- console.log(`Documentation updated: ${notification.params.uri}`);
- // Optionally clear any cached documentation
- }
- );
- }
-}
-```
-
-## Using the Enhanced Chatbot
-
-Here's how to use our enhanced chatbot:
-
-```typescript
-const bot = new EnhancedCustomerServiceBot(llmClient);
-await bot.initialize();
-
-// Example conversation
-const response1 = await bot.handleMessage(
- "How do I reset my password?"
-);
-// Bot responds with information from documentation
-
-const response2 = await bot.handleMessage(
- "I can't log in even after resetting my password"
-);
-// Bot creates a ticket and responds with next steps
-
-```
-
-## Error Handling
-
-Add robust error handling around MCP operations:
-
-```typescript
-class EnhancedCustomerServiceBot {
- // ... previous code ...
-
- async getRelevantDocs(message: string): Promise {
- try {
- const { resources } = await this.mcpClient.request(
- { method: "resources/list" },
- ListResourcesResultSchema
- );
-
- const docs = await Promise.all(
- resources.map(async (resource) => {
- try {
- const { contents } = await this.mcpClient.request(
- {
- method: "resources/read",
- params: { uri: resource.uri }
- },
- ReadResourceResultSchema
- );
- return contents[0].text;
- } catch (error) {
- console.error(`Failed to read resource ${resource.uri}:`, error);
- return ""; // Skip failed resources
- }
- })
- );
-
- return docs.join("\n\n");
- } catch (error) {
- console.error("Failed to list resources:", error);
- return ""; // Fallback to no documentation
- }
- }
-}
-```
-
-## Next Steps
-
-Now that you've enhanced your chatbot with MCP, you can:
-
-1. Add more integrations:
- - Connect to your actual documentation system
- - Integrate with your production ticketing system
- - Add CRM integration for customer context
-
-2. Improve the implementation:
- - Add better documentation relevance filtering
- - Implement more sophisticated prompt engineering
- - Add authentication and access control
- - Add monitoring and logging
- - Implement caching for frequently accessed resources
-
-3. Consider building custom MCP servers for your specific needs
-
-The example servers repository includes other servers you can experiment with, and you can build your own servers to expose custom functionality to your chatbot.
\ No newline at end of file
diff --git a/docs/guides/integrate-python.mdx b/docs/unused/integrate-python.mdx
similarity index 99%
rename from docs/guides/integrate-python.mdx
rename to docs/unused/integrate-python.mdx
index e84e9de..1ca1919 100644
--- a/docs/guides/integrate-python.mdx
+++ b/docs/unused/integrate-python.mdx
@@ -32,8 +32,8 @@ We'll build an "AI Web Analyzer" that:
```bash
# Install example MCP servers
- git clone https://github.com/modelcontextprotocol/example-servers
- cd example-servers
+ git clone https://github.com/modelcontextprotocol/servers
+ cd servers
npm install
npm run build
npm install -g
diff --git a/docs/guides/integrate-ts.mdx b/docs/unused/integrate-ts.mdx
similarity index 99%
rename from docs/guides/integrate-ts.mdx
rename to docs/unused/integrate-ts.mdx
index fdb3a2e..45dc832 100644
--- a/docs/guides/integrate-ts.mdx
+++ b/docs/unused/integrate-ts.mdx
@@ -40,8 +40,8 @@ We'll build an "AI Web Analyzer" that:
```bash
# Install example MCP servers
- git clone https://github.com/modelcontextprotocol/example-servers
- cd example-servers
+ git clone https://github.com/modelcontextprotocol/servers
+ cd servers
npm install
npm run build
npm install -g
diff --git a/favicon.svg b/favicon.svg
index 6a32332..03d9f85 100644
--- a/favicon.svg
+++ b/favicon.svg
@@ -1,49 +1,12 @@
-