Skip to content

MCP Tool inputSchema.properties stripped when registering tools from external MCP servers #912

Description

@billyandco

Environment

  • Runtime: Freebuff (AI Agent Runtime)
  • Connected MCP Server: marionette_mcp v0.6.0 (by LeanCode)
  • Underlying Library: mcp_dart v2.3.0 / v1.3.0

Symptom

When a third-party Model Context Protocol (MCP) server registers a tool with an inputSchema containing named properties, the Freebuff runtime registers the tool with properties: {}. As a result, the AI agent is unable to pass parameters to the tool.

Example

The connect tool in marionette_mcp is defined as follows:

// marionette_mcp source (vm_service_context.dart)
server.registerTool(
  'connect',
  inputSchema: ToolInputSchema(
    properties: {
      'uri': JsonSchema.string(
        description: 'VM service URI (e.g., ws://127.0.0.1:8181/ws)...',
      ),
    },
    required: ['uri'],
  ),
  ...
);

This generates standard JSON Schema in the MCP tools/list response:

{
  "name": "connect",
  "inputSchema": {
    "type": "object",
    "properties": {
      "uri": {
        "type": "string",
        "description": "VM service URI..."
      }
    },
    "required": ["uri"]
  }
}

However, Freebuff interprets the tool parameter schema as:

{
  "parameters": {
    "type": "object",
    "properties": {},
    "additionalProperties": false
  }
}

Impact

This affects every tool requiring parameters. Because properties is empty and additionalProperties is set to false, the AI agent cannot invoke any tool that accepts input arguments.

Execution Error

Attempting to call connect results in:

Invalid parameters for marionette__connect:
  path: ["uri"]  →  "expected string, received undefined"

Note: The validation error path ["uri"] indicates that a secondary validation layer correctly parses the schema (it knows uri is required), but the primary tool parameter definition exposed to the AI model retains properties: {}.


Evidence

  1. Source Code Schema Definition: marionette_mcp v0.6.0 (vm_service_context.dart, lines 62–68) explicitly defines properties: {'uri': JsonSchema.string(...)} and required: ['uri'].
  2. Correct Serialization: mcp_dart's JsonObject.toJson() correctly outputs the properties:
return {
  'type': 'object',
  if (properties != null)
    'properties': properties!.map((k, v) => MapEntry(k, _jsonSchemaValue(v))),
  if (required != null && required!.isNotEmpty) 'required': required,
  ...
};
  1. Not a marionette_mcp Version Issue: Tested across major versions (0.6.0, 0.5.0, 0.4.0, 0.1.0) — all reproduce the identical properties: {} behavior.
  2. Not an mcp_dart Version Issue: Tested on both v1.3.0 and v2.3.0 with identical results.

Root Cause (Hypothesis)

The Freebuff MCP tool registration pipeline likely:

  1. Receives the tools/list JSON-RPC response correctly.
  2. Parses inputSchema as a JSON Schema object.
  3. Drops the properties map when building the internal tool definition — either by instantiating type: "object" without mapping over properties, or via a schema parser that discards properties.

Suggested Fix

In the Freebuff runtime's MCP client implementation (where tools/list responses are ingested):

  1. Pass-through Properties: Ensure inputSchema.properties is preserved and mapped into the internal tool definition rather than being replaced with an empty object.
  2. Preserve Required Fields: Ensure inputSchema.required is properly plumbed through to mark mandatory parameters.
  3. Verification: Test with MCP servers registering parameterized tools (e.g., marionette_mcp, firebase-mcp-server) and verify that tool parameters are visible to and callable by the agent.

Workaround

  • None available on the user side. The fix must be made within the runtime's MCP client handling logic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions