Skip to content

Commit 00bca0d

Browse files
more
1 parent 21ed548 commit 00bca0d

File tree

1 file changed

+30
-16
lines changed

1 file changed

+30
-16
lines changed

src/mcp_utils/schema.py

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@
1212
logger = logging.getLogger("mcp_utils")
1313

1414

15+
def build_json_schema_for_msgspec_struct(struct_type: type[Any]) -> dict[str, Any]:
16+
"""Return a clean JSON Schema dict for a msgspec Struct.
17+
"""
18+
if struct_type is None:
19+
return {"type": "object", "properties": {}}
20+
21+
(schemas,), components = msgspec.json.schema_components([struct_type])
22+
23+
# Try direct component by the class name for stable selection
24+
name = getattr(struct_type, "__name__", None)
25+
if name and name in components:
26+
return components[name]
27+
else:
28+
raise ValueError()
29+
30+
1531
class Role(str, Enum):
1632
"""Role in the MCP protocol."""
1733

@@ -100,13 +116,13 @@ class CancelledNotification(msgspec.Struct):
100116
class ClientCapabilities(msgspec.Struct):
101117
"""Capabilities a client may support."""
102118

103-
experimental: dict[str, dict[str, Any]] | None | msgspec.UnsetType = msgspec.UNSET
104-
roots: dict[str, bool] | None | msgspec.UnsetType = msgspec.UNSET
105-
sampling: dict[str, Any] | None | msgspec.UnsetType = msgspec.UNSET
106-
prompts: dict[str, bool] | None | msgspec.UnsetType = msgspec.UNSET
107-
resources: dict[str, bool] | None | msgspec.UnsetType = msgspec.UNSET
108-
tools: dict[str, bool] | None | msgspec.UnsetType = msgspec.UNSET
109-
logging: dict[str, bool] | None | msgspec.UnsetType = msgspec.UNSET
119+
experimental: dict[str, dict[str, Any]] | msgspec.UnsetType = msgspec.UNSET
120+
roots: dict[str, bool] | msgspec.UnsetType = msgspec.UNSET
121+
sampling: dict[str, Any] | msgspec.UnsetType = msgspec.UNSET
122+
prompts: dict[str, bool] | msgspec.UnsetType = msgspec.UNSET
123+
resources: dict[str, bool] | msgspec.UnsetType = msgspec.UNSET
124+
tools: dict[str, bool] | msgspec.UnsetType = msgspec.UNSET
125+
logging: dict[str, bool] | msgspec.UnsetType = msgspec.UNSET
110126

111127

112128
class CompleteRequestArgument(msgspec.Struct):
@@ -203,7 +219,7 @@ class ListResourcesResult(msgspec.Struct):
203219
"""Result of listing resources."""
204220

205221
resources: list[ResourceInfo]
206-
nextCursor: str | None | msgspec.UnsetType = msgspec.UNSET
222+
nextCursor: str | msgspec.UnsetType = msgspec.UNSET
207223

208224

209225
class ResourceTemplateInfo(msgspec.Struct):
@@ -233,7 +249,7 @@ class ListResourceTemplateResult(msgspec.Struct):
233249
"""Result of listing resource templates."""
234250

235251
resourceTemplates: list[ResourceTemplateInfo]
236-
nextCursor: str | None | msgspec.UnsetType = msgspec.UNSET
252+
nextCursor: str | msgspec.UnsetType = msgspec.UNSET
237253

238254

239255
class ReadResourceRequest(msgspec.Struct):
@@ -291,7 +307,7 @@ class ListPromptsResult(msgspec.Struct):
291307
"""Result of listing prompts."""
292308

293309
prompts: list[PromptInfo]
294-
nextCursor: str | None | msgspec.UnsetType = msgspec.UNSET
310+
nextCursor: str | msgspec.UnsetType = msgspec.UNSET
295311

296312

297313
class GetPromptRequest(msgspec.Struct):
@@ -332,27 +348,25 @@ class ToolInfo(msgspec.Struct, omit_defaults=True):
332348
name: str
333349
inputSchema: dict[str, Any]
334350
description: str | None = None
335-
arg_model: type[msgspec.Struct] | None | msgspec.UnsetType = msgspec.UNSET
351+
arg_model: type[msgspec.Struct] | msgspec.UnsetType = msgspec.UNSET
336352

337353
@classmethod
338354
def from_callable(cls, callable: Callable, name: str) -> "ToolInfo":
339355
"""Create a ToolInfo from a callable."""
340356
metadata = inspect_callable(callable)
341-
# Generate a Pydantic-like schema: root as $ref with $defs components.
342-
# Also key the root definition using the tool name for stability.
343357

344358
return cls(
345359
name=name,
346360
description=callable.__doc__ or "",
347-
inputSchema=list(msgspec.json.schema_components([metadata.arg_model])[1].values())[0], # f this.
361+
inputSchema=build_json_schema_for_msgspec_struct(metadata.arg_model),
348362
)
349363

350364

351365
class ListToolsResult(msgspec.Struct):
352366
"""Result of listing tools."""
353367

354368
tools: list[ToolInfo]
355-
nextCursor: str | None | msgspec.UnsetType = msgspec.UNSET
369+
nextCursor: str | msgspec.UnsetType = msgspec.UNSET
356370

357371
class SubscribeRequest(msgspec.Struct):
358372
"""Request to subscribe to a resource."""
@@ -441,7 +455,7 @@ class ListRootsResult(msgspec.Struct):
441455
"""Result of listing roots."""
442456

443457
roots: list[RootInfo]
444-
nextCursor: str | None | msgspec.UnsetType = msgspec.UNSET
458+
nextCursor: str | msgspec.UnsetType = msgspec.UNSET
445459

446460
class ErrorResponse(msgspec.Struct):
447461
"""Error response in MCP."""

0 commit comments

Comments
 (0)