-
Notifications
You must be signed in to change notification settings - Fork 59
feat: use structuredContent with outputSchema in example servers #220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
All servers now return structuredContent alongside JSON text content. All mcp-apps now read structuredContent directly (no JSON.parse fallback). Updated servers: - basic-server-vanillajs - budget-allocator-server - cohort-heatmap-server - customer-segmentation-server - integration-server - scenario-modeler-server - system-monitor-server - threejs-server - video-resource-server - wiki-explorer-server
Define output schemas for structuredContent validation:
- basic-server-vanillajs: { time: string }
- budget-allocator-server: BudgetDataResponseSchema
- cohort-heatmap-server: CohortDataSchema
- customer-segmentation-server: customers/segments schema
- integration-server: { time: string }
- scenario-modeler-server: templates/defaultInputs schema
- system-monitor-server: SystemStatsSchema
- threejs-server: { code, height }
- video-resource-server: { videoUri, description }
- wiki-explorer-server: { page, links, error }
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-wiki-explorer
commit: |
All servers now return structuredContent alongside JSON text content. All mcp-apps now read structuredContent directly (no JSON.parse fallback). Updated servers: - basic-server-vanillajs - budget-allocator-server - cohort-heatmap-server - customer-segmentation-server - integration-server - scenario-modeler-server - system-monitor-server - threejs-server - video-resource-server - wiki-explorer-server
Define output schemas for structuredContent validation:
- basic-server-vanillajs: { time: string }
- budget-allocator-server: BudgetDataResponseSchema
- cohort-heatmap-server: CohortDataSchema
- customer-segmentation-server: customers/segments schema
- integration-server: { time: string }
- scenario-modeler-server: templates/defaultInputs schema
- system-monitor-server: SystemStatsSchema
- threejs-server: { code, height }
- video-resource-server: { videoUri, description }
- wiki-explorer-server: { page, links, error }
c999ada to
a6c34d7
Compare
…contextprotocol/ext-apps into ochafik/structured-content
| const time = new Date().toISOString(); | ||
| const data = { time }; | ||
| return { | ||
| content: [{ type: "text", text: JSON.stringify({ time }) }], | ||
| content: [{ type: "text", text: JSON.stringify(data) }], | ||
| structuredContent: data, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm inclined to write this as either:
const data = { time: new Date().toISOString() };
return {
content: [{ type: "text", text: JSON.stringify(data) }],
structuredContent: data,
}; Or as:
const time = new Date().toISOString();
return {
content: [{ type: "text", text: time }],
structuredContent: { time },
}; depending on how strict we want to be about content vs structuredContent equivalence.
I also think we should update the Quickstart guide to match whatever basic-server-vanillajs does, because it links to it as the full example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Updated to match the quickstart pattern:
const time = new Date().toISOString();
return {
content: [{ type: "text", text: time }],
structuredContent: { time },
};The quickstart guide already uses this pattern (lines 127-132), so no changes needed there.
| const data = result.structuredContent as { time: string }; | ||
| return data.time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally, I wrote this as:
const { time } = (result.structuredContent as { time?: string }) ?? {};
return time ?? "[ERROR]";to handle potential type desync, though I don't feel too strongly about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Updated to use the defensive pattern:
const { time } = (result.structuredContent as { time?: string }) ?? {};
return time ?? "[ERROR]";This also matches what the quickstart guide shows (lines 223-224).
| content: [ | ||
| { | ||
| type: "text", | ||
| text: JSON.stringify(response), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Originally, this was richly formatted text — see 61cd4ed#diff-4360a472ed891e48c204f1cf177aec8fb637d96bff5047cba6a1e4a899971b1aL224-R270.
Not sure whether we care about restoring that for these examples.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restored! Added formatBudgetSummary that produces human-readable output like:
Budget Allocator Configuration
==============================
Default Budget: $100,000
Available Presets: $50,000, $100,000, $250,000, $500,000
Categories:
- Marketing: 25% default
- Engineering: 35% default
...
The structuredContent still contains the full data for the UI.
| ); | ||
|
|
||
| return { | ||
| content: [{ type: "text", text: JSON.stringify(data) }], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, originally this was richly formatted text: 61cd4ed#diff-681e498d6715bbf8d9931228b1e274db793e8898940120cdd812cd320fabf692L152-R179.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restored! Added formatCohortSummary that produces:
Cohort Analysis: 12 cohorts, 12 periods
Average retention: 45.2%
Metric: retention, Period: monthly
| customProjections: customScenario?.projections, | ||
| customSummary: customScenario?.summary, | ||
| }), | ||
| text: JSON.stringify(data), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restored! Added formatCurrency and formatScenarioSummary that produce:
SaaS Scenario Modeler
========================================
Available Templates:
🌱 Bootstrapped Growth: Low burn, steady growth, path to profitability
🚀 VC Rocketship: High burn, explosive growth, raise more later
...
Custom Scenario:
Ending MRR: $62.5K
ARR: $750.0K
Total Revenue: $678.2K
...
- Simplify server.ts to return plain time string in text content (not JSON), matching the quickstart guide pattern - Add defensive coding in mcp-app.ts with optional chaining and fallback to handle potential type mismatches gracefully
Restore the human-readable text formatting functions that were removed, providing meaningful summaries in the text content while keeping structuredContent for programmatic UI consumption: - budget-allocator-server: formatBudgetSummary with config overview - cohort-heatmap-server: formatCohortSummary with retention stats - scenario-modeler-server: formatScenarioSummary with financial metrics
Summary
Update all example servers to use
structuredContentfor typed tool outputs, with correspondingoutputSchemadeclarations.Changes:
Add
structuredContentto tool results - All servers now return structured data directly instead of requiring JSON.parse on the client sideAdd
outputSchemato tool definitions - Each tool now declares its output schema using Zod, enabling validation and documentationSimplify mcp-app clients - Clients now read
result.structuredContentdirectly instead of parsing JSON from text contentUpdated servers (10):
basic-server-vanillajs-{ time: string }budget-allocator-server-BudgetDataResponseSchemacohort-heatmap-server-CohortDataSchemacustomer-segmentation-server-{ customers, segments }integration-server-{ time: string }scenario-modeler-server-{ templates, defaultInputs, ... }system-monitor-server-SystemStatsSchemathreejs-server-{ code, height }video-resource-server-{ videoUri, description }wiki-explorer-server-{ page, links, error }Test plan
🤖 Generated with Claude Code