feat: add MCP/skill tool protocol, tasks/tools pages, chat UX overhaul
Tools page: skill & MCP server management with [[skill:]]/[[mcp:]] protocol (up to 3 rounds). New Tasks and Tools pages. Chat: session snapshots, empty-session reuse, per-message model_id, unified JSON prediction suggestions. Settings: upload size limit, prediction options, model enable/disable. Schema additions with ensure_column migrations. Add FEATURES/ARCHITECTURE docs.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""本地 MCP 测试服务器(Streamable HTTP / JSON-RPC POST)。
|
||||
|
||||
用法:python scripts/test_mcp_server.py [端口] 默认 8765
|
||||
提供两个工具:
|
||||
- get_current_time:返回当前时间(无参数)
|
||||
- echo_text:原样返回 text 参数
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
|
||||
|
||||
class McpHandler(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
# 供健康检查/就绪探测使用
|
||||
self._json({"ok": True})
|
||||
|
||||
def do_POST(self):
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = self.rfile.read(length).decode("utf-8")
|
||||
try:
|
||||
req = json.loads(body)
|
||||
except Exception:
|
||||
self._json(
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": None,
|
||||
"error": {"code": -32700, "message": "Parse error"},
|
||||
}
|
||||
)
|
||||
return
|
||||
method = req.get("method")
|
||||
rid = req.get("id")
|
||||
if method == "initialize":
|
||||
result = {
|
||||
"protocolVersion": "2025-03-26",
|
||||
"capabilities": {"tools": {}},
|
||||
"serverInfo": {"name": "test-mcp-server", "version": "1.0.0"},
|
||||
}
|
||||
self._json({"jsonrpc": "2.0", "id": rid, "result": result})
|
||||
elif method == "tools/list":
|
||||
result = {
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_current_time",
|
||||
"description": "获取当前时间",
|
||||
"inputSchema": {"type": "object", "properties": {}},
|
||||
},
|
||||
{
|
||||
"name": "echo_text",
|
||||
"description": "原样返回输入的文本",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {"text": {"type": "string"}},
|
||||
"required": ["text"],
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
self._json({"jsonrpc": "2.0", "id": rid, "result": result})
|
||||
elif method == "tools/call":
|
||||
params = req.get("params", {})
|
||||
name = params.get("name")
|
||||
args = params.get("arguments", {})
|
||||
if name == "get_current_time":
|
||||
content = [{"type": "text", "text": time.strftime("%Y-%m-%d %H:%M:%S")}]
|
||||
elif name == "echo_text":
|
||||
content = [{"type": "text", "text": str(args.get("text", ""))}]
|
||||
else:
|
||||
self._json(
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": rid,
|
||||
"error": {"code": -32602, "message": f"unknown tool {name}"},
|
||||
}
|
||||
)
|
||||
return
|
||||
self._json({"jsonrpc": "2.0", "id": rid, "result": {"content": content}})
|
||||
else:
|
||||
self._json(
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": rid,
|
||||
"error": {"code": -32601, "message": f"unknown method {method}"},
|
||||
}
|
||||
)
|
||||
|
||||
def _json(self, obj):
|
||||
data = json.dumps(obj).encode("utf-8")
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8765
|
||||
print(f"test-mcp-server listening on http://127.0.0.1:{port}/mcp")
|
||||
HTTPServer(("127.0.0.1", port), McpHandler).serve_forever()
|
||||
Reference in New Issue
Block a user