@muxoai/platform 1.2.1 → 1.2.3

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/dist/mcp.js CHANGED
@@ -1,23 +1,68 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { ROOT_DIR } from "./config.js";
5
+ /**
6
+ * Concise server instructions (<512 chars) per OpenAI Plugin MCP Server specification:
7
+ * https://developers.openai.com/plugins/build/mcp-server
8
+ */
9
+ export const MUXO_MCP_SERVER_INSTRUCTIONS = "Muxo governs SaaS actions (Composio app.*), Instant tools (instant.*), Cloud Infrastructure (Stripe Projects resource.*), Supermemory v5 recall, and Microsoft Agent Governance Ed25519 receipts. Workflow: 1) search_tools & inspect_tool. 2) plan_action to get a plan_*. 3) If authHandoff.required is true, show redirectUrl and call wait_for_connection. 4) Execute via the matching risk tool (execute_read/write/admin/financial/provisioning/destructive). 5) Verify via get_receipt.";
1
10
  export const MUXO_MCP_TOOLS = [
2
11
  {
3
12
  name: "get_profile",
4
- description: "Get the authenticated actor profile, workspace ID, and subscription tier.",
5
- inputSchema: { type: "object", properties: {} },
13
+ title: "Get Authenticated Profile",
14
+ description: "Get the authenticated actor profile, user ID, email, workspace ID, and subscription tier.",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {},
18
+ additionalProperties: false,
19
+ },
20
+ outputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ id: { type: "string", description: "Unique user identifier" },
24
+ name: { type: "string", description: "Display name" },
25
+ email: { type: "string", description: "Email address" },
26
+ workspaceId: { type: "string", description: "Active workspace ID" },
27
+ workspaceName: { type: "string", description: "Active workspace name" },
28
+ tier: { type: "string", description: "Workspace subscription tier" },
29
+ },
30
+ required: ["id"],
31
+ },
32
+ annotations: {
33
+ readOnlyHint: true,
34
+ destructiveHint: false,
35
+ openWorldHint: false,
36
+ },
37
+ _meta: {
38
+ "openai/profile": true,
39
+ },
6
40
  },
7
41
  {
8
42
  name: "get_organization",
9
- description: "Get workspace governance policy, monthly action usage, credit balance, and active connection/resource counts.",
10
- inputSchema: { type: "object", properties: {} },
43
+ title: "Get Organization & Billing Summary",
44
+ description: "Get workspace governance policy, monthly action usage, credit balance, Merchant-of-Record supplier settlement summary, and active connection/resource counts.",
45
+ inputSchema: {
46
+ type: "object",
47
+ properties: {},
48
+ additionalProperties: false,
49
+ },
50
+ annotations: {
51
+ readOnlyHint: true,
52
+ destructiveHint: false,
53
+ openWorldHint: false,
54
+ },
11
55
  },
12
56
  {
13
57
  name: "search_tools",
58
+ title: "Search Unified Tool Catalog",
14
59
  description: "Search the unified Muxo catalog across Connected Apps (Composio SDK: app.*), Instant Tools (Composio Instant: instant.*), and Cloud Infrastructure (Stripe Projects: resource.*).",
15
60
  inputSchema: {
16
61
  type: "object",
17
62
  properties: {
18
63
  query: {
19
64
  type: "string",
20
- description: "Search keywords (e.g. 'postgres', 'github issue', 'web search', 'redis')",
65
+ description: "Search keywords (e.g. 'postgres', 'github issue', 'web search', 'seo audit', 'redis')",
21
66
  },
22
67
  lane: {
23
68
  type: "string",
@@ -26,35 +71,56 @@ export const MUXO_MCP_TOOLS = [
26
71
  },
27
72
  risk_level: {
28
73
  type: "string",
29
- enum: ["read", "write", "admin", "financial", "provisioning", "destructive"],
74
+ enum: [
75
+ "read",
76
+ "write",
77
+ "admin",
78
+ "financial",
79
+ "provisioning",
80
+ "destructive",
81
+ ],
30
82
  },
31
83
  limit: { type: "number", default: 20 },
32
84
  },
85
+ additionalProperties: false,
86
+ },
87
+ annotations: {
88
+ readOnlyHint: true,
89
+ destructiveHint: false,
90
+ openWorldHint: true,
33
91
  },
34
92
  },
35
93
  {
36
94
  name: "inspect_tool",
37
- description: "Inspect a tool's full input JSON schema, risk classification, provider lane, and credit cost before planning.",
95
+ title: "Inspect Tool Schema & Risk",
96
+ description: "Inspect a tool's full input JSON schema, risk classification, provider lane, LLM context URL, and credit cost before planning.",
38
97
  inputSchema: {
39
98
  type: "object",
40
99
  required: ["tool_slug"],
41
100
  properties: {
42
101
  tool_slug: {
43
102
  type: "string",
44
- description: "Canonical Muxo tool slug (e.g. 'instant.hackernews.top_stories' or 'resource.neon.launch')",
103
+ description: "Canonical Muxo tool slug (e.g. 'instant.seo.audit', 'app.gmail.send_email', or 'resource.turso.database')",
45
104
  },
46
105
  },
106
+ additionalProperties: false,
107
+ },
108
+ annotations: {
109
+ readOnlyHint: true,
110
+ destructiveHint: false,
111
+ openWorldHint: false,
47
112
  },
48
113
  },
49
114
  {
50
115
  name: "connection_status",
116
+ title: "Check Connection Status",
51
117
  description: "Check connection status across Composio OAuth apps, Instant wallet, and linked Stripe Projects cloud providers.",
52
118
  inputSchema: {
53
119
  type: "object",
54
120
  properties: {
55
121
  provider: {
56
122
  type: "string",
57
- description: "Optional provider filter (e.g. 'github', 'slack', 'neon', 'supabase')",
123
+ description: "Optional provider filter (e.g. 'github', 'gmail', 'slack', 'neon', 'turso')",
58
124
  },
59
125
  sync_live: {
60
126
  type: "boolean",
@@ -62,11 +128,18 @@ export const MUXO_MCP_TOOLS = [
62
128
  description: "Whether to sync live status from upstream Composio and Stripe Projects",
63
129
  },
64
130
  },
131
+ additionalProperties: false,
132
+ },
133
+ annotations: {
134
+ readOnlyHint: true,
135
+ destructiveHint: false,
136
+ openWorldHint: true,
65
137
  },
66
138
  },
67
139
  {
68
140
  name: "start_connection",
69
- description: "Initiate an OAuth connection for a Connected App (Composio) or link a cloud provider (Stripe Projects).",
141
+ title: "Start OAuth Connection Handoff",
142
+ description: "Initiate a managed OAuth connection handoff for a Connected App (Composio) or link a cloud provider (Stripe Projects).",
70
143
  inputSchema: {
71
144
  type: "object",
72
145
  required: ["provider"],
@@ -85,10 +158,17 @@ export const MUXO_MCP_TOOLS = [
85
158
  description: "Optional OAuth callback URL",
86
159
  },
87
160
  },
161
+ additionalProperties: false,
162
+ },
163
+ annotations: {
164
+ readOnlyHint: false,
165
+ destructiveHint: false,
166
+ openWorldHint: true,
88
167
  },
89
168
  },
90
169
  {
91
170
  name: "wait_for_connection",
171
+ title: "Wait for OAuth Connection Handoff",
92
172
  description: "Poll and wait for an external user's pending OAuth connection handoff to become active before resuming a planned operation.",
93
173
  inputSchema: {
94
174
  type: "object",
@@ -104,11 +184,18 @@ export const MUXO_MCP_TOOLS = [
104
184
  description: "Maximum seconds to poll for OAuth completion (0-120, default 15)",
105
185
  },
106
186
  },
187
+ additionalProperties: false,
188
+ },
189
+ annotations: {
190
+ readOnlyHint: true,
191
+ destructiveHint: false,
192
+ openWorldHint: true,
107
193
  },
108
194
  },
109
195
  {
110
196
  name: "plan_action",
111
- description: "Create a governed execution plan (plan_*) for any tool or infrastructure provisioning operation. Evaluates workspace policy, risk level, and credit balance.",
197
+ title: "Create Governed Action Plan",
198
+ description: "Create a governed execution plan (plan_*) for any tool or infrastructure provisioning operation. Evaluates workspace policy, risk level, Supermemory v5 recall, Ed25519 signature, and credit balance.",
112
199
  inputSchema: {
113
200
  type: "object",
114
201
  required: ["tool_slug"],
@@ -123,21 +210,35 @@ export const MUXO_MCP_TOOLS = [
123
210
  description: "Audit reason explaining why this action is being planned",
124
211
  },
125
212
  },
213
+ additionalProperties: false,
214
+ },
215
+ annotations: {
216
+ readOnlyHint: false,
217
+ destructiveHint: false,
218
+ openWorldHint: false,
126
219
  },
127
220
  },
128
221
  {
129
222
  name: "get_plan",
130
- description: "Inspect the status, risk level, and approval state of a planned action.",
223
+ title: "Get Action Plan",
224
+ description: "Inspect the status, risk level, governance decision record, and approval state of a planned action.",
131
225
  inputSchema: {
132
226
  type: "object",
133
227
  required: ["plan_id"],
134
228
  properties: {
135
229
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
136
230
  },
231
+ additionalProperties: false,
232
+ },
233
+ annotations: {
234
+ readOnlyHint: true,
235
+ destructiveHint: false,
236
+ openWorldHint: false,
137
237
  },
138
238
  },
139
239
  {
140
240
  name: "get_run_context",
241
+ title: "Get Workspace Context & Memory",
141
242
  description: "Get the workspace runtime context, Supermemory v5 contextual brain (static/dynamic profile + hybrid search recall), Microsoft Agent Governance status, active provisioned Stripe Projects resources, and redacted environment variable keys.",
142
243
  inputSchema: {
143
244
  type: "object",
@@ -147,10 +248,17 @@ export const MUXO_MCP_TOOLS = [
147
248
  description: "Optional semantic search query to recall relevant workspace memories from Supermemory v5",
148
249
  },
149
250
  },
251
+ additionalProperties: false,
252
+ },
253
+ annotations: {
254
+ readOnlyHint: true,
255
+ destructiveHint: false,
256
+ openWorldHint: false,
150
257
  },
151
258
  },
152
259
  {
153
260
  name: "execute_read",
261
+ title: "Execute Read Plan",
154
262
  description: "Execute an approved plan with riskLevel = 'read'.",
155
263
  inputSchema: {
156
264
  type: "object",
@@ -158,10 +266,17 @@ export const MUXO_MCP_TOOLS = [
158
266
  properties: {
159
267
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
160
268
  },
269
+ additionalProperties: false,
270
+ },
271
+ annotations: {
272
+ readOnlyHint: true,
273
+ destructiveHint: false,
274
+ openWorldHint: true,
161
275
  },
162
276
  },
163
277
  {
164
278
  name: "execute_write",
279
+ title: "Execute Write Plan",
165
280
  description: "Execute an approved plan with riskLevel = 'write'.",
166
281
  inputSchema: {
167
282
  type: "object",
@@ -169,10 +284,17 @@ export const MUXO_MCP_TOOLS = [
169
284
  properties: {
170
285
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
171
286
  },
287
+ additionalProperties: false,
288
+ },
289
+ annotations: {
290
+ readOnlyHint: false,
291
+ destructiveHint: false,
292
+ openWorldHint: true,
172
293
  },
173
294
  },
174
295
  {
175
296
  name: "execute_admin",
297
+ title: "Execute Admin Plan",
176
298
  description: "Execute an approved plan with riskLevel = 'admin'.",
177
299
  inputSchema: {
178
300
  type: "object",
@@ -180,10 +302,17 @@ export const MUXO_MCP_TOOLS = [
180
302
  properties: {
181
303
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
182
304
  },
305
+ additionalProperties: false,
306
+ },
307
+ annotations: {
308
+ readOnlyHint: false,
309
+ destructiveHint: false,
310
+ openWorldHint: true,
183
311
  },
184
312
  },
185
313
  {
186
314
  name: "execute_financial",
315
+ title: "Execute Financial Plan",
187
316
  description: "Execute an approved plan with riskLevel = 'financial'.",
188
317
  inputSchema: {
189
318
  type: "object",
@@ -191,10 +320,17 @@ export const MUXO_MCP_TOOLS = [
191
320
  properties: {
192
321
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
193
322
  },
323
+ additionalProperties: false,
324
+ },
325
+ annotations: {
326
+ readOnlyHint: false,
327
+ destructiveHint: false,
328
+ openWorldHint: true,
194
329
  },
195
330
  },
196
331
  {
197
332
  name: "execute_provisioning",
333
+ title: "Execute Infrastructure Provisioning Plan",
198
334
  description: "Execute an approved infrastructure provisioning plan with riskLevel = 'provisioning' via Stripe Projects.",
199
335
  inputSchema: {
200
336
  type: "object",
@@ -202,10 +338,17 @@ export const MUXO_MCP_TOOLS = [
202
338
  properties: {
203
339
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
204
340
  },
341
+ additionalProperties: false,
342
+ },
343
+ annotations: {
344
+ readOnlyHint: false,
345
+ destructiveHint: false,
346
+ openWorldHint: true,
205
347
  },
206
348
  },
207
349
  {
208
350
  name: "execute_destructive",
351
+ title: "Execute Destructive Plan",
209
352
  description: "Execute an approved plan with riskLevel = 'destructive'.",
210
353
  inputSchema: {
211
354
  type: "object",
@@ -213,10 +356,17 @@ export const MUXO_MCP_TOOLS = [
213
356
  properties: {
214
357
  plan_id: { type: "string", description: "Plan ID (plan_*)" },
215
358
  },
359
+ additionalProperties: false,
360
+ },
361
+ annotations: {
362
+ readOnlyHint: false,
363
+ destructiveHint: true,
364
+ openWorldHint: true,
216
365
  },
217
366
  },
218
367
  {
219
368
  name: "get_run",
369
+ title: "Get Execution Run",
220
370
  description: "Get the execution status, output, duration, and metered cost of a run (run_*).",
221
371
  inputSchema: {
222
372
  type: "object",
@@ -224,10 +374,17 @@ export const MUXO_MCP_TOOLS = [
224
374
  properties: {
225
375
  run_id: { type: "string", description: "Run ID (run_*)" },
226
376
  },
377
+ additionalProperties: false,
378
+ },
379
+ annotations: {
380
+ readOnlyHint: true,
381
+ destructiveHint: false,
382
+ openWorldHint: false,
227
383
  },
228
384
  },
229
385
  {
230
386
  name: "cancel_run",
387
+ title: "Cancel Execution Run",
231
388
  description: "Cancel an in-progress run and issue a cancellation receipt.",
232
389
  inputSchema: {
233
390
  type: "object",
@@ -235,11 +392,18 @@ export const MUXO_MCP_TOOLS = [
235
392
  properties: {
236
393
  run_id: { type: "string", description: "Run ID (run_*)" },
237
394
  },
395
+ additionalProperties: false,
396
+ },
397
+ annotations: {
398
+ readOnlyHint: false,
399
+ destructiveHint: true,
400
+ openWorldHint: false,
238
401
  },
239
402
  },
240
403
  {
241
404
  name: "get_receipt",
242
- description: "Fetch and cryptographically verify the HMAC-SHA256 chained execution receipt (rcpt_*) for a run.",
405
+ title: "Verify Execution Receipt",
406
+ description: "Fetch and cryptographically verify the HMAC-SHA256 + Ed25519 chained execution receipt (rcpt_*) for a run.",
243
407
  inputSchema: {
244
408
  type: "object",
245
409
  required: ["receipt_id"],
@@ -249,9 +413,185 @@ export const MUXO_MCP_TOOLS = [
249
413
  description: "Receipt ID (rcpt_*) or Run ID (run_*)",
250
414
  },
251
415
  },
416
+ additionalProperties: false,
417
+ },
418
+ annotations: {
419
+ readOnlyHint: true,
420
+ destructiveHint: false,
421
+ openWorldHint: false,
252
422
  },
253
423
  },
254
424
  ];
425
+ /**
426
+ * OpenAI Company Knowledge standard `search` and `fetch` tool definitions
427
+ * per https://developers.openai.com/plugins/build/mcp-server#company-knowledge-compatibility
428
+ */
429
+ export const OPENAI_COMPANY_KNOWLEDGE_TOOLS = [
430
+ {
431
+ name: "search",
432
+ title: "Search Muxo Tools & Workspace Memory",
433
+ description: "Search across Muxo tools, provisioned cloud resources, and Supermemory v5 workspace knowledge.",
434
+ inputSchema: {
435
+ type: "object",
436
+ required: ["query"],
437
+ properties: {
438
+ query: { type: "string", description: "Search query string." },
439
+ },
440
+ additionalProperties: false,
441
+ },
442
+ annotations: {
443
+ readOnlyHint: true,
444
+ destructiveHint: false,
445
+ openWorldHint: false,
446
+ },
447
+ },
448
+ {
449
+ name: "fetch",
450
+ title: "Fetch Muxo Tool or Memory Record",
451
+ description: "Retrieve complete details for a Muxo tool, resource, or workspace memory record by ID.",
452
+ inputSchema: {
453
+ type: "object",
454
+ required: ["id"],
455
+ properties: {
456
+ id: {
457
+ type: "string",
458
+ description: "Identifier returned by search (e.g. 'tool:instant.seo.audit' or 'memory:mem_123').",
459
+ },
460
+ },
461
+ additionalProperties: false,
462
+ },
463
+ annotations: {
464
+ readOnlyHint: true,
465
+ destructiveHint: false,
466
+ openWorldHint: false,
467
+ },
468
+ },
469
+ ];
470
+ function sha256Digest(content) {
471
+ const hash = crypto
472
+ .createHash("sha256")
473
+ .update(Buffer.from(content, "utf8"))
474
+ .digest("hex");
475
+ return `sha256:${hash}`;
476
+ }
477
+ function parseFrontmatter(markdown) {
478
+ const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---/);
479
+ if (!match)
480
+ return {};
481
+ const result = {};
482
+ for (const line of match[1].split(/\r?\n/)) {
483
+ const idx = line.indexOf(":");
484
+ if (idx > 0) {
485
+ const k = line.slice(0, idx).trim();
486
+ const v = line.slice(idx + 1).trim();
487
+ if (k && v)
488
+ result[k] = v;
489
+ }
490
+ }
491
+ return result;
492
+ }
493
+ function readSkillFileOrDefault(relPath, fallback) {
494
+ try {
495
+ const absPath = path.join(ROOT_DIR, "plugins", "muxo", "skills", relPath);
496
+ if (fs.existsSync(absPath)) {
497
+ return fs.readFileSync(absPath, "utf8");
498
+ }
499
+ }
500
+ catch {
501
+ // Fallback to embedded markdown
502
+ }
503
+ return fallback;
504
+ }
505
+ export function getMuxoMcpSkills() {
506
+ const muxoSkillMd = readSkillFileOrDefault("muxo/SKILL.md", `---
507
+ name: muxo
508
+ description: Route governed Muxo work between the hosted MCP-backed app and the local Muxo CLI across Connected Apps (Composio), Instant Tools, Cloud Infrastructure (Stripe Projects), Supermemory v5, and Microsoft Agent Governance.
509
+ ---
510
+
511
+ # Muxo
512
+
513
+ Use \`search_tools\`, \`inspect_tool\`, \`plan_action\`, \`wait_for_connection\`, and \`execute_<risk>\` to run governed actions across Connected Apps (\`app.*\`), Instant Tools (\`instant.*\`), and Cloud Infrastructure (\`resource.*\`).
514
+ `);
515
+ const muxoCliMd = readSkillFileOrDefault("muxo/references/cli.md", `# Local Muxo CLI\n\nRun \`muxo login --signup\`, \`muxo search\`, \`muxo link <provider> --wait\`, \`muxo exec\`, and \`muxo env pull\`.`);
516
+ const muxoMcpMd = readSkillFileOrDefault("muxo/references/mcp.md", `# Hosted Muxo MCP App\n\nFollow \`search_tools\` -> \`inspect_tool\` -> \`plan_action\` -> \`wait_for_connection\` -> \`execute_<risk>\` -> \`get_receipt\`.`);
517
+ const setupSkillMd = readSkillFileOrDefault("setup/SKILL.md", `---
518
+ name: setup
519
+ description: Guided onboarding skill for setting up the Muxo plugin in OpenAI ChatGPT and Codex. Helps users verify workspace authorization, connect external SaaS apps via OAuth handoff, provision cloud infrastructure, or install the local Muxo CLI.
520
+ ---
521
+
522
+ # Muxo Onboarding & Setup
523
+
524
+ Call \`get_profile\` and \`get_organization\` to verify your workspace connection, or run \`npx -y @muxoai/cli@latest login --signup\` in a terminal.
525
+ `);
526
+ const muxoFm = parseFrontmatter(muxoSkillMd);
527
+ const setupFm = parseFrontmatter(setupSkillMd);
528
+ const muxoFiles = [
529
+ {
530
+ path: "SKILL.md",
531
+ uri: "skill://muxo/muxo/SKILL.md",
532
+ size: Buffer.byteLength(muxoSkillMd, "utf8"),
533
+ digest: sha256Digest(muxoSkillMd),
534
+ mimeType: "text/markdown",
535
+ content: muxoSkillMd,
536
+ },
537
+ {
538
+ path: "references/cli.md",
539
+ uri: "skill://muxo/muxo/references/cli.md",
540
+ size: Buffer.byteLength(muxoCliMd, "utf8"),
541
+ digest: sha256Digest(muxoCliMd),
542
+ mimeType: "text/markdown",
543
+ content: muxoCliMd,
544
+ },
545
+ {
546
+ path: "references/mcp.md",
547
+ uri: "skill://muxo/muxo/references/mcp.md",
548
+ size: Buffer.byteLength(muxoMcpMd, "utf8"),
549
+ digest: sha256Digest(muxoMcpMd),
550
+ mimeType: "text/markdown",
551
+ content: muxoMcpMd,
552
+ },
553
+ ];
554
+ const setupFiles = [
555
+ {
556
+ path: "SKILL.md",
557
+ uri: "skill://muxo/setup/SKILL.md",
558
+ size: Buffer.byteLength(setupSkillMd, "utf8"),
559
+ digest: sha256Digest(setupSkillMd),
560
+ mimeType: "text/markdown",
561
+ content: setupSkillMd,
562
+ },
563
+ ];
564
+ const muxoName = muxoFm.name || "muxo";
565
+ const muxoDesc = muxoFm.description ||
566
+ "Route governed Muxo work between the hosted MCP-backed app and the local Muxo CLI.";
567
+ const setupName = setupFm.name || "setup";
568
+ const setupDesc = setupFm.description ||
569
+ "Guided onboarding skill for setting up the Muxo plugin in OpenAI ChatGPT and Codex.";
570
+ return [
571
+ {
572
+ name: muxoName,
573
+ description: muxoDesc,
574
+ uri: "skill://muxo/muxo/SKILL.md",
575
+ version: muxoFiles[0].digest,
576
+ frontmatter: {
577
+ name: muxoName,
578
+ description: muxoDesc,
579
+ },
580
+ files: muxoFiles,
581
+ },
582
+ {
583
+ name: setupName,
584
+ description: setupDesc,
585
+ uri: "skill://muxo/setup/SKILL.md",
586
+ version: setupFiles[0].digest,
587
+ frontmatter: {
588
+ name: setupName,
589
+ description: setupDesc,
590
+ },
591
+ files: setupFiles,
592
+ },
593
+ ];
594
+ }
255
595
  export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
256
596
  switch (toolName) {
257
597
  case "get_profile":
@@ -313,6 +653,65 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
313
653
  return engine.cancelRun(ctx, String(args.run_id || ""));
314
654
  case "get_receipt":
315
655
  return engine.getReceipt(ctx, String(args.receipt_id || args.run_id || ""));
656
+ // OpenAI Company Knowledge standard `search` and `fetch` tool support
657
+ case "search": {
658
+ const q = String(args.query || "").trim();
659
+ const [toolsRes, memRes] = await Promise.all([
660
+ engine.searchTools({ query: q, limit: 10 }),
661
+ engine.getMemoryOverview(ctx, q),
662
+ ]);
663
+ const toolHits = toolsRes.tools.map((t) => ({
664
+ id: `tool:${t.slug}`,
665
+ title: `${t.name} (${t.slug})`,
666
+ url: t.providerUrl || `https://docs.muxo.ai/tools/${encodeURIComponent(t.slug)}`,
667
+ snippet: `${t.description} [lane=${t.lane}, risk=${t.riskLevel}, cost=${t.creditCost}cr]`,
668
+ }));
669
+ const memHits = (memRes.memories || []).slice(0, 5).map((m) => ({
670
+ id: `memory:${m.id}`,
671
+ title: m.title,
672
+ url: `https://app.muxo.ai/?memory=${encodeURIComponent(m.id)}`,
673
+ snippet: m.content.slice(0, 240),
674
+ }));
675
+ return {
676
+ results: [...toolHits, ...memHits],
677
+ };
678
+ }
679
+ case "fetch": {
680
+ const rawId = String(args.id || "").trim();
681
+ const slug = rawId.startsWith("tool:") ? rawId.slice(5) : rawId;
682
+ if (rawId.startsWith("memory:")) {
683
+ const memId = rawId.slice(7);
684
+ const memRes = await engine.getMemoryOverview(ctx);
685
+ const found = (memRes.memories || []).find((m) => m.id === memId);
686
+ if (!found)
687
+ throw new Error(`Memory record not found: ${rawId}`);
688
+ return {
689
+ id: rawId,
690
+ title: found.title,
691
+ text: found.content,
692
+ url: `https://app.muxo.ai/?memory=${encodeURIComponent(found.id)}`,
693
+ metadata: {
694
+ namespace: found.namespace,
695
+ kind: found.kind,
696
+ createdAt: found.createdAt,
697
+ },
698
+ };
699
+ }
700
+ const tool = await engine.inspectTool(slug);
701
+ return {
702
+ id: `tool:${tool.slug}`,
703
+ title: tool.name,
704
+ text: JSON.stringify(tool, null, 2),
705
+ url: tool.providerUrl ||
706
+ `https://docs.muxo.ai/tools/${encodeURIComponent(tool.slug)}`,
707
+ metadata: {
708
+ slug: tool.slug,
709
+ lane: tool.lane,
710
+ riskLevel: tool.riskLevel,
711
+ creditCost: String(tool.creditCost),
712
+ },
713
+ };
714
+ }
316
715
  default:
317
716
  throw new Error(`Unknown MCP tool: ${toolName}`);
318
717
  }
@@ -321,22 +720,32 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
321
720
  const id = rpc.id ?? null;
322
721
  const method = String(rpc.method || "");
323
722
  const params = (rpc.params || {});
324
- if (method === "notifications/initialized") {
723
+ if (method === "notifications/initialized" ||
724
+ method.startsWith("notifications/")) {
325
725
  return null;
326
726
  }
327
727
  try {
328
728
  if (method === "initialize") {
729
+ const requestedProtocol = typeof params.protocolVersion === "string" &&
730
+ params.protocolVersion.trim()
731
+ ? params.protocolVersion.trim()
732
+ : "2025-06-18";
329
733
  return {
330
734
  jsonrpc: "2.0",
331
735
  id,
332
736
  result: {
333
- protocolVersion: "2024-11-05",
737
+ protocolVersion: requestedProtocol,
738
+ instructions: MUXO_MCP_SERVER_INSTRUCTIONS,
334
739
  serverInfo: {
335
740
  name: "muxo-mcp-server",
336
- version: "1.0.0",
741
+ version: "1.2.3",
337
742
  },
338
743
  capabilities: {
339
- tools: {},
744
+ tools: { listChanged: false },
745
+ resources: { listChanged: false },
746
+ extensions: {
747
+ "io.modelcontextprotocol/skills": {},
748
+ },
340
749
  },
341
750
  },
342
751
  };
@@ -357,10 +766,14 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
357
766
  const toolName = String(params.name || "");
358
767
  const toolArgs = (params.arguments || {});
359
768
  const output = await dispatchMcpToolCall(engine, ctx, toolName, toolArgs);
769
+ const structuredContent = output && typeof output === "object" && !Array.isArray(output)
770
+ ? output
771
+ : { data: output };
360
772
  return {
361
773
  jsonrpc: "2.0",
362
774
  id,
363
775
  result: {
776
+ structuredContent,
364
777
  content: [
365
778
  {
366
779
  type: "text",
@@ -371,6 +784,98 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
371
784
  },
372
785
  };
373
786
  }
787
+ // SEP-2640 Skills Import Extension (`io.modelcontextprotocol/skills`)
788
+ if (method === "skills/list") {
789
+ const skills = getMuxoMcpSkills().map((s) => ({
790
+ name: s.name,
791
+ description: s.description,
792
+ uri: s.uri,
793
+ version: s.version,
794
+ digest: s.files[0]?.digest || "",
795
+ files: s.files.length,
796
+ }));
797
+ return {
798
+ jsonrpc: "2.0",
799
+ id,
800
+ result: { skills },
801
+ };
802
+ }
803
+ if (method === "skills/get") {
804
+ const requestedName = String(params.name || "muxo").trim();
805
+ const skill = getMuxoMcpSkills().find((s) => s.name === requestedName);
806
+ if (!skill) {
807
+ return {
808
+ jsonrpc: "2.0",
809
+ id,
810
+ error: {
811
+ code: -32602,
812
+ message: `Skill not found: ${requestedName}`,
813
+ },
814
+ };
815
+ }
816
+ return {
817
+ jsonrpc: "2.0",
818
+ id,
819
+ result: {
820
+ skill: {
821
+ name: skill.name,
822
+ description: skill.description,
823
+ uri: skill.uri,
824
+ version: skill.version,
825
+ digest: skill.files[0]?.digest || "",
826
+ },
827
+ frontmatter: skill.frontmatter,
828
+ files: skill.files.map((f) => ({
829
+ path: f.path,
830
+ uri: f.uri,
831
+ size: f.size,
832
+ digest: f.digest,
833
+ mimeType: f.mimeType,
834
+ })),
835
+ },
836
+ };
837
+ }
838
+ if (method === "resources/list") {
839
+ const resources = getMuxoMcpSkills().flatMap((s) => s.files.map((f) => ({
840
+ uri: f.uri,
841
+ name: `${s.name}/${f.path}`,
842
+ description: s.description,
843
+ mimeType: f.mimeType,
844
+ })));
845
+ return {
846
+ jsonrpc: "2.0",
847
+ id,
848
+ result: { resources },
849
+ };
850
+ }
851
+ if (method === "resources/read") {
852
+ const uri = String(params.uri || "").trim();
853
+ const allFiles = getMuxoMcpSkills().flatMap((s) => s.files);
854
+ const found = allFiles.find((f) => f.uri === uri);
855
+ if (!found) {
856
+ return {
857
+ jsonrpc: "2.0",
858
+ id,
859
+ error: {
860
+ code: -32602,
861
+ message: `Resource not found: ${uri}`,
862
+ },
863
+ };
864
+ }
865
+ return {
866
+ jsonrpc: "2.0",
867
+ id,
868
+ result: {
869
+ contents: [
870
+ {
871
+ uri: found.uri,
872
+ mimeType: found.mimeType,
873
+ text: found.content,
874
+ },
875
+ ],
876
+ },
877
+ };
878
+ }
374
879
  return {
375
880
  jsonrpc: "2.0",
376
881
  id,