Skip to content

createNameBasedHandler breaks any MCP tool with a 'name' property #37

@ftrudeau-pelcro

Description

@ftrudeau-pelcro

Bug

Relay::createHandlerFunction() checks hasNameParameter() (line 285-287) which matches any MCP tool whose input schema has a property called name. When matched, it routes to createNameBasedHandler() which hardcodes a handler accepting only ($name, $selector, $width, $height) — designed for browser automation tools like screenshot/resize.

This breaks all generic API tools that happen to have a name property (e.g. create_product, create_coupon, create_plan). The LLM's arguments get stuffed into the $name parameter as a single object, and all other tool params (site_id, address_required, etc.) are lost.

Reproduction

  1. Connect to any MCP server that exposes a tool with a name property in its input schema:
{
  "name": "create_product",
  "inputSchema": {
    "properties": {
      "site_id": { "type": "number" },
      "name": { "type": "string" },
      "address_required": { "type": "boolean" }
    },
    "required": ["site_id", "name", "address_required"]
  }
}
  1. Ask the LLM to call the tool.

  2. The JSON-RPC tools/call request sent to the MCP server has all arguments nested under "name" instead of flat:

Actual (broken):

{"name": "create_product", "arguments": {"name": {"site_id": 15, "name": "Test Product", "address_required": false}}}

Expected:

{"name": "create_product", "arguments": {"site_id": 15, "name": "Test Product", "address_required": false}}
  1. Tools without a name property (e.g. create_customer with email, first_name, etc.) work correctly because they fall through to the generic handler at line 212.

Root cause

Relay.php lines 203-204 and 285-313:

// Line 285 - matches ANY tool with a "name" property
protected function hasNameParameter(array $definition): bool
{
    return data_get($definition, 'inputSchema.properties.name') !== null;
}

// Line 298 - hardcoded for browser tools only
protected function createNameBasedHandler(string $toolName): callable
{
    return function ($name = null, $selector = null, $width = null, $height = null) use ($toolName): string {
        $params = ['name' => $name];
        // ...only handles selector, width, height — all other params lost
    };
}

Suggested fix

The hasNameParameter check is too broad. It should either:

  • Be removed entirely (let all tools use the generic handler at line 212)
  • Be narrowed to only match browser automation tools (e.g. check for selector + name together)
  • Check that the tool only has name/selector/width/height properties before using the specialized handler

The generic handler at line 212 already handles named parameters correctly and works for all tool shapes.

Environment

  • prism-php/relay v1.8.0
  • echolabsdev/prism v0.99.22
  • PHP 8.3
  • MCP server: Cloudflare Worker with Streamable HTTP transport

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