-
Notifications
You must be signed in to change notification settings - Fork 207
Description
Summary
mcporter currently unwraps any object that contains a data field and returns data directly during call-result parsing. This breaks tool responses whose payload shape includes both data and other meaningful fields such as status, error, summary, message, or meta.
In practice, an error payload like this:
{
"status": "error",
"summary": "Failed to create base: name is required",
"error": {
"type": "USER_ERROR",
"message": "Base name is required and cannot be empty or only whitespace",
"retryable": false,
"code": "INVALID_NAME"
},
"data": {},
"meta": {},
"trace_id": "trace-123"
}is rendered by mcporter as:
{}That output is misleading because the actual error fields are dropped before rendering.
Impact
- Users see
{}instead of the real error payload. - Structured error fields become inaccessible from
createCallResult().json(). - Tool failures can look like empty success-ish payloads, which makes debugging much harder.
- The issue affects multiple result paths, not just one rendering mode.
Affected Paths
The problem happens in the shared call-result parsing logic in src/result-utils.ts.
Current behavior:
- Objects with a
jsonfield are unwrapped tojson. - Objects with a
datafield are also unwrapped todata. - The
databranch does not check whetherdatais the only field.
That means these kinds of payloads are incorrectly collapsed:
structuredContentobjects that includedataplus error metadata- parsed JSON from text blocks
- parsed JSON from JSON content blocks
Root Cause
tryParseJson() treats any object containing data as a wrapper envelope and returns only record.data.
The code path effectively behaves like:
if ('data' in record) {
return record.data ?? null;
}That assumption is too broad. data is not always a transport envelope. In many APIs it is just one field among several top-level fields.
Expected Behavior
mcporter should only unwrap data when data is the only key in the object.
Expected rules:
- If an object has
json, unwrapjson. - If an object has only
data, unwrapdata. - If an object has
dataand any other keys, preserve the full object.
Reproduction
One minimal shape that reproduces the problem:
{
"content": [
{
"type": "text",
"text": "{\"status\":\"error\",\"summary\":\"Failed\",\"data\":{},\"meta\":{}}"
}
]
}Observed behavior:
createCallResult(response).json()returns{}.
Expected behavior:
createCallResult(response).json()returns the full parsed object withstatus,summary,data, andmeta.
Proposed Fix
Refine envelope unwrapping so data is only treated as an envelope when it is the sole field on the object.
Suggested logic:
if ('json' in record) {
return record.json ?? null;
}
if ('data' in record) {
return Object.keys(record).length === 1 ? (record.data ?? null) : record;
}Validation
Add regression coverage for both of these cases:
structuredContentwithdataplus error fields should preserve the full object.- Text or JSON content that parses into an object with
dataplus error fields should also preserve the full object.
Why This Matters
This bug hides the most important part of failed tool results: the actual error payload. For users debugging MCP integrations, seeing {} instead of the real error structure creates the false impression that the server returned nothing useful.