Pass entity JSON Schemas to MCP tool definitions#7
Merged
mgoldsborough merged 5 commits intomainfrom Mar 5, 2026
Merged
Conversation
create_* and update_* tools used `dict[str, Any]` type annotations, which
FastMCP converted to `{"type": "object"}` with no properties. LLMs had no
way to see field structure, types, or constraints — causing consistent
validation failures on entities with nested objects or arrays.
Replace @mcp.tool() decorator for create/update tools with mcp.add_tool()
using a closure-factory Tool subclass that accepts raw JSON Schema parameters.
The entity schemas (already used for server-side validation) are now passed
directly to the MCP tool definition — single source of truth.
Closes #6
Replace McpServer (Zod-coupled) with low-level Server class to pass
raw JSON Schema directly to MCP tool inputSchema. Eliminates Zod
dependency for tool registration.
- Add prepareEntitySchema() to strip base fields and meta keywords
- Update tools omit required (partial merge semantics)
- Falls back to opaque {type: object} when no schema exists
- Rewrite tests with schema verification integration tests
Companion to 4e48605 (Python implementation).
Fixes: #6
Raw Tool subclasses (Python) and low-level Server handlers (TypeScript) bypass SDK automatic deserialization. Object arguments like data and filter may arrive as JSON strings over stdio transport. Parse them before dispatching to entity handlers. Adds tests for create/update with stringified data arguments.
Python: wrap json.loads in try/except to match TypeScript behavior —
malformed strings starting with { or [ no longer crash the tool handler.
TypeScript: use err.message instead of String(err) for cleaner error
output in tool call responses.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
create_*andupdate_*tools used opaquedict[str, Any]/z.record(z.string(), z.unknown()), producing{"type": "object"}with no properties. LLMs couldn't see field structure for entities with nested objects.@mcp.tool()decorator withmcp.add_tool()using a closure-factoryToolsubclass (_make_entity_tool). Raw JSON Schema passed directly to MCP toolinputSchema.McpServer(Zod-coupled) with low-levelServerclass. Eliminates Zod dependency for tool registration — raw JSON Schema passed directly.prepareEntitySchema()strips base entity fields (id,type,created_at, etc.) and JSON Schema meta keywords ($schema,$id). Update tools omitrequired(partial merge semantics). Falls back to opaque{"type": "object"}when no schema exists.Test plan
make -C lib/python checkgreenmake -C lib/typescript checkgreenFixes #6