update
Browse files- .clinerules +14 -29
- Dockerfile +2 -3
- app.py +122 -13
- memory-bank/activeContext.md +19 -0
- memory-bank/productContext.md +3 -0
- memory-bank/progress.md +17 -0
- memory-bank/projectbrief.md +7 -0
- memory-bank/systemPatterns.md +3 -0
- memory-bank/techContext.md +3 -0
- push.sh +0 -1
- requirements.txt +4 -1
- 博客.md +216 -0
.clinerules
CHANGED
|
@@ -1,42 +1,23 @@
|
|
| 1 |
# 自定义指令
|
| 2 |
CUSTOM_INSTRUCTIONS = """
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
-
# 基本配置
|
| 5 |
-
env_tool(虚拟环境管理工具): conda
|
| 6 |
-
env_name(虚拟环境名称): airs-ai
|
| 7 |
-
env_activate_cmd(激活虚拟环境命令): conda activate {env_name}
|
| 8 |
|
| 9 |
-
#
|
| 10 |
-
|
|
|
|
|
|
|
| 11 |
|
| 12 |
-
# 项目要求
|
| 13 |
-
向用户调研
|
| 14 |
-
|
| 15 |
-
# 开发资源参考
|
| 16 |
-
暂无
|
| 17 |
-
|
| 18 |
-
---
|
| 19 |
-
|
| 20 |
-
# 虚拟环境要求
|
| 21 |
-
- 虚拟环境工具:{env_tool}
|
| 22 |
-
- 使用名为{env_name}的虚拟环境,如果没有则创建,如果有则运行下面的命令行:{env_activate_cmd}
|
| 23 |
-
|
| 24 |
-
# 项目管理
|
| 25 |
-
- 使用 Memory Bank作为项目管理工具
|
| 26 |
-
- 用户可以到当前目录下通过指令进行任务管理
|
| 27 |
-
- Memory Bank 中使用中文记录的项目信息
|
| 28 |
-
|
| 29 |
-
# 交流
|
| 30 |
-
- 如非特别指明,必须使用中文进行交流
|
| 31 |
-
- 如果需求不明确时,必须找用户进行需求调研,调研时,一次只提问一个问题
|
| 32 |
|
|
|
|
|
|
|
| 33 |
|
| 34 |
"""
|
| 35 |
-
# 自动批准规则
|
| 36 |
-
AUTO_APPROVE = true
|
| 37 |
|
| 38 |
|
| 39 |
-
---
|
| 40 |
description: Describes Cline's Memory Bank system, its structure, and workflows for maintaining project knowledge across sessions.
|
| 41 |
author: https://github.com/nickbaumann98
|
| 42 |
version: 1.0
|
|
@@ -166,3 +147,7 @@ flowchart TD
|
|
| 166 |
Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state.
|
| 167 |
|
| 168 |
REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# 自定义指令
|
| 2 |
CUSTOM_INSTRUCTIONS = """
|
| 3 |
+
# 必须遵守的约束
|
| 4 |
+
1. 所有交流均采用中文
|
| 5 |
+
2. conda 环境使用 learning
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
+
# 实现目标
|
| 9 |
+
1. 使用MCP的python-sdk开发一个只用一个端口服务,即可加载多个应用的MCP服务
|
| 10 |
+
2. 端口为 7860,
|
| 11 |
+
3. 假设有MCP应用名称为为app01,则MCP服务路径为:http://localhost:7860/app01/sse,假设有MCP应用名称为为app02,则MCP服务路径为:http://localhost:7860/app02/sse,其他同理
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
# 知识参考
|
| 15 |
+
1. 如果有任何关于 MCP python-sdk 的问题,请阅读:https://github.com/modelcontextprotocol/python-sdk
|
| 16 |
|
| 17 |
"""
|
|
|
|
|
|
|
| 18 |
|
| 19 |
|
| 20 |
+
---
|
| 21 |
description: Describes Cline's Memory Bank system, its structure, and workflows for maintaining project knowledge across sessions.
|
| 22 |
author: https://github.com/nickbaumann98
|
| 23 |
version: 1.0
|
|
|
|
| 147 |
Note: When triggered by **update memory bank**, I MUST review every memory bank file, even if some don't require updates. Focus particularly on activeContext.md and progress.md as they track current state.
|
| 148 |
|
| 149 |
REMEMBER: After every memory reset, I begin completely fresh. The Memory Bank is my only link to previous work. It must be maintained with precision and clarity, as my effectiveness depends entirely on its accuracy.
|
| 150 |
+
|
| 151 |
+
"""
|
| 152 |
+
# 自动批准规则
|
| 153 |
+
AUTO_APPROVE = true
|
Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
# you will also find guides on how best to write your Dockerfile
|
| 3 |
|
| 4 |
-
FROM python:3.13
|
| 5 |
|
| 6 |
RUN useradd -m -u 1000 user
|
| 7 |
USER user
|
|
@@ -13,5 +13,4 @@ COPY --chown=user ./requirements.txt requirements.txt
|
|
| 13 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 14 |
|
| 15 |
COPY --chown=user . /app
|
| 16 |
-
|
| 17 |
-
CMD ["python", "app.py"]
|
|
|
|
| 1 |
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
# you will also find guides on how best to write your Dockerfile
|
| 3 |
|
| 4 |
+
FROM python:3.13
|
| 5 |
|
| 6 |
RUN useradd -m -u 1000 user
|
| 7 |
USER user
|
|
|
|
| 13 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 14 |
|
| 15 |
COPY --chown=user . /app
|
| 16 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
app.py
CHANGED
|
@@ -1,18 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from mcp.server.fastmcp import FastMCP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
-
#
|
| 4 |
-
|
| 5 |
-
mcp = FastMCP("Demo", message_path="/messages/", sse_path="/app01/sse")
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
|
|
|
| 14 |
|
| 15 |
-
if __name__ == "__main__":
|
| 16 |
-
|
| 17 |
-
mcp.settings.port = 7860
|
| 18 |
-
mcp.run(transport='sse')
|
|
|
|
| 1 |
+
import uvicorn
|
| 2 |
+
from fastapi import FastAPI
|
| 3 |
+
from starlette.routing import Mount
|
| 4 |
+
from starlette.requests import Request
|
| 5 |
+
from starlette.responses import StreamingResponse
|
| 6 |
+
import asyncio
|
| 7 |
+
import json
|
| 8 |
+
|
| 9 |
from mcp.server.fastmcp import FastMCP
|
| 10 |
+
from mcp.server.sse import SseServerTransport
|
| 11 |
+
from starlette.applications import Starlette
|
| 12 |
+
from starlette.routing import Mount, Route
|
| 13 |
+
|
| 14 |
+
def create_sse_server(mcp: FastMCP):
|
| 15 |
+
"""Create a Starlette app that handles SSE connections and message handling"""
|
| 16 |
+
transport = SseServerTransport("/messages/")
|
| 17 |
+
|
| 18 |
+
# Define handler functions
|
| 19 |
+
async def handle_sse(request):
|
| 20 |
+
async with transport.connect_sse(
|
| 21 |
+
request.scope, request.receive, request._send
|
| 22 |
+
) as streams:
|
| 23 |
+
await mcp._mcp_server.run(
|
| 24 |
+
streams[0], streams[1], mcp._mcp_server.create_initialization_options()
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
# Create Starlette routes for SSE and message handling
|
| 28 |
+
routes = [
|
| 29 |
+
Route("/sse/", endpoint=handle_sse),
|
| 30 |
+
Mount("/messages/", app=transport.handle_post_message),
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
# Create a Starlette app
|
| 34 |
+
return Starlette(routes=routes)
|
| 35 |
+
|
| 36 |
+
# 创建 MCP 应用实例
|
| 37 |
+
class App01:
|
| 38 |
+
def __init__(self):
|
| 39 |
+
self.mcp = FastMCP(name="app01", stateless_http=True)
|
| 40 |
+
self.register_endpoints()
|
| 41 |
+
|
| 42 |
+
def register_endpoints(self):
|
| 43 |
+
@self.mcp.resource("app01://info")
|
| 44 |
+
def app01_info() -> str:
|
| 45 |
+
"""Information about App01"""
|
| 46 |
+
return "This is App01"
|
| 47 |
+
|
| 48 |
+
@self.mcp.tool()
|
| 49 |
+
def app01_echo(message: str) -> str:
|
| 50 |
+
"""Echo a message in App01"""
|
| 51 |
+
return f"App01 Echo: {message}"
|
| 52 |
+
|
| 53 |
+
@self.mcp.tool()
|
| 54 |
+
def app01_add_integers(num1: int, num2: int) -> int:
|
| 55 |
+
"""Add two integers in App01"""
|
| 56 |
+
return num1 + num2
|
| 57 |
+
|
| 58 |
+
async def sse_endpoint(self, request: Request):
|
| 59 |
+
print("Entering App01 SSE endpoint")
|
| 60 |
+
try:
|
| 61 |
+
# 这里可以实现 app01 的 SSE 逻辑
|
| 62 |
+
yield {"event": "message", "data": "Hello from App01"}
|
| 63 |
+
import asyncio
|
| 64 |
+
await asyncio.sleep(1) # 示例:每秒发送一条消息
|
| 65 |
+
yield {"event": "message", "data": "Another message from App01"}
|
| 66 |
+
except Exception as e:
|
| 67 |
+
print(f"Error in App01 SSE endpoint: {e}")
|
| 68 |
+
# Optionally yield an error event to the client
|
| 69 |
+
# yield {"event": "error", "data": str(e)}
|
| 70 |
+
print("Exiting App01 SSE endpoint")
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class App02:
|
| 74 |
+
def __init__(self):
|
| 75 |
+
self.mcp = FastMCP(name="app02", stateless_http=True)
|
| 76 |
+
self.register_endpoints()
|
| 77 |
+
|
| 78 |
+
def register_endpoints(self):
|
| 79 |
+
@self.mcp.resource("app02://status")
|
| 80 |
+
def app02_status() -> str:
|
| 81 |
+
"""Status of App02"""
|
| 82 |
+
return "App02 is running"
|
| 83 |
+
|
| 84 |
+
@self.mcp.tool()
|
| 85 |
+
def app02_process(data: str) -> str:
|
| 86 |
+
"""Process data in App02"""
|
| 87 |
+
return f"App02 Processing: {data}"
|
| 88 |
+
|
| 89 |
+
@self.mcp.tool()
|
| 90 |
+
def app02_multiply_integers(num1: int, num2: int) -> int:
|
| 91 |
+
"""Multiply two integers in App02"""
|
| 92 |
+
return num1 * num2
|
| 93 |
+
|
| 94 |
+
async def sse_endpoint(self, request: Request):
|
| 95 |
+
print("Entering App02 SSE endpoint")
|
| 96 |
+
try:
|
| 97 |
+
# 这里可以实现 app02 的 SSE 逻辑
|
| 98 |
+
yield {"event": "message", "data": "Hello from App02"}
|
| 99 |
+
import asyncio
|
| 100 |
+
await asyncio.sleep(2) # 示例:每2秒发送一条消息
|
| 101 |
+
yield {"event": "message", "data": "Another message from App02"}
|
| 102 |
+
except Exception as e:
|
| 103 |
+
print(f"Error in App02 SSE endpoint: {e}")
|
| 104 |
+
# Optionally yield an error event to the client
|
| 105 |
+
# yield {"event": "error", "data": str(e)}
|
| 106 |
+
print("Exiting App02 SSE endpoint")
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
# 初始化应用
|
| 110 |
+
app01_instance = App01()
|
| 111 |
+
app02_instance = App02()
|
| 112 |
|
| 113 |
+
# 创建 FastAPI 应用
|
| 114 |
+
app = FastAPI()
|
|
|
|
| 115 |
|
| 116 |
+
# 挂载 MCP 应用的 SSE 端点
|
| 117 |
+
# 使用 Mount 来指定路径前缀
|
| 118 |
+
app.mount("/app01", app=app01_instance.mcp.sse_app())
|
| 119 |
+
app.mount("/app02", app=app02_instance.mcp.sse_app())
|
| 120 |
|
| 121 |
+
# 根路径,用于测试 FastAPI 是否正常工作
|
| 122 |
+
@app.get("/")
|
| 123 |
+
async def read_root():
|
| 124 |
+
return {"message": "FastAPI is running"}
|
| 125 |
|
| 126 |
+
# if __name__ == "__main__":
|
| 127 |
+
# uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
memory-bank/activeContext.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 当前背景
|
| 2 |
+
|
| 3 |
+
**当前工作重点:**
|
| 4 |
+
实现一个使用 MCP Python SDK 的单端口多应用 MCP 服务。
|
| 5 |
+
|
| 6 |
+
**最近的更改:**
|
| 7 |
+
- 成功运行了 MCP 服务在端口 7860。
|
| 8 |
+
- 为 `app01` 应用添加了一个名为 `app01_add_integers` 的整数加法工具。
|
| 9 |
+
- 验证了 `app01_add_integers` 工具可以正常工作。
|
| 10 |
+
|
| 11 |
+
**下一步计划:**
|
| 12 |
+
- 确保服务在添加新工具和应用后依然稳定运行。
|
| 13 |
+
- 根据用户需求添加更多的 MCP 应用和工具。
|
| 14 |
+
- 完善记忆库文档以更详细地记录项目进展和技术细节。
|
| 15 |
+
|
| 16 |
+
**当前的决策和注意事项:**
|
| 17 |
+
- 使用 FastAPI 作为基础框架来托管 MCP 应用。
|
| 18 |
+
- 每个 MCP 应用通过 `FastMCP` 实例管理自己的工具和资源。
|
| 19 |
+
- 使用 `app.mount` 将不同的 MCP 应用挂载到不同的 URL 路径下。
|
memory-bank/productContext.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 产品背景
|
| 2 |
+
|
| 3 |
+
请在此处填写项目的目的、解决的问题、工作方式和用户体验目标。
|
memory-bank/progress.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 项目进度
|
| 2 |
+
|
| 3 |
+
**已完成的工作:**
|
| 4 |
+
- 成功搭建并运行了使用 MCP Python SDK 的单端口多应用 MCP 服务 (端口 7860)。
|
| 5 |
+
- 为 `app01` 应用添加了 `app01_add_integers` 工具。
|
| 6 |
+
- 验证了 `app01_add_integers` 工具的功能。
|
| 7 |
+
|
| 8 |
+
**剩余的工作:**
|
| 9 |
+
- 根据用户需求添加更多的 MCP 应用和工具。
|
| 10 |
+
- 持续监控和确保服务的稳定性。
|
| 11 |
+
- 完善项目文档。
|
| 12 |
+
|
| 13 |
+
**当前状态:**
|
| 14 |
+
服务已基本框架搭建完成,并已成功添加并验证了一个工具。
|
| 15 |
+
|
| 16 |
+
**已知问题:**
|
| 17 |
+
- 在服务重启后,可能需要短暂等待才能成功调用新添加的工具(可能是初始化时间)。
|
memory-bank/projectbrief.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 项目简报
|
| 2 |
+
|
| 3 |
+
**核心需求和目标:**
|
| 4 |
+
|
| 5 |
+
1. 使用 MCP 的 Python SDK 开发一个只用一个端口服务,即可加载多个应用的 MCP 服务。
|
| 6 |
+
2. 服务端口为 7860。
|
| 7 |
+
3. MCP 服务路径格式为 `http://localhost:7860/app_name/sse`,其中 `app_name` 是 MCP 应用的名称(例如:app01, app02)。
|
memory-bank/systemPatterns.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 系统模式
|
| 2 |
+
|
| 3 |
+
请在此处填写系统的架构、关键技术决策、设计模式和组件关系。
|
memory-bank/techContext.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 技术背景
|
| 2 |
+
|
| 3 |
+
请在此处填写项目使用的技术、开发环境设置、技术约束和依赖项。
|
push.sh
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
ssh-add ~/.ssh/id_ed25519_airsltd
|
| 2 |
git add .
|
| 3 |
git commit -m "update"
|
| 4 |
git push
|
|
|
|
|
|
|
| 1 |
git add .
|
| 2 |
git commit -m "update"
|
| 3 |
git push
|
requirements.txt
CHANGED
|
@@ -1 +1,4 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi
|
| 2 |
+
uvicorn
|
| 3 |
+
fastmcp
|
| 4 |
+
sse_starlette
|
博客.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 【MCP实战】基于Python SDK构建单端口多应用MCP服务
|
| 2 |
+
|
| 3 |
+
## 1. 项目背景与目标
|
| 4 |
+
|
| 5 |
+
在当前大模型智能体快速发展的背景下,如何有效地管理和调用各种外部工具(Tool)成为了一个关键问题。Model Context Protocol (MCP) 提供了一种标准化的方式来解决这个问题。本项目旨在利用 MCP 的 Python SDK,构建一个**单端口服务,能够加载并管理多个独立的 MCP 应用**。
|
| 6 |
+
|
| 7 |
+
核心目标如下:
|
| 8 |
+
- 使用 Python SDK 实现一个 MCP 服务。
|
| 9 |
+
- 服务运行在 **7860 端口**。
|
| 10 |
+
- 支持通过统一的端口和不同的路径访问不同的 MCP 应用,路径格式为 `http://localhost:7860/app_name/sse`。
|
| 11 |
+
|
| 12 |
+
## 2. 技术选型与实现思路
|
| 13 |
+
|
| 14 |
+
为了实现单端口多应用的服务,我们选择了 **FastAPI** 作为基础框架,因为它轻量、高性能,并且易于集成。MCP Python SDK 提供了 `FastMCP` 类,可以方便地与 FastAPI 集成。
|
| 15 |
+
|
| 16 |
+
实现思路是:
|
| 17 |
+
1. 创建一个主 FastAPI 应用。
|
| 18 |
+
2. 为每个独立的 MCP 应用创建一个 `FastMCP` 实例。
|
| 19 |
+
3. 使用 FastAPI 的 `app.mount()` 方法将每个 `FastMCP` 实例挂载到主应用的指定路径下(例如 `/app01`, `/app02`)。
|
| 20 |
+
4. 主应用监听 7860 端口。
|
| 21 |
+
|
| 22 |
+
这样,通过访问 `http://localhost:7860/app01/sse` 就可以与 `app01` 应用通信,访问 `http://localhost:7860/app02/sse` 就可以与 `app02` 应用通信,实现了单端口多应用的目标。
|
| 23 |
+
|
| 24 |
+
## 3. 代码实现示例
|
| 25 |
+
|
| 26 |
+
以下是 `app.py` 的核心代码示例,展示了如何使用 FastAPI 和 FastMCP 挂载多个应用:
|
| 27 |
+
|
| 28 |
+
```python
|
| 29 |
+
import uvicorn
|
| 30 |
+
from fastapi import FastAPI
|
| 31 |
+
from mcp.server.fastmcp import FastMCP
|
| 32 |
+
import mcp.types as types
|
| 33 |
+
|
| 34 |
+
# 创建主 FastAPI 应用
|
| 35 |
+
app = FastAPI(
|
| 36 |
+
title="Multi-App MCP Server",
|
| 37 |
+
description="A single-port server hosting multiple MCP applications",
|
| 38 |
+
version="0.1.0",
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
# 创建第一个 MCP 应用实例 (app01)
|
| 42 |
+
app01 = FastMCP("app01")
|
| 43 |
+
|
| 44 |
+
# 为 app01 添加一个示例工具
|
| 45 |
+
@app01.tool()
|
| 46 |
+
def app01_add_integers(num1: int, num2: int) -> int:
|
| 47 |
+
"""Adds two integers"""
|
| 48 |
+
return num1 + num2
|
| 49 |
+
|
| 50 |
+
# 创建第二个 MCP 应用实例 (app02)
|
| 51 |
+
app02 = FastMCP("app02")
|
| 52 |
+
|
| 53 |
+
# 为 app02 添加一个示例工具
|
| 54 |
+
@app02.tool()
|
| 55 |
+
def app02_multiply_integers(num1: int, num2: int) -> int:
|
| 56 |
+
"""Multiplies two integers"""
|
| 57 |
+
return num1 * num2
|
| 58 |
+
|
| 59 |
+
# 将 MCP 应用挂载到主 FastAPI 应用的不同路径下
|
| 60 |
+
app.mount("/app01", app01.app)
|
| 61 |
+
app.mount("/app02", app02.app)
|
| 62 |
+
|
| 63 |
+
# 根路径或其他API路由 (可选)
|
| 64 |
+
@app.get("/")
|
| 65 |
+
async def read_root():
|
| 66 |
+
return {"message": "Multi-App MCP Server is running"}
|
| 67 |
+
|
| 68 |
+
if __name__ == "__main__":
|
| 69 |
+
# 运行主 FastAPI 应用,监听 7860 端口
|
| 70 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
**代码说明:**
|
| 74 |
+
- 我们导入了必要的库:`uvicorn`, `FastAPI`, `FastMCP`, `mcp.types`。
|
| 75 |
+
- 创建了主 `FastAPI` 应用 `app`。
|
| 76 |
+
- 创建了两个 `FastMCP` 实例 `app01` 和 `app02`,分别代表两个独立的 MCP 应用。
|
| 77 |
+
- 使用 `@app01.tool()` 和 `@app02.tool()` 装饰器为各自的应用添加了示例工具。
|
| 78 |
+
- 最关键的是使用 `app.mount("/app_name", app_instance.app)` 将每个 `FastMCP` 实例的内部 FastAPI 应用挂载到主应用的 `/app_name` 路径下。
|
| 79 |
+
- 最后,使用 `uvicorn.run()` 启动主应用,监听 7860 端口。
|
| 80 |
+
|
| 81 |
+
## 4. 项目进展与已完成工作
|
| 82 |
+
|
| 83 |
+
目前,项目的基础框架已经搭建完成,并成功实现了单端口多应用的架构。
|
| 84 |
+
|
| 85 |
+
**已完成的工作:**
|
| 86 |
+
- 成功搭建并运行了使用 MCP Python SDK 的单端口多应用 MCP 服务 (端口 7860)。
|
| 87 |
+
- 为 `app01` 应用添加了 `app01_add_integers` 工具,并验证了其功能。
|
| 88 |
+
- 为 `app02` 应用添加了 `app02_multiply_integers` 工具,并验证了其功能。
|
| 89 |
+
- 成功处理了包含加法和乘法的复合数学表达式计算请求,验证了不同应用工具的协同工作。
|
| 90 |
+
|
| 91 |
+
**当前状态:**
|
| 92 |
+
服务已基本框架搭建完成,并已成功添加并验证了两个应用的示例工具。
|
| 93 |
+
|
| 94 |
+
## 5. 在Cline中测试
|
| 95 |
+
|
| 96 |
+
在Cline中,我们可以直接调用已连接的MCP服务器提供的工具进行测试。以下是一些测试算例:
|
| 97 |
+
|
| 98 |
+
**测试1:1+1=?**
|
| 99 |
+
使用 `app01` 的 `app01_add_integers` 工具计算:
|
| 100 |
+
```xml
|
| 101 |
+
<use_mcp_tool>
|
| 102 |
+
<server_name>app01</server_name>
|
| 103 |
+
<tool_name>app01_add_integers</tool_name>
|
| 104 |
+
<arguments>
|
| 105 |
+
{
|
| 106 |
+
"num1": 1,
|
| 107 |
+
"num2": 1
|
| 108 |
+
}
|
| 109 |
+
</arguments>
|
| 110 |
+
</use_mcp_tool>
|
| 111 |
+
```
|
| 112 |
+
结果:2
|
| 113 |
+
|
| 114 |
+
**测试2:2*2=?**
|
| 115 |
+
使用 `app02` 的 `app02_multiply_integers` 工具计算:
|
| 116 |
+
```xml
|
| 117 |
+
<use_mcp_tool>
|
| 118 |
+
<server_name>app02</server_name>
|
| 119 |
+
<tool_name>app02_multiply_integers</tool_name>
|
| 120 |
+
<arguments>
|
| 121 |
+
{
|
| 122 |
+
"num1": 2,
|
| 123 |
+
"num2": 2
|
| 124 |
+
}
|
| 125 |
+
</arguments>
|
| 126 |
+
</use_mcp_tool>
|
| 127 |
+
```
|
| 128 |
+
结果:4
|
| 129 |
+
|
| 130 |
+
**测试3:1+1=? 2*2=?**
|
| 131 |
+
分别调用 `app01_add_integers` 和 `app02_multiply_integers` 工具:
|
| 132 |
+
```xml
|
| 133 |
+
<use_mcp_tool>
|
| 134 |
+
<server_name>app01</server_name>
|
| 135 |
+
<tool_name>app01_add_integers</tool_name>
|
| 136 |
+
<arguments>
|
| 137 |
+
{
|
| 138 |
+
"num1": 1,
|
| 139 |
+
"num2": 1
|
| 140 |
+
}
|
| 141 |
+
</arguments>
|
| 142 |
+
</use_mcp_tool>
|
| 143 |
+
```
|
| 144 |
+
结果:2
|
| 145 |
+
```xml
|
| 146 |
+
<use_mcp_tool>
|
| 147 |
+
<server_name>app02</server_name>
|
| 148 |
+
<tool_name>app02_multiply_integers</tool_name>
|
| 149 |
+
<arguments>
|
| 150 |
+
{
|
| 151 |
+
"num1": 2,
|
| 152 |
+
"num2": 2
|
| 153 |
+
}
|
| 154 |
+
</arguments>
|
| 155 |
+
</use_mcp_tool>
|
| 156 |
+
```
|
| 157 |
+
结果:4
|
| 158 |
+
|
| 159 |
+
**测试4:1+1+2*2=?**
|
| 160 |
+
根据数学运算顺序,先计算乘法,再计算加法。
|
| 161 |
+
首先计算 2*2:
|
| 162 |
+
```xml
|
| 163 |
+
<use_mcp_tool>
|
| 164 |
+
<server_name>app02</server_name>
|
| 165 |
+
<tool_name>app02_multiply_integers</tool_name>
|
| 166 |
+
<arguments>
|
| 167 |
+
{
|
| 168 |
+
"num1": 2,
|
| 169 |
+
"num2": 2
|
| 170 |
+
}
|
| 171 |
+
</arguments>
|
| 172 |
+
</use_mcp_tool>
|
| 173 |
+
```
|
| 174 |
+
结果:4
|
| 175 |
+
然后计算 1+1+4:
|
| 176 |
+
```xml
|
| 177 |
+
<use_mcp_tool>
|
| 178 |
+
<server_name>app01</server_name>
|
| 179 |
+
<tool_name>app01_add_integers</tool_name>
|
| 180 |
+
<arguments>
|
| 181 |
+
{
|
| 182 |
+
"num1": 1,
|
| 183 |
+
"num2": 1
|
| 184 |
+
}
|
| 185 |
+
</arguments>
|
| 186 |
+
</use_mcp_tool>
|
| 187 |
+
```
|
| 188 |
+
结果:2
|
| 189 |
+
最后计算 2+4:
|
| 190 |
+
```xml
|
| 191 |
+
<use_mcp_tool>
|
| 192 |
+
<server_name>app01</server_name>
|
| 193 |
+
<tool_name>app01_add_integers</tool_name>
|
| 194 |
+
<arguments>
|
| 195 |
+
{
|
| 196 |
+
"num1": 2,
|
| 197 |
+
"num2": 4
|
| 198 |
+
}
|
| 199 |
+
</arguments>
|
| 200 |
+
</use_mcp_tool>
|
| 201 |
+
```
|
| 202 |
+
结果:6
|
| 203 |
+
|
| 204 |
+
这些测试表明,我们可以通过Cline成功调用不同MCP应用中的工具,并进行复杂的计算。
|
| 205 |
+
|
| 206 |
+
## 6. 总结与展望
|
| 207 |
+
|
| 208 |
+
本项目成功地探索了如何使用 MCP Python SDK 和 FastAPI 构建一个高效、可扩展的单端口多应用 MCP 服务。这种架构使得在同一个端口下集成多个不同的 MCP 功能成为可能,极大地简化了部署和管理。
|
| 209 |
+
|
| 210 |
+
未来可以继续完善的功能包括:
|
| 211 |
+
- 添加更多的 MCP 应用和工具,涵盖不同的功能领域。
|
| 212 |
+
- 实现更灵活的应用加载机制,例如动态加载或配置。
|
| 213 |
+
- 增强错误处理和日志记录。
|
| 214 |
+
- 编写更完善的文档和示例。
|
| 215 |
+
|
| 216 |
+
通过 MCP 协议,我们可以更便捷地将各种能力封装成工具,赋能给大模型智能体,从而构建更强大、更实用的 AI 应用。
|