From b948b60306a2c1e36cdd0d0004bfaba09d8c199f Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Mon, 19 Oct 2026 12:49:35 +0000 Subject: [PATCH] feat: log available MCP tools with tags at info level The generated tool list is now logged at INFO (default) and each line includes the tool's OpenAPI tags alongside its name. The list is only skipped when LOG_LEVEL is above INFO. --- README.md | 4 ++-- src/xmcp/server.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3cf56da..f1f6273 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,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. With `LOG_LEVEL=DEBUG`, the list of generated MCP tools (name and -description) is logged at startup. +string. At startup the generated tool list (name, tags and description) is +logged at INFO; set `LOG_LEVEL=WARNING` to suppress it. ### Per-client API keys (HTTP transport) diff --git a/src/xmcp/server.py b/src/xmcp/server.py index 9ccbd5f..4d58f1d 100644 --- a/src/xmcp/server.py +++ b/src/xmcp/server.py @@ -108,15 +108,16 @@ async def _prepare_tools( f": {', '.join(sorted(tool.name for tool in tools))}" if tools else "", ) - if logger.isEnabledFor(logging.DEBUG): + if logger.isEnabledFor(logging.INFO): unique: dict[str, object] = {} for tool in tools: unique.setdefault(tool.name, tool) - logger.debug("Available MCP tools (%d):", len(unique)) + logger.info("Available MCP tools (%d):", len(unique)) for tool in unique.values(): + tags = f" [{', '.join(sorted(tool.tags))}]" if tool.tags else "" description = (tool.description or "").strip().splitlines() suffix = f" — {description[0]}" if description else "" - logger.debug(" - %s%s", tool.name, suffix) + logger.info(" - %s%s%s", tool.name, tags, suffix) def main() -> None: @@ -140,7 +141,7 @@ def main() -> None: if ( config.tools_included is not None or config.tools_tags_included is not None - or logger.isEnabledFor(logging.DEBUG) + or logger.isEnabledFor(logging.INFO) ): asyncio.run( _prepare_tools(