Skip to content

Commit 1b794cb

Browse files
committed
show-server-info
1 parent e16d1be commit 1b794cb

File tree

2 files changed

+62
-125
lines changed

2 files changed

+62
-125
lines changed

src/mcp/server/fastmcp/server.py

Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
GetPromptResult,
4343
ImageContent,
4444
ServerInfo,
45+
ServerInfoAsset,
4546
TextContent,
4647
)
4748
from mcp.types import Prompt as MCPPrompt
@@ -92,9 +93,9 @@ class Settings(BaseSettings, Generic[LifespanResultT]):
9293
description="List of dependencies to install in the server environment",
9394
)
9495

95-
lifespan: (
96-
Callable[[FastMCP], AbstractAsyncContextManager[LifespanResultT]] | None
97-
) = Field(None, description="Lifespan context manager")
96+
lifespan: Callable[[FastMCP], AbstractAsyncContextManager[LifespanResultT]] | None = Field(
97+
None, description="Lifespan context manager"
98+
)
9899

99100

100101
def lifespan_wrapper(
@@ -110,27 +111,17 @@ async def wrap(s: MCPServer[LifespanResultT]) -> AsyncIterator[object]:
110111

111112

112113
class FastMCP:
113-
def __init__(
114-
self, name: str | None = None, instructions: str | None = None, **settings: Any
115-
):
114+
def __init__(self, name: str | None = None, instructions: str | None = None, **settings: Any):
116115
self.settings = Settings(**settings)
117116

118117
self._mcp_server = MCPServer(
119118
name=name or "FastMCP",
120119
instructions=instructions,
121-
lifespan=lifespan_wrapper(self, self.settings.lifespan)
122-
if self.settings.lifespan
123-
else default_lifespan,
124-
)
125-
self._tool_manager = ToolManager(
126-
warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools
127-
)
128-
self._resource_manager = ResourceManager(
129-
warn_on_duplicate_resources=self.settings.warn_on_duplicate_resources
130-
)
131-
self._prompt_manager = PromptManager(
132-
warn_on_duplicate_prompts=self.settings.warn_on_duplicate_prompts
120+
lifespan=lifespan_wrapper(self, self.settings.lifespan) if self.settings.lifespan else default_lifespan,
133121
)
122+
self._tool_manager = ToolManager(warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools)
123+
self._resource_manager = ResourceManager(warn_on_duplicate_resources=self.settings.warn_on_duplicate_resources)
124+
self._prompt_manager = PromptManager(warn_on_duplicate_prompts=self.settings.warn_on_duplicate_prompts)
134125
self.dependencies = self.settings.dependencies
135126

136127
# Set up MCP protocol handlers
@@ -158,7 +149,7 @@ def run(self, transport: Literal["stdio", "sse"] = "stdio") -> None:
158149
raise ValueError(f"Unknown transport: {transport}")
159150

160151
anyio.run(self._run, transport)
161-
152+
162153
async def _run(self, transport: Literal["stdio", "sse"]):
163154
if self.settings.show_server_info:
164155
await self._log_server_info()
@@ -172,7 +163,8 @@ async def _log_server_info(self):
172163
logger.info(f"Server name: {server_info.name}")
173164
logger.info(f"Server: {server_info.host}:{server_info.port}")
174165
logger.info(f"Instructions: {server_info.instructions}")
175-
for asset_type, asset_list in server_info.assets.items():
166+
for asset_type, asset_list in server_info.assets.model_dump().items():
167+
asset_list: list[ServerInfoAsset]
176168
if not asset_list:
177169
continue
178170
logger.info(f"{asset_type}:")
@@ -185,7 +177,7 @@ async def get_server_info(self) -> ServerInfo:
185177
Asynchronously retrieves and returns server information.
186178
187179
This method gathers details about the server, including its name, host, port,
188-
instructions, and various assets such as tools, resources,
180+
instructions, and various assets such as tools, resources,
189181
prompts, and resource templates.
190182
191183
Returns: ServerInfo
@@ -198,7 +190,7 @@ async def get_server_info(self) -> ServerInfo:
198190
tools=await self.list_tools() or [],
199191
resources=await self.list_resources() or [],
200192
prompts=await self.list_prompts() or [],
201-
resource_templates=await self.list_resource_templates() or []
193+
resource_templates=await self.list_resource_templates() or [],
202194
)
203195

204196
def _setup_handlers(self) -> None:
@@ -300,9 +292,7 @@ def add_tool(
300292
"""
301293
self._tool_manager.add_tool(fn, name=name, description=description)
302294

303-
def tool(
304-
self, name: str | None = None, description: str | None = None
305-
) -> Callable[[AnyFunction], AnyFunction]:
295+
def tool(self, name: str | None = None, description: str | None = None) -> Callable[[AnyFunction], AnyFunction]:
306296
"""Decorator to register a tool.
307297
308298
Tools can optionally request a Context object by adding a parameter with the
@@ -331,8 +321,7 @@ async def async_tool(x: int, context: Context) -> str:
331321
# Check if user passed function directly instead of calling decorator
332322
if callable(name):
333323
raise TypeError(
334-
"The @tool decorator was used incorrectly. "
335-
"Did you forget to call it? Use @tool() instead of @tool"
324+
"The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool"
336325
)
337326

338327
def decorator(fn: AnyFunction) -> AnyFunction:
@@ -412,8 +401,7 @@ def decorator(fn: AnyFunction) -> AnyFunction:
412401

413402
if uri_params != func_params:
414403
raise ValueError(
415-
f"Mismatch between URI parameters {uri_params} "
416-
f"and function parameters {func_params}"
404+
f"Mismatch between URI parameters {uri_params} and function parameters {func_params}"
417405
)
418406

419407
# Register as template
@@ -446,9 +434,7 @@ def add_prompt(self, prompt: Prompt) -> None:
446434
"""
447435
self._prompt_manager.add_prompt(prompt)
448436

449-
def prompt(
450-
self, name: str | None = None, description: str | None = None
451-
) -> Callable[[AnyFunction], AnyFunction]:
437+
def prompt(self, name: str | None = None, description: str | None = None) -> Callable[[AnyFunction], AnyFunction]:
452438
"""Decorator to register a prompt.
453439
454440
Args:
@@ -563,9 +549,7 @@ async def list_prompts(self) -> list[MCPPrompt]:
563549
for prompt in prompts
564550
]
565551

566-
async def get_prompt(
567-
self, name: str, arguments: dict[str, Any] | None = None
568-
) -> GetPromptResult:
552+
async def get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult:
569553
"""Get a prompt by name with arguments."""
570554
try:
571555
messages = await self._prompt_manager.render_prompt(name, arguments)
@@ -663,21 +647,15 @@ def request_context(self) -> RequestContext[ServerSessionT, LifespanContextT]:
663647
raise ValueError("Context is not available outside of a request")
664648
return self._request_context
665649

666-
async def report_progress(
667-
self, progress: float, total: float | None = None
668-
) -> None:
650+
async def report_progress(self, progress: float, total: float | None = None) -> None:
669651
"""Report progress for the current operation.
670652
671653
Args:
672654
progress: Current progress value e.g. 24
673655
total: Optional total value e.g. 100
674656
"""
675657

676-
progress_token = (
677-
self.request_context.meta.progressToken
678-
if self.request_context.meta
679-
else None
680-
)
658+
progress_token = self.request_context.meta.progressToken if self.request_context.meta else None
681659

682660
if progress_token is None:
683661
return
@@ -695,9 +673,7 @@ async def read_resource(self, uri: str | AnyUrl) -> Iterable[ReadResourceContent
695673
Returns:
696674
The resource content as either text or bytes
697675
"""
698-
assert (
699-
self._fastmcp is not None
700-
), "Context is not available outside of a request"
676+
assert self._fastmcp is not None, "Context is not available outside of a request"
701677
return await self._fastmcp.read_resource(uri)
702678

703679
async def log(
@@ -715,18 +691,12 @@ async def log(
715691
logger_name: Optional logger name
716692
**extra: Additional structured data to include
717693
"""
718-
await self.request_context.session.send_log_message(
719-
level=level, data=message, logger=logger_name
720-
)
694+
await self.request_context.session.send_log_message(level=level, data=message, logger=logger_name)
721695

722696
@property
723697
def client_id(self) -> str | None:
724698
"""Get the client ID if available."""
725-
return (
726-
getattr(self.request_context.meta, "client_id", None)
727-
if self.request_context.meta
728-
else None
729-
)
699+
return getattr(self.request_context.meta, "client_id", None) if self.request_context.meta else None
730700

731701
@property
732702
def request_id(self) -> str:

0 commit comments

Comments
 (0)