實戰:用 Python 搭建 MCP 服務 —— 模型上下文協議(Model Context Protocol)應用指南

📌 實戰:用 Python 搭建 MCP 服務 —— 模型上下文協議(Model Context Protocol)應用指南

標簽:#MCP #AI工程化 #Python #LLM上下文管理 #Agent架構
在這里插入圖片描述


🎯 引言:為什么需要 MCP?

在構建大語言模型(LLM)驅動的智能體(Agent)系統時,一個核心挑戰是:如何在多輪對話、工具調用、多Agent協作中,高效、結構化地傳遞和管理上下文?

傳統方式(如字符串拼接、JSON隨意傳遞)往往導致:

  • 上下文結構混亂,難以調試
  • Agent 間協作信息丟失
  • 工具調用參數與模型輸入耦合嚴重
  • 多輪對話狀態難以追蹤

為解決這些問題,業界提出了 MCP(Model Context Protocol)—— 模型上下文協議。它是一種標準化的上下文數據交換格式與通信協議,旨在統一 Agent、Tool、Memory、Planner 等模塊之間的“語言”。

本文將手把手教你用 Python 實現一個簡易但完整的 MCP 服務,讓你的 LLM 應用從此告別“上下文泥潭”。


🧩 一、MCP 協議核心概念

MCP 定義了上下文數據的結構化表示,核心包含:

  1. Context Frame(上下文幀):一次交互的完整上下文單元,包含:

    • session_id:會話標識
    • turn_id:輪次編號
    • role:發送者角色(user / system / tool / agent)
    • content:內容(支持文本、結構化數據、工具調用等)
    • metadata:元信息(時間戳、來源、置信度等)
    • tools_called:本輪調用的工具列表
    • state:當前會話狀態(如 waiting_tool, thinking, responding)
  2. MCP Service:負責接收、路由、轉換、持久化上下文幀的服務層。

  3. MCP Client:Agent 或 Tool 通過 Client 發送/接收上下文幀。


🚀 二、Python 實戰:搭建 MCP 服務

我們使用 FastAPI + Pydantic + Redis(可選)構建一個輕量級 MCP 服務。

📁 項目結構:

mcp_service/
├── models/
│   └── mcp.py          # MCP 數據模型
├── services/
│   └── context_manager.py  # 上下文管理邏輯
├── api/
│   └── routes.py       # API 路由
├── main.py             # 啟動入口
└── requirements.txt

🔧 Step 1:定義 MCP 數據模型(models/mcp.py)

# models/mcp.py
from pydantic import BaseModel, Field
from typing import List, Optional, Dict, Any
from enum import Enum
from datetime import datetimeclass RoleEnum(str, Enum):USER = "user"SYSTEM = "system"TOOL = "tool"AGENT = "agent"class ToolCall(BaseModel):tool_name: strarguments: Dict[str, Any]call_id: strclass ContextFrame(BaseModel):session_id: str = Field(..., description="會話唯一ID")turn_id: int = Field(..., description="對話輪次")role: RoleEnumcontent: strtools_called: List[ToolCall] = Field(default_factory=list)state: str = Field(default="responding")metadata: Dict[str, Any] = Field(default_factory=dict)timestamp: datetime = Field(default_factory=datetime.utcnow)class Config:json_encoders = {datetime: lambda v: v.isoformat()}

🧠 Step 2:實現上下文管理器(services/context_manager.py)

# services/context_manager.py
from typing import List, Dict
from .models.mcp import ContextFrame
import redis
import jsonclass ContextManager:def __init__(self, use_redis=False):self.sessions: Dict[str, List[ContextFrame]] = {}self.use_redis = use_redisif use_redis:self.redis_client = redis.Redis(host='localhost', port=6379, db=0)def add_frame(self, frame: ContextFrame):sid = frame.session_idif sid not in self.sessions:self.sessions[sid] = []self.sessions[sid].append(frame)if self.use_redis:key = f"mcp:session:{sid}"self.redis_client.rpush(key, frame.json())self.redis_client.expire(key, 3600)  # 1小時過期def get_session_frames(self, session_id: str) -> List[ContextFrame]:if self.use_redis:key = f"mcp:session:{session_id}"frames_data = self.redis_client.lrange(key, 0, -1)return [ContextFrame.parse_raw(f) for f in frames_data]else:return self.sessions.get(session_id, [])def get_latest_frame(self, session_id: str) -> Optional[ContextFrame]:frames = self.get_session_frames(session_id)return frames[-1] if frames else None

🌐 Step 3:構建 FastAPI 路由(api/routes.py)

# api/routes.py
from fastapi import APIRouter, HTTPException
from ..models.mcp import ContextFrame
from ..services.context_manager import ContextManagerrouter = APIRouter()
context_manager = ContextManager(use_redis=False)  # 可配置為 True@router.post("/mcp/push", summary="推送上下文幀")
async def push_context_frame(frame: ContextFrame):try:context_manager.add_frame(frame)return {"status": "success", "message": "Frame added"}except Exception as e:raise HTTPException(status_code=500, detail=str(e))@router.get("/mcp/session/{session_id}", summary="獲取會話所有幀")
async def get_session_frames(session_id: str):frames = context_manager.get_session_frames(session_id)return {"session_id": session_id, "frames": frames}@router.get("/mcp/session/{session_id}/latest", summary="獲取最新幀")
async def get_latest_frame(session_id: str):frame = context_manager.get_latest_frame(session_id)if not frame:raise HTTPException(status_code=404, detail="Session or frame not found")return frame

? Step 4:啟動服務(main.py)

# main.py
from fastapi import FastAPI
from api.routes import routerapp = FastAPI(title="MCP Service", version="0.1.0")app.include_router(router, prefix="/api/v1")@app.get("/")
def read_root():return {"message": "Welcome to MCP Service - Model Context Protocol"}if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

📦 Step 5:安裝依賴(requirements.txt)

fastapi
uvicorn
pydantic
redis  # 可選
python-dotenv  # 可選

啟動服務:

pip install -r requirements.txt
python main.py

訪問 http://localhost:8000/docs 查看自動生成的 API 文檔!


🧪 三、客戶端調用示例

你可以用任何 HTTP 客戶端調用 MCP 服務。以下是 Python 示例:

# client_example.py
import requests
import json
from datetime import datetimeurl = "http://localhost:8000/api/v1/mcp/push"frame_data = {"session_id": "chat_123","turn_id": 1,"role": "user","content": "今天北京天氣如何?","tools_called": [],"state": "waiting_tool","metadata": {"source": "web", "user_id": "u_001"}
}response = requests.post(url, json=frame_data)
print(response.json())# 獲取最新幀
resp = requests.get("http://localhost:8000/api/v1/mcp/session/chat_123/latest")
print(resp.json())

🧠 四、在 Agent 系統中集成 MCP

假設你有一個天氣查詢 Agent,它可以這樣使用 MCP:

class WeatherAgent:def __init__(self, mcp_url="http://localhost:8000/api/v1"):self.mcp_url = mcp_urldef process(self, user_input: str, session_id: str, turn_id: int):# 1. 接收用戶輸入 → 推送 MCP 幀self._push_frame(session_id, turn_id, "user", user_input)# 2. 決定調用工具tool_call = {"tool_name": "get_weather","arguments": {"location": "北京"},"call_id": "tc_001"}# 3. 推送 Agent 思考幀self._push_frame(session_id, turn_id + 1, "agent","正在調用天氣API...",tools_called=[tool_call],state="calling_tool")# 4. 模擬工具返回weather_result = "北京,晴,25°C"self._push_frame(session_id, turn_id + 2, "tool",weather_result,metadata={"tool_name": "get_weather", "call_id": "tc_001"})# 5. Agent 生成最終回復final_reply = f"為您查詢到:{weather_result}"self._push_frame(session_id, turn_id + 3, "agent",final_reply,state="responding")return final_replydef _push_frame(self, session_id, turn_id, role, content, **kwargs):data = {"session_id": session_id,"turn_id": turn_id,"role": role,"content": content,**kwargs}requests.post(f"{self.mcp_url}/mcp/push", json=data)

? 五、MCP 的進階價值

  1. 可觀測性:所有上下文幀可被記錄、查詢、分析,便于調試復雜 Agent 行為。
  2. 狀態恢復:通過 session_id 可恢復中斷的對話狀態。
  3. 多Agent協作:不同 Agent 可訂閱同一 session,實現上下文共享。
  4. 審計與合規:完整記錄對話軌跡,滿足企業合規要求。
  5. 插件化擴展:可輕松接入 Memory、Planner、Guardrail 等模塊。

🔚 結語

MCP 不是銀彈,但它為混亂的 LLM 上下文管理提供了一種標準化、可擴展、可觀測的解決方案。通過本文的實戰,你已掌握:

  • MCP 協議的核心結構
  • 用 Python + FastAPI 快速搭建 MCP 服務
  • 在 Agent 中集成 MCP 實現上下文流轉

下一步,你可以:

  • 接入 Redis / PostgreSQL 實現持久化
  • 增加 WebSocket 支持實現實時推送
  • 開發 MCP 瀏覽器插件可視化上下文流
  • 與 LangChain / LlamaIndex 集成

🌟 讓 MCP 成為你 AI 工程化架構的“中樞神經系統”,告別上下文混亂,擁抱結構化智能!


💬 評論區開放:你在項目中是如何管理 LLM 上下文的?是否遇到過上下文丟失或混亂的問題?歡迎分享!

#MCP #AI架構 #Python實戰 #LLMOps #智能體開發

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96484.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96484.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96484.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

宋紅康 JVM 筆記 Day16|垃圾回收相關概念

一、今日視頻區間 P154-P168 二、一句話總結 System.gc()的理解;內存溢出與內存泄漏;Stop The World;垃圾回收的并行與并發;安全點與安全區域;再談引用:強引用;再談引用:軟引用;再談…

OpenCV 高階 圖像金字塔 用法解析及案例實現

目錄 一、什么是圖像金字塔? 二、圖像金字塔的核心作用 三、圖像金字塔的核心操作:上下采樣 3.1 向下采樣( pyrDown ):從高分辨率到低分辨率 1)原理與步驟 2)關鍵注意事項 3)…

【ARMv7】系統復位上電后的程序執行過程

引子:對于ARMv7-M系列SOC來說,上電后程序復位執行的過程相對來說比較簡單,因為絕大部分芯片,都是XIP(eXecute In Place,就地執行)模式執行程序,不需要通過BooROM->PL(preloader)-…

神經網絡的初始化:權重與偏置的數學策略

在深度學習中,神經網絡的初始化是一個看似不起眼,卻極其重要的環節。它就像是一場漫長旅程的起點,起點的選擇是否恰當,往往決定了整個旅程的順利程度。今天,就讓我們一起深入探討神經網絡初始化的數學策略,…

第 16 篇:服務網格的未來 - Ambient Mesh, eBPF 與 Gateway API

系列文章:《Istio 服務網格詳解》 第 16 篇:服務網格的未來 - Ambient Mesh, eBPF 與 Gateway API 本篇焦點: 反思當前主流 Sidecar 模式的挑戰與權衡。 深入了解 Istio 官方的未來演進方向:Ambient Mesh (無邊車模式)。 探討革命性技術 eBPF 將如何從根本上重塑服務網格的…

擺動序列:如何讓數組“上下起伏”地最長?

文章目錄摘要描述題解答案題解代碼分析代碼解析示例測試及結果時間復雜度空間復雜度總結摘要 今天我們要聊的是 LeetCode 第 376 題 —— 擺動序列。 題目的意思其實很有意思:如果一個序列里的相鄰差值能保持正負交替,就叫做“擺動”。比如 [1, 7, 4, 9…

玩轉Docker | 使用Docker部署KissLists任務管理工具

玩轉Docker | 使用Docker部署KissLists任務管理工具 前言 一、KissLists介紹 KissLists簡介 KissLists核心特點 KissLists注意事項 二、系統要求 環境要求 環境檢查 Docker版本檢查 檢查操作系統版本 三、部署KissLists服務 下載KissLists鏡像 編輯部署文件 創建容器 檢查容器狀…

【滑動窗口】C++高效解決子數組問題

個人主頁 : zxctscl 專欄 【C】、 【C語言】、 【Linux】、 【數據結構】、 【算法】 如有轉載請先通知 文章目錄前言1 209. 長度最小的子數組1.1 分析1.2 代碼2 3. 無重復字符的最長子串2.1 分析2.2 代碼3 1004. 最大連續1的個數 III3.1 分析3.2 代碼4 1658. 將 x …

[rStar] 搜索代理(MCTS/束搜索)

第2章:搜索代理(MCTS/束搜索) 歡迎回到rStar 在前一章中,我們學習了求解協調器,它就像是解決數學問題的項目經理。 它組織整個過程,但本身并不進行"思考",而是將這項工作委托給其專家團隊。 今天&#x…

Electron 核心模塊速查表

為了更全面地覆蓋常用 API,以下表格補充了更多實用方法和場景化示例,同時保持格式清晰易讀。 一、主進程模塊 模塊名核心用途關鍵用法 示例注意事項app應用生命周期管理? 退出應用:app.quit()? 重啟應用:app.relaunch() 后需…

Qt C++ 圖形繪制完全指南:從基礎到進階實戰

Qt C 圖形繪制完全指南:從基礎到進階實戰 前言 Qt框架提供了強大的2D圖形繪制能力,通過QPainter類及其相關組件,開發者可以輕松實現各種復雜的圖形繪制需求。本文將系統介紹Qt圖形繪制的核心技術,并通過實例代碼演示各種繪制技巧…

二分搜索邊界問題

在使用二分搜索的時候&#xff0c;更新條件不總是相同&#xff0c;雖然說使用bS目的就是為了target&#xff0c;但也有如下幾種情況&#xff1a;求第一個target的索引求第一個>target的索引求第一個>target的索引求最后一個target的索引求最后一個<target的索引求最后…

【springboot+vue3】博客論壇管理系統(源碼+文檔+調試+基礎修改+答疑)

目錄 一、整體目錄&#xff1a; 項目包含源碼、調試、修改教程、調試教程、講解視頻、開發文檔&#xff08;項目摘要、前言、技術介紹、可行性分析、流程圖、結構圖、ER屬性圖、數據庫表結構信息、功能介紹、測試致謝等約1萬字&#xff09; 二、運行截圖 三、代碼部分&…

20250907_梳理異地備份每日自動巡檢Python腳本邏輯流程+安裝Python+PyCharm+配置自動運行

一、邏輯流程(autocheckbackup.py在做什么) 1.連接Linux服務器 用 paramiko 登錄你配置的 Linux 服務器(10.1.3.15, 10.1.3.26),進入指定目錄(如 /home, /backup/mes),遞歸列出文件。 采集到的信息:服務器IP、目錄、數據庫名稱、文件名、大小、修改時間。 2.連接Wind…

terraform-state詳解

一、Treeaform-state的作用 Terraform-state是指Terroform的狀態&#xff0c;是terraform不可缺少的生命周期元素。本質上來講&#xff0c;terraform狀態是你的基礎設施配置的元數據存儲庫&#xff0c;terraform會把它管理的資源狀態保存在一個狀態文件里。 默認情況下&#xf…

四、kubernetes 1.29 之 Pod 生命周期

一、概述當容器與 pause 容器共享網絡&#xff08;Network&#xff09;、IPC&#xff08;進程間通信&#xff09;和 PID&#xff08;進程命名空間&#xff09;后&#xff0c;二者形成了一種緊密的 "共享命名空間" 關系&#xff0c;共同構成了 Kubernetes 中 "Po…

AI與環保:禮貌用語背后的能源挑戰與解決方案

程序員的技術管理推薦閱讀 窄化效應&#xff1a;程序員與管理者的隱形情緒陷阱 從“激勵”到“保健”&#xff1a;80后與90后程序員&#xff0c;到底想要什么&#xff1f; 從“激勵”到“保健”&#xff1a;80后與90后程序員&#xff0c;到底想要什么&#xff1f; 場景引入&…

OpenCV C++ 特征提取:從角點檢測到對象識別

特征提取是計算機視覺的核心技術,通過識別圖像中具有代表性的關鍵點及其描述信息,實現圖像匹配、對象識別、姿態估計等高級任務。本章將系統講解從基礎的圖像金字塔、角點檢測,到復雜的 ORB 和 SIFT 特征提取與匹配,最終實現基于特征的對象檢測完整流程。 一、圖像金字塔 …

Codeforces Round 1049 (Div. 2) D題題解記錄

大致題意&#xff1a;給定nnn個區間(li,ri)(l_i,r_i)(li?,ri?)。每次選取兩個尚未被標記的區間(l1,r1)(l_1,r_1)(l1?,r1?)與(l2,r2)(l_2,r_2)(l2?,r2?)&#xff0c;使得他們均被標記&#xff0c;同時可以任選x∈[l1,r1]&#xff0c;y∈[l2,r2]x\in[l_1,r_1]&#xff0c;y…

《WINDOWS 環境下32位匯編語言程序設計》第15章 注冊表和INI文件

15.1 注冊表和INI文件簡介在一個操作系統中&#xff0c;無論是操作系統本身還是運行于其中的大部分應用程序&#xff0c;都需要使用某種方式保存配置信息。在DOS系統中&#xff0c;配置信息往往是軟件的開發者根據自己的喜好用各種途徑加以保存的&#xff0c;比如在磁盤上面寫一…