Skip to content

feat(mcp): type mcp block replies from declared output schemas - #9466

Open
waleedlatif1 wants to merge 4 commits into
stagingfrom
feat/mcp-output-schema
Open

waleedlatif1 wants to merge 4 commits into
stagingfrom
feat/mcp-output-schema

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

MCP servers may declare an outputSchema on a tool and return structuredContent (spec 2025-06-18), but Sim dropped the schema at discovery: McpClient.listTools copied only name, description and inputSchema, and the MCP block declared only content. So nothing showed a tool's reply shape, and a reference such as <mcp.structuredContent.status> failed validation even when the tool returned it. Anyone (or any agent) parsing an MCP reply had to guess field names.

This keeps the declared schema end to end and types the block's reply from it:

  • Discovery keeps outputSchema on McpTool. The discovery cache carries it, and managed connections persist it in their existing mcp_tools jsonb snapshot (a $type change only, no migration).
  • Surfaces: GET /api/v2/mcp-servers/{id}/tools (and so the CLI's mcp-servers tools list), mcp_list_operations, the editor's tool list, and the integration catalog (an optional field on the synced IntegrationCatalogResponse). The v2 tool shape is .strict(), so keeping the field without declaring it would have turned discovery into a 500; a route test pins that.
  • Typed output: the MCP block gains a hidden, server-managed toolOutputSchema sub-block, a structure-only snapshot (types, properties, items; no description strings, since block inputs are scanned for <…> references) bound to the server and operation it was taken for. The editor writes it when an operation is picked; applyWorkflowOperations writes it for API/Copilot edits through the same authorized discovery use cases, best effort and only when the snapshot is missing or stale. With a matching snapshot the block declares structuredContent beside content, so:
    • the run's reference check accepts declared fields (an omitted declared field resolves empty) and still rejects undeclared ones,
    • lint walks paths below structuredContent and names the declared fields (unknown-field … has no output field "structuredContent.onCall" … Declared fields: …),
    • workflows deps fills mock leaves under structuredContent with the declared skeleton.
  • Unchanged: a tool without a schema, an operation chosen at run time, a list action, or a snapshot for another server/operation leaves the block's outputs exactly as before. content is untouched for every workflow.

Companion: a mothership change adds the same optional outputSchema to the source of integration-catalog.ts and regenerates the CLI grammar (mcp-servers tools list shape). It will be linked once opened.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

Tests were written first and confirmed red against the current code, then green:

  • serializer/mcp-output-schema.test.ts: serializer → runtime schema → reference resolution (declared, omitted-declared, undeclared, and every "no typed output" case).
  • lib/workflows/editing/dangling-refs.test.ts: lint accepts declared paths, flags undeclared nested ones with the declared field list, unchanged without a schema.
  • lib/workflows/application/mcp-output-schemas.test.ts: edit-time snapshots (declared/undeclared, one discovery per server, stale snapshot replaced, references/list/empty skipped, active canonical member only, discovery failure keeps the edit, managed connections).
  • lib/mcp/client.test.ts, lib/internal/mcp/list-operations.test.ts, app/api/v2/mcp-servers/[mcpServerId]/tools/route.test.ts, lib/mothership/integrations/application/catalog.test.ts, lib/credentials/application/discover-managed-mcp-tools.test.ts, lib/mothership/agent-cli/engines.test.ts (deps).

Local: bun run lint:check, bun run type-check, bun run check:audits, check-block-registry.ts origin/staging, check:test-types, and the related Vitest suites (~11.5k tests across lib/mcp, lib/workflows, serializer, blocks, executor, lib/mothership, tools, MCP routes) all pass.

Reviewers: the snapshot binding in getMcpStructuredContentOutputs (only a snapshot for the block's current server and operation applies), and the edit-time discovery in apply-workflow-operations.ts (bounded at 10s, cache-aside, never fails the edit).

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

MCP servers may declare an outputSchema on a tool and return
structuredContent, but discovery copied only name, description and
inputSchema, so no surface showed a reply shape and the MCP block declared
only content. Agents building workflows guessed field names, and a
reference such as <mcp.structuredContent.x> failed validation even when the
tool returned it.

- Discovery keeps a declared outputSchema on McpTool; the tool cache carries
  it, and managed connections persist it in the existing mcp_tools jsonb
  snapshot (type only, no migration).
- Surfaced on GET /api/v2/mcp-servers/{id}/tools (and so the CLI's
  mcp-servers tools list), mcp_list_operations, the editor tool list, and the
  integration catalog (synced contract, optional field). The v2 tool shape is
  strict, so keeping the field without declaring it would have turned
  discovery into a 500.
- The MCP block gains a hidden, server-managed toolOutputSchema sub-block: a
  structure-only snapshot of the selected operation's schema, bound to the
  server and operation it was taken for. The editor writes it when an
  operation is picked; applyWorkflowOperations writes it for agent edits,
  through the same authorized discovery use cases, best effort and only when
  the snapshot is missing or stale.
- With a matching snapshot, the block declares a typed structuredContent
  output beside content, so the run's reference check, lint (which now walks
  paths below structuredContent and names the declared fields) and the tag
  paths all read the declared shape, and workflows deps fills mock leaves
  from it. Without one, outputs are exactly as before.
@vercel

vercel Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 30, 2026 4:39am UTC

Request Review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@greptile-apps

greptile-apps Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues remain.

Summary

Keeps MCP tools’ declared outputSchema through discovery and uses saved reply shapes to type structuredContent.

  • MCP tool listings now include each tool’s declared reply schema.
  • Picked MCP operations keep a snapshot of their reply shape.
  • Matching MCP schemas type structuredContent and check its field paths.
  • Workflow dependency mocks include declared MCP reply fields.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[MCP tool outputSchema] --> B[Discovery and stored tool lists]
  B --> C[Snapshot bound to server and operation]
  C --> D[Declared structuredContent fields]
  D --> E[Runtime references]
  D --> F[Reference lint]
  D --> G[Dependency mocks]
Loading

Reviews (4) · Last reviewed commit: "fix(mcp): carry a whole structuredConten..." · Reviewed by Greptile

Comment thread apps/sim/lib/workflows/blocks/outputs.ts Outdated
Comment thread apps/sim/lib/mcp/output-schema.ts Outdated
Comment thread apps/sim/lib/workflows/editing/lint.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 42 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/workflows/blocks/outputs.ts Outdated
Comment thread apps/sim/lib/mcp/output-schema.ts Outdated
Comment thread apps/sim/lib/workflows/application/mcp-output-schemas.ts
Comment thread apps/sim/lib/workflows/application/apply-workflow-operations.ts Outdated
Comment thread apps/sim/lib/mcp/output-schema.ts Outdated
Comment thread apps/sim/lib/workflows/editing/lint.ts
- Read the MCP target with the block's saved canonical modes in lint,
  workflows deps and effective outputs, so a dormant basic/advanced member
  never selects or drops the snapshot.
- Expand repeated bracket indices before the nested lint check, as the run
  resolves them.
- Stop expanding a schema once its node budget is spent and leave that object
  open, instead of saving an untyped node per remaining field.
- Keep every declared field name, constructor and __proto__ included.
- Snapshot only blocks the edit changed, and discover best effort, so an
  unreachable server neither slows unrelated edits nor gets marked unhealthy.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 42 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/mothership/agent-cli/engines/deps.ts
Comment thread apps/sim/lib/mcp/output-schema.ts
…__ fields safely

workflows deps now adds an operation's declared fields wherever a consumer reads a structuredContent value whole, beside the paths it reads by name. Trigger mock payloads define sampled fields with Object.fromEntries, so a declared __proto__ field stays a field instead of replacing the sample's prototype.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 44 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/mothership/agent-cli/engines/deps.ts
A whole read now adds every declared field below it, through nested objects and array items, even where the consumer also reads a nested path by name.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 44 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Turn on auto-fix | Re-trigger cubic

This branch was previously deployed

1 inactive deployment
Preview — abe2ffd2 Deployed Oct 30, 2026 by vercel[bot]
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