Install command
Not provided
Master MCP server development from scratch. Create custom Claude Desktop integrations with TypeScript/Python in 60 minutes using production-ready patterns.
Open the source and read safety notes before installing.
Source-backed facts for citing this resource, derived directly from the registry — also available as plain text for AI assistants.
Decision playbook
Signals are present but mixed. Use the checklist below to confirm the source and operational safety for your environment.
0
78
—
No baseline selected
No major trust-signal divergence detected in the current selection.
Confirm ownership and provenance before trusting install instructions.
Source link availableRequired
Open the canonical repository and verify ownership.
Source provenance statusRequired
Marked as source-backed.
Metadata reviewed
Registry metadata indicates a reviewed listing.
Validate risk disclosures before installation or API wiring.
Safety notes presentRequired
Review the listed safety guidance before running commands.
Privacy notes presentRequired
Review data handling notes before connecting accounts or secrets.
Trust level risk gateRequired
Trust level does not block evaluation.
Check package metadata and artifact integrity signals.
Install payload available
Install or copy payload is available for review.
Package verification flag
No package verification flag provided.
Checksum metadata
No checksum provided for downloaded artifact.
Use compare context to validate trade-offs before adoption.
Compare tray has multiple entries
Add at least one more entry to compare trust differences.
Baseline comparison available
No baseline peer selected yet.
Diverging trust signals identified
No major trust-signal divergence found.
Setup at a glance
Copy-ready — paste the snippet to get started.
Install command
Not provided
Config snippet
Not provided
Copy snippet
Provided
Prerequisites
None
Platforms
1 listed
Difficulty
87/100
Adoption plan
Current risk score 16/100. Use staged verification before broader rollout.
Validate source and review signals before any execution.
Confirm source provenanceRequired
Source URL/provenance metadata is present.
Confirm metadata review state
Listing has review metadata.
Verify install payload
Install/config payload exists and can be inspected.
Confirm safety, privacy, and package integrity signals.
Review safety notesRequired
Safety notes are present.
Review privacy notesRequired
Privacy notes are present.
Verify package integrity metadata
No package verification/checksum metadata.
Adopt in controlled steps based on the selected plan.
Run in isolated sandbox firstRequired
Use a constrained sandbox and observe behavior across multiple tasks.
Roll out graduallyRequired
Roll out to a small cohort before wider usage.
Set monitoring and fallback
Define rollback path and monitor errors after adoption.
Evidence readiness
Required evidence gates are covered (5/6 signals complete).
Source repository/provenance is listed.
Required in this preset
Review metadata is present.
Required in this preset
Safety notes are present.
Required in this preset
Privacy notes are present.
Optional in this preset
Package integrity metadata is missing.
Optional in this preset
Install payload is available.
Required in this preset
Required evidence gates are covered for this preset.
Decision timeline
5/6 steps complete with no blocking gaps for this preset.
triage
Source/provenance metadata is available.
triage
Review metadata is available.
verify
Safety notes are available.
verify
Privacy notes are available.
verify
Package integrity metadata is missing.
rollout
Install payload is available.
No required blockers for this timeline preset.
Safety & privacy surface
1 safety and 1 privacy notes across 2 risk areas. Review closely: credentials & tokens, network access.
## Overview
The Model Context Protocol (MCP) is an open standard for connecting AI applications to external tools and data. An MCP server is a small program you write that exposes capabilities; an MCP host (Claude Code, Claude Desktop, and other clients) connects to it and lets Claude use what it offers. Once a server is connected to Claude Code, you can ask Claude to query your database, read an issue tracker, or call an API directly instead of pasting data into the chat.
This guide walks through the official MCP quickstart: a small weather server written in Python that exposes two tools, then how to connect it to Claude Code with `claude mcp add`. The same flow applies whether you write the server in Python, TypeScript, or another supported SDK.
### What a server can expose
MCP servers provide three kinds of capabilities. Most servers start with tools.
| Primitive | What it is | Who triggers it | Typical use |
| --- | --- | --- | --- |
| **Tools** | Functions the model can call (with user approval) | The LLM, during a task | Run a query, call an API, perform an action |
| **Resources** | File-like data identified by a URI that clients can read | The user / client (e.g. `@server:protocol://path` in Claude Code) | API responses, file contents, schemas |
| **Prompts** | Pre-written templates that help accomplish a task | The user (surface as `/mcp__server__prompt` commands) | Reusable workflows and canned instructions |
## Build a minimal server (Python)
### Requirements
- Python 3.10 or higher
- The Python MCP SDK version 1.2.0 or higher
- [`uv`](https://docs.astral.sh/uv/) for project and dependency management
When implementing a stdio-based server, never write to stdout (for example with `print()`): stdout carries the JSON-RPC messages, and writing to it corrupts the protocol and breaks the server. Log to stderr instead (`print(..., file=sys.stderr)` or the `logging` module).
### Set up the project
After installing `uv`, create and set up the project:
```bash
# Create a new directory for our project
uv init weather
cd weather
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv add "mcp[cli]" httpx
# Create our server file
touch weather.py
```
### Write the server
`FastMCP` uses Python type hints and docstrings to generate tool definitions automatically, so each `@mcp.tool()` function becomes a callable tool. Put the following in `weather.py`. It queries the US National Weather Service API and exposes `get_alerts` and `get_forecast`:
```python
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
# Initialize FastMCP server
mcp = FastMCP("weather")
# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""Make a request to the NWS API with proper error handling."""
headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception:
return None
def format_alert(feature: dict) -> str:
"""Format an alert feature into a readable string."""
props = feature["properties"]
return f"""
Event: {props.get("event", "Unknown")}
Area: {props.get("areaDesc", "Unknown")}
Severity: {props.get("severity", "Unknown")}
Description: {props.get("description", "No description available")}
Instructions: {props.get("instruction", "No specific instructions provided")}
"""
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get weather alerts for a US state.
Args:
state: Two-letter US state code (e.g. CA, NY)
"""
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data or "features" not in data:
return "Unable to fetch alerts or no alerts found."
if not data["features"]:
return "No active alerts for this state."
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a location.
Args:
latitude: Latitude of the location
longitude: Longitude of the location
"""
# First get the forecast grid endpoint
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return "Unable to fetch forecast data for this location."
# Get the forecast URL from the points response
forecast_url = points_data["properties"]["forecast"]
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast."
# Format the periods into a readable forecast
periods = forecast_data["properties"]["periods"]
forecasts = []
for period in periods[:5]: # Only show next 5 periods
forecast = f"""
{period["name"]}:
Temperature: {period["temperature"]}°{period["temperatureUnit"]}
Wind: {period["windSpeed"]} {period["windDirection"]}
Forecast: {period["detailedForecast"]}
"""
forecasts.append(forecast)
return "\n---\n".join(forecasts)
def main():
# Initialize and run the server
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
```
Start it locally with `uv run weather.py`. The server runs over stdio and listens for messages from an MCP host.
> **TypeScript instead?** The quickstart's TypeScript version uses `@modelcontextprotocol/sdk` and `zod`, registers tools with `server.registerTool(...)`, and runs over `StdioServerTransport`. The structure mirrors the Python version above.
## Choosing a transport
A transport is how the host and server exchange JSON-RPC messages. The minimal server above uses stdio. Remote servers use HTTP.
| Transport | How it runs | Best for | Notes |
| --- | --- | --- | --- |
| **stdio** | Local process the host launches and talks to over stdin/stdout | Local tools, scripts, anything needing direct system access | Never log to stdout; Claude Code does not auto-reconnect local processes |
| **HTTP** (Streamable HTTP) | Remote server reached over HTTP | Cloud-hosted services | Recommended remote transport; supports OAuth; `streamable-http` is the spec name and an accepted alias for `http` |
| **SSE** | Remote server using Server-Sent Events | Legacy remote servers | Deprecated in Claude Code; use HTTP where available |
## Connect the server to Claude Code
Add the server with `claude mcp add`. For a local stdio server, everything after the `--` separator is the command Claude Code runs to launch your server:
```bash
claude mcp add weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
```
The `--` (double dash) separates Claude Code's own options (`--transport`, `--env`, `--scope`) from the command that starts the server. Everything after `--` is passed through untouched. Use the absolute path to your project directory.
Pass secrets to the process with `--env`:
```bash
claude mcp add --env API_KEY=your-key weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
```
> When using `--env`, place at least one other option between `--env` and the server name. If the name comes directly after `--env`, the CLI reads it as another `KEY=value` pair and rejects it.
For a remote server, add it by URL instead:
```bash
# Recommended remote transport
claude mcp add --transport http my-remote-server https://mcp.example.com/mcp
```
### Choose a scope
`--scope` controls where the configuration is stored and who sees it:
| Scope | Loads in | Shared with team | Stored in |
| --- | --- | --- | --- |
| `local` (default) | Current project only | No | `~/.claude.json` |
| `project` | Current project only | Yes, via version control | `.mcp.json` in project root |
| `user` | All your projects | No | `~/.claude.json` |
```bash
# Share the server with your team via a checked-in .mcp.json
claude mcp add --scope project weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
```
For security, Claude Code prompts for approval before using project-scoped servers from a `.mcp.json` file.
### Manage and verify
```bash
# List all configured servers
claude mcp list
# Get details for one server
claude mcp get weather
# Remove a server
claude mcp remove weather
```
Inside a Claude Code session, run `/mcp` to check connection status and the tool count for each server. With tools connected, you can ask Claude to use them in plain language, for example: "What are the active weather alerts in CA?"
## Using resources and prompts in Claude Code
If your server exposes resources, reference them with `@` mentions using the format `@server:protocol://resource/path`, for example `@github:issue://123`. Resources appear in the `@` autocomplete alongside files and are fetched automatically when referenced.
If your server exposes prompts, they show up as slash commands in the form `/mcp__servername__promptname`. Pass arguments space-separated after the command, for example `/mcp__github__pr_review 456`.
## Security notes
- Tools run with the privileges of the process you launch, so only connect servers you trust. Servers that fetch external content can expose you to prompt-injection risk.
- Tool calls require user approval before they execute.
- Remote servers often require authentication. Claude Code supports OAuth 2.0: add the server, then run `/mcp` and complete the browser login. Tokens are stored securely and refreshed automatically.
- Have Claude scaffold a server for you with the official `mcp-server-dev` plugin: `/plugin install mcp-server-dev@claude-plugins-official`, then `/mcp-server-dev:build-mcp-server`.
## References
- [Build an MCP server (quickstart)](https://modelcontextprotocol.io/quickstart/server)
- [Connect Claude Code to tools via MCP](https://code.claude.com/docs/en/mcp)
- [Model Context Protocol](https://modelcontextprotocol.io/)The Model Context Protocol (MCP) is an open standard for connecting AI applications to external tools and data. An MCP server is a small program you write that exposes capabilities; an MCP host (Claude Code, Claude Desktop, and other clients) connects to it and lets Claude use what it offers. Once a server is connected to Claude Code, you can ask Claude to query your database, read an issue tracker, or call an API directly instead of pasting data into the chat.
This guide walks through the official MCP quickstart: a small weather server written in Python that exposes two tools, then how to connect it to Claude Code with claude mcp add. The same flow applies whether you write the server in Python, TypeScript, or another supported SDK.
MCP servers provide three kinds of capabilities. Most servers start with tools.
| Primitive | What it is | Who triggers it | Typical use |
|---|---|---|---|
| Tools | Functions the model can call (with user approval) | The LLM, during a task | Run a query, call an API, perform an action |
| Resources | File-like data identified by a URI that clients can read | The user / client (e.g. @server:protocol://path in Claude Code) |
API responses, file contents, schemas |
| Prompts | Pre-written templates that help accomplish a task | The user (surface as /mcp__server__prompt commands) |
Reusable workflows and canned instructions |
uv for project and dependency managementWhen implementing a stdio-based server, never write to stdout (for example with print()): stdout carries the JSON-RPC messages, and writing to it corrupts the protocol and breaks the server. Log to stderr instead (print(..., file=sys.stderr) or the logging module).
After installing uv, create and set up the project:
# Create a new directory for our project
uv init weather
cd weather
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv add "mcp[cli]" httpx
# Create our server file
touch weather.py
FastMCP uses Python type hints and docstrings to generate tool definitions automatically, so each @mcp.tool() function becomes a callable tool. Put the following in weather.py. It queries the US National Weather Service API and exposes get_alerts and get_forecast:
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
# Initialize FastMCP server
mcp = FastMCP("weather")
# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"
async def make_nws_request(url: str) -> dict[str, Any] | None:
"""Make a request to the NWS API with proper error handling."""
headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception:
return None
def format_alert(feature: dict) -> str:
"""Format an alert feature into a readable string."""
props = feature["properties"]
return f"""
Event: {props.get("event", "Unknown")}
Area: {props.get("areaDesc", "Unknown")}
Severity: {props.get("severity", "Unknown")}
Description: {props.get("description", "No description available")}
Instructions: {props.get("instruction", "No specific instructions provided")}
"""
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get weather alerts for a US state.
Args:
state: Two-letter US state code (e.g. CA, NY)
"""
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data or "features" not in data:
return "Unable to fetch alerts or no alerts found."
if not data["features"]:
return "No active alerts for this state."
alerts = [format_alert(feature) for feature in data["features"]]
return "\n---\n".join(alerts)
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a location.
Args:
latitude: Latitude of the location
longitude: Longitude of the location
"""
# First get the forecast grid endpoint
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return "Unable to fetch forecast data for this location."
# Get the forecast URL from the points response
forecast_url = points_data["properties"]["forecast"]
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast."
# Format the periods into a readable forecast
periods = forecast_data["properties"]["periods"]
forecasts = []
for period in periods[:5]: # Only show next 5 periods
forecast = f"""
{period["name"]}:
Temperature: {period["temperature"]}°{period["temperatureUnit"]}
Wind: {period["windSpeed"]} {period["windDirection"]}
Forecast: {period["detailedForecast"]}
"""
forecasts.append(forecast)
return "\n---\n".join(forecasts)
def main():
# Initialize and run the server
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
Start it locally with uv run weather.py. The server runs over stdio and listens for messages from an MCP host.
TypeScript instead? The quickstart's TypeScript version uses
@modelcontextprotocol/sdkandzod, registers tools withserver.registerTool(...), and runs overStdioServerTransport. The structure mirrors the Python version above.
A transport is how the host and server exchange JSON-RPC messages. The minimal server above uses stdio. Remote servers use HTTP.
| Transport | How it runs | Best for | Notes |
|---|---|---|---|
| stdio | Local process the host launches and talks to over stdin/stdout | Local tools, scripts, anything needing direct system access | Never log to stdout; Claude Code does not auto-reconnect local processes |
| HTTP (Streamable HTTP) | Remote server reached over HTTP | Cloud-hosted services | Recommended remote transport; supports OAuth; streamable-http is the spec name and an accepted alias for http |
| SSE | Remote server using Server-Sent Events | Legacy remote servers | Deprecated in Claude Code; use HTTP where available |
Add the server with claude mcp add. For a local stdio server, everything after the -- separator is the command Claude Code runs to launch your server:
claude mcp add weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
The -- (double dash) separates Claude Code's own options (--transport, --env, --scope) from the command that starts the server. Everything after -- is passed through untouched. Use the absolute path to your project directory.
Pass secrets to the process with --env:
claude mcp add --env API_KEY=your-key weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
When using
--env, place at least one other option between--envand the server name. If the name comes directly after--env, the CLI reads it as anotherKEY=valuepair and rejects it.
For a remote server, add it by URL instead:
# Recommended remote transport
claude mcp add --transport http my-remote-server https://mcp.example.com/mcp
--scope controls where the configuration is stored and who sees it:
| Scope | Loads in | Shared with team | Stored in |
|---|---|---|---|
local (default) |
Current project only | No | ~/.claude.json |
project |
Current project only | Yes, via version control | .mcp.json in project root |
user |
All your projects | No | ~/.claude.json |
# Share the server with your team via a checked-in .mcp.json
claude mcp add --scope project weather -- uv --directory /ABSOLUTE/PATH/TO/weather run weather.py
For security, Claude Code prompts for approval before using project-scoped servers from a .mcp.json file.
# List all configured servers
claude mcp list
# Get details for one server
claude mcp get weather
# Remove a server
claude mcp remove weather
Inside a Claude Code session, run /mcp to check connection status and the tool count for each server. With tools connected, you can ask Claude to use them in plain language, for example: "What are the active weather alerts in CA?"
If your server exposes resources, reference them with @ mentions using the format @server:protocol://resource/path, for example @github:issue://123. Resources appear in the @ autocomplete alongside files and are fetched automatically when referenced.
If your server exposes prompts, they show up as slash commands in the form /mcp__servername__promptname. Pass arguments space-separated after the command, for example /mcp__github__pr_review 456.
/mcp and complete the browser login. Tokens are stored securely and refreshed automatically.mcp-server-dev plugin: /plugin install mcp-server-dev@claude-plugins-official, then /mcp-server-dev:build-mcp-server.Build Claude MCP Servers side by side with 2 alternatives on trust, install, platform support, and disclosed safety notes — all from reviewed registry metadata.
1 trust signal differ across this comparison (Submitter).
| Field | Master MCP server development from scratch. Create custom Claude Desktop integrations with TypeScript/Python in 60 minutes using production-ready patterns. Open dossier | A practical pre-installation review workflow for Model Context Protocol servers. Inventory tools, resources, prompts, credentials, network reach, storage, and runtime permissions before connecting a server to Claude or another MCP client. Open dossier | Connect existing MCP servers to Claude Code with claude mcp add: stdio, HTTP, and SSE transports, local/project/user scopes, .mcp.json, and /mcp OAuth. Open dossier |
|---|---|---|---|
| Next steps | |||
| Trust | |||
| Review status | ReviewedMaintainer reviewed | ReviewedMaintainer reviewed | ReviewedMaintainer reviewed |
| Package trust | Package not verified | Package not verified | Package not verified |
| Source provenance | Source-backed | Source-backed | Source-backed |
| SubmitterDiffers | — | MkDev11 | — |
| Install risk | Review first | Review first | Review first |
| Notes | Safety ✓ Privacy ✓ | Safety ✓ Privacy ✓ | Safety ✓ Privacy ✓ |
| Brand | — | — | — |
| Category | guides | guides | guides |
| Source | source-backed | source-backed | source-backed |
| Author | JSONbored | MkDev11 | JSONbored |
| Added | 2025-10-27 | 2026-06-04 | 2025-10-27 |
| Platforms | Claude Code | Claude Code | Claude Code |
| Source repo | — | — | — |
| Safety notes | ✓Building and connecting an MCP server runs a local process (or connects to a remote one) that executes tools with your user privileges; only connect servers you trust and review the command and URL first. | ✓An MCP server gives Claude Code model-callable tools that can run on your behalf; a stdio server runs as a local process with your environment access, so treat installing one as running third-party code. Anthropic reviews connectors against its listing criteria before adding them to the Anthropic Directory but does not security-audit or manage any MCP server, so trust verification is your responsibility (per code.claude.com/docs/en/security). Servers that fetch external content can expose you to prompt injection; Claude Code requires trust verification for new MCP servers and prompts for approval before using project-scoped servers from .mcp.json. Prefer least-privilege credentials, scoped directories, and explicit approval for side-effect tools. | ✓Local stdio servers run their command with your user privileges, and remote servers expose model-controlled tools, so connect only servers you trust and review the command, URL, and headers first. |
| Privacy notes | ✓Connecting servers can pass secrets via --env and OAuth tokens stored in Claude Code's local config; the server process can access whatever data and credentials you grant it. | ✓MCP servers can expose local files, resources, prompt templates, tool arguments, tool outputs, logs, and retrieved data to the connected client and model workflow. For HTTP/SSE transports, OAuth access tokens are stored in the system keychain (macOS) or a credentials file; use "Clear authentication" in the /mcp menu to revoke access. For stdio servers, credentials come from the environment you pass in. Restrict OAuth scopes with oauth.scopes in .mcp.json so a remote server only receives the access it needs, and revoke credentials and delete persisted state when uninstalling a server that had access to private repositories, databases, or files. | ✓Server URLs, command paths, header names, and tool results can expose internal hosts and private data; keep API keys and tokens out of shared `.mcp.json` and use environment-variable expansion or `/mcp` OAuth instead. |
| Prerequisites | — none listed |
|
|
| Install | — | — | — |
| Config | — | — | — |
| Citations | |||
| Claim | Unclaimed | Unclaimed | Unclaimed |
Loading live community signals…
A short, calm digest of reviewed Claude resources. Unsubscribe any time.