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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions