Skip to content

Commit 61cd4ed

Browse files
Use content instead of structuredContent in examples
Not all MCP clients support structuredContent in MCP tool results, so examples now return data as JSON in content and parse it client-side. Pattern used: - Server: content: [{ type: "text", text: JSON.stringify(data) }] - Client: JSON.parse(result.content!.filter(...).map(...).join("")) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 45259c5 commit 61cd4ed

File tree

14 files changed

+65
-150
lines changed

14 files changed

+65
-150
lines changed

examples/basic-server-react/server.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import cors from "cors";
55
import express, { type Request, type Response } from "express";
66
import fs from "node:fs/promises";
77
import path from "node:path";
8-
import { z } from "zod";
98
import { RESOURCE_URI_META_KEY } from "../../dist/src/app";
109

1110
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3001;
@@ -30,14 +29,12 @@ const server = new McpServer({
3029
title: "Get Time",
3130
description: "Returns the current server time as an ISO 8601 string.",
3231
inputSchema: {},
33-
outputSchema: { time: z.string() },
3432
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
3533
},
3634
async (): Promise<CallToolResult> => {
3735
const time = new Date().toISOString();
3836
return {
39-
content: [{ type: "text", text: time }],
40-
structuredContent: { time },
37+
content: [{ type: "text", text: JSON.stringify({ time }) }],
4138
};
4239
},
4340
);

examples/basic-server-react/src/mcp-app.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ const log = {
2020

2121

2222
function extractTime(callToolResult: CallToolResult): string {
23-
const { time } = (callToolResult.structuredContent as { time?: string }) ?? {};
24-
return time ?? "[ERROR]";
23+
const text = callToolResult.content!
24+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
25+
.map((c) => c.text)
26+
.join("");
27+
const { time } = JSON.parse(text) as { time: string };
28+
return time;
2529
}
2630

2731

examples/basic-server-vanillajs/server.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import cors from "cors";
55
import express, { type Request, type Response } from "express";
66
import fs from "node:fs/promises";
77
import path from "node:path";
8-
import { z } from "zod";
98
import { RESOURCE_URI_META_KEY } from "../../dist/src/app";
109

1110
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3001;
@@ -30,14 +29,12 @@ const server = new McpServer({
3029
title: "Get Time",
3130
description: "Returns the current server time as an ISO 8601 string.",
3231
inputSchema: {},
33-
outputSchema: { time: z.string() },
3432
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
3533
},
3634
async (): Promise<CallToolResult> => {
3735
const time = new Date().toISOString();
3836
return {
39-
content: [{ type: "text", text: time }],
40-
structuredContent: { time },
37+
content: [{ type: "text", text: JSON.stringify({ time }) }],
4138
};
4239
},
4340
);

examples/basic-server-vanillajs/src/mcp-app.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ const log = {
1515

1616

1717
function extractTime(result: CallToolResult): string {
18-
const { time } = (result.structuredContent as { time?: string }) ?? {};
19-
return time ?? "[ERROR]";
18+
const text = result.content!
19+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
20+
.map((c) => c.text)
21+
.join("");
22+
const { time } = JSON.parse(text) as { time: string };
23+
return time;
2024
}
2125

2226

examples/budget-allocator-server/server.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -221,30 +221,6 @@ function generateHistory(
221221
return months;
222222
}
223223

224-
// ---------------------------------------------------------------------------
225-
// Response Formatting
226-
// ---------------------------------------------------------------------------
227-
228-
function formatBudgetSummary(data: BudgetDataResponse): string {
229-
const lines: string[] = [
230-
"Budget Allocator Configuration",
231-
"==============================",
232-
"",
233-
`Default Budget: ${data.config.currencySymbol}${data.config.defaultBudget.toLocaleString()}`,
234-
`Available Presets: ${data.config.presetBudgets.map((b) => `${data.config.currencySymbol}${b.toLocaleString()}`).join(", ")}`,
235-
"",
236-
"Categories:",
237-
...data.config.categories.map(
238-
(c) => ` - ${c.name}: ${c.defaultPercent}% default`,
239-
),
240-
"",
241-
`Historical Data: ${data.analytics.history.length} months`,
242-
`Benchmark Stages: ${data.analytics.stages.join(", ")}`,
243-
`Default Stage: ${data.analytics.defaultStage}`,
244-
];
245-
return lines.join("\n");
246-
}
247-
248224
// ---------------------------------------------------------------------------
249225
// MCP Server Setup
250226
// ---------------------------------------------------------------------------
@@ -263,7 +239,6 @@ server.registerTool(
263239
description:
264240
"Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage",
265241
inputSchema: {},
266-
outputSchema: BudgetDataResponseSchema.shape,
267242
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
268243
},
269244
async (): Promise<CallToolResult> => {
@@ -292,10 +267,9 @@ server.registerTool(
292267
content: [
293268
{
294269
type: "text",
295-
text: formatBudgetSummary(response),
270+
text: JSON.stringify(response),
296271
},
297272
],
298-
structuredContent: response,
299273
};
300274
},
301275
);

examples/budget-allocator-server/src/mcp-app.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,13 @@ const app = new App({ name: "Budget Allocator", version: "1.0.0" });
606606

607607
app.ontoolresult = (result) => {
608608
log.info("Received tool result:", result);
609-
const data = result.structuredContent as unknown as BudgetDataResponse;
609+
const text = result
610+
.content!.filter(
611+
(c): c is { type: "text"; text: string } => c.type === "text",
612+
)
613+
.map((c) => c.text)
614+
.join("");
615+
const data = JSON.parse(text) as BudgetDataResponse;
610616
if (data?.config && data?.analytics) {
611617
initializeUI(data.config, data.analytics);
612618
}

examples/cohort-heatmap-server/server.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,6 @@ function generateCohortData(
149149
};
150150
}
151151

152-
function formatCohortSummary(data: CohortData): string {
153-
const avgRetention = data.cohorts
154-
.flatMap((c) => c.cells)
155-
.filter((cell) => cell.periodIndex > 0)
156-
.reduce((sum, cell, _, arr) => sum + cell.retention / arr.length, 0);
157-
158-
return `Cohort Analysis: ${data.cohorts.length} cohorts, ${data.periods.length} periods
159-
Average retention: ${(avgRetention * 100).toFixed(1)}%
160-
Metric: ${data.metric}, Period: ${data.periodType}`;
161-
}
162-
163152
const server = new McpServer({
164153
name: "Cohort Heatmap Server",
165154
version: "1.0.0",
@@ -176,7 +165,6 @@ const server = new McpServer({
176165
description:
177166
"Returns cohort retention heatmap data showing customer retention over time by signup month",
178167
inputSchema: GetCohortDataInputSchema.shape,
179-
outputSchema: CohortDataSchema.shape,
180168
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
181169
},
182170
async ({ metric, periodType, cohortCount, maxPeriods }) => {
@@ -188,8 +176,7 @@ const server = new McpServer({
188176
);
189177

190178
return {
191-
content: [{ type: "text", text: formatCohortSummary(data) }],
192-
structuredContent: data,
179+
content: [{ type: "text", text: JSON.stringify(data) }],
193180
};
194181
},
195182
);

examples/cohort-heatmap-server/src/mcp-app.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ function CohortHeatmapInner({ app }: { app: App }) {
103103
maxPeriods: 12,
104104
},
105105
});
106-
setData(result.structuredContent as unknown as CohortData);
106+
const text = result
107+
.content!.filter(
108+
(c): c is { type: "text"; text: string } => c.type === "text",
109+
)
110+
.map((c) => c.text)
111+
.join("");
112+
setData(JSON.parse(text) as CohortData);
107113
} catch (e) {
108114
console.error("Failed to fetch cohort data:", e);
109115
} finally {

examples/customer-segmentation-server/server.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,6 @@ const GetCustomerDataInputSchema = z.object({
2727
.describe("Filter by segment (default: All)"),
2828
});
2929

30-
const CustomerSchema = z.object({
31-
id: z.string(),
32-
name: z.string(),
33-
segment: z.string(),
34-
annualRevenue: z.number(),
35-
employeeCount: z.number(),
36-
accountAge: z.number(),
37-
engagementScore: z.number(),
38-
supportTickets: z.number(),
39-
nps: z.number(),
40-
});
41-
42-
const SegmentSummarySchema = z.object({
43-
name: z.string(),
44-
count: z.number(),
45-
color: z.string(),
46-
});
47-
48-
const GetCustomerDataOutputSchema = z.object({
49-
customers: z.array(CustomerSchema),
50-
segments: z.array(SegmentSummarySchema),
51-
});
52-
5330
// Cache generated data for session consistency
5431
let cachedCustomers: Customer[] | null = null;
5532
let cachedSegments: SegmentSummary[] | null = null;
@@ -92,15 +69,13 @@ const server = new McpServer({
9269
description:
9370
"Returns customer data with segment information for visualization. Optionally filter by segment.",
9471
inputSchema: GetCustomerDataInputSchema.shape,
95-
outputSchema: GetCustomerDataOutputSchema.shape,
9672
_meta: { [RESOURCE_URI_META_KEY]: resourceUri },
9773
},
9874
async ({ segment }): Promise<CallToolResult> => {
9975
const data = getCustomerData(segment);
10076

10177
return {
102-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
103-
structuredContent: data,
78+
content: [{ type: "text", text: JSON.stringify(data) }],
10479
};
10580
},
10681
);

examples/customer-segmentation-server/src/mcp-app.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,13 @@ async function fetchData(): Promise<void> {
336336
arguments: {},
337337
});
338338

339-
const data = result.structuredContent as unknown as {
339+
const text = result
340+
.content!.filter(
341+
(c): c is { type: "text"; text: string } => c.type === "text",
342+
)
343+
.map((c) => c.text)
344+
.join("");
345+
const data = JSON.parse(text) as {
340346
customers: Customer[];
341347
segments: SegmentSummary[];
342348
};

0 commit comments

Comments
 (0)