|
5 | 5 | which is useful for tracking context truncation issues when AI agents call list_tools. |
6 | 6 |
|
7 | 7 | Usage: |
8 | | - Create a module in your MCP server project that can be called with -m syntax: |
| 8 | + python -m fastmcp_extensions.utils.describe_server --app <module:app> |
9 | 9 |
|
10 | | - ```python |
11 | | - # my_mcp_server/describe.py |
12 | | - from my_mcp_server.server import app |
13 | | - from fastmcp_extensions.utils.describe_server import run_measurement |
| 10 | + Example: |
| 11 | + python -m fastmcp_extensions.utils.describe_server --app my_mcp_server.server:app |
14 | 12 |
|
15 | | - if __name__ == "__main__": |
16 | | - run_measurement(app, server_name="my-mcp-server") |
17 | | - ``` |
18 | | -
|
19 | | - Then add a poe task: |
20 | | - ```toml |
21 | | - [tool.poe.tasks.mcp-describe-server] |
22 | | - cmd = "python -m my_mcp_server.describe" |
23 | | - help = "Describe MCP server tool list" |
24 | | - ``` |
25 | | -
|
26 | | - Run with: `poe mcp-describe-server` |
| 13 | + Poe task configuration: |
| 14 | + [tool.poe.tasks.mcp-describe-server] |
| 15 | + cmd = "python -m fastmcp_extensions.utils.describe_server --app my_mcp_server.server:app" |
| 16 | + help = "Describe MCP server tool list" |
27 | 17 |
|
28 | 18 | Output includes: |
29 | 19 | - Tool count |
|
33 | 23 |
|
34 | 24 | from __future__ import annotations |
35 | 25 |
|
| 26 | +import argparse |
36 | 27 | import asyncio |
| 28 | +import importlib |
37 | 29 | from dataclasses import dataclass |
38 | 30 | from typing import TYPE_CHECKING, Any |
39 | 31 |
|
@@ -159,3 +151,42 @@ async def get_tool_details(app: FastMCP) -> list[dict[str, Any]]: |
159 | 151 | ) |
160 | 152 |
|
161 | 153 | return details |
| 154 | + |
| 155 | + |
| 156 | +def _import_app(app_path: str) -> FastMCP: |
| 157 | + """Import an app from a module:attribute path.""" |
| 158 | + if ":" not in app_path: |
| 159 | + msg = f"Invalid app path '{app_path}'. Expected format: 'module.path:attribute'" |
| 160 | + raise ValueError(msg) |
| 161 | + |
| 162 | + module_path, attr_name = app_path.rsplit(":", 1) |
| 163 | + module = importlib.import_module(module_path) |
| 164 | + return getattr(module, attr_name) |
| 165 | + |
| 166 | + |
| 167 | +def main() -> None: |
| 168 | + """Main entry point for the MCP server description CLI.""" |
| 169 | + parser = argparse.ArgumentParser( |
| 170 | + description="Describe MCP server tool list", |
| 171 | + formatter_class=argparse.RawDescriptionHelpFormatter, |
| 172 | + epilog=__doc__, |
| 173 | + ) |
| 174 | + |
| 175 | + parser.add_argument( |
| 176 | + "--app", |
| 177 | + required=True, |
| 178 | + help="App module path in format 'module.path:attribute'", |
| 179 | + ) |
| 180 | + parser.add_argument( |
| 181 | + "--name", |
| 182 | + help="Optional server name for reporting", |
| 183 | + ) |
| 184 | + |
| 185 | + cli_args = parser.parse_args() |
| 186 | + |
| 187 | + app = _import_app(cli_args.app) |
| 188 | + run_measurement(app, server_name=cli_args.name) |
| 189 | + |
| 190 | + |
| 191 | +if __name__ == "__main__": |
| 192 | + main() |
0 commit comments