Skip to content

Pass entity JSON Schemas to MCP tool definitions#7

Merged
mgoldsborough merged 5 commits intomainfrom
fix/entity-schemas-in-mcp-tools
Mar 5, 2026
Merged

Pass entity JSON Schemas to MCP tool definitions#7
mgoldsborough merged 5 commits intomainfrom
fix/entity-schemas-in-mcp-tools

Conversation

@mgoldsborough
Copy link
Copy Markdown
Contributor

@mgoldsborough mgoldsborough commented Mar 5, 2026

Summary

  • Problem: create_* and update_* tools used opaque dict[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.
  • Fix (Python): Replace @mcp.tool() decorator with mcp.add_tool() using a closure-factory Tool subclass (_make_entity_tool). Raw JSON Schema passed directly to MCP tool inputSchema.
  • Fix (TypeScript): Replace McpServer (Zod-coupled) with low-level Server class. Eliminates Zod dependency for tool registration — raw JSON Schema passed directly.
  • Both: prepareEntitySchema() strips base entity fields (id, type, created_at, etc.) and JSON Schema meta keywords ($schema, $id). Update tools omit required (partial merge semantics). Falls back to opaque {"type": "object"} when no schema exists.

Test plan

  • Python: 211 tests passing, make -C lib/python check green
  • TypeScript: 166 tests passing, make -C lib/typescript check green
  • Manual: connect LeadGen example as MCP server, confirm Claude sees campaign field structure

Fixes #6

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.
@mgoldsborough mgoldsborough added the qa-reviewed QA review completed with no critical issues label Mar 5, 2026
@mgoldsborough mgoldsborough merged commit 9c13e1b into main Mar 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

qa-reviewed QA review completed with no critical issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Entity schemas not passed to MCP tool definitions — Claude can't see field structure

1 participant