[BUG] HTTP MCP transport doesn't resolve $ref in parameter schemas, causing JSON string parameters to not be parsed as objects

Resolved 💬 4 comments Opened Oct 29, 2025 by acfurlong Closed Jan 9, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

I set up the remote mcp servers for PagerDuty and Notion, which both use http.

claude mcp add --transport http notion https://mcp.notion.com/mcp
claude mcp add --transport http pagerduty https://mcp.pagerduty.com/mcp \
  --header "Authorization: Token PRIVATE"

Claude can call Notion with functions with objects as parameters

  Notion query:
  <invoke name="mcp__notion__notion-search">
  <parameter name="query">test</parameter>
  <parameter name="query_type">internal</parameter>
  <parameter name="filters">{"created_date_range": {"start_date": "2024-01-01", "end_date": "2025-01-01"},
  "created_by_user_ids": ["PRIVATE"]}</parameter>
  </invoke>

But when it tries to call PagerDuty functions with objects as parameters, it fails because the object is treated as a string instead of an object:

  PagerDuty query:
  <invoke name="mcp__pagerduty__list_incidents">
  <parameter name="query_model">{"limit": 25}</parameter>
  </invoke>

● pagerduty - list_incidents (MCP)(query_model: "{\"limit\": 25}")
  ⎿  Error: Input validation error: '{"limit": 25}' is not of type 'object'

When I try curling PagerDuty directly, it works:

  curl -v -X POST "https://mcp.pagerduty.com/mcp/" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -H "Authorization: Token PRIVATE" \
    -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "tools/call",
      "params": {
        "name": "list_incidents",
        "arguments": {
          "query_model": {
            "limit": 25,
            "status": ["resolved"],
            "since": "2025-10-01T00:00:00Z",
            "until": "2025-10-29T23:59:59Z"
          }
        }
      }
    }'

So the problem is on Claude's side, not PagerDuty's side. I asked Claude to compare the Notion and PagerDuty MCP setups and it discovered this:

● Let me look at the tool schemas I have. I can compare them directly:

  Notion's filters parameter:
  "filters": {
    "type": "object",
    "properties": {
      "created_by_user_ids": {...},
      "created_date_range": {...}
    }
  }

  PagerDuty's query_model parameter:
  "query_model": {
    "$ref": "#/$defs/IncidentQuery"
  }

  There's the difference!

  - Notion defines the object schema inline with "type": "object" directly in the parameter
  - PagerDuty uses a JSON Schema $ref to reference a definition in $defs

  This is the bug: Claude Code's HTTP transport client isn't properly resolving JSON Schema $ref references when determining
  how to serialize parameters. When it sees an inline "type": "object", it parses the JSON string correctly. When it sees a
  $ref, it doesn't resolve it and treats the parameter as a string.

  This is definitely a Claude Code bug - it should resolve $ref references in tool schemas before deciding how to serialize
  parameters. Both approaches are valid JSON Schema.

  You should report this specific issue: "HTTP MCP transport doesn't resolve $ref in parameter schemas, causing JSON string
  parameters to not be parsed as objects."

What Should Happen?

The parameter should be treated as an object and not a string and the query should work.

Error Messages/Logs

● pagerduty - list_incidents (MCP)(query_model: "{\"limit\": 25}")
  ⎿  Error: Input validation error: '{"limit": 25}' is not of type 'object'

Steps to Reproduce

  1. Set up/find an MCP server that uses a $ref in its parameter scheme. The MCP server that PagerDuty hosts themself does this.
  2. Configure Claude Code to use it.
  3. Ask Claude Code to do something that would require passing such a parameter.
  4. You will get an error.

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.0.28 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

iTerm2

Additional Information

I asked Claude for the schemas of some of the broken PagerDuty functions.

 Example 1: list_incidents
  {
    "name": "mcp__pagerduty__list_incidents",
    "description": "List incidents with optional filtering...",
    "parameters": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "$defs": {
        "IncidentQuery": {
          "properties": {
            "limit": {
              "anyOf": [
                {"maximum": 1000, "minimum": 1, "type": "integer"},
                {"type": "null"}
              ],
              "default": 1000,
              "description": "Maximum number of results to return. The maximum is 1000"
            },
            "status": {
              "anyOf": [
                {
                  "items": {
                    "enum": ["triggered", "acknowledged", "resolved"],
                    "type": "string"
                  },
                  "type": "array"
                },
                {"type": "null"}
              ],
              "default": null,
              "description": "filter incidents by status"
            }
            // ... more fields
          },
          "type": "object"
        }
      },
      "properties": {
        "query_model": {"$ref": "#/$defs/IncidentQuery"}
      },
      "required": ["query_model"],
      "type": "object"
    }
  }

  Example 2: create_incident
  {
    "name": "mcp__pagerduty__create_incident",
    "parameters": {
      "$defs": {
        "IncidentCreateRequest": {
          "properties": {
            "incident": {"$ref": "#/$defs/IncidentCreate"}
          },
          "required": ["incident"],
          "type": "object"
        },
        "IncidentCreate": {
          "properties": {
            "title": {"type": "string"},
            "service": {"$ref": "#/$defs/ServiceReference"}
          }
        }
      },
      "properties": {
        "create_model": {"$ref": "#/$defs/IncidentCreateRequest"}
      }
    }
  }

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗