diff --git a/README.md b/README.md index 709ff7c..bc907b1 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,8 @@ OPENAPI_SPEC_URL=https://petstore3.swagger.io/api/v3/openapi.json uv run xmcp Authentication examples: for a bearer token leave the defaults; for an API key header use `API_AUTH_HEADER=X-API-Key` with `API_AUTH_SCHEME` set to an empty -string. +string. With `LOG_LEVEL=DEBUG`, the list of generated MCP tools (name and +description) is logged at startup. ### Per-client API keys (HTTP transport) diff --git a/src/xmcp/server.py b/src/xmcp/server.py index d434b83..84d3238 100644 --- a/src/xmcp/server.py +++ b/src/xmcp/server.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio import logging import os @@ -53,6 +54,19 @@ def build_server(config: Config) -> FastMCP: return server +async def _log_available_tools(server: FastMCP) -> None: + """Log the tools generated from the OpenAPI document (DEBUG level).""" + tools = await server.list_tools() + unique: dict[str, object] = {} + for tool in tools: + unique.setdefault(tool.name, tool) + logger.debug("Available MCP tools (%d):", len(unique)) + for tool in unique.values(): + description = (tool.description or "").strip().splitlines() + suffix = f" — {description[0]}" if description else "" + logger.debug(" - %s%s", tool.name, suffix) + + def main() -> None: try: config = Config.from_env() @@ -71,6 +85,9 @@ def main() -> None: except SpecError as exc: raise SystemExit(f"Failed to load the OpenAPI document: {exc}") from exc + if logger.isEnabledFor(logging.DEBUG): + asyncio.run(_log_available_tools(server)) + # Logs go to stderr so the stdio transport's stdout stays protocol-clean. if config.transport == "http": logger.info("Serving MCP over streamable HTTP at http://%s:%d/mcp", config.host, config.port)