"""Self-check: prove the server can start before a client has to find out. Run with ``python -m app.mcp --check`` (or ``scripts/mcp_server.py --check``). The failure this exists for is the quiet one. A stdio MCP client spawns the server, the process starts, the handshake succeeds, and every tool call fails with a database error the model reads as "the tool is broken". Connecting once here, on demand, turns that into a message with a host and a port in it. It is deliberately independent of the transports: it builds the same server object the transports serve, so the tool count it prints is the tool count a client will see. """ from __future__ import annotations import sys import anyio from mcp.server.mcpserver import MCPServer from sqlalchemy import func, select from app.core.config import get_settings from app.db.session import SessionLocal from app.mcp.server import SERVER_VERSION from app.models import Paper, PaperSentence, Template, TemplateFieldLibrary def run_selfcheck(server: MCPServer) -> int: """Report the database, the tool surface, and where the tools come from.""" settings = get_settings() print(f"paper-doc MCP {SERVER_VERSION} (name={server.name})") print(f"database : {settings.safe_database_url}") try: with SessionLocal() as db: counts = { "paper": db.scalar(select(func.count(Paper.id))) or 0, "template": db.scalar(select(func.count(Template.id))) or 0, "paper_sentence": db.scalar(select(func.count(PaperSentence.id))) or 0, "template_field_library": db.scalar( select(func.count(TemplateFieldLibrary.id)) ) or 0, } except Exception as error: # noqa: BLE001 - the message is the point print(f"database : 连接失败 — {error}", file=sys.stderr) print( "检查 backend/.env 的 DB_* 配置,或用 proxy_endpoint skill 确认网络可达。", file=sys.stderr, ) return 1 print("rows : " + ", ".join(f"{name}={count}" for name, count in counts.items())) tools = anyio.run(server.list_tools) groups: dict[str, int] = {} for tool in tools: groups[tool.name.split("_", 1)[0]] = groups.get(tool.name.split("_", 1)[0], 0) + 1 print(f"tools : {len(tools)} " + ", ".join(f"{k}={v}" for k, v in sorted(groups.items()))) for tool in tools: print(f" - {tool.name}") return 0