docs/quickstart.mdx
Zachary Lee b0e8efae27
fixes
2024-12-09 22:49:46 -05:00

435 lines
No EOL
11 KiB
Text

---
title: "Quickstart"
description: "Get started with building your first MCP server and connecting it to an MCP host"
---
In this tutorial, we'll build a simple MCP server with a `get_weather` tool and connect it to a popular MCP host, Claude for Desktop. We'll start with a basic setup, and then progress to more complex use cases.
You can think of MCP as a bridge between your LLMs and your data and tools. Model Context Protocol was developed by Anthropic (the makers of [Claude](https://claude.ai)), but MCP can work with any Large Language Model provider that supports tool calling.
### What is MCP?
MCP is an open protocol that standardizes how applications provide context to LLMs. Think of it as the "Language Server Protocol for AI" - it separates the concerns of providing context from the LLM interaction itself. This separation enables:
1. **Modularity**: Each MCP server focuses on one specific integration or capability
2. **Reusability**: The same server can be used with any MCP-compatible client
3. **Composability**: Multiple servers can be combined to create powerful workflows
4. **Standardization**: A common protocol for all integrations reduces complexity
### What we'll be building
Many LLMs (including Claude) do not currently have the ability to fetch the current temperature and weather conditions. Let's use MCP to solve that!
<Frame>
<img src="/images/quickstart-weather.png" />
</Frame>
Servers can connect to any host. We'll walk through using Claude Desktop as the host and eventually show you how to build your own.
<Accordion title="Why Claude Desktop and not Claude.ai?">
Because servers are locally run, MCP currently only supports desktop hosts. Remote hosts are in active development.
</Accordion>
### Core MCP Concepts
MCP servers can provide three main types of capabilities:
1. **Resources**: File-like data that can be read by clients (like API responses or file contents)
2. **Tools**: Functions that can be called by the LLM (with user approval)
3. **Prompts**: Pre-written templates that help users accomplish specific tasks
This tutorial focuses on tools, but we have intermediate tutorials if you'd like to learn more about Resources and Prompts.
### Prerequisite knowledge
This quickstart assumes you have familiarity with:
- Python or TypeScript
- LLMs like Claude
It also helps to be familiar with [tool use (aka function calling)](https://docs.anthropic.com/en/docs/build-with-claude/tool-use), but it's not required.
### System requirements
For Python, make sure you have the latest version of Python installed. For TypeScript, make sure you have the latest version of Node installed.
### Set up your environment
<Tabs>
<Tab title="Python">
First, let's install `uv` and set up our Python project and environment:
<CodeGroup>
```bash MacOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
```
```bash Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
</CodeGroup>
</Tab>
<Tab title="Node">
First, let's install Node.js and npm if you haven't already. You can download them from [nodejs.org](https://nodejs.org/).
Verify your Node.js installation:
```bash
node --version
npm --version
```
For this tutorial, you'll need Node.js version 16 or higher.
</Tab>
</Tabs>
Now, let's create and set up our project:
<Tabs>
<Tab title='Python'>
<CodeGroup>
```bash MacOS/Linux
# Create a new directory for our project
uv init mcp-quickstart
cd mcp-quickstart
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv pip install mcp httpx
# Clean up boilerplate code
rm -rf hello.py
# Create our files
mkdir src
mkdir src/weather
touch src/__init__.py
touch src/server.py
```
```bash Windows
# Create a new directory for our project
uv init mcp-quickstart
cd mcp-quickstart
# Create virtual environment and activate it
uv venv
.venv\Scripts\activate
# Install dependencies
uv pip install mcp httpx
# Clean up boilerplate code
del /f /q hello.py
# Create our files
md src
md src\weather
echo.> src\__init__.py
echo.> src\server.py
```
</CodeGroup>
Add this code to __init__.py:
```python src/weather/__init__.py
from . import server
import asyncio
def main():
"""Main entry point for the package."""
asyncio.run(server.main())
# Optionally expose other important items at package level
__all__ = ['main', 'server']
```
</Tab>
<Tab title="Node">
```bash
# Create a new directory for our project
mkdir mcp-quickstart
cd mcp-quickstart
# Initialize a new npm project
npm init -y
# Install dependencies
npm install @modelcontextprotocol/sdk node-fetch
npm install -D @types/node typescript
```
Then create a new file called `src/index.ts` in your project directory:
```bash
mkdir src
touch src/index.ts
```
Update your package.json to add type: "module" and a build script:
```json package.json
{
"type": "module",
"bin": {
"mcp-quickstart": "./build/index.js"
},
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
},
"files": [
"build"
],
}
```
Create a tsconfig.json:
```json tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
</Tab>
</Tabs>
Now let's dive into building your server.
## Building your server
### Importing packages
Add these to your server.py:
```python
from typing import Any
import httpx
from mcp.server.models import InitializationOptions
import mcp.types as types
from mcp.server import NotificationOptions, Server
import mcp.server.stdio
```
### Setting up the instance
Then add the cache, server instance and the base URL for the NWS API:
```python
# Cache weather data
weather_cache: dict[str, Any] = {}
NWS_API_BASE = "https://api.weather.gov"
server = Server("weather")
```
### Implementing tool listing
We need to tell clients what tools are available. The `list_tools()` decorator registers this handler:
```python
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
return [
types.Tool(
name="get-weather",
description="Get weather data for a location",
inputSchema={
"type": "object",
"properties": {
"latitude": {"type": "number"},
"longitude": {"type": "number"},
},
"required": ["latitude", "longitude"],
},
)
]
```
This defines a single tool that requires latitude and longitude parameters.
### Implementing tool execution
The tool execution handler processes requests to get weather data:
```python
@server.call_tool()
async def handle_call_tool(
name: str,
arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
# Validate tool name and arguments
if name != "get-weather":
raise ValueError(f"Unknown tool: {name}")
if not arguments:
raise ValueError("Missing arguments")
lat = arguments.get("latitude")
lon = arguments.get("longitude")
if lat is None or lon is None:
raise ValueError("Missing latitude or longitude")
# Fetch weather data
async with httpx.AsyncClient() as client:
# Get grid point
points_url = f"{NWS_API_BASE}/points/{lat},{lon}"
points_response = await client.get(
points_url,
headers={"Accept": "application/json"}
)
points_data = points_response.json()
# Get forecast
forecast_url = points_data["properties"]["forecast"]
forecast_response = await client.get(
forecast_url,
headers={"Accept": "application/json"}
)
forecast_data = forecast_response.json()
# Cache the forecast data
location_key = f"{lat},{lon}"
weather_cache[location_key] = forecast_data
# Notify clients of resource changes
await server.request_context.session.send_resource_list_changed()
return [
types.TextContent(
type="text",
text=f"Retrieved weather data for location ({lat}, {lon})",
)
]
```
### Running the server
Finally, implement the main function to run the server:
```python
async def main():
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="weather",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
```
Your server is complete! Let's now test your server from an existing MCP host, Claude for Desktop.
## Testing your server with Claude for Desktop
<Note>
Unfortunately, Claude for Desktop is not yet available on Linux. Linux users can proceed to the [Building a client](/tutorials/building-a-client) tutorial for a workaround.
</Note>
First, make sure you have Claude for Desktop installed. [You can install the latest version here.](https://claude.ai/download)
Open your Claude Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor.
For example, if you have [VS Code](https://code.visualstudio.com/) installed:
<Tabs>
<Tab title="MacOS/Linux">
```bash
code ~/Library/Application\ Support/Claude/claude_desktop_config.json
```
</Tab>
<Tab title="Windows">
```powershell
code $env:AppData\Claude\claude_desktop_config.json
```
</Tab>
</Tabs>
Add this configuration (replace the parent folder path):
<Tabs>
<Tab title="MacOS/Linux">
```json
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"/PATH/TO/PARENT/FOLDER/mcp-quickstart",
"run",
"weather"
]
}
}
}
```
</Tab>
<Tab title="Windows">
```json
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"C:\\PATH\TO\PARENT\FOLDER\mcp-quickstart",
"run",
"weather"
]
}
}
}
```
</Tab>
</Tabs>
This tells Claude Desktop:
1. There's an MCP server named "weather"
2. Launch it by running `uv --directory /PATH/TO/PARENT/FOLDER/mcp-quickstart run weather`
Save the file, and restart **Claude Desktop**.
### Test with commands
You can now test your server by running the following commands in Claude Desktop:
- What's the weather in Brooklyn right now?
- What's the weather in San Francisco?
<Frame>
<img src="/images/quickstart-weather.png" />
</Frame>
<Note>
Since this is the US National Weather service, the queries will only work for US locations.
</Note>
## What's happening under the hood
When you ask a question:
1. The client sends your question to Claude
2. Claude analyzes the available tools and decides which one(s) to use
3. The client executes the chosen tool(s) through the MCP server
4. The results are sent back to Claude
5. Claude formulates a natural language response
6. The response is displayed to you!
## Next steps