diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index b698b0497..65583ede0 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -52,6 +52,8 @@ AnyFunction, ContentBlock, GetPromptResult, + ServerInfo, + ServerInfoAsset, ToolAnnotations, ) from mcp.types import Prompt as MCPPrompt @@ -103,6 +105,8 @@ class Settings(BaseSettings, Generic[LifespanResultT]): # prompt settings warn_on_duplicate_prompts: bool = True + show_server_info: bool = False + dependencies: list[str] = Field( default_factory=list, description="List of dependencies to install in the server environment", @@ -221,6 +225,15 @@ def run( if transport not in TRANSPORTS.__args__: # type: ignore raise ValueError(f"Unknown transport: {transport}") + anyio.run(self._run, transport, mount_path) + + async def _run( + self, + transport: Literal["stdio", "sse", "streamable-http"], + mount_path: str | None = None, + ) -> None: + if self.settings.show_server_info: + await self._log_server_info() match transport: case "stdio": anyio.run(self.run_stdio_async) @@ -229,6 +242,41 @@ def run( case "streamable-http": anyio.run(self.run_streamable_http_async) + async def _log_server_info(self): + server_info = await self.get_server_info() + logger.info(f"Server name: {server_info.name}") + logger.info(f"Server: {server_info.host}:{server_info.port}") + logger.info(f"Instructions: {server_info.instructions}") + for asset_type, asset_list in server_info.assets.model_dump().items(): + asset_list: list[ServerInfoAsset] + if not asset_list: + continue + logger.info(f"{asset_type}:") + for asset in asset_list: + logger.info(f" - {asset.name} - {asset.description}") + logger.info("Server running...") + + async def get_server_info(self) -> ServerInfo: + """ + Asynchronously retrieves and returns server information. + + This method gathers details about the server, including its name, host, port, + instructions, and various assets such as tools, resources, + prompts, and resource templates. + + Returns: ServerInfo + """ + return ServerInfo( + name=self.name, + host=self.settings.host, + port=self.settings.port, + instructions=self.instructions, + tools=await self.list_tools() or [], + resources=await self.list_resources() or [], + prompts=await self.list_prompts() or [], + resource_templates=await self.list_resource_templates() or [], + ) + def _setup_handlers(self) -> None: """Set up core MCP protocol handlers.""" self._mcp_server.list_tools()(self.list_tools) diff --git a/src/mcp/types.py b/src/mcp/types.py index 91432d69c..08d0639a3 100644 --- a/src/mcp/types.py +++ b/src/mcp/types.py @@ -1318,3 +1318,59 @@ class ServerResult( ] ): pass + + +class ServerInfoAsset(BaseModel): + name: str + description: str | None + + +class ServerInfoAssets(BaseModel): + tools: list[ServerInfoAsset] + prompts: list[ServerInfoAsset] + resources: list[ServerInfoAsset] + resource_templates: list[ServerInfoAsset] + + +class ServerInfo(BaseModel): + name: str + host: str + port: int + instructions: str | None + tools: list[Tool] + prompts: list[Prompt] + resources: list[Resource] + resource_templates: list[ResourceTemplate] + + @property + def assets(self) -> ServerInfoAssets: + return ServerInfoAssets( + tools=[ + ServerInfoAsset( + name=tool.name, + description=tool.description + ) + for tool in self.tools + ], + prompts=[ + ServerInfoAsset( + name=prompt.name, + description=prompt.description + ) + for prompt in self.prompts + ], + resources=[ + ServerInfoAsset( + name=resource.name, + description=resource.description + ) + for resource in self.resources + ], + resource_templates=[ + ServerInfoAsset( + name=resource_template.name, + description=resource_template.description + ) + for resource_template in self.resource_templates + ], + )