@nexusbloom/mcp-server 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +42 -33
- package/package.json +1 -1
- package/test-mcp-client.mjs +104 -0
package/index.js
CHANGED
|
@@ -76,6 +76,7 @@ async function fetchTools() {
|
|
|
76
76
|
price_type: t.price_type || t.pricing || "free",
|
|
77
77
|
version: t.version || "1.0.0",
|
|
78
78
|
type: "builtin",
|
|
79
|
+
input_schema: t.input_schema || null,
|
|
79
80
|
}));
|
|
80
81
|
toolsCacheTime = now;
|
|
81
82
|
return toolsCache;
|
|
@@ -90,42 +91,16 @@ async function fetchTools() {
|
|
|
90
91
|
// ---------------------------------------------------------------------------
|
|
91
92
|
|
|
92
93
|
async function fetchToolSchema(slug) {
|
|
93
|
-
|
|
94
|
-
const res = await fetch(`${API_URL}/tools/${encodeURIComponent(slug)}`, {
|
|
95
|
-
headers: apiHeaders(),
|
|
96
|
-
...FETCH_OPTS,
|
|
97
|
-
});
|
|
98
|
-
if (res.ok) {
|
|
99
|
-
const json = await res.json();
|
|
100
|
-
const tool = json.tool || json.data || json;
|
|
101
|
-
if (tool && tool.slug) {
|
|
102
|
-
return {
|
|
103
|
-
slug: tool.slug,
|
|
104
|
-
name: tool.name,
|
|
105
|
-
description: tool.short_description || tool.full_description || tool.description || "",
|
|
106
|
-
tags: (tool.tags || []).flat().filter(Boolean),
|
|
107
|
-
input_schema: tool.input_schema || {},
|
|
108
|
-
output_schema: tool.output_schema || {},
|
|
109
|
-
icon: tool.icon || "🔧",
|
|
110
|
-
price_type: tool.price_type || tool.pricing || "free",
|
|
111
|
-
version: tool.version || "1.0.0",
|
|
112
|
-
category: tool.category || "Platform Tools",
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
} catch (err) {
|
|
117
|
-
console.error(`Failed to fetch schema for ${slug}:`, err.message);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Fallback: try the manifest endpoint
|
|
94
|
+
// Primary: fetch manifest from /api/run/{slug} (the reliable endpoint)
|
|
121
95
|
try {
|
|
122
96
|
const res = await fetch(`${API_URL}/run/${encodeURIComponent(slug)}`, {
|
|
123
97
|
headers: apiHeaders(),
|
|
124
98
|
...FETCH_OPTS,
|
|
125
99
|
});
|
|
126
100
|
if (res.ok) {
|
|
127
|
-
|
|
128
|
-
const
|
|
101
|
+
// API returns { success: true, data: { manifest: { ... } } }
|
|
102
|
+
const body = await res.json();
|
|
103
|
+
const manifest = body.data?.manifest || body.manifest || body;
|
|
129
104
|
if (manifest && manifest.slug) {
|
|
130
105
|
return {
|
|
131
106
|
slug: manifest.slug,
|
|
@@ -156,7 +131,7 @@ async function executeTool(slug, params) {
|
|
|
156
131
|
const res = await fetch(`${API_URL}/run/${encodeURIComponent(slug)}`, {
|
|
157
132
|
method: "POST",
|
|
158
133
|
headers: apiHeaders(),
|
|
159
|
-
body: JSON.stringify(
|
|
134
|
+
body: JSON.stringify(params),
|
|
160
135
|
...FETCH_OPTS,
|
|
161
136
|
});
|
|
162
137
|
|
|
@@ -199,6 +174,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
199
174
|
description: `${t.name}: ${t.short_description || "No description"}${
|
|
200
175
|
t.category ? ` [${t.category}]` : ""
|
|
201
176
|
}`,
|
|
177
|
+
inputSchema: t.input_schema || {
|
|
178
|
+
type: "object",
|
|
179
|
+
properties: {},
|
|
180
|
+
},
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
// Also expose the meta-tool for list/schema/run
|
|
184
|
+
toolList.push({
|
|
185
|
+
name: "nexusbloom",
|
|
186
|
+
description: `Meta-tool to list, inspect, or run any NexusBloom tool. Use this when you need to discover tools or get schema details.`,
|
|
202
187
|
inputSchema: {
|
|
203
188
|
type: "object",
|
|
204
189
|
properties: {
|
|
@@ -221,7 +206,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
221
206
|
},
|
|
222
207
|
required: ["command"],
|
|
223
208
|
},
|
|
224
|
-
})
|
|
209
|
+
});
|
|
225
210
|
|
|
226
211
|
return { tools: toolList };
|
|
227
212
|
});
|
|
@@ -230,10 +215,34 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
230
215
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
231
216
|
const { name: toolName, arguments: args } = request.params;
|
|
232
217
|
|
|
218
|
+
// ── Direct tool execution by slug ──────────────────────────────
|
|
219
|
+
// AI agents can call any tool directly by its slug name.
|
|
220
|
+
// The tool's own input_schema defines the expected parameters.
|
|
221
|
+
// We verify the slug exists by checking against our tool list.
|
|
233
222
|
if (toolName !== "nexusbloom") {
|
|
234
|
-
|
|
223
|
+
const tools = await fetchTools();
|
|
224
|
+
const matched = tools.find((t) => t.slug === toolName);
|
|
225
|
+
if (!matched) {
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: "text", text: `Unknown tool: "${toolName}". Use the "nexusbloom" tool with command "list" to see available tools.` }],
|
|
228
|
+
isError: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const result = await executeTool(toolName, args || {});
|
|
233
|
+
const formatted = JSON.stringify(result.data, null, 2);
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{ type: "text", text: `# ${matched.name} (${toolName})\n\n\`\`\`json\n${formatted}\n\`\`\`` },
|
|
237
|
+
{ type: "resource", resource: { text: formatted, uri: "data:application/json,", mimeType: "application/json" } },
|
|
238
|
+
],
|
|
239
|
+
};
|
|
240
|
+
} catch (err) {
|
|
241
|
+
return { content: [{ type: "text", text: `Error executing "${toolName}": ${err.message}` }], isError: true };
|
|
242
|
+
}
|
|
235
243
|
}
|
|
236
244
|
|
|
245
|
+
// ── Legacy meta-tool: list/schema/run via sub-commands ─────────
|
|
237
246
|
const command = args?.command;
|
|
238
247
|
|
|
239
248
|
if (!command || !["list", "schema", "run"].includes(command)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexusbloom/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP server for NexusBloom — AI agents discover and execute tools through a single interface. No Supabase credentials needed, just connect to our API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server Test — uses the MCP SDK Client directly.
|
|
4
|
+
* Tests both direct slug execution and meta-tool paths.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node test-mcp-client.mjs
|
|
7
|
+
*/
|
|
8
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
console.log("═══ MCP Server Test ═══\n");
|
|
13
|
+
|
|
14
|
+
const transport = new StdioClientTransport({
|
|
15
|
+
command: "npx",
|
|
16
|
+
args: ["@nexusbloom/mcp-server"],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const client = new Client(
|
|
20
|
+
{ name: "mcp-test-client", version: "1.0.0" },
|
|
21
|
+
{ capabilities: {} }
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
await client.connect(transport);
|
|
25
|
+
console.log("✅ Connected to MCP server\n");
|
|
26
|
+
|
|
27
|
+
// ── Test 1: ListTools ─────────────────────────────────────────
|
|
28
|
+
const { tools } = await client.listTools();
|
|
29
|
+
console.log(`✅ Tools available: ${tools.length}`);
|
|
30
|
+
const slugs = tools.filter((t) => t.name !== "nexusbloom").map((t) => t.name);
|
|
31
|
+
const metaTool = tools.find((t) => t.name === "nexusbloom");
|
|
32
|
+
if (metaTool) console.log(`✅ Meta-tool "nexusbloom" registered`);
|
|
33
|
+
console.log(` Example tools: ${slugs.slice(0, 5).join(", ")}...`);
|
|
34
|
+
console.log();
|
|
35
|
+
|
|
36
|
+
// ── Test 2: Direct slug execution ─────────────────────────────
|
|
37
|
+
// AI agents call tools by their slug name directly
|
|
38
|
+
console.log("── Test: Direct slug execution ──");
|
|
39
|
+
const cronResult = await client.callTool({
|
|
40
|
+
name: "cron-expression-builder",
|
|
41
|
+
arguments: { expression: "0 0 * * *" },
|
|
42
|
+
});
|
|
43
|
+
const cronText = cronResult.content.find((c) => c.type === "text")?.text || "";
|
|
44
|
+
if (cronText.includes(`"valid": true`)) {
|
|
45
|
+
console.log("✅ cron-expression-builder executed directly by slug");
|
|
46
|
+
console.log(` → ${cronText.split("\n")[1] || "valid=true"}`);
|
|
47
|
+
} else {
|
|
48
|
+
console.log(`⚠ Unexpected: ${cronText.substring(0, 100)}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const dataResult = await client.callTool({
|
|
52
|
+
name: "data-generator",
|
|
53
|
+
arguments: { count: 2 },
|
|
54
|
+
});
|
|
55
|
+
const dataText = dataResult.content.find((c) => c.type === "text")?.text || "";
|
|
56
|
+
if (dataText.includes("data-generator")) {
|
|
57
|
+
console.log("✅ data-generator executed directly by slug");
|
|
58
|
+
}
|
|
59
|
+
console.log();
|
|
60
|
+
|
|
61
|
+
// ── Test 3: Meta-tool "list" ──────────────────────────────────
|
|
62
|
+
console.log("── Test: Meta-tool list ──");
|
|
63
|
+
const listResult = await client.callTool({
|
|
64
|
+
name: "nexusbloom",
|
|
65
|
+
arguments: { command: "list" },
|
|
66
|
+
});
|
|
67
|
+
const listText = listResult.content.find((c) => c.type === "text")?.text || "";
|
|
68
|
+
if (listText.includes("NexusBloom Tools")) {
|
|
69
|
+
console.log("✅ Meta-tool list works");
|
|
70
|
+
}
|
|
71
|
+
console.log();
|
|
72
|
+
|
|
73
|
+
// ── Test 4: Meta-tool "schema" ────────────────────────────────
|
|
74
|
+
console.log("── Test: Meta-tool schema ──");
|
|
75
|
+
const schemaResult = await client.callTool({
|
|
76
|
+
name: "nexusbloom",
|
|
77
|
+
arguments: { command: "schema", slug: "cron-expression-builder" },
|
|
78
|
+
});
|
|
79
|
+
const schemaText = schemaResult.content.find((c) => c.type === "text")?.text || "";
|
|
80
|
+
if (schemaText.includes("Cron Expression Builder")) {
|
|
81
|
+
console.log("✅ Meta-tool schema works");
|
|
82
|
+
}
|
|
83
|
+
console.log();
|
|
84
|
+
|
|
85
|
+
// ── Test 5: Meta-tool "run" ───────────────────────────────────
|
|
86
|
+
console.log("── Test: Meta-tool run ──");
|
|
87
|
+
const runResult = await client.callTool({
|
|
88
|
+
name: "nexusbloom",
|
|
89
|
+
arguments: { command: "run", slug: "data-generator", params: { count: 3 } },
|
|
90
|
+
});
|
|
91
|
+
const runText = runResult.content.find((c) => c.type === "text")?.text || "";
|
|
92
|
+
if (runText.includes("data-generator")) {
|
|
93
|
+
console.log("✅ Meta-tool run works");
|
|
94
|
+
}
|
|
95
|
+
console.log();
|
|
96
|
+
|
|
97
|
+
await client.close();
|
|
98
|
+
console.log("═══ All MCP tests passed! ═══");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main().catch((err) => {
|
|
102
|
+
console.error("❌ MCP test failed:", err.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|