Files
loogle-scripts/services/loogle-mcp/app/mcp/server.py
T

79 lines
2.5 KiB
Python

# -*- coding: utf-8 -*-
"""MCP JSON-RPC handler (Streamable HTTP compatible)."""
import json
import logging
from typing import Any, Optional
from . import tools
LOGGER = logging.getLogger("loogle_mcp.server")
PROTOCOL_VERSION = "2024-11-05"
def _error(req_id: Any, code: int, message: str) -> dict:
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": code, "message": message}}
def _result(req_id: Any, result: dict) -> dict:
return {"jsonrpc": "2.0", "id": req_id, "result": result}
def handle_message(body: dict, claims: Optional[dict]) -> dict:
method = body.get("method")
req_id = body.get("id")
params = body.get("params") or {}
if method == "initialize":
return _result(
req_id,
{
"protocolVersion": PROTOCOL_VERSION,
"capabilities": {"tools": {}, "resources": {}},
"serverInfo": {"name": "loogle-mcp", "version": "1.0.0"},
},
)
if method == "notifications/initialized":
return _result(req_id, {})
if method == "ping":
return _result(req_id, {})
if not claims:
return _error(req_id, -32001, "Autenticazione richiesta (Bearer token OAuth)")
if method == "tools/list":
return _result(req_id, {"tools": tools.tool_definitions()})
if method == "tools/call":
name = params.get("name")
arguments = params.get("arguments") or {}
try:
tool_result = tools.call_tool(name, arguments, claims)
return _result(req_id, tool_result)
except PermissionError as exc:
return _error(req_id, -32003, str(exc))
except FileNotFoundError as exc:
return _error(req_id, -32004, str(exc))
except Exception as exc:
LOGGER.exception("Tool %s failed", name)
return _error(req_id, -32000, str(exc))
if method == "resources/list":
return _result(req_id, {"resources": tools.list_resources(claims)})
if method == "resources/read":
uri = params.get("uri")
try:
resource = tools.read_resource(uri, claims)
return _result(req_id, {"contents": [resource]})
except FileNotFoundError as exc:
return _error(req_id, -32004, str(exc))
return _error(req_id, -32601, f"Metodo non supportato: {method}")
def handle_batch(messages: list, claims: Optional[dict]) -> list:
return [handle_message(msg, claims) for msg in messages if isinstance(msg, dict)]