Skip to content

Commit f0ed454

Browse files
committed
feat: use structuredContent in remaining example servers
Updated servers to return structuredContent alongside JSON text content: - basic-server-vanillajs - cohort-heatmap-server - customer-segmentation-server - system-monitor-server - video-resource-server - wiki-explorer-server Each mcp-app now prefers structuredContent when available, with fallback to JSON.parse for backwards compatibility.
1 parent f8154af commit f0ed454

12 files changed

Lines changed: 67 additions & 30 deletions

File tree

examples/basic-server-vanillajs/server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ export function createServer(): McpServer {
3232
},
3333
async (): Promise<CallToolResult> => {
3434
const time = new Date().toISOString();
35+
const data = { time };
3536
return {
36-
content: [{ type: "text", text: JSON.stringify({ time }) }],
37+
content: [{ type: "text", text: JSON.stringify(data) }],
38+
structuredContent: data,
3739
};
3840
},
3941
);

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

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

1616

1717
function extractTime(result: CallToolResult): string {
18-
const { text } = result.content?.find((c) => c.type === "text")!;
19-
return text;
18+
// Prefer structuredContent if available, with fallback to parsing text content
19+
if (result.structuredContent && typeof result.structuredContent === "object") {
20+
const data = result.structuredContent as { time?: string };
21+
if (data.time) {
22+
return data.time;
23+
}
24+
}
25+
// Fallback: parse JSON from text content
26+
const textContent = result.content?.find((c) => c.type === "text");
27+
if (textContent && "text" in textContent) {
28+
const parsed = JSON.parse(textContent.text) as { time?: string };
29+
return parsed.time ?? textContent.text;
30+
}
31+
return "[no time data]";
2032
}
2133

2234

examples/cohort-heatmap-server/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ export function createServer(): McpServer {
181181

182182
return {
183183
content: [{ type: "text", text: JSON.stringify(data) }],
184+
structuredContent: data,
184185
};
185186
},
186187
);

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,17 @@ function CohortHeatmapInner({
123123
maxPeriods: 12,
124124
},
125125
});
126-
const text = result
127-
.content!.filter(
128-
(c): c is { type: "text"; text: string } => c.type === "text",
129-
)
130-
.map((c) => c.text)
131-
.join("");
132-
setData(JSON.parse(text) as CohortData);
126+
if (result.structuredContent) {
127+
setData(result.structuredContent as CohortData);
128+
} else {
129+
const text = result
130+
.content!.filter(
131+
(c): c is { type: "text"; text: string } => c.type === "text",
132+
)
133+
.map((c) => c.text)
134+
.join("");
135+
setData(JSON.parse(text) as CohortData);
136+
}
133137
} catch (e) {
134138
console.error("Failed to fetch cohort data:", e);
135139
} finally {

examples/customer-segmentation-server/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export function createServer(): McpServer {
8585

8686
return {
8787
content: [{ type: "text", text: JSON.stringify(data) }],
88+
structuredContent: data,
8889
};
8990
},
9091
);

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,16 @@ async function fetchData(): Promise<void> {
377377
arguments: {},
378378
});
379379

380-
const text = result
381-
.content!.filter(
382-
(c): c is { type: "text"; text: string } => c.type === "text",
383-
)
384-
.map((c) => c.text)
385-
.join("");
386-
const data = JSON.parse(text) as {
380+
// Use structuredContent if available, otherwise fall back to parsing JSON from text content
381+
const data = (result.structuredContent ??
382+
JSON.parse(
383+
result
384+
.content!.filter(
385+
(c): c is { type: "text"; text: string } => c.type === "text",
386+
)
387+
.map((c) => c.text)
388+
.join(""),
389+
)) as {
387390
customers: Customer[];
388391
segments: SegmentSummary[];
389392
};

examples/system-monitor-server/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export function createServer(): McpServer {
151151

152152
return {
153153
content: [{ type: "text", text: JSON.stringify(stats) }],
154+
structuredContent: stats,
154155
};
155156
},
156157
);

examples/system-monitor-server/src/mcp-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ async function fetchStats(): Promise<void> {
271271
)
272272
.map((c) => c.text)
273273
.join("");
274-
const stats = JSON.parse(text) as SystemStats;
274+
const stats = (result.structuredContent ?? JSON.parse(text)) as SystemStats;
275275

276276
// Initialize chart on first data if needed
277277
if (!state.chart && stats.cpu.count > 0) {

examples/video-resource-server/server.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,13 @@ ${Object.entries(VIDEO_LIBRARY)
133133
},
134134
async ({ videoId }): Promise<CallToolResult> => {
135135
const video = VIDEO_LIBRARY[videoId];
136+
const data = {
137+
videoUri: `videos://${videoId}`,
138+
description: video.description,
139+
};
136140
return {
137-
content: [
138-
{
139-
type: "text",
140-
text: JSON.stringify({
141-
videoUri: `videos://${videoId}`,
142-
description: video.description,
143-
}),
144-
},
145-
],
141+
content: [{ type: "text", text: JSON.stringify(data) }],
142+
structuredContent: data,
146143
};
147144
},
148145
);

examples/video-resource-server/src/mcp-app.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ const videoInfoEl = document.getElementById("video-info")!;
2828
function parseToolResult(
2929
result: CallToolResult,
3030
): { videoUri: string; description: string } | null {
31+
// Use structuredContent if available
32+
if (result.structuredContent) {
33+
return result.structuredContent as {
34+
videoUri: string;
35+
description: string;
36+
};
37+
}
38+
39+
// Fall back to parsing JSON from text content
3140
const text = result.content
3241
?.filter((c): c is { type: "text"; text: string } => c.type === "text")
3342
.map((c) => c.text)

0 commit comments

Comments
 (0)