Model Context Protocol (MCP) 是一個開放協議,它使 LLM 應用與外部資料來源和工具之間的無縫整合成為可能。無論你是建立 AI 驅動的 IDE、改善 chat 交互,還是建立自訂的 AI 工作流程,MCP 提供了一種標準化的方式,將 LLM 與它們所需的上下文連接起來。
目前,MCP 已經累積了足夠的臨界規模和動能,因此它被視為 2023-2025 年「代理開放標準」之爭的潛在贏家。有人預計,以目前的速度,MCP 將在 7 月超OpenAPI:
MCP 的核心是一個 client-server 架構,host 應用程式可以連接到多個伺服器:
MCP客戶端是模型上下文協定(MCP)架構中的核心元件,負責建立和管理與MCP伺服器的連線。它實現了協定的客戶端部分,處理以下功能:
MCP client 的工作流程如下:
MCP伺服器是模型上下文協定(MCP)架構中的基礎元件,為客戶端提供工具、資源和功能。它實現了協定的伺服器端,負責:
1.初始化
2. 訊息交換
初始化後,支援以下模式:
3. 終止
任一方可以終止連線:
SQLite 實作一個集中範例
SQLite MCP 伺服器和你的本機 SQLite 資料庫之間的通訊完全發生在你的機器上 — 你的 SQLite 資料庫不會暴露在網際網路上。 Model Context Protocol 確保 Claude Desktop 只能透過定義良好的介面執行核准的資料庫作。這為你提供了一種安全的方式,讓 Claude 分析和互動你的本地數據,同時完全控制它可以存取的內容。
Example要安裝之軟件:
# 使用 winget
winget install --id=astral-sh.uv -e
winget install git.git sqlite.sqlite
# 或直接下载:
# uv: https://docs.astral.sh/uv/
# Git: https://git-scm.com
# SQLite: https://www.sqlite.org/download.html
建立一個簡單Windows的 SQLite 資料庫進行測試:
# 创建一个新的 SQLite 数据库
$sql = @'
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
price REAL
);
INSERT INTO products (name, price) VALUES
('Widget', 19.99),
('Gadget', 29.99),
('Gizmo', 39.99),
('Smart Watch', 199.99),
('Wireless Earbuds', 89.99),
('Portable Charger', 24.99),
('Bluetooth Speaker', 79.99),
('Phone Stand', 15.99),
('Laptop Sleeve', 34.99),
('Mini Drone', 299.99),
('LED Desk Lamp', 45.99),
('Keyboard', 129.99),
('Mouse Pad', 12.99),
('USB Hub', 49.99),
('Webcam', 69.99),
('Screen Protector', 9.99),
('Travel Adapter', 27.99),
('Gaming Headset', 159.99),
('Fitness Tracker', 119.99),
('Portable SSD', 179.99);
'@
cd ~
& sqlite3 test.db $sql
配置 Claude Desktop:
在文字編輯器中開啟 中的 Claude Desktop 應用程式配置。 %APPDATA%\Claude\claude_desktop_config.json
新增以下配置(將 YOUR_USERNAME 替換為您的實際使用者名稱):
{
"mcpServers": {
"sqlite": {
"command": "uvx",
"args": [
"mcp-server-sqlite",
"--db-path",
"C:\\Users\\YOUR_USERNAME\\test.db"
]
}
}
}
這告訴 Claude Desktop:
3. 測試
問題:
你能連接到我的 SQLite 資料庫並告訴我有哪些產品及其價格嗎?
Claude Desktop 將會:
背後發生了什麼事?
當你使用 MCP 與 Claude Desktop 互動時:
先決條件
您需要 Python 3.10 或更高版本:
python --version # Should be 3.10 或 higher
透過 homebrew 安裝 uv
brew install uv
uv --version # Should be 0.4.18 或 higher
有關更多信息,請參閱 https://docs.astral.sh/uv/
使用 MCP 專案建立器建立新專案
uvx create-mcp-server --path weather_service
cd weather_service
安裝其他依賴項
uv add httpx python-dotenv
設定環境
OPENWEATHER_API_KEY=your-api-key-here #創造:.env
新增基本導入和設定, 在weather_service/src/weather_service/server.py
import os
import json
import logging
from datetime import datetime, timedelta
from collections.abc import Sequence
from functools import lru_cache
from typing import Any
import httpx
import asyncio
from dotenv import load_dotenv
from mcp.server import Server
from mcp.types import (
Resource,
Tool,
TextContent,
ImageContent,
EmbeddedResource,
LoggingLevel
)
from pydantic import AnyUrl
# Load environment variables
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("weather-server")
# API configuration
API_KEY = os.getenv("OPENWEATHER_API_KEY")
if not API_KEY:
raise ValueError("OPENWEATHER_API_KEY environment variable required")
API_BASE_URL = "http://api.openweathermap.org/data/2.5"
DEFAULT_CITY = "London"
CURRENT_WEATHER_ENDPOINT = "weather"
FORECAST_ENDPOINT = "forecast"
# The rest of our server implementation will go here
新增天氣取得功能
# Create reusable params
http_params = {
"appid": API_KEY,
"units": "metric"
}
async def fetch_weather(city: str) -> dict[str, Any]:
async with httpx.AsyncClient() as client:
response = await client.get(
f"{API_BASE_URL}/weather",
params={"q": city, **http_params}
)
response.raise_for_status()
data = response.json()
return {
"temperature": data["main"]["temp"],
"conditions": data["weather"][0]["description"],
"humidity": data["main"]["humidity"],
"wind_speed": data["wind"]["speed"],
"timestamp": datetime.now().isoformat()
}
app = Server("weather-server")
實作資源處理程序, 將這些與資源相關的處理程序加入到我們的 main 函數中:
app = Server("weather-server")
@app.list_resources()
async def list_resources() -> list[Resource]:
"""List available weather resources."""
uri = AnyUrl(f"weather://{DEFAULT_CITY}/current")
return [
Resource(
uri=uri,
name=f"Current weather in {DEFAULT_CITY}",
mimeType="application/json",
description="Real-time weather data"
)
]
@app.read_resource()
async def read_resource(uri: AnyUrl) -> str:
"""Read current weather data for a city."""
city = DEFAULT_CITY
if str(uri).startswith("weather://") and str(uri).endswith("/current"):
city = str(uri).split("/")[-2]
else:
raise ValueError(f"Unknown resource: {uri}")
try:
weather_data = await fetch_weather(city)
return json.dumps(weather_data, indent=2)
except httpx.HTTPError as e:
raise RuntimeError(f"Weather API error: {str(e)}")
實施工具處理程序, 新增以下與工具相關的處理程序:
app = Server("weather-server")
# Resource implementation ...
@app.list_tools()
async def list_tools() -> list[Tool]:
"""List available weather tools."""
return [
Tool(
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"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: Any) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
"""Handle tool calls for weather forecasts."""
if name != "get_forecast":
raise ValueError(f"Unknown tool: {name}")
if not isinstance(arguments, dict) or "city" not in arguments:
raise ValueError("Invalid forecast arguments")
city = arguments["city"]
days = min(int(arguments.get("days", 3)), 5)
try:
async with httpx.AsyncClient() as client:
response = await client.get(
f"{API_BASE_URL}/{FORECAST_ENDPOINT}",
params={
"q": city,
"cnt": days * 8, # API returns 3-hour intervals
**http_params,
}
)
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 [
TextContent(
type="text",
text=json.dumps(forecasts, indent=2)
)
]
except httpx.HTTPError as e:
logger.error(f"Weather API error: {str(e)}")
raise RuntimeError(f"Weather API error: {str(e)}")
新增 main 函數, 將此新增至 的結尾:weather_service/src/weather_service/server.py
async def main():
# Import here to avoid issues with event loops
from mcp.server.stdio import stdio_server
async with stdio_server() as (read_stream, write_stream):
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
在 init.py 中檢查您的切入點, 將此加入到 的結尾:weather_service/src/weather_service/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']
更新 Claude 配置, 搭:claude_desktop_config.json
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"--directory",
"path/to/your/project",
"run",
"weather-service"
],
"env": {
"OPENWEATHER_API_KEY": "your-api-key"
}
}
}
}
重啟 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?
比較天氣
Can you analyze the forecast for both Tokyo and San Francisco and tell me which city would be better for outdoor photography this week?
參考理解:
Python SDK: https://github.com/modelcontextprotocol/python-sdk?tab=readme-ov-file#documentation
MCP中文文件: https://mcp-docs.cn/clients
————————————————
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本聲明。
原文連結:https://blog.csdn.net/qq_45066628/article/details/146225428