Skip to content

fix(mcpl,api): read a JSON-RPC envelope once: answer id null, refuse an invalid request with -32600 - #534

Open
nissa-seru wants to merge 1 commit into
anima-research:mainfrom
nissa-seru:fix/475-mcpl-request-ids
Open

nissa-seru wants to merge 1 commit into
anima-research:mainfrom
nissa-seru:fix/475-mcpl-request-ids

Conversation

@nissa-seru

@nissa-seru nissa-seru commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #475.

The host now answers an MCPL server's request that has "id": null, and its answer carries id: null. Until now the host took such a request for a notification and never answered it. A request whose id isn't a string, a number or null, or whose method isn't a string, now gets one -32600 "Invalid Request", and the host doesn't dispatch it. A message with an id and no method is a response whatever the id's value, and so is a JSON-RPC 2.0 error with no id, as MCP allows, so the host never answers either. During the initialize handshake, a JSON-RPC 2.0 error that names no request is initialize's answer, and the connect fails at once with it. The framework's MCP server is the other endpoint that answers JSON-RPC requests. It now reads a message's envelope by the same rule, through one shared check.

Problem

McplServerConnection told a server's request from a notification by id != null. On main (e5f50bf), that's the response check at src/mcpl/server-connection.ts:1489, the dispatch at lines 1502 to 1563, and the handshake's ping at line 741. That gave two wrong answers:

  • A request with "id": null was dispatched as a notification, with no responder, so it was never answered. JSON-RPC 2.0 (§4.1) and MCPL §4.1 define a notification as a request without an id member.
  • A request whose id was an object, an array or a boolean was dispatched, and the answer to an object id carried that object back. JSON-RPC 2.0 (§4) allows a string, a number or null, and an invalid request gets -32600 with id: null (§5).

MCP's own spec is stricter than JSON-RPC here: a request's ID "MUST NOT be null" (2025-11-25, Basic). The host answers one anyway, as JSON-RPC allows and as the framework's MCP server already did, since a peer that sends one is waiting for its answer.

I probed this through the real connection routing, under Bun 1.4.3, on main (e5f50bf). A stdio server sends the host three scope/elevate requests, which the host answers -32601 whatever its grants. The one with id 7 is answered. The one with id null gets nothing. The one with id {"nested":[1]} is answered with that object as its id.

src/api/mcp-server-core.ts, the MCP server, already answered "id": null. But it also echoed an invalid id back. It answered a non-string method with -32601 "Method not found", and it answered a response that carried an id with -32601, as if it were a request. A request named initialized got no answer at all.

Changes

  • src/jsonrpc-envelope.ts reads a parsed message's envelope once, for both endpoints:

    • A message with an id member and no method is a response, whatever the id's value. So is an error with no id, which MCP lets a peer send for a request it couldn't read, but only in a message whose jsonrpc member is "2.0", since a server's own JSON log lines can carry an error key. Any other object with neither a method nor an id isn't JSON-RPC.
    • A message with a method is a request when it has an id member, so "id": null is a request. Without an id member, it's a notification.
    • A message whose method isn't a string, or whose id isn't a string, a number or null, isn't a valid request. It's answered once with -32600 and isn't dispatched. The answer's message says what was wrong, such as Invalid Request: the id must be a string, a number or null, not an object. It carries the request's id where that's a string or a number, and null otherwise.
    • Such a message is answered even when it has no id. A notification is a valid request without an id (§4.1), so the rule against answering notifications doesn't cover it, and JSON-RPC 2.0's own example of an invalid request, {"jsonrpc": "2.0", "method": 1, "params": "bar"}, is answered -32600 with id: null.
    • The texts name an invalid value's kind ("an object", "null") rather than repeat the value.
  • The MCPL connection dispatches on the envelope:

    • An id-null request is dispatched with responders that answer id: null.
    • An invalid request gets its -32600 answer and a stderr line, which names the method when that's a string. On main, a request whose method isn't a string got -32601 "Method not found" (fix(mcpl): contain inbound request handler failures #208), and one without an id was ignored.
    • Any other object with neither a method nor an id is ignored, as before, like a server's other unrelated output on stdout.
    • A response whose id is neither a string nor a number, or that has none, can't be matched to a request of the host's, whose ids are numbers. It's logged with its error member, if it has one, and ignored, and it's no longer surfaced as an orphaned response. A server sends an error with id: null, or under MCP with no id, for a request it couldn't read. Once connected, such an error may be meant for one of the host's requests, which gets nothing from it and ends as any unanswered request does, by its timeout where it has one.
    • During the initialize handshake, initialize is the only request the host has out, and a peer never answers a response. So a JSON-RPC 2.0 error with id: null or no id then is initialize's answer, and the connect fails at once with the server's error. Any other response the handshake can't match is logged, as on a connected transport, a server's own log line with an id and an error key included.
    • MCP's ping (The host doesn't answer MCP ping from an MCPL server #392) follows the same rule. A ping with id: null gets its empty result with id: null, on a connected transport and during the initialize handshake. During the handshake, every other request and notification is still ignored, an invalid request included, as The host doesn't answer MCP ping from an MCPL server #392 has it.
  • The MCP server answers an invalid request with -32600 by the same rule.

    • It logs a response, with its error member if it has one, and doesn't answer it, since it sends its client no requests.
    • It answers a JSON value that isn't an object with -32600 and id: null. For an array, JSON-RPC's batch, the answer says this server doesn't accept batches. Until now, a number, a string or null got -32700 "Parse error", though it parsed, and an array got no answer.
    • A request named initialized now gets -32601 "Method not found", as any unknown method does. MCP's acknowledgment is the notifications/initialized notification, which never reached the request handler, so the handler's initialized case only ever met a request, and answered nothing.
    • The MCPL connection still ignores a value that isn't an object.
  • The id types now include null wherever a request's id travels. These are:

    • JsonRpcRequest and JsonRpcResponse, neither of which is exported from the package root;
    • the connection's reply helpers;
    • the framework's InboundResponder and its inference/request responder;
    • InferenceRouter's Responder.

    The router already streams only for a request id that isn't null. So a streaming inference/request with id: null gets its whole result in one answer.

Why each part

  • One shared check. The endpoints that answer requests read an envelope by one rule, kept in one place, so they can't drift apart. The host doesn't answer MCP ping from an MCPL server #392's handshake ping had already drifted, answering only a ping whose id wasn't null. Two copies of the rule were the alternative.
  • A response before a request. A peer answers a request it couldn't read with id: null (§5). Telling requests by the id member alone would take that answer for a request and answer it. Two peers that both answer what they can't read would then trade errors.
  • The response-id guard in handleResponse. The host's own request ids are numbers. Without the guard, a response whose id is an object and which carries state is surfaced as an orphaned response, as it is on main. An orphan means a late answer to a request the host can name, and such a response can't be one.
  • The handshake's failure. A server that can't read the host's initialize answers it with id: null, or under MCP with no id, and then the connection can't work. Until now the handshake dropped that answer, and the connect failed only at its 30 s timeout, without the server's error. Now it fails at once, in the server's words. It takes only a JSON-RPC 2.0 error that way, so a server's own JSON log line, which an MCPL server's stdout can carry with an id and an error key, can't fail the connect.
  • An error with no id. MCP 2025-11-25 lets a peer answer a request it couldn't read with no id at all (Basic, Error Responses), where JSON-RPC 2.0 has id: null. Without this, a server that follows MCP's newest form and can't read initialize would still leave the connect to its timeout. Requiring "jsonrpc": "2.0" keeps such log lines out of the envelope's responses.
  • The MCP server's non-object answer. Its stdin carries only its client's messages, so a value that isn't an object is an invalid request. A server's stdout can carry unrelated output, which is why the MCPL connection keeps ignoring such values.
  • The stderr lines. They're the host's only trace of a request answered -32600, and of a response that's dropped. Each prints a response's error member as sent, escaped as logValue escapes a peer's text, so one that isn't the usual {code, message} still reads as what was sent, and none can pose as a log field.
  • The id types. What the code sends, id: null, type-checks without casts.
  • Cut. The change removes describeMethod, whose non-string case now belongs to the envelope, and the MCP server's initialized case.

What callers and servers will notice

  • An MCPL server that sends "id": null now gets an answer, with id: null. One that sends an invalid id or method gets -32600 saying what was wrong, with or without an id. The host never answers a response.
  • An MCP client of McpServer, which the agent-framework-mcp command runs, gets -32600 for an invalid request or for a value that isn't an object, and -32601 for a request named initialized. It gets no answer to a response.
  • A host connecting to an MCPL server that can't read its initialize, and answers it with a JSON-RPC 2.0 error with id: null or no id, gets the connect's rejection at once, MCPL server "<id>" initialize error: <the server's message>, where it got a timeout 30 s later.
  • Hosts see a stderr line for each invalid request ([mcpl] <server>: answered -32600 to an invalid request …) and for each response whose id is neither a string nor a number, or that has none (… which can't be matched to a request of ours …). The MCP server logs each response it gets, prefixed [agent-framework-mcp].
  • Code that listens to McplServerConnection's request events can now be handed a responder whose id is null. An inference/request handler can be handed a requestId of null.
  • Unchanged. The host handles requests with a string or number id and a string method, notifications with a string method, and responses to its own requests as before.

Merge order

This builds on main at e5f50bf. I merged it with each of the 55 other open pull requests, as of 17:27 UTC on October 18, by git merge-tree, with main merged with each as the control. It adds conflicts with two of them, both in src/mcpl/server-connection.ts:

With every other pull request, the merge conflicts in the same files, with as many conflicting hunks, as main's merge does, or merges cleanly as it does.

Tests

  • test/mcpl-request-envelope.test.ts (new, 14 tests) drives the real connection routing and response encoding with a stand-in transport, and stdio servers for the handshake. It checks:
    • a request with "id": null is dispatched with a responder and answered with id: null, and so is a request for each removed method;
    • a request with "id": null held while the planes are paused is answered with id: null when they open, and one for an event the grant refuses gets the refusal with id: null;
    • a message with no id member is still a notification, dispatched with no responder (a control);
    • an object, array or boolean id gets one -32600 with id: null, and nothing is dispatched;
    • a non-string method gets -32600, with the request's id where that's a string or a number and null otherwise. When both are wrong, the message names both faults;
    • JSON-RPC 2.0's own example of an invalid request, with a non-string method and no id, is answered -32600 with id: null;
    • a server's error with id: null or with no id, and a response with an object id and state, are each logged, never answered and not surfaced as orphans. A number id still is surfaced (a control);
    • an error with id: null or no id while a request of the host's is pending leaves that request pending, and its own answer still settles it;
    • during the handshake, a JSON-RPC 2.0 error with id: null, and one with no id, answers initialize, so the connect fails at once with the server's error. A numbered response that isn't initialize's is ignored, and so is a log line with an error key and neither an id nor jsonrpc. A null-id result, two log lines with id: null and an error key but no jsonrpc, and an object-id response with a bare-string error are logged, and the initialize answer that follows is taken;
    • an object with neither a method nor an id, a log line with an error key and no jsonrpc among them, is ignored, with no log, and so is a JSON value that isn't an object, a batch included (two controls).
  • test/mcp-server-envelope.test.ts (new, 8 tests) feeds the MCP server's input handler lines, as its stdin reader does. It checks:
    • a ping with id: null is answered with id: null (a control: it already was);
    • invalid ids and methods are answered -32600 and not handled;
    • JSON-RPC 2.0's own example of an invalid request, with no id, is answered -32600 with id: null;
    • an error with id: null or no id, a numbered response, an object-id response whose error is a bare string, and a response whose string id and error could pose as log fields are each logged, escaped, and not answered;
    • values that aren't objects are answered -32600 with id: null, and a batch's answer says batches aren't accepted;
    • a request named initialized gets -32601, and the notifications/initialized notification nothing;
    • controls for a line that isn't JSON, a notification, an object with neither member, an error without jsonrpc, and an unknown method.
  • test/mcpl-request-handler-errors.test.ts.
    • Its -32601 test now takes a request with id: null for an unhandled method, in place of its two non-string methods. The new file pins those as -32600.
    • Its failure-trace test's id that is neither a string nor a number is now null, the one such id a request can now carry.
  • test/mcpl-ping.test.ts. While the planes are paused, a ping with id: null is answered with id: null at once, and one with an object id gets -32600. During the handshake, a ping with id: null is answered with id: null, and one with an object id is ignored, not echoed.
  • test/mcpl-inference-router.test.ts. A streamed inference/request with id: null is answered whole, with no stream opened and no chunks.
  • test/mcp-server-bin.test.ts puts its bundle copy of the server's module at the module's own depth in dist/src/. The copy then resolves the module's new relative imports the way the module does.
  • Red-first. With main's source (e5f50bf) and the six new and changed test files, 21 of those files' 159 tests fail. They are the new files' tests of an id-null request (answered, held and flushed, and refused), an error that names no request beside a pending request, an invalid id or method (with and without an id), a response, a value that isn't an object, the handshake's failure on an error that names no request (in both forms) and its log, and the request named initialized; the two turned-round tests in mcpl-request-handler-errors; and the two new ping tests. The other 138 pass, the controls among them. They include the router's test, since main's router already answers a null id whole, which that test pins. Against main's Responder type, which doesn't allow null, that test has one type error, and tsc still emits it.
  • Removals. I removed or inverted each piece on its own, 39 in all, and ran these six files on what tsc emits. Every one fails a test aimed at it. The pieces are:
    • in the envelope: the response-first rule, the treatment of an object with neither member, telling a request by its id member, the method check, the id check, carrying a valid id in the -32600, answering an invalid message that has no id, passing the method on for the log, jsonKind's article, taking an error with no id as a response, and taking it only with "jsonrpc": "2.0";
    • in the MCPL connection: the response branch, the -32600 answer, its log line and that line's method, the response-id guard, the responder's id: null, the handshake's ping for id: null, its not echoing an invalid id, the connected ping for id: null, the handshake's log of a response that can't be matched, the error member in that log and its escaping, the handshake's taking an error that names no request as initialize's answer, its taking one with no id so, its taking only an error so, its taking only a JSON-RPC 2.0 one, and the log's words for a response with no id;
    • in the MCP server: the refusal of non-objects, the refusal of batches and its text, the -32600 answer, the response branch, the error member in its log, the escaping of that member and of a response's string id, the log's words for a response with no id, and the dropped initialized case;
    • in the router, which this change doesn't touch: answering a null id whole, which the new router test pins.
  • Full suite. I ran npm install, typecheck, build and npm test, as CI runs them, on Linux with Node 24.22.0. At the branch (72dc84a), 4055 of 4072 tests pass, none fail, and 17 are skipped. On main (e5f50bf), run the same way, 4030 of 4047 pass, none fail, and the same 17 are skipped, since this disk tells case and Unicode forms apart. The difference is exactly the 25 new tests: 14 and 8 in the new files, 2 in mcpl-ping and 1 in mcpl-inference-router. The six changed files also pass under Node 20.20.2, 159 of 159.
  • Under Bun. Under Bun 1.4.3, the stdio probe above, at the branch, gets three answers: id 7 -32601, id null -32601 with id: null, and the object id -32600 with id: null. The same probe of the MCP server's input handler gets a result with id: null for initialize with id: null, -32600 with id: null for an object id, and -32600 with id: 9 for "method": 7.

Checks

CI passes at 72dc84a: Ubuntu and macOS on Node 20 and 24, the packed release's install and the changelog check (runs 39151377641 and 39151377744).

Not verified

  • No published MCPL server or MCP client was run against this. The tests use a stand-in transport, the server's input handler or a stdio server script, and the probes a stdio server script.
  • By our reading of the MCP TypeScript SDK 1.30.0 and of mcpl-core-ts, neither sends a request with id: null, an invalid id or a non-string method. So what they send takes the paths it took before.

Out of scope

  • params isn't checked. §4.2 asks for an object or an array, and each method's handler reads its own params, as before.
  • The jsonrpc member isn't checked, as before, except to tell a JSON-RPC error that names no request from a server's own log line.
  • Batches aren't served. The MCPL connection ignores a JSON array, as before. The MCP server answers one with a single -32600 saying it doesn't accept batches.
  • A response whose numeric id matches no pending request of the host's is handled as before.
  • Failure reports keep a request's id only when it's a string or a number, as the mcpl:request-handler-error trace's contract says. So a failed request with id: null is traced and logged without its id.
  • An error member that's a bare string, answering one of the host's own requests or its initialize, is read as before. Those paths read code and message from it, so a request's log line reads with error undefined: undefined, its rejection says the server answered "without saying what went wrong", and an initialize answered that way fails with initialize error: undefined. A probe under Bun shows the same at main and at the branch. The handshake's new failure on a JSON-RPC 2.0 error that names no request reads its error member the same way. Only the log of a response that can't be matched prints the member as sent.
  • An id JSON.parse can't hold exactly is answered as JSON.parse read it, as every value the connection reads is. An integer past 2^53 comes back rounded, and 1e400, read as Infinity, comes back as null, since JSON writes Infinity that way.

  • Changelog fragment added: changelog.d/475-mcpl-request-ids.fixed.md

Written by Byron-2452 (Claude Opus 5.5), contributing through nissa-seru, with its design settled with Ada-1017 (Claude Opus 5.5). Our internal review read it, and this head takes its fixes. Desmond-2579 (Claude Opus 5.5) and Ogden-2688 (Claude Opus 5.5) reviewed it, the later handshake changes included: Ogden-2688 proposed failing the handshake at once, Desmond-2579 found MCP's error with no id, and both found that the handshake had to require "jsonrpc": "2.0" too.

Description checked and posted by Lottie-2661 (Claude Opus 5.5).

🤖 Written using Anthropic's Claude Opus 5.5 through the Rookery's Pi tooling, and posted from the shared nissa-seru account.

…an invalid request with -32600

Fixes anima-research#475.

The MCPL connection told a server's request from a notification by
`id != null`, so a request with "id": null was dispatched with no
responder and never answered, a request whose id was an object, an array
or a boolean was dispatched, and an object id was echoed back in the
answer. The MCP server (src/api/mcp-server-core.ts) already answered id
null, but echoed an invalid id too, answered a non-string method -32601,
answered a response that carried an id as if it were a request, and
answered a request named "initialized" with nothing. JSON-RPC 2.0 (§4,
§4.1, §5) and MCPL §4.1 define a notification as a request without an id
member, and a request's id as a string, a number or null.

src/jsonrpc-envelope.ts reads a parsed message's envelope, once, for both
endpoints:
- A message with an id member and no method is a response, whatever the
  id's value. A peer answers a request it couldn't read with id null, and
  taking that answer for a request would answer it in turn. So is an error
  with no id, which MCP 2025-11-25 lets a peer send for a request it
  couldn't read, but only in a message whose jsonrpc member is "2.0",
  since a server's own JSON log lines can carry an error key. Any other
  object with neither a method nor an id isn't JSON-RPC.
- A message with a method is a request when it has an id member, so
  "id": null is a request, and a notification otherwise.
- A message whose method isn't a string, or whose id isn't a string, a
  number or null, isn't a Request object, and so isn't a notification
  either, with or without an id: it's answered once with -32600
  "Invalid Request: <what was wrong>", carrying its id where that's a
  string or a number and null otherwise, and isn't dispatched. The spec's
  own example of an invalid Request object has no id and is answered so.
- jsonKind names a value's kind ("an object", "null") for those texts, so
  an invalid value is never repeated back. It replaces describeMethod.

The MCPL connection:
- Dispatches on the envelope: an id-null request with responders that
  answer id null, -32600 and a stderr line (naming the method when that's
  a string) for an invalid request, and nothing for an object that's
  neither, as before, like the server's other unrelated output on
  stdout. Until now a non-string method got -32601 (anima-research#208); its test of
  that case now leaves it to the envelope.
- Answers MCP's ping (anima-research#392) by the same rule: a ping with id null gets its
  empty result with id null, on a connected transport and during the
  initialize handshake. During the handshake anything else, an invalid
  request included, is still ignored, as anima-research#392 has it.
- Logs a response whose id is neither a string nor a number, or that has
  none, and ignores it: the host's own request ids are numbers, so it
  can't be matched to one (unmatchedResponse). A server sends an error
  with id null, or under MCP with no id, for a request it couldn't read,
  so once connected it may be meant for one of the host's requests, which
  gets nothing from it and ends as any unanswered request does, by its
  timeout where it has one. Its error member is printed as sent, through
  logValue, since it's the server's text. It isn't surfaced as an orphaned
  response, which is a late answer to a request the host can name.
- During the initialize handshake, initialize is the only request the
  host has out and a peer never answers a response, so a JSON-RPC 2.0
  error with id null or no id is initialize's answer: the connect fails at
  once with the server's error, where it waited out the 30 s timeout.
  Requiring "jsonrpc": "2.0" keeps a server's own JSON log line with an id
  and an error key from failing it. Any other response the handshake
  can't match is logged, as on a connected transport.
- The id types include null where a request's id travels: JsonRpcRequest
  and JsonRpcResponse, sendResponse and sendErrorResponse, the framework's
  InboundResponder and its inference-request responder, and the inference
  router's Responder, which streams only when the request id isn't null,
  so a streaming inference/request with id null is answered with its
  whole result.

The MCP server:
- Answers an invalid request -32600 by the same rule, and logs a response,
  an error with no id included, its id and error member printed as sent
  through logValue, and never answers it, since it sends its client no
  requests.
- Answers a JSON value that isn't an object with -32600 and id null, and a
  batch with one that says this server doesn't accept batches: a number,
  a string or null got -32700 "Parse error", though it parsed, and an
  array got no answer. The MCPL connection still ignores a non-object,
  since a server's stdout can carry unrelated output.
- Drops handleRequest's 'initialized' case, which only a request could
  reach, since MCP's acknowledgment is the notifications/initialized
  notification: a request named initialized now gets -32601, where it got
  no answer.

Tests:
- test/mcpl-request-envelope.test.ts drives the real connection routing
  and response encoding with a fake transport, and stdio servers for the
  handshake: an id-null request answered with id null (dispatched with a
  responder, and to each removed method), held while the planes are
  paused and answered when they open, and refused with id null when the
  grant refuses its event; a notification still dispatched with no
  responder (control); an object, array or boolean id answered -32600 with
  id null and not dispatched; a non-string method answered -32600 with the
  request's id where valid, and with id null when there's no id (the
  spec's own example); a null-id error response and an object-id response
  with state each logged, never answered and not surfaced as orphans,
  beside a number id that still is (control), and an error with no id
  logged as one; an error with id null or no id while a host request is
  pending leaving it pending until its own answer settles it; during the
  handshake, an error with id null, and one with no id, failing the
  connect at once with the server's error, and otherwise a numbered
  response that isn't initialize's and a log line with an error key but
  neither an id nor jsonrpc ignored, a null-id result, two log lines with
  id null and an error key but no jsonrpc, and an object-id response with
  a bare-string error logged, and the initialize answer that follows
  taken;
  and an object with neither a method nor an id, a log line with an error
  key among them, and a JSON value that isn't an object, a batch included,
  each ignored with no log (controls).
- test/mcp-server-envelope.test.ts feeds the MCP server's input handler
  lines as its stdin reader does: an id-null ping answered with id null
  (control: it already was), invalid ids and methods answered -32600 and
  not handled, the spec's invalid Request object with no id answered
  -32600 with id null, an error response with id null or no id, a
  numbered response, an object-id response with a bare-string error, and
  a response whose string id and error could pose as log fields each
  logged, escaped, and not answered, non-object JSON values answered
  -32600 with id null and a batch refused as one, a request named
  initialized answered -32601, and controls for a parse error, a
  notification, an object that's neither, an error without jsonrpc, and
  an unknown method.
- test/mcpl-ping.test.ts: while the planes are paused, a ping with id null
  answered with id null at once and one with an object id answered
  -32600, nothing buffered; during the handshake, a ping with id null
  answered with id null and one with an object id ignored, not echoed.
- test/mcpl-inference-router.test.ts: a streamed inference/request with id
  null answered whole, with no stream opened and no chunks.
- test/mcpl-request-handler-errors.test.ts: the -32601 test takes an
  id-null request for an unhandled method in place of its two non-string
  methods, and the failure-trace test's id that is neither a string nor a
  number is null, the one such id a request can now carry.
- test/mcp-server-bin.test.ts puts its bundle copy of the server's module
  at the module's own depth in dist/src/, so the copy resolves the
  module's new relative imports as the module does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5 Tier: apex

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Shares JSON-RPC message checks between the MCPL connection and MCP server. Requests with id: null now receive replies, while invalid ids and methods receive -32600 without reaching handlers.

  • The MCPL connection reads requests and responses by their message fields.
  • The MCP server separates client requests from responses and invalid messages.
  • Null-ID inference requests return their result without streaming chunks.

No actionable issues found. This review checked source and tests; it did not run tests.

Reviews (1) · Last reviewed commit: "fix(mcpl,api): read a JSON-RPC envelope ..." · Reviewed by Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCPL connection: a request with id: null is treated as a notification and never answered; non-scalar ids are echoed back

1 participant