|
6 | 6 | import re |
7 | 7 | from collections.abc import AsyncIterator, Awaitable, Callable, Iterable, Sequence |
8 | 8 | from contextlib import AbstractAsyncContextManager, asynccontextmanager |
9 | | -from typing import Any, Generic, Literal, overload |
| 9 | +from typing import Any, Generic, Literal, TypeVar, overload |
10 | 10 |
|
11 | 11 | import anyio |
12 | 12 | import pydantic_core |
|
44 | 44 | from mcp.server.streamable_http_manager import StreamableHTTPSessionManager |
45 | 45 | from mcp.server.transport_security import TransportSecuritySettings |
46 | 46 | from mcp.shared.context import LifespanContextT, RequestContext, RequestT |
47 | | -from mcp.types import Annotations, AnyFunction, ContentBlock, GetPromptResult, Icon, ToolAnnotations |
| 47 | +from mcp.types import Annotations, ContentBlock, GetPromptResult, Icon, ToolAnnotations |
48 | 48 | from mcp.types import Prompt as MCPPrompt |
49 | 49 | from mcp.types import PromptArgument as MCPPromptArgument |
50 | 50 | from mcp.types import Resource as MCPResource |
|
53 | 53 |
|
54 | 54 | logger = get_logger(__name__) |
55 | 55 |
|
| 56 | +_CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) |
| 57 | + |
56 | 58 |
|
57 | 59 | class Settings(BaseSettings, Generic[LifespanResultT]): |
58 | 60 | """FastMCP server settings. |
@@ -361,7 +363,7 @@ async def read_resource(self, uri: AnyUrl | str) -> Iterable[ReadResourceContent |
361 | 363 |
|
362 | 364 | def add_tool( |
363 | 365 | self, |
364 | | - fn: AnyFunction, |
| 366 | + fn: Callable[..., Any], |
365 | 367 | name: str | None = None, |
366 | 368 | title: str | None = None, |
367 | 369 | description: str | None = None, |
@@ -417,7 +419,7 @@ def tool( |
417 | 419 | icons: list[Icon] | None = None, |
418 | 420 | meta: dict[str, Any] | None = None, |
419 | 421 | structured_output: bool | None = None, |
420 | | - ) -> Callable[[AnyFunction], AnyFunction]: |
| 422 | + ) -> Callable[[_CallableT], _CallableT]: |
421 | 423 | """Decorator to register a tool. |
422 | 424 |
|
423 | 425 | Tools can optionally request a Context object by adding a parameter with the |
@@ -455,7 +457,7 @@ async def async_tool(x: int, context: Context) -> str: |
455 | 457 | "The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool" |
456 | 458 | ) |
457 | 459 |
|
458 | | - def decorator(fn: AnyFunction) -> AnyFunction: |
| 460 | + def decorator(fn: _CallableT) -> _CallableT: |
459 | 461 | self.add_tool( |
460 | 462 | fn, |
461 | 463 | name=name, |
@@ -507,7 +509,7 @@ def resource( |
507 | 509 | icons: list[Icon] | None = None, |
508 | 510 | annotations: Annotations | None = None, |
509 | 511 | meta: dict[str, Any] | None = None, |
510 | | - ) -> Callable[[AnyFunction], AnyFunction]: |
| 512 | + ) -> Callable[[_CallableT], _CallableT]: |
511 | 513 | """Decorator to register a function as a resource. |
512 | 514 |
|
513 | 515 | The function will be called when the resource is read to generate its content. |
@@ -553,7 +555,7 @@ async def get_weather(city: str) -> str: |
553 | 555 | "Did you forget to call it? Use @resource('uri') instead of @resource" |
554 | 556 | ) |
555 | 557 |
|
556 | | - def decorator(fn: AnyFunction) -> AnyFunction: |
| 558 | + def decorator(fn: _CallableT) -> _CallableT: |
557 | 559 | # Check if this should be a template |
558 | 560 | sig = inspect.signature(fn) |
559 | 561 | has_uri_params = "{" in uri and "}" in uri |
@@ -618,7 +620,7 @@ def prompt( |
618 | 620 | title: str | None = None, |
619 | 621 | description: str | None = None, |
620 | 622 | icons: list[Icon] | None = None, |
621 | | - ) -> Callable[[AnyFunction], AnyFunction]: |
| 623 | + ) -> Callable[[_CallableT], _CallableT]: |
622 | 624 | """Decorator to register a prompt. |
623 | 625 |
|
624 | 626 | Args: |
@@ -660,7 +662,7 @@ async def analyze_file(path: str) -> list[Message]: |
660 | 662 | "Did you forget to call it? Use @prompt() instead of @prompt" |
661 | 663 | ) |
662 | 664 |
|
663 | | - def decorator(func: AnyFunction) -> AnyFunction: |
| 665 | + def decorator(func: _CallableT) -> _CallableT: |
664 | 666 | prompt = Prompt.from_function(func, name=name, title=title, description=description, icons=icons) |
665 | 667 | self.add_prompt(prompt) |
666 | 668 | return func |
@@ -1086,7 +1088,7 @@ async def elicit( |
1086 | 1088 |
|
1087 | 1089 | Args: |
1088 | 1090 | schema: A Pydantic model class defining the expected response structure, according to the specification, |
1089 | | - only primive types are allowed. |
| 1091 | + only primitive types are allowed. |
1090 | 1092 | message: Optional message to present to the user. If not provided, will use |
1091 | 1093 | a default message based on the schema |
1092 | 1094 |
|
@@ -1158,10 +1160,7 @@ async def log( |
1158 | 1160 | """ |
1159 | 1161 |
|
1160 | 1162 | if extra: |
1161 | | - log_data = { |
1162 | | - "message": message, |
1163 | | - **extra, |
1164 | | - } |
| 1163 | + log_data = {"message": message, **extra} |
1165 | 1164 | else: |
1166 | 1165 | log_data = message |
1167 | 1166 |
|
|
0 commit comments