Skip to content

feat(core): parse JSON text results from MCP tools without an output schema - #48357

Merged
rekram1-node merged 1 commit into
v2from
codemode-parse-text
Sep 10, 2026
Merged

rekram1-node merged 1 commit into
v2from
codemode-parse-text

Conversation

@rekram1-node

@rekram1-node rekram1-node commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Most MCP servers return JSON serialized into a text content block with no structuredContent. Code mode handed the program a string, so this failed on every such tool and the model had to guess JSON.parse:

const result = await tools.github.list_issues({ repo })
result.issues.length        // TypeError — result is '{"issues":[…]}'

Agents assume JSON returned as text is already an object, so parse it for them. The change is in McpTool where the result's output is already chosen — the one place that sees structuredContent, the content blocks, and whether the server declared an outputSchema:

const output = () => {
  if (result.structured !== undefined) return result.structured
  if (text === "") return null
  // Agents assume JSON returned as text is already an object, so parse it when the server declares no schema.
  if (tool.outputSchema === undefined && (text.startsWith("{") || text.startsWith("["))) {
    try {
      return JSON.parse(text)
    } catch {}
  }
  return text
}
  • Structured output is used as is.
  • No outputSchema only. A declared schema is never second-guessed. Code mode already advertises schemaless MCP tools as Promise<unknown>, so the signature does not change.
  • Objects and arrays only. "42" or "null" as text stay text; anything that fails to parse stays text.

Scope

output is in-process only: the persisted tool state (ToolStateCompleted) has content, not output, and the model, TUI, and history all read content, which is unchanged. Only code mode programs see the parsed value.

Tests

test/mcp.test.ts: new demo.issues / demo.count / demo.typed fixtures. Through code mode, (await tools.demo.issues({})).issues[0].id works, count (text 42) stays a string, and typed (declares { type: "string" }) stays a string. A direct direct_issues call shows output parsed while content keeps the original text.

@rekram1-node rekram1-node changed the title feat(core): parse JSON text tool results in code mode feat(core): parse JSON text results from MCP tools without an output schema Sep 10, 2026
@rekram1-node
rekram1-node merged commit 929374c into v2 Sep 10, 2026
10 checks passed
@rekram1-node
rekram1-node deleted the codemode-parse-text branch September 10, 2026 20:20
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant