Files
PlantAI-rag-new/tooling/cap/fake_mcp_server.py
T
jerryandClaude Fable 5 8c103ea382 feat(capabilities): S1+S2 机制地基+多轮记忆(能力框架/热加载/MCP Provider/history 线程化)
- capabilities/{manifests,registry,providers,install_manager}.py + tool_runner.py:
  三层机制(注册层/调用层/安装管理层),四 Provider,热加载差分刷新
- configs/capabilities.yaml: 唯一注册入口(明文热加载面)
- api.py: QARequest+history/capabilities, /capabilities/install loopback 路由
- llm_client.py: complete() tools 透传 + complete_raw_messages() 工具调用循环支持
- pipeline.py/answer_composer.py: history 线程化(只进 Dialogue Context,检索零回归)
- sdk: services/history.py(3轮/16k预算) + routers/qa.py session_id 剥离注入
- compile_qa.sh: rsync 允许子目录 + capabilities.yaml 入 install 清单
- tooling/cap/: fake_mcp_server.py + cap_selfcheck.py 机制自检
- requirements.lock: mcp 2.1.1 + 依赖 12 包

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 13:00:35 +08:00

132 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""fake_mcp_server.py —— 自检用假 MCP server(stdio,一个 echo 工具)。
用官方 mcp SDK 2.x 的 lowlevel Server + add_request_handler 实现;
若 mcp SDK 未安装则退化为纯 stdio JSON-RPC 手工实现(保底)。
S1 端到端自检用它验证「热加载 + 工具调用」全链。
"""
from __future__ import annotations
import json
import sys
def _serve_manual() -> int:
"""无 mcp SDK 保底:JSON-RPC over stdio(initialize/tools-list/tools-call)。"""
for line in sys.stdin:
try:
message = json.loads(line)
except Exception:
continue
method = message.get("method")
msg_id = message.get("id")
if method == "initialize":
reply = {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {"tools": {}},
"serverInfo": {"name": "fake-echo", "version": "0.1.0"},
},
}
elif method == "notifications/initialized":
continue
elif method == "tools/list":
reply = {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"tools": [
{
"name": "echo",
"description": "回显文本",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string", "description": "要回显的文本"}
},
"required": ["text"],
},
}
]
},
}
elif method == "tools/call":
params = message.get("params") or {}
arguments = params.get("arguments") or {}
text = str(arguments.get("text", ""))
reply = {
"jsonrpc": "2.0",
"id": msg_id,
"result": {
"content": [{"type": "text", "text": f"echo: {text}"}],
"isError": False,
},
}
else:
reply = {
"jsonrpc": "2.0",
"id": msg_id,
"error": {"code": -32601, "message": f"unknown method {method}"},
}
sys.stdout.write(json.dumps(reply, ensure_ascii=False) + "\n")
sys.stdout.flush()
return 0
def _serve_mcp() -> int:
from mcp.server.lowlevel import Server
from mcp.server.stdio import stdio_server
import mcp.types as types
import anyio
server = Server("fake-echo")
async def handle_list_tools(ctx, params: types.PaginatedRequestParams):
return types.ListToolsResult(
tools=[
types.Tool(
name="echo",
description="回显文本",
inputSchema={
"type": "object",
"properties": {
"text": {"type": "string", "description": "要回显的文本"}
},
"required": ["text"],
},
)
]
)
async def handle_call_tool(ctx, params: types.CallToolRequestParams):
arguments = params.arguments or {}
text = str(arguments.get("text", ""))
return types.CallToolResult(
content=[types.TextContent(type="text", text=f"echo: {text}")],
is_error=False,
)
server.add_request_handler("tools/list", types.PaginatedRequestParams, handle_list_tools)
server.add_request_handler("tools/call", types.CallToolRequestParams, handle_call_tool)
async def run() -> None:
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
anyio.run(run)
return 0
def main() -> int:
try:
import mcp # noqa: F401
except ImportError:
return _serve_manual()
return _serve_mcp()
if __name__ == "__main__":
raise SystemExit(main())