Repository navigation
Description
Summary
When using the Figma MCP server (mcp.figma.com/mcp) with OpenCode, get_design_context returns a large React+Tailwind code blob that routinely exceeds OpenCode's 50 KB / 2,000 line tool-output truncation limit. The full output is silently offloaded to a tool-output file and the model is left with a truncated preview. The model rarely reads the spill file, so frontend code generated from Figma silently diverges from the source design — missing nodes, wrong colors, dropped table rows, broken layout. This is the single biggest cause of "Figma-to-code fidelity is poor" reports and it is not a Figma MCP bug — it is OpenCode's generic tool-output truncation policy misfiring on MCP tool results.
Reproduction (concrete, just ran on v1.17.14)
opencodev1.17.14 on macOS, Figma MCP configured as remote (https://mcp.figma.com/mcp), authenticated via OAuth.- Created a Figma design file with a realistic dashboard: header + 4 KPI tiles (each with a 12-bar sparkline) + a 45-row data table + footer. ~390 nodes total. Not unusually complex — a single medium screen.
- Called
get_design_context(fileKey, nodeId=rootId, clientFrameworks=react, clientLanguages=typescript).
Result
- Full MCP tool output: 54,606 bytes / 1,060 lines (measured at
<REDACTED: local tool-output spill file>). - Truncation threshold (default):
MAX_BYTES = 50 * 1024= 51,200 bytes;MAX_LINES = 2_000. Byte cap fires first. - What the model actually received: the React/JSX code cut off mid-node at
Row/John Collison → <p>$0— i.e. the 41st of 45 table rows. The trailing ~3,414 bytes were dropped, which include:- the last 4 table rows (John Collison, Evan Spiegel, Bobby Murphy…),
- the footer,
- all the closing
</div>tags, - the Figma MCP metadata footer (
SUPER CRITICAL: ... convert to match target stack, asset URL declarations, node-id legend).
The truncation marker returned to the model:
...3414 bytes truncated...
The tool call succeeded but the output was truncated. Full output saved to: <REDACTED: user-local tool-output spill file path>
Use the Task tool to have explore agent process this file with Grep and Read (with offset/limit). Do NOT read the full file yourself - delegate to save context.
Observed downstream damage (why generated frontend "deviates from Figma")
When the model builds from the truncated preview, without reading the spill file:
- Missing nodes: the last ~10% of the subtree (rows, footer, trailing structure) simply do not exist in the model's view → they are missing in the generated React component.
- Broken JSX: the preview ends mid-
<p>with no closing tags. The model either hallucinates the rest or emits unbalanced markup. - Lost design-intent metadata: the Figma MCP footer that carries conversion hints and asset URLs is in the truncated tail, so image sources and "convert to your stack" guidance are gone.
- Color/spacing drift on larger files: at ~55 KB this repro is borderline. Real production Figma frames (full landing pages, dashboards with charts, multi-section marketing pages) easily hit 150–400 KB. There the head-preview still fits, but the model never sees the bulk of token bindings, variant props, or nested component structure — so it guesses, and the result is the "many data points deviate from the Figma reference" symptom the user reported.
- The hint doesn't help enough: the truncation message tells the model to
Task-delegate reading the spill file. In practice the model frequently skips that (it looks like a one-shot code gen task) and writes code from the head preview directly.
Root cause (source-confirmed)
In packages/opencode/src/session/tools.ts, every MCP tool result flows through:
const truncated = yield* truncate.output(textParts.join("\n\n"), {}, input.agent)
const metadata = {
...result.metadata,
truncated: truncated.truncated,
...(truncated.truncated && { outputPath: truncated.outputPath }),
}Truncate.output (packages/opencode/src/tool/truncate.ts) uses fixed defaults from packages/core/src/tool-output-store.ts:
export const MAX_LINES = 2_000
export const MAX_BYTES = 50 * 1024 // 50 KBWhen either threshold is exceeded, the full text is written to a tool-output/tool_<id> file and the model receives only a head/tail preview + a hint. For MCP tools that return structured, essential-to-fidelity payloads (Figma get_design_context, Playwright DOM snapshots, large DB query results, get_figjam, etc.), the 50 KB cap is far too low and the head-only preview is the wrong shape:
- The preview is the head of the payload, but for Figma the head is just the first few nodes — the structure is spread across the whole document, and the metadata footer is at the tail. Both are critical.
Readitself is capped at the same 50 KB (packages/opencode/src/tool/read.ts→MAX_BYTES = 50 * 1024), so even if the model reads the spill file, it gets re-truncated and has to page with offset/limit — which issue Tool output truncation loses the most important content (background_output synthesis drop, read offset ignored, grep head_limit bypassed) #33650 already notes is buggy (offset ignored when limit is large). So the recovery path is also broken.
Why this is worse for Figma than for e.g. Bash/Read
- Bash/Read output is usually linear text where the head or tail carries most of the signal — a head+tail preview is a reasonable summary.
- Figma
get_design_contextoutput is structured code + a metadata footer. Neither end is a summary; both ends carry distinct, non-redundant information (head = opening structure, tail = closing structure + conversion hints + asset map). A head-only preview loses ~50% of the signal even at 2× the threshold. - Figma MCP is also the canonical "design-to-code" path that the OpenCode skills (
figma-implement-design,figma-use) explicitly route throughget_design_context. So the truncation policy actively undermines a first-class documented workflow.
Expected behavior
- Raise the truncation threshold for MCP tool results, or make it per-tool/per-server configurable. 50 KB is a 2010-era limit; modern MCP tools (Figma, Playwright, Notion, Linear) routinely return 100–500 KB of structured JSON that is cheap to keep in context relative to its value. A saner default would be ~500 KB–1 MB, with a configurable cap.
- For MCP tools that return code/JSON, don't head-truncate — stream to file and pass a path, or send the whole thing when under the (higher) cap. The current "head preview + hope the model re-reads" pattern is the worst of both worlds: it costs a round-trip and still loses data.
- Make the recovery path actually work: if OpenCode is going to keep spill files,
Readmust respectoffset/limitreliably (see Tool output truncation loses the most important content (background_output synthesis drop, read offset ignored, grep head_limit bypassed) #33650 symptom 2) and the truncation hint should be framed as a hard requirement, not a suggestion the model can skip. - Surface truncation to the user in the TUI — currently the only signal is a line buried in the tool result that the model often ignores. A visible "⚠ tool output truncated, X bytes saved to Y, model may be missing data" indicator would let users catch silent fidelity loss.
- (Nice-to-have) Per-MCP-server overrides in
opencode.jsonso power users can bump Figma's limit without raising it for everything.
Environment
- OpenCode:
1.17.14(npmopencode-ai, darwin-arm64) - OS: macOS (darwin, Apple Silicon)
- Figma MCP: remote,
https://mcp.figma.com/mcp, OAuth-authenticated - Reproduction file: created via
create_new_file+use_figma(dashboard, 45-row table, ~390 nodes). Reproduces on any Figma frame whoseget_design_contextJSON exceeds ~50 KB — i.e. most real screens.
Workaround for affected users
Bump the limits in opencode.json under a tool_output document entry (undocumented but present in Config):
```jsonc
{
"tool_output": {
"max_bytes": 1048576, // 1 MB
"max_lines": 20000
}
}
```
This eliminates the truncation for the vast majority of Figma frames. But it's a global sledgehammer (also raises it for Bash/grep/etc.) and is not discoverable — most users hit the silent truncation first and conclude "Figma-to-code in OpenCode is just bad."
Related issues
- Tool output truncation loses the most important content (background_output synthesis drop, read offset ignored, grep head_limit bypassed) #33650 — truncation loses the most important content (background_output synthesis drop, read offset ignored, grep head_limit bypassed). Same family of bugs, different symptoms. The
Read-ignores-offsetsymptom there is the broken recovery path for this one. - tool-output spill files are not cleaned up and can consume tens of GB #29694 — tool-output spill files not cleaned up, consume tens of GB. Same spill-file mechanism.
- Read tool 50 KB byte cap undocumented in tool description - AI may edit based on incomplete content #30773 — Read tool 50 KB byte cap undocumented. Same
MAX_BYTES = 50 * 1024constant, same family.
Severity
High. This silently corrupts the most-hyped OpenCode workflow (Figma design-to-code) on any non-trivial screen, with no user-visible warning, and the documented recovery path (re-read the spill file) is itself broken. Users experience it as "the AI generates code that doesn't match my Figma" and blame either the model or Figma MCP — neither of which is at fault.
Activity
github-actions commentedon Jul 7, 2026
This issue might be a duplicate of existing issues. Please check:
MAX_BYTES = 50 * 1024threshold, the brokenReadoffset/limit recovery path, and the general pattern of tail-truncation losing critical content (which you've already cross-referenced).It may be worth checking whether one of those existing issues is the right place to track this, or if the Figma-specific angle (structured code + metadata footer, design-to-code workflow impact) warrants keeping it separate.
github-actions commentedon Sep 6, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.