Skip to content

Commit 408415c

Browse files
authored
Merge branch 'main' into content_block_handling
2 parents 64010ff + fe4f31c commit 408415c

36 files changed

+404
-177
lines changed

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,9 @@ python-version = "3.10"
129129
# Rules with too many errors to fix right now (40+ each)
130130
no-matching-overload = "ignore" # 126 errors
131131
unknown-argument = "ignore" # 61 errors
132-
unresolved-attribute = "ignore" # 60 errors
133132

134133
# Rules with moderate errors that need more investigation
135134
call-non-callable = "ignore" # 7 errors
136-
missing-argument = "ignore" # 23 errors
137135

138136
[tool.ruff.lint]
139137
extend-select = ["I", "UP"]

src/fastmcp/client/client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ async def cancel(
505505
) -> None:
506506
"""Send a cancellation notification for an in-progress request."""
507507
notification = mcp.types.ClientNotification(
508-
mcp.types.CancelledNotification(
508+
root=mcp.types.CancelledNotification(
509509
method="notifications/cancelled",
510510
params=mcp.types.CancelledNotificationParams(
511511
requestId=request_id,
@@ -743,13 +743,13 @@ async def get_prompt(
743743

744744
async def complete_mcp(
745745
self,
746-
ref: mcp.types.ResourceReference | mcp.types.PromptReference,
746+
ref: mcp.types.ResourceTemplateReference | mcp.types.PromptReference,
747747
argument: dict[str, str],
748748
) -> mcp.types.CompleteResult:
749749
"""Send a completion request and return the complete MCP protocol result.
750750
751751
Args:
752-
ref (mcp.types.ResourceReference | mcp.types.PromptReference): The reference to complete.
752+
ref (mcp.types.ResourceTemplateReference | mcp.types.PromptReference): The reference to complete.
753753
argument (dict[str, str]): Arguments to pass to the completion request.
754754
755755
Returns:
@@ -766,13 +766,13 @@ async def complete_mcp(
766766

767767
async def complete(
768768
self,
769-
ref: mcp.types.ResourceReference | mcp.types.PromptReference,
769+
ref: mcp.types.ResourceTemplateReference | mcp.types.PromptReference,
770770
argument: dict[str, str],
771771
) -> mcp.types.Completion:
772772
"""Send a completion request to the server.
773773
774774
Args:
775-
ref (mcp.types.ResourceReference | mcp.types.PromptReference): The reference to complete.
775+
ref (mcp.types.ResourceTemplateReference | mcp.types.PromptReference): The reference to complete.
776776
argument (dict[str, str]): Arguments to pass to the completion request.
777777
778778
Returns:

src/fastmcp/client/elicitation.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ async def _elicitation_handler(
5959
"Elicitation responses must be serializable as a JSON object (dict). Received: "
6060
f"{result.content!r}"
6161
)
62-
return MCPElicitResult(**result.model_dump() | {"content": content})
62+
return MCPElicitResult(
63+
_meta=result.meta,
64+
action=result.action,
65+
content=content,
66+
)
67+
6368
except Exception as e:
6469
return mcp.types.ErrorData(
6570
code=mcp.types.INTERNAL_ERROR,

src/fastmcp/contrib/mcp_mixin/mcp_mixin.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from fastmcp.prompts.prompt import Prompt
99
from fastmcp.resources.resource import Resource
1010
from fastmcp.tools.tool import Tool
11+
from fastmcp.utilities.types import get_fn_name
1112

1213
if TYPE_CHECKING:
1314
from fastmcp.server import FastMCP
@@ -34,7 +35,7 @@ def mcp_tool(
3435

3536
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
3637
call_args = {
37-
"name": name or func.__name__,
38+
"name": name or get_fn_name(func),
3839
"description": description,
3940
"tags": tags,
4041
"annotations": annotations,
@@ -63,7 +64,7 @@ def mcp_resource(
6364
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
6465
call_args = {
6566
"uri": uri,
66-
"name": name or func.__name__,
67+
"name": name or get_fn_name(func),
6768
"description": description,
6869
"mime_type": mime_type,
6970
"tags": tags,
@@ -88,7 +89,7 @@ def mcp_prompt(
8889

8990
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
9091
call_args = {
91-
"name": name or func.__name__,
92+
"name": name or get_fn_name(func),
9293
"description": description,
9394
"tags": tags,
9495
"enabled": enabled,
@@ -146,7 +147,21 @@ def register_tools(
146147
registration_info["name"] = (
147148
f"{prefix}{separator}{registration_info['name']}"
148149
)
149-
tool = Tool.from_function(fn=method, **registration_info)
150+
151+
tool = Tool.from_function(
152+
fn=method,
153+
name=registration_info.get("name"),
154+
title=registration_info.get("title"),
155+
description=registration_info.get("description"),
156+
tags=registration_info.get("tags"),
157+
annotations=registration_info.get("annotations"),
158+
exclude_args=registration_info.get("exclude_args"),
159+
serializer=registration_info.get("serializer"),
160+
output_schema=registration_info.get("output_schema"),
161+
meta=registration_info.get("meta"),
162+
enabled=registration_info.get("enabled"),
163+
)
164+
150165
mcp_server.add_tool(tool)
151166

152167
def register_resources(
@@ -175,7 +190,19 @@ def register_resources(
175190
registration_info["uri"] = (
176191
f"{prefix}{separator}{registration_info['uri']}"
177192
)
178-
resource = Resource.from_function(fn=method, **registration_info)
193+
194+
resource = Resource.from_function(
195+
fn=method,
196+
uri=registration_info["uri"],
197+
name=registration_info.get("name"),
198+
description=registration_info.get("description"),
199+
mime_type=registration_info.get("mime_type"),
200+
tags=registration_info.get("tags"),
201+
enabled=registration_info.get("enabled"),
202+
annotations=registration_info.get("annotations"),
203+
meta=registration_info.get("meta"),
204+
)
205+
179206
mcp_server.add_resource(resource)
180207

181208
def register_prompts(
@@ -200,7 +227,15 @@ def register_prompts(
200227
registration_info["name"] = (
201228
f"{prefix}{separator}{registration_info['name']}"
202229
)
203-
prompt = Prompt.from_function(fn=method, **registration_info)
230+
prompt = Prompt.from_function(
231+
fn=method,
232+
name=registration_info.get("name"),
233+
title=registration_info.get("title"),
234+
description=registration_info.get("description"),
235+
tags=registration_info.get("tags"),
236+
enabled=registration_info.get("enabled"),
237+
meta=registration_info.get("meta"),
238+
)
204239
mcp_server.add_prompt(prompt)
205240

206241
def register_all(

src/fastmcp/experimental/utilities/openapi/director.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,14 @@ def build(
6969
request_data["content"] = body
7070

7171
# Step 5: Create httpx.Request
72-
return httpx.Request(**{k: v for k, v in request_data.items() if v is not None})
72+
return httpx.Request(
73+
method=request_data["method"],
74+
url=request_data["url"],
75+
params=request_data.get("params"),
76+
headers=request_data.get("headers"),
77+
json=request_data.get("json"),
78+
content=request_data.get("content"),
79+
)
7380

7481
def _unflatten_arguments(
7582
self, route: HTTPRoute, flat_args: dict[str, Any]

src/fastmcp/prompts/prompt.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,16 @@ def to_mcp_prompt(
100100
)
101101
for arg in self.arguments or []
102102
]
103-
kwargs = {
104-
"name": self.name,
105-
"description": self.description,
106-
"arguments": arguments,
107-
"title": self.title,
108-
"_meta": self.get_meta(include_fastmcp_meta=include_fastmcp_meta),
109-
}
110-
return MCPPrompt(**kwargs | overrides)
103+
104+
return MCPPrompt(
105+
name=overrides.get("name", self.name),
106+
description=overrides.get("description", self.description),
107+
arguments=arguments,
108+
title=overrides.get("title", self.title),
109+
_meta=overrides.get(
110+
"_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
111+
),
112+
)
111113

112114
@staticmethod
113115
def from_function(

src/fastmcp/resources/resource.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from fastmcp.utilities.components import FastMCPComponent
2525
from fastmcp.utilities.types import (
2626
find_kwarg_by_type,
27+
get_fn_name,
2728
)
2829

2930
if TYPE_CHECKING:
@@ -122,16 +123,18 @@ def to_mcp_resource(
122123
**overrides: Any,
123124
) -> MCPResource:
124125
"""Convert the resource to an MCPResource."""
125-
kwargs = {
126-
"uri": self.uri,
127-
"name": self.name,
128-
"description": self.description,
129-
"mimeType": self.mime_type,
130-
"title": self.title,
131-
"annotations": self.annotations,
132-
"_meta": self.get_meta(include_fastmcp_meta=include_fastmcp_meta),
133-
}
134-
return MCPResource(**kwargs | overrides)
126+
127+
return MCPResource(
128+
name=overrides.get("name", self.name),
129+
uri=overrides.get("uri", self.uri),
130+
description=overrides.get("description", self.description),
131+
mimeType=overrides.get("mimeType", self.mime_type),
132+
title=overrides.get("title", self.title),
133+
annotations=overrides.get("annotations", self.annotations),
134+
_meta=overrides.get(
135+
"_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
136+
),
137+
)
135138

136139
def __repr__(self) -> str:
137140
return f"{self.__class__.__name__}(uri={self.uri!r}, name={self.name!r}, description={self.description!r}, tags={self.tags})"
@@ -182,7 +185,7 @@ def from_function(
182185
return cls(
183186
fn=fn,
184187
uri=uri,
185-
name=name or fn.__name__,
188+
name=name or get_fn_name(fn),
186189
title=title,
187190
description=description or inspect.getdoc(fn),
188191
mime_type=mime_type or "text/plain",

src/fastmcp/resources/template.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,16 +154,18 @@ def to_mcp_template(
154154
**overrides: Any,
155155
) -> MCPResourceTemplate:
156156
"""Convert the resource template to an MCPResourceTemplate."""
157-
kwargs = {
158-
"uriTemplate": self.uri_template,
159-
"name": self.name,
160-
"description": self.description,
161-
"mimeType": self.mime_type,
162-
"title": self.title,
163-
"annotations": self.annotations,
164-
"_meta": self.get_meta(include_fastmcp_meta=include_fastmcp_meta),
165-
}
166-
return MCPResourceTemplate(**kwargs | overrides)
157+
158+
return MCPResourceTemplate(
159+
name=overrides.get("name", self.name),
160+
uriTemplate=overrides.get("uriTemplate", self.uri_template),
161+
description=overrides.get("description", self.description),
162+
mimeType=overrides.get("mimeType", self.mime_type),
163+
title=overrides.get("title", self.title),
164+
annotations=overrides.get("annotations", self.annotations),
165+
_meta=overrides.get(
166+
"_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
167+
),
168+
)
167169

168170
@classmethod
169171
def from_mcp_template(cls, mcp_template: MCPResourceTemplate) -> ResourceTemplate:

src/fastmcp/server/dependencies.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from mcp.server.auth.middleware.auth_context import (
66
get_access_token as _sdk_get_access_token,
77
)
8+
from mcp.server.auth.provider import (
9+
AccessToken as _SDKAccessToken,
10+
)
811
from starlette.requests import Request
912

1013
from fastmcp.server.auth import AccessToken
@@ -107,17 +110,27 @@ def get_access_token() -> AccessToken | None:
107110
The access token if an authenticated user is available, None otherwise.
108111
"""
109112
#
110-
obj = _sdk_get_access_token()
111-
if obj is None or isinstance(obj, AccessToken):
112-
return obj
113+
access_token: _SDKAccessToken | None = _sdk_get_access_token()
114+
115+
if access_token is None or isinstance(access_token, AccessToken):
116+
return access_token
113117

114118
# If the object is not a FastMCP AccessToken, convert it to one if the fields are compatible
115119
# This is a workaround for the case where the SDK returns a different type
116120
# If it fails, it will raise a TypeError
117121
try:
118-
return AccessToken(**obj.model_dump())
122+
access_token_as_dict = access_token.model_dump()
123+
return AccessToken(
124+
token=access_token_as_dict["token"],
125+
client_id=access_token_as_dict["client_id"],
126+
scopes=access_token_as_dict["scopes"],
127+
# Optional fields
128+
expires_at=access_token_as_dict.get("expires_at"),
129+
resource_owner=access_token_as_dict.get("resource_owner"),
130+
claims=access_token_as_dict.get("claims"),
131+
)
119132
except Exception as e:
120133
raise TypeError(
121-
f"Expected fastmcp.server.auth.auth.AccessToken, got {type(obj).__name__}. "
134+
f"Expected fastmcp.server.auth.auth.AccessToken, got {type(access_token).__name__}. "
122135
"Ensure the SDK is using the correct AccessToken type."
123136
) from e

src/fastmcp/server/server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,8 @@ async def _mcp_get_prompt(
812812
813813
Delegates to _get_prompt, which should be overridden by FastMCP subclasses.
814814
"""
815+
import fastmcp.server.context
816+
815817
logger.debug(
816818
f"[{self.name}] Handler called: get_prompt %s with %s", name, arguments
817819
)

0 commit comments

Comments
 (0)