mcp
This commit is contained in:
93
scripts/mcp-server/src/mcp_server/server.py
Normal file
93
scripts/mcp-server/src/mcp_server/server.py
Normal file
@@ -0,0 +1,93 @@
|
||||
"""Local-only MCP server over stdio."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from mcp_server.docs_sync import check_catalog_parity
|
||||
from mcp_server.tools import invoke_tool, list_tools_payload
|
||||
|
||||
|
||||
def _is_local_only() -> bool:
|
||||
return os.environ.get("MCP_ALLOW_REMOTE", "").lower() not in {"1", "true", "yes"}
|
||||
|
||||
|
||||
def _guard_local() -> None:
|
||||
if not _is_local_only():
|
||||
return
|
||||
if os.environ.get("SSH_CONNECTION"):
|
||||
_write_response({"error": {"code": -32099, "message": "Remote access denied"}})
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _write_response(payload: dict[str, Any]) -> None:
|
||||
sys.stdout.write(json.dumps(payload) + "\n")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def handle_request(request: Mapping[str, Any]) -> dict[str, Any]:
|
||||
"""Dispatch a JSON-RPC request to the appropriate MCP handler."""
|
||||
method = request.get("method")
|
||||
params = request.get("params") or {}
|
||||
if method == "listTools":
|
||||
return {"result": list_tools_payload()}
|
||||
if method == "invokeTool":
|
||||
name = params.get("name") or ""
|
||||
args = params.get("args") or {}
|
||||
try:
|
||||
return {"result": invoke_tool(name, args)}
|
||||
except Exception as exc: # noqa: BLE001
|
||||
return {
|
||||
"result": {
|
||||
"status": "failed",
|
||||
"output": f"Service unavailable: {exc}",
|
||||
"actions": ["retry locally", "call listTools to verify availability"],
|
||||
"docsAnchor": {},
|
||||
}
|
||||
}
|
||||
if method == "syncDocs":
|
||||
return {"result": check_catalog_parity()}
|
||||
return {
|
||||
"error": {
|
||||
"code": -32601,
|
||||
"message": (
|
||||
f"Method '{method}' not found. Call listTools to discover supported methods."
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Run the MCP server in stdio mode."""
|
||||
_guard_local()
|
||||
for line in sys.stdin:
|
||||
if not line.strip():
|
||||
continue
|
||||
try:
|
||||
request = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
_write_response({"error": {"code": -32700, "message": "Parse error"}})
|
||||
continue
|
||||
try:
|
||||
response = handle_request(request)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
_write_response(
|
||||
{
|
||||
"result": {
|
||||
"status": "failed",
|
||||
"output": f"Service unavailable: {exc}",
|
||||
"actions": ["retry locally", "call listTools to verify availability"],
|
||||
"docsAnchor": {},
|
||||
}
|
||||
}
|
||||
)
|
||||
continue
|
||||
_write_response(response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user