fix(mcp): accept reserved _meta field in tools/call params (#2670)

* fix(mcp): accept reserved _meta field in tools/call params

The memory MCP server rejected any tools/call whose params contained a key
other than name/arguments, returning -32602 "Unknown or missing memory tool."

MCP clients (e.g. Claude Code) attach the spec-reserved `_meta` field
(such as progressToken) to request params, so every tool call from a
compliant client failed and the entire memory MCP surface was unreachable —
even though initialize/tools-list and the `ecc memory` CLI kept working.

Per the MCP base protocol, `_meta` is reserved for request metadata and
must be accepted. Add it to the params key allowlist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(mcp): validate _meta shape and cover tools/call param allowlist

Address CodeRabbit review on #2670:
- Validate params._meta when present: accept metadata objects, reject null,
  arrays, and scalar values (reuses isRecord). Keeps _meta optional and
  preserves existing name/arguments/unexpected-key rejection.
- Add regression tests: accept _meta with progressToken, reject malformed
  _meta values, and continue rejecting unrelated top-level params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Yowon Jeong
2026-08-04 00:28:09 -04:00
committed by GitHub
co-authored by Claude Opus 4.8
parent ab373716e7
commit 7b76082b13
2 changed files with 39 additions and 1 deletions
+4 -1
View File
@@ -437,7 +437,10 @@ function createMemoryMcpService(options = {}) {
!isRecord(params)
|| typeof name !== 'string'
|| !TOOL_BY_NAME.has(name)
|| Object.keys(params).some(key => !['name', 'arguments'].includes(key))
// `_meta` is reserved by MCP for request metadata (e.g. progressToken); accept it,
// but when present it must be a metadata object — reject null, arrays, and scalars.
|| (Object.prototype.hasOwnProperty.call(params, '_meta') && !isRecord(params._meta))
|| Object.keys(params).some(key => !['name', 'arguments', '_meta'].includes(key))
) {
return jsonRpcError(message.id, -32602, 'Unknown or missing memory tool.');
}