Skip to content

Undefined property Notification::$id at Protocol.php:123 → HTTP 500 when a client sends a JSON-RPC notification (dev-main) #84

Description

@onerealkewlguy

Summary

src/Protocol.php:123 accesses ->id on a PhpMcp\Schema\JsonRpc\Notification, which by JSON-RPC 2.0 spec has no id (that's exactly what distinguishes a notification from a request). In a strict/production PHP environment this "Undefined property" notice is promoted to an ErrorException, so the request aborts with an HTTP 500. Any MCP client that sends a notification (e.g. notifications/initialized immediately after the initialize handshake) trips it, which can take down the whole session — every subsequent method call then 500s.

Error

production.ERROR: Undefined property: PhpMcp\Schema\JsonRpc\Notification::$id
{"exception":"[object] (ErrorException(code: 0): Undefined property: PhpMcp\Schema\JsonRpc\Notification::$id
  at .../vendor/php-mcp/server/src/Protocol.php:123)
#0 .../Illuminate/Foundation/Bootstrap/HandleExceptions.php(256):
     Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'Undefined prope...', '.../Protocol.php', 123)

Version

php-mcp/server dev-main (as vendored by the Leantime MCP-server plugin).

Environment / how it surfaced

  • Self-hosted Leantime (Laravel 11) with its MCP-server plugin, PHP 8.x, APP_ENV=production (where undefined-property notices become ErrorExceptions and fault the request).
  • The MCP protocol endpoint returns HTTP 500 on every method call from a client that sends a notification. Observed with a standard MCP stdio bridge that sends notifications/initialized right after initialize.
  • Leantime's separate non-MCP JSON-RPC endpoint (/api/jsonrpc) is unaffected — only the MCP protocol path (Protocol.php) fails, which points at notification handling rather than the app.

Likely cause / suggested fix

Protocol.php reads $message->id without distinguishing a Request (has id) from a Notification (no id). A guard before the property access would fix it — e.g. branch on the message type (instanceof Request) before reading id, or read it defensively ($id = $message instanceof Notification ? null : $message->id;). Notifications should be dispatched without ever touching id.

Happy to test a patch against this setup if useful.

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