Skip to content

Unify argument parsing between MCP handlers and agent tool executor #1060

Closed

Description

@malibio

Problem

Issue #1040 established the shared ops/ layer so both MCP handlers and local agent tool executors delegate to the same business logic. However, the argument parsing layer above ops still diverges:

  • MCP handlers (packages/core/src/mcp/handlers/nodes.rs): Accept flat properties (e.g., {"id": "...", "status": "done"}) and pass them through to the ops layer, which handles namespacing.
  • Local agent tool executor (packages/agent/src/local_agent/tools.rs): Previously required the model to wrap properties in a "properties" object (e.g., {"id": "...", "properties": {"status": "done"}}). This was partially fixed inline but not systematically aligned.

This divergence means the 8B model's flat tool calls fail on the agent path but would succeed via MCP.

Specific Gaps

  1. Argument normalization: MCP handlers and agent tool executors parse arguments differently — no shared "args → typed input" adapter.
  2. Property flattening: The agent executor now collects unknown top-level keys into properties, but this logic is duplicated inline rather than shared.
  3. Error handling: MCP handlers return MCP error codes; agent executor returns ToolError variants. Error messages differ for the same underlying failure.
  4. Tool definitions: The agent defines tool schemas in tools.rs (def_create_node(), etc.) while MCP defines them in handlers/. These can drift apart.

Proposed Solution

Extract a shared argument adapter layer that both MCP handlers and agent tool executors use:

Model/Client → Argument Adapter (shared) → ops/ layer → NodeService

Options:

  • Option A: Move argument parsing into the ops layer itself (ops functions accept Value and parse internally)
  • Option B: Create ops::args module with parse_create_node_args(Value) → CreateNodeInput, etc.
  • Option C: Generate tool definitions + argument parsers from a single schema definition

Prior Work

Acceptance Criteria

  • create_node and update_node argument parsing is shared between MCP and agent executor
  • Flat properties are accepted uniformly (no "properties" wrapper required)
  • Tool schema definitions are generated from a single source (no drift)
  • Error messages are consistent between MCP and agent paths
  • find_skills pattern (shared ops function) extended to remaining tools

Activity

  1. malibio commented on Apr 7, 2026

    @malibio
    CollaboratorAuthor

    Additional finding: Tool definition schema drift causes runtime failures

    The create_schema agent tool definition drifted from the MCP handler's SchemaRelationship struct:

    • Agent tool used target → MCP expects targetType (camelCase serde)
    • Agent tool omitted direction and cardinality → MCP requires them (not Optional)
    • Agent tool used field_type → MCP expects type (serde rename)
    • Agent tool used core_values → MCP expects coreValues (camelCase)

    These were fixed manually but will recur unless tool definitions are generated from the same source as the MCP handler structs.

    Concrete task for unification:

    • The agent's def_create_schema() tool definition must match CreateSchemaParams, SchemaField, and SchemaRelationship serde formats exactly
    • Consider generating tool JSON schemas from the Rust structs (e.g., via schemars crate or a build-time codegen step)
    • At minimum, add integration tests that verify the agent tool schema accepts the same JSON as the MCP handler
  2. malibio commented on Apr 7, 2026

    @malibio
    CollaboratorAuthor

    Baseline: 128 test files, 3918 tests passed

  3. self-assigned this
    on Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions