模型上下文协议演示

MCP演示项目展示如何为AI应用构建MCP服务器和客户端,实现AI与外部数据和工具的标准化通信。

  • by gariciodaro
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 gariciodaro/MCP-TEST

使用说明

MCP演示项目

实际演示 模型上下文协议(MCP) -演示如何构建 MCP服务器 和 MCP客户端 对于人工智能应用。

什么是MCP?

MCP是一种规范人工智能应用程序如何与外部数据和工具通信的协议。它有两个方面:

  • MCP服务器 -展示AI使用的功能(工具、资源、提示)
  • MCP客户端 -生活在您的AI应用程序中,连接到服务器,编排LLM+工具
┌─────────────────────────────────────┐
│   Your AI Application               │
│   ┌─────────────────────────────┐   │
│   │  MCP Client                 │   │
│   │  - Connects to MCP servers  │   │
│   │  - Manages tool execution   │   │
│   │  - Orchestrates with LLM    │   │
│   └──────────────┬──────────────┘   │
└──────────────────┼──────────────────┘
                   │ MCP Protocol
                   ▼
┌─────────────────────────────────────┐
│   MCP Server                        │
│   - Exposes Tools, Resources,       │
│     Prompts                         │
└─────────────────────────────────────┘

这是给谁的?

如果你正在建造或维护 人工智能驱动的应用程序,你需要了解两者:

  • 构建服务器 将您的API/数据暴露给AI
  • 建立客户 将您的AI应用程序连接到MCP服务器

项目结构

MCP-TEST/
├── weather-mcp-server/     # MCP Server (Python + FastMCP)
│   └── weather.py          # Exposes weather tools, resources, prompts
│
├── mcp-demo-backend/       # MCP Client + API (FastAPI)
│   ├── main.py             # App setup, CORS, router registration
│   ├── config.py           # API key, CORS origins
│   ├── models.py           # Pydantic request/response schemas
│   ├── mcp_client.py       # Unified MCP client with elicitation support
│   └── routes/
│       ├── http.py         # REST endpoints (no elicitation)
│       └── websocket.py    # WebSocket with elicitation support
│
├── mcp-demo-frontend/      # Web UI (Vite + React)
│   └── src/App.jsx         # Chat interface with MCP features
│
└── NOTES.md                # Detailed notes & troubleshooting

MCP服务器功能

MCP服务器公开了三种核心功能类型。以下是每种方法在实践中的工作原理:

1.工具🔧

AI可以执行的操作 -如API调用或函数。

工具让AI 做事当你问“纽约的天气怎么样?”时,人工智能会调用 get_forecast 带有坐标的工具。

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location."""
    # Calls National Weather Service API
    # Returns formatted forecast

在UI中: 问一个问题→ AI决定使用工具→ 工具执行→ AI总结了结果。

Claude桌面应用程序示例

-> 注: Claude Desktop不支持服务器功能:启发式、采样。

2.资源📦

AI可以读取的数据 -静态或动态信息。

资源就像AI可以访问的文件或文档。它们是只读的,URI可寻址的。

@mcp.resource("weather://supported-states")
def get_supported_states() -> str:
    """List of all supported US state codes."""
    return "AL: Alabama, AK: Alaska, ..."

@mcp.resource("weather://example-cities")
def get_example_cities() -> str:
    """Cities with pre-loaded coordinates."""
    return "New York: 40.7128, -74.0060 ..."

在UI中: 单击资源→ 查看其内容。AI还可以读取这些内容以获取上下文。


3.提示📝

预先构建的对话启动器 -结构化输入模板。

提示通过表单而不是自由文本引导用户完成常见的工作流程。

@mcp.prompt()
def weekly_planning(city: str) -> str:
    """Get a detailed weather summary for weekly planning."""
    return f"""I need to plan my week in {city}. 
    Please get the forecast and any alerts, then provide:
    1. Day-by-day breakdown
    2. Best days for outdoor activities
    3. Clothing recommendations"""

在UI中: 选择提示→ 填写论点→ 预览→ 在聊天中使用。


4.启发💬

提出后续问题的工具 -交互式中期执行输入。

启发式允许工具暂停执行并要求用户提供其他信息。这实现了对话式、多步骤的工作流程。

from pydantic import BaseModel

class TripDetails(BaseModel):
    travel_date: str
    num_days: int
    activities: str

@mcp.tool()
async def plan_trip(destination: str, ctx: Context) -> str:
    """Plan a trip with weather-aware recommendations."""
    
    # Pause and ask user for details
    result = await ctx.elicit(
        message=f"Planning trip to {destination}. Please provide details:",
        schema=TripDetails
    )
    
    if result.action == "cancel":
        return "Trip planning cancelled."
    
    # Continue with user's input
    trip_data = result.data
    # ... fetch weather, generate recommendations

在UI中:

  1. 询问“计划一次纽约之旅”
  2. AI呼叫 plan_trip 工具
  3. 模态出现,询问旅行日期、持续时间、活动
  4. 用户填写表单并提交
  5. 工具继续使用该数据
  6. AI返回带有天气的个性化旅行计划

为什么激励很重要: 传统的工具是即发即弃。启发式使工具能够与用户进行对话,根据需要收集上下文。

Visual Studio代码示例

-> 注: vscode为所有MCP协议功能提供所有支持:关联、采样(客户端)、资源、提示、工具(服务器端)


5.取样🤖

服务器向客户端请求AI协助 -反向LLM流。

采样允许MCP服务器请求客户端的LLM处理数据。客户没有要求人工智能使用工具 工具向客户端请求人工智能帮助.

from mcp.types import SamplingMessage, TextContent as MCPTextContent

@mcp.tool()
async def analyze_weather_pattern(cities: str, ctx: Context) -> str:
    """Analyze weather patterns using AI assistance."""
    
    # Fetch weather data for cities...
    weather_data = await fetch_weather(cities)
    
    # Request client's LLM to analyze the data
    result = await ctx.session.create_message(
        messages=[
            SamplingMessage(
                role="user",
                content=MCPTextContent(
                    type="text",
                    text=f"Analyze this weather data: {weather_data}"
                )
            )
        ],
        max_tokens=500,
        system_prompt="You are a weather analyst."
    )
    
    return f"Analysis: {result.content.text}"

在UI中:

  1. 询问“分析纽约、洛杉矶、芝加哥的天气模式”
  2. AI呼叫 analyze_weather_pattern 工具
  3. 工具从NWS API获取天气数据
  4. 工具要求通过采样进行AI分析
  5. Modal出现:“服务器希望AI分析数据。批准吗?”
  6. 用户点击“批准并生成”
  7. 客户的LLM分析天气数据
  8. 工具返回组合原始数据+AI分析

为什么采样很重要:

  • 服务器不需要自己的AI -使用客户端的LLM访问权限
  • 循环中的人类 -用户看到并批准服务器的请求
  • 数据本地化 -服务器只发送分析所需的内容
  • 一致的AI -所有操作都采用相同的模型

MCP客户端功能

后端实现了一个MCP客户端,该客户端连接到服务器并与Claude协调工具执行。

建筑

┌─────────────────────────────────────────────────────────┐
│  Frontend (React)                                       │
│  - WebSocket connection for real-time chat              │
│  - Elicitation modal for user input                     │
└────────────────────────┬────────────────────────────────┘
                         │ WebSocket
                         ▼
┌─────────────────────────────────────────────────────────┐
│  Backend (FastAPI)                                      │
│  ┌───────────────────────────────────────────────────┐  │
│  │  MCP Client                                       │  │
│  │  - Connects to MCP servers via stdio              │  │
│  │  - Sends queries to Claude                        │  │
│  │  - Executes tool calls                            │  │
│  │  - Handles elicitation callbacks                  │  │
│  └───────────────────────────────────────────────────┘  │
└────────────────────────┬────────────────────────────────┘
                         │ stdio
                         ▼
┌─────────────────────────────────────────────────────────┐
│  MCP Server (weather.py)                                │
│  - Tools, Resources, Prompts                            │
│  - Elicitation via ctx.elicit()                         │
│  - Sampling via ctx.session.create_message()            │
└─────────────────────────────────────────────────────────┘

为什么是WebSocket?

HTTP是请求-响应:一个请求→ 一个回应。

采集和采样要求 多次交换 在一次“聊天”中:

  1. 用户发送消息
  2. AI开始处理,工具需要输入(启发)或AI帮助(采样)
  3. 服务器向客户端发送请求
  4. 用户响应(启发)或批准AI调用(采样)
  5. 工具继续
  6. 服务器发送最终响应

这在HTTP中是不可能的。WebSocket提供了所需的双向通道。


快速开始

先决条件

  • Python 3.11+与conda
  • Node.js 18+
  • 无烟煤API键

1.设置MCP服务器

cd weather-mcp-server
conda activate mcp
# Server runs via stdio, started automatically by the client

2.启动后端

cd mcp-demo-backend
# Create .env with your API key
echo ANTHROPIC_API_KEY=your-key-here > .env

conda activate mcp
uvicorn main:app --reload --port 8000

3.启动前端

cd mcp-demo-frontend
npm install
npm run dev
# Open http://localhost:5173

4.连接和测试

  1. 点击 连接 在UI中
  2. 尝试: “纽约的天气预报是什么?”
  3. 观看AI使用 get_forecast 工具
  4. 探索资源和提示选项卡

关键概念

特性 它是什么 类比
工具 要执行的操作 动词- “做点什么”
资源 要读取的数据 名词- “获取信息”
提示 结构化模板 表单- “指导工作流程”
引出 中期执行问题 对话- “要求更多”
采样 服务器请求AI帮助 委派- “帮我分析一下”

后端结构

mcp-demo-backend/
├── main.py             # FastAPI app, CORS, router registration
├── config.py           # Environment config (API key, CORS origins)
├── models.py           # Pydantic schemas for API requests/responses
├── mcp_client.py       # Unified MCP client
│   ├── MCPClient       # Main class
│   ├── connect()       # Connect to MCP server via stdio
│   ├── list_tools()    # Get available tools
│   ├── list_resources()# Get available resources
│   ├── list_prompts()  # Get available prompts
│   ├── call_tool()     # Execute a tool (with optional elicitation)
│   └── process_query() # Full Claude conversation loop
│
└── routes/
    ├── http.py         # REST API (no elicitation support)
    │   └── /status, /connect, /chat, /tools, /resources, /prompts
    │
    └── websocket.py    # WebSocket API (with elicitation)
        └── /ws/chat    # Real-time chat with elicitation support

后续步骤

  • [x] 添加激励支持✅ 已实施!
  • [x] 添加采样功能✅ 已实施!
  • []添加根功能

资源