Skip to content

Commit ae4157b

Browse files
committed
feat: Add expand-node tool to wiki-explorer and update tool descriptions
Wiki Explorer: - Add expand-node tool - the critical missing tool for graph exploration - Claude can now programmatically expand nodes to discover linked articles Server descriptions updated to mention widget tools: - map-server: navigate-to, get-current-view - pdf-server: go-to-page, get-page-text, search-text, set-zoom, get-document-info - budget-allocator: get-allocations, set-allocation, set-total-budget, etc. - shadertoy: set-shader-source, get-shader-info - wiki-explorer: expand-node, search-article, highlight-node, etc. All descriptions now mention 'Use list_widget_tools to discover available actions.'
1 parent 8f592a3 commit ae4157b

File tree

6 files changed

+126
-5
lines changed

6 files changed

+126
-5
lines changed

examples/budget-allocator-server/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export function createServer(): McpServer {
269269
{
270270
title: "Get Budget Data",
271271
description:
272-
"Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage",
272+
"Returns budget configuration with 24 months of historical allocations and industry benchmarks by company stage. The widget exposes tools: get-allocations (current allocations), set-allocation (adjust a category), set-total-budget (change budget), set-company-stage (change benchmark stage), get-benchmark-comparison (compare to industry). Use list_widget_tools to discover available actions.",
273273
inputSchema: {},
274274
outputSchema: BudgetDataResponseSchema,
275275
_meta: { ui: { resourceUri } },

examples/map-server/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export function createServer(): McpServer {
148148
{
149149
title: "Show Map",
150150
description:
151-
"Display an interactive world map zoomed to a specific bounding box. Use the GeoCode tool to find the bounding box of a location.",
151+
"Display an interactive world map zoomed to a specific bounding box. Use the GeoCode tool to find the bounding box of a location. The widget exposes tools: navigate-to (fly to a new location), get-current-view (get camera position and visible bounds). Use list_widget_tools to discover available actions.",
152152
inputSchema: {
153153
west: z
154154
.number()

examples/pdf-server/server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ Use this tool when the user asks to view, display, read, or open a PDF. Accepts:
136136
- URLs from list_pdfs (preloaded PDFs)
137137
- Any arxiv.org URL (loaded dynamically)
138138
139-
The viewer supports zoom, navigation, text selection, and fullscreen mode.`,
139+
The viewer supports zoom, navigation, text selection, and fullscreen mode.
140+
141+
The widget exposes tools: go-to-page (navigate to a page), get-page-text (extract text), search-text (find text in document), set-zoom (adjust zoom level), get-document-info (get metadata). Use list_widget_tools to discover available actions.`,
140142
inputSchema: {
141143
url: z
142144
.string()

examples/shadertoy-server/server.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ LIMITATIONS - Do NOT use:
4949
- VR features (mainVR not available)
5050
5151
For procedural noise:
52-
float hash(vec2 p) { return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }`;
52+
float hash(vec2 p) { return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }
53+
54+
The widget exposes tools: set-shader-source (update shader code), get-shader-info (get source and errors). Compilation errors are also sent to model context. Use list_widget_tools to discover available actions.`;
5355

5456
const DEFAULT_FRAGMENT_SHADER = `void mainImage(out vec4 fragColor, in vec2 fragCoord) {
5557
vec2 uv = fragCoord / iResolution.xy;

examples/wiki-explorer-server/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export function createServer(): McpServer {
8686
{
8787
title: "Get First-Degree Links",
8888
description:
89-
"Returns all Wikipedia pages that the given page links to directly.",
89+
"Returns all Wikipedia pages that the given page links to directly. The widget exposes tools: expand-node (explore a node's links - the key interaction!), search-article (find articles), get-current-article (get displayed article), highlight-node (highlight a graph node), get-visible-nodes (list visible nodes). Use list_widget_tools to discover available actions.",
9090
inputSchema: z.object({
9191
url: z
9292
.string()

examples/wiki-explorer-server/src/mcp-app.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,123 @@ app.registerTool(
576576
},
577577
);
578578

579+
// Tool: Expand a node to show its linked pages
580+
app.registerTool(
581+
"expand-node",
582+
{
583+
title: "Expand Node",
584+
description:
585+
"Expand a node to fetch and display all Wikipedia pages it links to. This is the core way to explore the graph.",
586+
inputSchema: z.object({
587+
identifier: z
588+
.string()
589+
.describe("The title or URL of the node to expand"),
590+
}),
591+
},
592+
async (args) => {
593+
const { identifier } = args as { identifier: string };
594+
const lowerIdentifier = identifier.toLowerCase();
595+
596+
// Find node by title (case-insensitive partial match) or exact URL
597+
const node = graphData.nodes.find(
598+
(n) =>
599+
n.url === identifier || n.title.toLowerCase().includes(lowerIdentifier),
600+
);
601+
602+
if (!node) {
603+
return {
604+
content: [
605+
{ type: "text" as const, text: `Node not found: ${identifier}` },
606+
],
607+
structuredContent: {
608+
success: false,
609+
error: "Node not found in graph",
610+
availableNodes: graphData.nodes.map((n) => n.title),
611+
},
612+
};
613+
}
614+
615+
if (node.state === "expanded") {
616+
return {
617+
content: [
618+
{
619+
type: "text" as const,
620+
text: `Node "${node.title}" is already expanded`,
621+
},
622+
],
623+
structuredContent: {
624+
success: true,
625+
alreadyExpanded: true,
626+
node: { url: node.url, title: node.title },
627+
},
628+
};
629+
}
630+
631+
if (node.state === "error") {
632+
return {
633+
content: [
634+
{
635+
type: "text" as const,
636+
text: `Node "${node.title}" has an error: ${node.errorMessage}`,
637+
},
638+
],
639+
structuredContent: {
640+
success: false,
641+
error: node.errorMessage,
642+
},
643+
};
644+
}
645+
646+
try {
647+
// Fetch the linked pages using the server tool
648+
const result = await app.callServerTool({
649+
name: "get-first-degree-links",
650+
arguments: { url: node.url },
651+
});
652+
653+
graph.warmupTicks(0);
654+
handleToolResultData(result);
655+
656+
const response = result.structuredContent as unknown as ToolResponse;
657+
const linksAdded = response?.links?.length ?? 0;
658+
659+
// Center on the expanded node
660+
if (node.x !== undefined && node.y !== undefined) {
661+
graph.centerAt(node.x, node.y, 500);
662+
}
663+
664+
return {
665+
content: [
666+
{
667+
type: "text" as const,
668+
text: `Expanded "${node.title}" - found ${linksAdded} linked articles`,
669+
},
670+
],
671+
structuredContent: {
672+
success: true,
673+
node: { url: node.url, title: node.title },
674+
linksAdded,
675+
},
676+
};
677+
} catch (e) {
678+
setNodeState(node.url, "error", "Request failed");
679+
updateGraph();
680+
return {
681+
content: [
682+
{
683+
type: "text" as const,
684+
text: `Failed to expand "${node.title}": ${e instanceof Error ? e.message : String(e)}`,
685+
},
686+
],
687+
structuredContent: {
688+
success: false,
689+
error: String(e),
690+
},
691+
};
692+
}
693+
},
694+
);
695+
579696
// Tool: Get list of currently visible nodes in the graph
580697
app.registerTool(
581698
"get-visible-nodes",

0 commit comments

Comments
 (0)