H022329's picture
Upload folder using huggingface_hub
6b62834 verified
Raw
History Blame Contribute Delete
4.31 kB
"""MCP (Model Context Protocol) Server.
Exposes this system's tools and resources to external MCP clients via stdio.
"""
import asyncio
import json
import sys
from typing import Any
class MCPServer:
"""Expose Agentic RAG tools as an MCP server.
Runs as a stdio-based JSON-RPC server that external MCP clients can connect to.
"""
def __init__(self, tool_registry=None, name: str = "agentic_rag",
version: str = "0.1.0"):
self.name = name
self.version = version
self.tool_registry = tool_registry
self._running = False
async def run_stdio(self) -> None:
"""Run the MCP server over stdio (stdin/stdout).
Reads JSON-RPC requests from stdin and writes responses to stdout.
"""
self._running = True
reader = asyncio.StreamReader()
protocol = asyncio.StreamReaderProtocol(reader)
await asyncio.get_event_loop().connect_read_pipe(lambda: protocol, sys.stdin)
while self._running:
try:
line = await asyncio.wait_for(reader.readline(), timeout=300.0)
if not line:
break
request = json.loads(line.decode())
response = await self._handle_request(request)
sys.stdout.write(json.dumps(response) + "\n")
sys.stdout.flush()
except asyncio.TimeoutError:
break
except json.JSONDecodeError:
continue
except Exception as e:
error_response = {
"jsonrpc": "2.0",
"id": request.get("id") if "request" in dir() else None,
"error": {"code": -32603, "message": str(e)},
}
sys.stdout.write(json.dumps(error_response) + "\n")
sys.stdout.flush()
async def _handle_request(self, request: dict) -> dict:
"""Handle a single JSON-RPC request."""
method = request.get("method", "")
req_id = request.get("id")
handlers = {
"initialize": self._handle_initialize,
"tools/list": self._handle_tools_list,
"tools/call": self._handle_tools_call,
"resources/list": self._handle_resources_list,
}
handler = handlers.get(method)
if handler:
result = await handler(request.get("params", {}))
return {"jsonrpc": "2.0", "id": req_id, "result": result}
else:
return {
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32601, "message": f"Method not found: {method}"},
}
async def _handle_initialize(self, params: dict) -> dict:
return {
"protocolVersion": "2024-11-05",
"capabilities": {"tools": {}},
"serverInfo": {"name": self.name, "version": self.version},
}
async def _handle_tools_list(self, params: dict) -> dict:
tools = self.tool_registry.get_all() if self.tool_registry else []
return {
"tools": [
{
"name": t.name,
"description": t.description,
"inputSchema": t.parameters_schema,
}
for t in tools
]
}
async def _handle_tools_call(self, params: dict) -> dict:
tool_name = params.get("name", "")
arguments = params.get("arguments", {})
tool = self.tool_registry.get(tool_name) if self.tool_registry else None
if tool is None:
return {
"content": [{"type": "text", "text": f"Tool not found: {tool_name}"}],
"isError": True,
}
try:
result = await tool.execute(**arguments)
return {
"content": [{"type": "text", "text": str(result)}],
}
except Exception as e:
return {
"content": [{"type": "text", "text": f"Error: {e}"}],
"isError": True,
}
async def _handle_resources_list(self, params: dict) -> dict:
return {"resources": []}
def stop(self) -> None:
"""Stop the MCP server."""
self._running = False