@muxoai/platform 1.4.0 → 1.4.1

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.
Files changed (54) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/ARCHITECTURE.md +16 -6
  4. package/README.md +1 -1
  5. package/dist/cli.js +317 -10
  6. package/dist/composio-catalog.d.ts +58 -0
  7. package/dist/composio-catalog.js +474 -0
  8. package/dist/config.d.ts +10 -0
  9. package/dist/config.js +16 -0
  10. package/dist/durable-workflow.d.ts +45 -0
  11. package/dist/durable-workflow.js +90 -0
  12. package/dist/engine.d.ts +276 -5
  13. package/dist/engine.js +1261 -71
  14. package/dist/mcp-schema.d.ts +125 -0
  15. package/dist/mcp-schema.js +1076 -0
  16. package/dist/mcp.d.ts +2 -30
  17. package/dist/mcp.js +505 -539
  18. package/dist/memory-graph.d.ts +21 -0
  19. package/dist/memory-graph.js +173 -0
  20. package/dist/nl.js +155 -0
  21. package/dist/oauth.d.ts +32 -0
  22. package/dist/oauth.js +134 -0
  23. package/dist/policy.d.ts +75 -1
  24. package/dist/policy.js +1119 -0
  25. package/dist/providers/composio-instant.js +225 -5
  26. package/dist/providers/composio-sdk.d.ts +68 -5
  27. package/dist/providers/composio-sdk.js +683 -78
  28. package/dist/providers/microsoft-governance.d.ts +28 -1
  29. package/dist/providers/microsoft-governance.js +224 -11
  30. package/dist/providers/stripe-billing.d.ts +42 -0
  31. package/dist/providers/stripe-billing.js +230 -1
  32. package/dist/providers/stripe-projects.d.ts +451 -3
  33. package/dist/providers/stripe-projects.js +2106 -87
  34. package/dist/providers/supermemory.d.ts +74 -1
  35. package/dist/providers/supermemory.js +426 -0
  36. package/dist/provisioning-managed.d.ts +50 -0
  37. package/dist/provisioning-managed.js +155 -0
  38. package/dist/sdk.d.ts +440 -3
  39. package/dist/sdk.js +305 -3
  40. package/dist/server.js +1841 -232
  41. package/dist/store.d.ts +113 -6
  42. package/dist/store.js +675 -52
  43. package/dist/types.d.ts +192 -3
  44. package/dist/ui/console-html.d.ts +10 -1
  45. package/dist/ui/console-html.js +1082 -452
  46. package/dist/version.d.ts +1 -1
  47. package/dist/version.js +1 -1
  48. package/package.json +2 -2
  49. package/plugins/muxo/.claude-plugin/plugin.json +1 -1
  50. package/plugins/muxo/.codex-plugin/plugin.json +1 -1
  51. package/plugins/muxo/plugin.json +2 -2
  52. package/plugins/muxo/skills/muxo/SKILL.md +42 -1
  53. package/plugins/muxo/skills/muxo/references/mcp.md +3 -2
  54. package/plugins/muxo/skills/setup/SKILL.md +8 -0
package/dist/mcp.js CHANGED
@@ -2,524 +2,9 @@ import crypto from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { ROOT_DIR } from "./config.js";
5
+ import { APPROVED_PLAN_STATUSES, DEFAULT_TOOL_SECURITY_SCHEMES, MUXO_MCP_SERVER_INSTRUCTIONS, MUXO_MCP_TOOLS, OPENAI_COMPANY_KNOWLEDGE_TOOLS, PUBLIC_MCP_TOOL_NAMES, PUBLIC_TOOL_SECURITY_SCHEMES, attachMcpHarnessGuidance, MuxoToolError, buildApprovalUrl, buildOnboardTeamGuide, clampWaitSeconds, errorPayloadFrom, findMcpSkill, securitySchemesForTool, } from "./mcp-schema.js";
5
6
  import { MUXO_VERSION } from "./version.js";
6
- const DEFAULT_TOOL_SECURITY_SCHEMES = [
7
- { type: "noauth" },
8
- {
9
- type: "oauth2",
10
- scopes: ["muxo:mcp", "muxo:read", "muxo:execute", "muxo:provision"],
11
- },
12
- ];
13
- /**
14
- * Concise server instructions (<512 chars) per OpenAI Plugin MCP Server specification:
15
- * https://developers.openai.com/plugins/build/mcp-server
16
- */
17
- export const MUXO_MCP_SERVER_INSTRUCTIONS = "Muxo governs SaaS actions (Connected Apps: app.*), Instant tools (instant.*), Cloud Infrastructure (resource.*), Workspace Memory recall, and verifiable audit records. 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.";
18
- export const MUXO_MCP_TOOLS = [
19
- {
20
- name: "get_profile",
21
- title: "Get Authenticated Profile",
22
- description: "Get the authenticated actor profile, user ID, email, workspace ID, and subscription tier.",
23
- inputSchema: {
24
- type: "object",
25
- properties: {},
26
- additionalProperties: false,
27
- },
28
- outputSchema: {
29
- $schema: "https://json-schema.org/draft/2020-12/schema",
30
- type: "object",
31
- properties: {
32
- id: {
33
- type: "string",
34
- minLength: 1,
35
- pattern: "\\S",
36
- description: "Unique identifier for the user.",
37
- },
38
- name: {
39
- type: "string",
40
- description: "Full name of the user.",
41
- },
42
- email: {
43
- type: "string",
44
- description: "Email address of the user.",
45
- },
46
- nickname: {
47
- type: "string",
48
- description: "Handle or username of the user.",
49
- },
50
- workspaceId: {
51
- type: "string",
52
- description: "Active workspace ID.",
53
- },
54
- workspaceName: {
55
- type: "string",
56
- description: "Active workspace name.",
57
- },
58
- tier: {
59
- type: "string",
60
- description: "Workspace subscription tier.",
61
- },
62
- authType: {
63
- type: "string",
64
- description: "Authentication type (session or api_key).",
65
- },
66
- actorId: {
67
- type: "string",
68
- description: "Actor identifier.",
69
- },
70
- user: {
71
- type: "object",
72
- description: "User profile record.",
73
- },
74
- },
75
- required: ["id"],
76
- additionalProperties: false,
77
- },
78
- securitySchemes: [
79
- { type: "noauth" },
80
- { type: "oauth2", scopes: ["muxo:read"] },
81
- ],
82
- annotations: {
83
- readOnlyHint: true,
84
- destructiveHint: false,
85
- openWorldHint: false,
86
- },
87
- _meta: {
88
- "openai/profile": true,
89
- },
90
- },
91
- {
92
- name: "get_organization",
93
- title: "Get Organization & Billing Summary",
94
- description: "Get workspace governance policy, monthly action usage, credit balance, Merchant-of-Record supplier settlement summary, and active connection/resource counts.",
95
- inputSchema: {
96
- type: "object",
97
- properties: {},
98
- additionalProperties: false,
99
- },
100
- annotations: {
101
- readOnlyHint: true,
102
- destructiveHint: false,
103
- openWorldHint: false,
104
- },
105
- },
106
- {
107
- name: "search_tools",
108
- title: "Search Unified Tool Catalog",
109
- description: "Search the unified Muxo catalog across Connected Apps (app.*), Instant Tools (instant.*), and Cloud Infrastructure (resource.*).",
110
- inputSchema: {
111
- type: "object",
112
- properties: {
113
- query: {
114
- type: "string",
115
- description: "Search keywords (e.g. 'postgres', 'github issue', 'web search', 'seo audit', 'redis')",
116
- },
117
- lane: {
118
- type: "string",
119
- enum: ["all", "composio_sdk", "composio_instant", "stripe_projects"],
120
- default: "all",
121
- },
122
- risk_level: {
123
- type: "string",
124
- enum: [
125
- "read",
126
- "write",
127
- "admin",
128
- "financial",
129
- "provisioning",
130
- "destructive",
131
- ],
132
- },
133
- limit: { type: "number", default: 20 },
134
- },
135
- additionalProperties: false,
136
- },
137
- annotations: {
138
- readOnlyHint: true,
139
- destructiveHint: false,
140
- openWorldHint: true,
141
- },
142
- },
143
- {
144
- name: "inspect_tool",
145
- title: "Inspect Tool Schema & Risk",
146
- description: "Inspect a tool's full input JSON schema, risk classification, provider lane, LLM context URL, and credit cost before planning.",
147
- inputSchema: {
148
- type: "object",
149
- required: ["tool_slug"],
150
- properties: {
151
- tool_slug: {
152
- type: "string",
153
- description: "Canonical Muxo tool slug (e.g. 'instant.seo.audit', 'app.gmail.send_email', or 'resource.turso.database')",
154
- },
155
- },
156
- additionalProperties: false,
157
- },
158
- annotations: {
159
- readOnlyHint: true,
160
- destructiveHint: false,
161
- openWorldHint: false,
162
- },
163
- },
164
- {
165
- name: "connection_status",
166
- title: "Check Connection Status",
167
- description: "Check connection status across Connected Apps, Instant Tools, and linked Cloud Infrastructure providers.",
168
- inputSchema: {
169
- type: "object",
170
- properties: {
171
- provider: {
172
- type: "string",
173
- description: "Optional provider filter (e.g. 'github', 'gmail', 'slack', 'neon', 'turso')",
174
- },
175
- sync_live: {
176
- type: "boolean",
177
- default: true,
178
- description: "Whether to sync live connection status from upstream providers",
179
- },
180
- },
181
- additionalProperties: false,
182
- },
183
- annotations: {
184
- readOnlyHint: true,
185
- destructiveHint: false,
186
- openWorldHint: true,
187
- },
188
- },
189
- {
190
- name: "start_connection",
191
- title: "Start OAuth Connection Handoff",
192
- description: "Initiate a managed OAuth connection handoff for a Connected App or link a Cloud Infrastructure provider.",
193
- inputSchema: {
194
- type: "object",
195
- required: ["provider"],
196
- properties: {
197
- provider: {
198
- type: "string",
199
- description: "Provider or toolkit slug (e.g. 'github', 'gmail', 'slack', 'neon')",
200
- },
201
- lane: {
202
- type: "string",
203
- enum: ["composio_sdk", "stripe_projects"],
204
- description: "Provider lane (defaults to composio_sdk unless prefixed with resource.)",
205
- },
206
- callback_url: {
207
- type: "string",
208
- description: "Optional OAuth callback URL",
209
- },
210
- },
211
- additionalProperties: false,
212
- },
213
- annotations: {
214
- readOnlyHint: false,
215
- destructiveHint: false,
216
- openWorldHint: true,
217
- },
218
- },
219
- {
220
- name: "wait_for_connection",
221
- title: "Wait for OAuth Connection Handoff",
222
- description: "Poll and wait for an external user's pending OAuth connection handoff to become active before resuming a planned operation.",
223
- inputSchema: {
224
- type: "object",
225
- required: ["provider"],
226
- properties: {
227
- provider: {
228
- type: "string",
229
- description: "Provider or toolkit slug (e.g. 'github', 'gmail', 'slack', 'notion', 'linear')",
230
- },
231
- timeout_seconds: {
232
- type: "number",
233
- default: 15,
234
- description: "Maximum seconds to poll for OAuth completion (0-120, default 15)",
235
- },
236
- },
237
- additionalProperties: false,
238
- },
239
- annotations: {
240
- readOnlyHint: true,
241
- destructiveHint: false,
242
- openWorldHint: true,
243
- },
244
- },
245
- {
246
- name: "plan_action",
247
- title: "Create Governed Action Plan",
248
- description: "Create a governed execution plan (plan_*) for any tool, billing operation, or infrastructure provisioning operation. Accepts either an exact tool_slug (e.g. 'instant.seo.audit', 'billing.credits.topup', 'resource.turso.database') or a natural-language instruction (e.g. 'audit seo for https://muxo.ai'). Evaluates workspace policy, risk level, Workspace Memory recall, safety guardrails, BYOK vs Muxo-funded mode, and credit balance.",
249
- inputSchema: {
250
- type: "object",
251
- required: ["tool_slug"],
252
- properties: {
253
- tool_slug: {
254
- type: "string",
255
- description: "Muxo tool slug (e.g. 'instant.seo.audit', 'billing.credits.topup') or natural-language request",
256
- },
257
- input: {
258
- type: "object",
259
- description: "Arguments matching the tool's inputSchema (auto-extracted when tool_slug is natural language)",
260
- },
261
- reason: {
262
- type: "string",
263
- description: "Audit reason explaining why this action is being planned",
264
- },
265
- },
266
- additionalProperties: false,
267
- },
268
- annotations: {
269
- readOnlyHint: false,
270
- destructiveHint: false,
271
- openWorldHint: false,
272
- },
273
- },
274
- {
275
- name: "get_plan",
276
- title: "Get Action Plan",
277
- description: "Inspect the status, risk level, governance decision record, and approval state of a planned action.",
278
- inputSchema: {
279
- type: "object",
280
- required: ["plan_id"],
281
- properties: {
282
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
283
- },
284
- additionalProperties: false,
285
- },
286
- annotations: {
287
- readOnlyHint: true,
288
- destructiveHint: false,
289
- openWorldHint: false,
290
- },
291
- },
292
- {
293
- name: "get_run_context",
294
- title: "Get Workspace Context & Memory",
295
- 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.",
296
- inputSchema: {
297
- type: "object",
298
- properties: {
299
- query: {
300
- type: "string",
301
- description: "Optional semantic search query to recall relevant workspace memories from Supermemory v5",
302
- },
303
- },
304
- additionalProperties: false,
305
- },
306
- annotations: {
307
- readOnlyHint: true,
308
- destructiveHint: false,
309
- openWorldHint: false,
310
- },
311
- },
312
- {
313
- name: "execute_read",
314
- title: "Execute Read Plan",
315
- description: "Execute an approved plan with riskLevel = 'read'.",
316
- inputSchema: {
317
- type: "object",
318
- required: ["plan_id"],
319
- properties: {
320
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
321
- },
322
- additionalProperties: false,
323
- },
324
- annotations: {
325
- readOnlyHint: true,
326
- destructiveHint: false,
327
- openWorldHint: true,
328
- },
329
- },
330
- {
331
- name: "execute_write",
332
- title: "Execute Write Plan",
333
- description: "Execute an approved plan with riskLevel = 'write'.",
334
- inputSchema: {
335
- type: "object",
336
- required: ["plan_id"],
337
- properties: {
338
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
339
- },
340
- additionalProperties: false,
341
- },
342
- annotations: {
343
- readOnlyHint: false,
344
- destructiveHint: false,
345
- openWorldHint: true,
346
- },
347
- },
348
- {
349
- name: "execute_admin",
350
- title: "Execute Admin Plan",
351
- description: "Execute an approved plan with riskLevel = 'admin'.",
352
- inputSchema: {
353
- type: "object",
354
- required: ["plan_id"],
355
- properties: {
356
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
357
- },
358
- additionalProperties: false,
359
- },
360
- annotations: {
361
- readOnlyHint: false,
362
- destructiveHint: false,
363
- openWorldHint: true,
364
- },
365
- },
366
- {
367
- name: "execute_financial",
368
- title: "Execute Financial Plan",
369
- description: "Execute an approved plan with riskLevel = 'financial'.",
370
- inputSchema: {
371
- type: "object",
372
- required: ["plan_id"],
373
- properties: {
374
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
375
- },
376
- additionalProperties: false,
377
- },
378
- annotations: {
379
- readOnlyHint: false,
380
- destructiveHint: false,
381
- openWorldHint: true,
382
- },
383
- },
384
- {
385
- name: "execute_provisioning",
386
- title: "Execute Infrastructure Provisioning Plan",
387
- description: "Execute an approved infrastructure provisioning plan with riskLevel = 'provisioning' via Stripe Projects.",
388
- inputSchema: {
389
- type: "object",
390
- required: ["plan_id"],
391
- properties: {
392
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
393
- },
394
- additionalProperties: false,
395
- },
396
- annotations: {
397
- readOnlyHint: false,
398
- destructiveHint: false,
399
- openWorldHint: true,
400
- },
401
- },
402
- {
403
- name: "execute_destructive",
404
- title: "Execute Destructive Plan",
405
- description: "Execute an approved plan with riskLevel = 'destructive'.",
406
- inputSchema: {
407
- type: "object",
408
- required: ["plan_id"],
409
- properties: {
410
- plan_id: { type: "string", description: "Plan ID (plan_*)" },
411
- },
412
- additionalProperties: false,
413
- },
414
- annotations: {
415
- readOnlyHint: false,
416
- destructiveHint: true,
417
- openWorldHint: true,
418
- },
419
- },
420
- {
421
- name: "get_run",
422
- title: "Get Execution Run",
423
- description: "Get the execution status, output, duration, and metered cost of a run (run_*).",
424
- inputSchema: {
425
- type: "object",
426
- required: ["run_id"],
427
- properties: {
428
- run_id: { type: "string", description: "Run ID (run_*)" },
429
- },
430
- additionalProperties: false,
431
- },
432
- annotations: {
433
- readOnlyHint: true,
434
- destructiveHint: false,
435
- openWorldHint: false,
436
- },
437
- },
438
- {
439
- name: "cancel_run",
440
- title: "Cancel Execution Run",
441
- description: "Cancel an in-progress run and issue a cancellation receipt.",
442
- inputSchema: {
443
- type: "object",
444
- required: ["run_id"],
445
- properties: {
446
- run_id: { type: "string", description: "Run ID (run_*)" },
447
- },
448
- additionalProperties: false,
449
- },
450
- annotations: {
451
- readOnlyHint: false,
452
- destructiveHint: true,
453
- openWorldHint: false,
454
- },
455
- },
456
- {
457
- name: "get_receipt",
458
- title: "Verify Execution Receipt",
459
- description: "Fetch and cryptographically verify the HMAC-SHA256 + Ed25519 chained execution receipt (rcpt_*) for a run.",
460
- inputSchema: {
461
- type: "object",
462
- required: ["receipt_id"],
463
- properties: {
464
- receipt_id: {
465
- type: "string",
466
- description: "Receipt ID (rcpt_*) or Run ID (run_*)",
467
- },
468
- },
469
- additionalProperties: false,
470
- },
471
- annotations: {
472
- readOnlyHint: true,
473
- destructiveHint: false,
474
- openWorldHint: false,
475
- },
476
- },
477
- ];
478
- /**
479
- * OpenAI Company Knowledge standard `search` and `fetch` tool definitions
480
- * per https://developers.openai.com/plugins/build/mcp-server#company-knowledge-compatibility
481
- */
482
- export const OPENAI_COMPANY_KNOWLEDGE_TOOLS = [
483
- {
484
- name: "search",
485
- title: "Search Muxo Tools & Workspace Memory",
486
- description: "Search across Muxo tools, provisioned cloud resources, and Supermemory v5 workspace knowledge.",
487
- inputSchema: {
488
- type: "object",
489
- required: ["query"],
490
- properties: {
491
- query: { type: "string", description: "Search query string." },
492
- },
493
- additionalProperties: false,
494
- },
495
- annotations: {
496
- readOnlyHint: true,
497
- destructiveHint: false,
498
- openWorldHint: false,
499
- },
500
- },
501
- {
502
- name: "fetch",
503
- title: "Fetch Muxo Tool or Memory Record",
504
- description: "Retrieve complete details for a Muxo tool, resource, or workspace memory record by ID.",
505
- inputSchema: {
506
- type: "object",
507
- required: ["id"],
508
- properties: {
509
- id: {
510
- type: "string",
511
- description: "Identifier returned by search (e.g. 'tool:instant.seo.audit' or 'memory:mem_123').",
512
- },
513
- },
514
- additionalProperties: false,
515
- },
516
- annotations: {
517
- readOnlyHint: true,
518
- destructiveHint: false,
519
- openWorldHint: false,
520
- },
521
- },
522
- ];
7
+ export { DEFAULT_TOOL_SECURITY_SCHEMES, MUXO_MCP_SERVER_INSTRUCTIONS, MUXO_MCP_TOOLS, OPENAI_COMPANY_KNOWLEDGE_TOOLS, PUBLIC_MCP_TOOL_NAMES, PUBLIC_TOOL_SECURITY_SCHEMES, attachMcpHarnessGuidance, securitySchemesForTool, };
523
8
  function sha256Digest(content) {
524
9
  const hash = crypto
525
10
  .createHash("sha256")
@@ -692,9 +177,7 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
692
177
  case "wait_for_connection":
693
178
  return engine.waitForConnection(ctx, {
694
179
  provider: String(args.provider || ""),
695
- timeoutSeconds: args.timeout_seconds !== undefined
696
- ? Number(args.timeout_seconds)
697
- : 15,
180
+ timeoutSeconds: clampWaitSeconds(args.timeout_seconds),
698
181
  });
699
182
  case "plan_action":
700
183
  return engine.planAction(ctx, {
@@ -708,9 +191,128 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
708
191
  reason: args.reason ? String(args.reason) : undefined,
709
192
  });
710
193
  case "get_plan":
711
- return engine.getPlan(ctx, String(args.plan_id || ""));
712
- case "get_run_context":
713
- return engine.getRunContext(ctx, args.query ? String(args.query) : undefined);
194
+ if (args.wait_for_approval === true || args.wait === true) {
195
+ return engine.waitForPlanApproval(ctx, {
196
+ planId: String(args.plan_id || ""),
197
+ timeoutSeconds: clampWaitSeconds(args.timeout_seconds, 15, 60),
198
+ });
199
+ }
200
+ {
201
+ const plan = engine.getPlan(ctx, String(args.plan_id || ""));
202
+ return {
203
+ ok: true,
204
+ approved: APPROVED_PLAN_STATUSES.has(plan.approvalStatus),
205
+ timedOut: false,
206
+ plan,
207
+ approvalStatus: plan.approvalStatus,
208
+ approvalUrl: buildApprovalUrl(engine.config.baseUrl, plan.id),
209
+ };
210
+ }
211
+ case "get_run_context": {
212
+ const action = String(args.action || "").trim().toLowerCase();
213
+ const prompt = String(args.prompt || "").trim();
214
+ const query = args.query ? String(args.query) : undefined;
215
+ const rawParamRules = Array.isArray(args.parameter_rules)
216
+ ? args.parameter_rules
217
+ : Array.isArray(args.parameterRules)
218
+ ? args.parameterRules
219
+ : undefined;
220
+ if (action === "memory_graph") {
221
+ return engine.getMemoryGraph(ctx, query);
222
+ }
223
+ if (action === "governance_status") {
224
+ return engine.getGovernanceOverview(ctx);
225
+ }
226
+ if (action === "list_workspaces") {
227
+ const workspaces = engine.store.listUserWorkspaces(ctx.user.id, ctx.workspace.id);
228
+ return {
229
+ ok: true,
230
+ action,
231
+ currentWorkspaceId: ctx.workspace.id,
232
+ activeWorkspace: workspaces.find((w) => w.id === ctx.workspace.id) || {
233
+ id: ctx.workspace.id,
234
+ name: ctx.workspace.name,
235
+ slug: ctx.workspace.slug,
236
+ tier: ctx.workspace.tier,
237
+ },
238
+ workspaces,
239
+ };
240
+ }
241
+ if (action === "switch_workspace") {
242
+ const targetWsId = String(args.workspace_id || query || prompt || "").trim();
243
+ if (!targetWsId) {
244
+ throw new Error("workspace_id is required when action='switch_workspace'");
245
+ }
246
+ const switched = engine.store.switchUserWorkspace(ctx.user.id, targetWsId);
247
+ if (!switched) {
248
+ throw new Error(`Workspace ${targetWsId} not found or not linked to your account. Call get_run_context with action='list_workspaces' to see accessible workspaces.`);
249
+ }
250
+ return {
251
+ ok: true,
252
+ action,
253
+ switched: true,
254
+ workspaceId: switched.workspace.id,
255
+ workspace: switched.workspace,
256
+ workspaces: engine.store.listUserWorkspaces(ctx.user.id, switched.workspace.id),
257
+ message: `Active workspace for your session is now ${switched.workspace.name} (${switched.workspace.id}). API keys stay bound to their own workspace; use a key minted for ${switched.workspace.id} to target it over MCP.`,
258
+ };
259
+ }
260
+ if (action === "onboard_team") {
261
+ return buildOnboardTeamGuide({
262
+ baseUrl: engine.config.baseUrl,
263
+ workspaceId: ctx.workspace.id,
264
+ workspaceName: ctx.workspace.name,
265
+ teamName: String(args.team_name || args.teamName || query || prompt || "").trim(),
266
+ workspaces: engine.store.listUserWorkspaces(ctx.user.id, ctx.workspace.id),
267
+ });
268
+ }
269
+ if (action === "set_guardrail" &&
270
+ (prompt || (rawParamRules && rawParamRules.length > 0))) {
271
+ return engine.applyNaturalLanguageGuardrail(ctx, prompt, {
272
+ parameterRules: rawParamRules,
273
+ source: rawParamRules ? "mcp_harness" : "deterministic",
274
+ });
275
+ }
276
+ if (action === "scan_context") {
277
+ const textToScan = String(args.content || prompt || query || "");
278
+ return engine.scanForContextPoisoning(ctx.workspace.id, textToScan);
279
+ }
280
+ if (action === "forget") {
281
+ if (!(query || prompt)) {
282
+ throw new Error("query is required when action='forget'");
283
+ }
284
+ return engine.forgetWorkspaceMemoryMatching(ctx, query || prompt);
285
+ }
286
+ if (action === "recall") {
287
+ return engine.getMemoryOverview(ctx, query);
288
+ }
289
+ if (action === "remember") {
290
+ if (prompt && !args.content) {
291
+ return engine.doNaturalLanguage(ctx, { prompt });
292
+ }
293
+ const record = await engine.addWorkspaceMemory(ctx, {
294
+ title: String(args.title || prompt.slice(0, 60) || "Workspace Fact"),
295
+ content: String(args.content || prompt || query || ""),
296
+ kind: "fact",
297
+ });
298
+ const overview = await engine.getMemoryOverview(ctx);
299
+ return {
300
+ ok: true,
301
+ memory: record,
302
+ activeDefaults: overview.activeDefaults,
303
+ explanation: overview.explanation,
304
+ };
305
+ }
306
+ if (prompt && !action) {
307
+ return engine.doNaturalLanguage(ctx, { prompt });
308
+ }
309
+ const runCtx = await engine.getRunContext(ctx, query);
310
+ if (args.include_graph === true) {
311
+ const memoryGraph = await engine.getMemoryGraph(ctx, query);
312
+ return { ...runCtx, memoryGraph };
313
+ }
314
+ return runCtx;
315
+ }
714
316
  case "execute_read":
715
317
  return engine.executePlanForRisk(ctx, String(args.plan_id || ""), "read");
716
318
  case "execute_write":
@@ -726,9 +328,92 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
726
328
  case "get_run":
727
329
  return engine.getRun(ctx, String(args.run_id || ""));
728
330
  case "cancel_run":
729
- return engine.cancelRun(ctx, String(args.run_id || ""));
730
- case "get_receipt":
731
- return engine.getReceipt(ctx, String(args.receipt_id || args.run_id || ""));
331
+ return engine.cancelRun(ctx, String(args.run_id || ""), args.reason ? String(args.reason) : undefined);
332
+ case "get_receipt": {
333
+ const targetId = String(args.receipt_id || args.run_id || "latest").trim();
334
+ if (targetId === "chain") {
335
+ return engine.verifyReceiptChain(ctx);
336
+ }
337
+ const verified = engine.getReceipt(ctx, targetId);
338
+ if (args.verify_chain === true) {
339
+ const receiptChain = engine.verifyReceiptChain(ctx);
340
+ return { ...verified, receiptChain };
341
+ }
342
+ return verified;
343
+ }
344
+ // Supermemory MCP & Governance direct tool aliases for agent harness interoperability
345
+ case "who_am_i":
346
+ return engine.getProfile(ctx);
347
+ case "list_spaces": {
348
+ const overview = await engine.getMemoryOverview(ctx);
349
+ return {
350
+ activeSpace: overview.namespace,
351
+ spaces: [
352
+ {
353
+ id: overview.namespace,
354
+ containerTag: overview.namespace,
355
+ workspaceId: ctx.workspace.id,
356
+ workspaceName: ctx.workspace.name,
357
+ active: true,
358
+ },
359
+ ],
360
+ };
361
+ }
362
+ case "search_memory":
363
+ case "list_memories":
364
+ return engine.getMemoryOverview(ctx, args.query ? String(args.query) : undefined);
365
+ case "add_memory":
366
+ case "remember": {
367
+ const prompt = String(args.prompt || "").trim();
368
+ if (prompt && !args.content) {
369
+ return engine.doNaturalLanguage(ctx, { prompt });
370
+ }
371
+ const content = String(args.content || args.memory || prompt || "");
372
+ const title = String(args.title || content.slice(0, 60) || "Workspace Memory");
373
+ const record = await engine.addWorkspaceMemory(ctx, {
374
+ title,
375
+ content,
376
+ kind: args.kind || "fact",
377
+ });
378
+ const overview = await engine.getMemoryOverview(ctx);
379
+ return {
380
+ ok: true,
381
+ memory: record,
382
+ activeDefaults: overview.activeDefaults,
383
+ explanation: overview.explanation,
384
+ };
385
+ }
386
+ case "forget_memory": {
387
+ const query = String(args.query || args.id || args.memory || "").trim();
388
+ if (!query)
389
+ throw new Error("query is required to forget a memory");
390
+ return engine.forgetWorkspaceMemoryMatching(ctx, query);
391
+ }
392
+ case "memory_graph":
393
+ return engine.getMemoryGraph(ctx, args.query ? String(args.query) : undefined);
394
+ case "set_guardrail":
395
+ case "configure_guardrails": {
396
+ const rawParamRules = Array.isArray(args.parameter_rules)
397
+ ? args.parameter_rules
398
+ : Array.isArray(args.parameterRules)
399
+ ? args.parameterRules
400
+ : undefined;
401
+ return engine.applyNaturalLanguageGuardrail(ctx, String(args.prompt || args.rule || args.instruction || ""), {
402
+ parameterRules: rawParamRules,
403
+ source: rawParamRules ? "mcp_harness" : "deterministic",
404
+ });
405
+ }
406
+ case "governance_status":
407
+ return engine.getGovernanceOverview(ctx);
408
+ case "verify_receipt_chain":
409
+ return engine.verifyReceiptChain(ctx, args.limit ? Number(args.limit) : 100);
410
+ case "do":
411
+ return engine.doNaturalLanguage(ctx, {
412
+ prompt: String(args.prompt || args.instruction || args.query || ""),
413
+ input: args.input || undefined,
414
+ dryRun: Boolean(args.dry_run || args.dryRun),
415
+ autoApprove: args.auto_approve !== false && args.autoApprove !== false,
416
+ });
732
417
  // OpenAI Company Knowledge standard `search` and `fetch` tool support
733
418
  case "search": {
734
419
  const q = String(args.query || "").trim();
@@ -789,7 +474,7 @@ export async function dispatchMcpToolCall(engine, ctx, toolName, args = {}) {
789
474
  };
790
475
  }
791
476
  default:
792
- throw new Error(`Unknown MCP tool: ${toolName}`);
477
+ throw new MuxoToolError(`Unknown MCP tool: '${toolName}'. Call tools/list for the canonical Muxo MCP tools.`, { code: "unknown_mcp_tool", statusCode: 404, payload: { toolName } });
793
478
  }
794
479
  }
795
480
  export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
@@ -819,6 +504,7 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
819
504
  capabilities: {
820
505
  tools: { listChanged: false },
821
506
  resources: { listChanged: false },
507
+ prompts: { listChanged: false },
822
508
  extensions: {
823
509
  "io.modelcontextprotocol/skills": {},
824
510
  },
@@ -829,6 +515,126 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
829
515
  if (method === "ping") {
830
516
  return { jsonrpc: "2.0", id, result: {} };
831
517
  }
518
+ if (method === "prompts/list") {
519
+ return {
520
+ jsonrpc: "2.0",
521
+ id,
522
+ result: {
523
+ prompts: [
524
+ {
525
+ name: "context",
526
+ title: "Workspace Memory & Governance Context",
527
+ description: "Ready-to-attach workspace context (Supermemory v5 profile, bi-temporal facts, learned parameter defaults, and active Microsoft Governance guardrails).",
528
+ arguments: [
529
+ {
530
+ name: "query",
531
+ description: "Optional topic or task query to focus memory recall",
532
+ required: false,
533
+ },
534
+ ],
535
+ },
536
+ {
537
+ name: "governed_execution",
538
+ title: "Governed Tool Execution Workflow",
539
+ description: "Step-by-step assistant prompt for discovering, planning, approving, executing, and verifying a governed Muxo action.",
540
+ arguments: [
541
+ {
542
+ name: "task",
543
+ description: "Natural-language task to plan and execute",
544
+ required: false,
545
+ },
546
+ ],
547
+ },
548
+ {
549
+ name: "security_audit",
550
+ title: "Workspace Governance, Memory Graph & Receipt Chain Audit",
551
+ description: "Inspect the workspace's 9-module Microsoft Agent Governance posture, Bi-Temporal Knowledge Graph, and Ed25519 AgenticReceipt hash chain.",
552
+ arguments: [],
553
+ },
554
+ ],
555
+ },
556
+ };
557
+ }
558
+ if (method === "prompts/get") {
559
+ const promptName = String(params.name || "context").trim();
560
+ const promptArgs = (params.arguments || {});
561
+ if (promptName === "context") {
562
+ const query = promptArgs.query ? String(promptArgs.query) : undefined;
563
+ const runCtx = await engine.getRunContext(ctx, query);
564
+ return {
565
+ jsonrpc: "2.0",
566
+ id,
567
+ result: {
568
+ description: "Ready-to-attach Muxo workspace memory, active defaults, and safety guardrails.",
569
+ messages: [
570
+ {
571
+ role: "user",
572
+ content: {
573
+ type: "text",
574
+ text: String(runCtx.llmSystemPrompt || runCtx.explanation.preferred),
575
+ },
576
+ },
577
+ ],
578
+ },
579
+ };
580
+ }
581
+ if (promptName === "governed_execution") {
582
+ const task = String(promptArgs.task || "the user's requested operation");
583
+ const runCtx = await engine.getRunContext(ctx);
584
+ return {
585
+ jsonrpc: "2.0",
586
+ id,
587
+ result: {
588
+ description: "Governed Muxo execution workflow prompt",
589
+ messages: [
590
+ {
591
+ role: "user",
592
+ content: {
593
+ type: "text",
594
+ text: `${runCtx.llmSystemPrompt}\n\n## Task\nExecute "${task}" safely using Muxo:\n1. Call \`search_tools\` and \`inspect_tool\` (or pass a natural-language request to \`plan_action\`).\n2. Call \`plan_action\` and inspect \`plan.approvalStatus\`, \`authHandoff\`, and \`llmGuidance.nextToolCalls\`.\n3. If \`authHandoff.required\` is true, present \`humanHandoff.markdownForUser\` and call \`wait_for_connection\`.\n4. If \`approvalStatus === "pending_approval"\`, present \`humanHandoff.markdownForUser\` and call \`get_plan\` with \`wait_for_approval: true\`.\n5. Execute with \`execute_<riskLevel>\` and verify the cryptographic receipt with \`get_receipt\`.`,
595
+ },
596
+ },
597
+ ],
598
+ },
599
+ };
600
+ }
601
+ if (promptName === "security_audit") {
602
+ const [gov, graph, chain] = await Promise.all([
603
+ Promise.resolve(engine.getGovernanceOverview(ctx)),
604
+ engine.getMemoryGraph(ctx),
605
+ Promise.resolve(engine.verifyReceiptChain(ctx)),
606
+ ]);
607
+ return {
608
+ jsonrpc: "2.0",
609
+ id,
610
+ result: {
611
+ description: "Workspace governance, bi-temporal graph, and receipt chain audit",
612
+ messages: [
613
+ {
614
+ role: "user",
615
+ content: {
616
+ type: "text",
617
+ text: [
618
+ `# Muxo Security, Memory & Cryptographic Audit`,
619
+ `## 1. Microsoft Agent Governance (9 Modules)\n${gov.explanation.preferred}`,
620
+ `## 2. Bi-Temporal Knowledge Graph\n${graph.explanation.preferred}\n\`\`\`mermaid\n${graph.mermaid}\n\`\`\``,
621
+ `## 3. Portable Ed25519 AgenticReceipt Chain\n${chain.explanation.preferred}`,
622
+ ].join("\n\n"),
623
+ },
624
+ },
625
+ ],
626
+ },
627
+ };
628
+ }
629
+ return {
630
+ jsonrpc: "2.0",
631
+ id,
632
+ error: {
633
+ code: -32602,
634
+ message: `Prompt not found: ${promptName}`,
635
+ },
636
+ };
637
+ }
832
638
  if (method === "tools/list") {
833
639
  return {
834
640
  jsonrpc: "2.0",
@@ -836,7 +642,7 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
836
642
  result: {
837
643
  tools: MUXO_MCP_TOOLS.map((t) => ({
838
644
  ...t,
839
- securitySchemes: t.securitySchemes || DEFAULT_TOOL_SECURITY_SCHEMES,
645
+ securitySchemes: securitySchemesForTool(t.name),
840
646
  })),
841
647
  },
842
648
  };
@@ -844,7 +650,8 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
844
650
  if (method === "tools/call") {
845
651
  const toolName = String(params.name || "");
846
652
  const toolArgs = (params.arguments || {});
847
- const output = await dispatchMcpToolCall(engine, ctx, toolName, toolArgs);
653
+ const rawOutput = await dispatchMcpToolCall(engine, ctx, toolName, toolArgs);
654
+ const output = attachMcpHarnessGuidance(toolName, toolArgs, rawOutput);
848
655
  const structuredContent = output && typeof output === "object" && !Array.isArray(output)
849
656
  ? output
850
657
  : { data: output };
@@ -885,16 +692,14 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
885
692
  };
886
693
  }
887
694
  if (method === "skills/get") {
888
- const requestedUri = String(params.uri || "").trim();
889
- const requestedName = String(params.name || "muxo").trim();
890
- const skill = getMuxoMcpSkills().find((s) => s.uri === requestedUri || s.name === requestedName);
695
+ const { skill, requested } = findMcpSkill(getMuxoMcpSkills(), params);
891
696
  if (!skill) {
892
697
  return {
893
698
  jsonrpc: "2.0",
894
699
  id,
895
700
  error: {
896
701
  code: -32602,
897
- message: `Skill not found: ${requestedUri || requestedName}`,
702
+ message: `Skill not found: ${requested}`,
898
703
  },
899
704
  };
900
705
  }
@@ -929,20 +734,184 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
929
734
  };
930
735
  }
931
736
  if (method === "resources/list") {
932
- const resources = getMuxoMcpSkills().flatMap((s) => s.files.map((f) => ({
737
+ const skillResources = getMuxoMcpSkills().flatMap((s) => s.files.map((f) => ({
933
738
  uri: f.uri,
934
739
  name: `${s.name}/${f.path}`,
935
740
  description: s.description,
936
741
  mimeType: f.mimeType,
937
742
  })));
743
+ const dynamicResources = [
744
+ {
745
+ uri: "muxo://profile",
746
+ name: "Workspace Profile & Active Memory Defaults",
747
+ description: "Stable and recent Supermemory v5 profile context, active auto-fill defaults, and Ed25519 Agent DID for the active workspace.",
748
+ mimeType: "application/json",
749
+ },
750
+ {
751
+ uri: "supermemory://profile",
752
+ name: "Supermemory Active Space Profile",
753
+ description: "Supermemory MCP compatible profile resource (static + dynamic facts and preferences) for the active workspace.",
754
+ mimeType: "application/json",
755
+ },
756
+ {
757
+ uri: "supermemory://spaces",
758
+ name: "Supermemory Accessible Spaces",
759
+ description: "Compact list of accessible workspace memory spaces with the active containerTag marked.",
760
+ mimeType: "application/json",
761
+ },
762
+ {
763
+ uri: "muxo://context",
764
+ name: "Governed Workspace Run Context",
765
+ description: "Ready-to-inject workspace context including guardrails, learned defaults, provisioned cloud resources, and Supermemory recall.",
766
+ mimeType: "application/json",
767
+ },
768
+ {
769
+ uri: "muxo://memory/graph",
770
+ name: "Bi-Temporal Knowledge Graph",
771
+ description: "Entity & relationship graph with active facts, superseded historical facts (validFrom/validTo), and Mermaid topology.",
772
+ mimeType: "application/json",
773
+ },
774
+ {
775
+ uri: "muxo://governance/policy",
776
+ name: "Microsoft Agent Governance & Guardrails",
777
+ description: "9-module Microsoft Agent Governance status, plain-English guardrails, Bayesian trust score, and OWASP ASI-06 scan status.",
778
+ mimeType: "application/json",
779
+ },
780
+ {
781
+ uri: "muxo://receipts/chain",
782
+ name: "Cryptographic AgenticReceipt Hash Chain",
783
+ description: "Tamper-evident SHA-256 + portable Ed25519 AgenticReceipt chain verification report.",
784
+ mimeType: "application/json",
785
+ },
786
+ ];
938
787
  return {
939
788
  jsonrpc: "2.0",
940
789
  id,
941
- result: { resources },
790
+ result: { resources: [...skillResources, ...dynamicResources] },
942
791
  };
943
792
  }
944
793
  if (method === "resources/read") {
945
794
  const uri = String(params.uri || "").trim();
795
+ if (uri === "muxo://profile" || uri === "supermemory://profile") {
796
+ const overview = await engine.getMemoryOverview(ctx);
797
+ const profile = engine.getProfile(ctx);
798
+ const payload = {
799
+ uri,
800
+ workspaceId: ctx.workspace.id,
801
+ workspaceSlug: ctx.workspace.slug,
802
+ namespace: overview.namespace,
803
+ profile: overview.context.profile,
804
+ activeDefaults: overview.activeDefaults,
805
+ activeGuardrails: overview.activeGuardrails,
806
+ actor: profile,
807
+ explanation: overview.explanation,
808
+ };
809
+ return {
810
+ jsonrpc: "2.0",
811
+ id,
812
+ result: {
813
+ contents: [
814
+ {
815
+ uri,
816
+ mimeType: "application/json",
817
+ text: JSON.stringify(payload, null, 2),
818
+ },
819
+ ],
820
+ },
821
+ };
822
+ }
823
+ if (uri === "muxo://spaces" || uri === "supermemory://spaces") {
824
+ const overview = await engine.getMemoryOverview(ctx);
825
+ const payload = {
826
+ activeSpace: overview.namespace,
827
+ spaces: [
828
+ {
829
+ id: overview.namespace,
830
+ containerTag: overview.namespace,
831
+ workspaceId: ctx.workspace.id,
832
+ workspaceName: ctx.workspace.name,
833
+ active: true,
834
+ },
835
+ ],
836
+ };
837
+ return {
838
+ jsonrpc: "2.0",
839
+ id,
840
+ result: {
841
+ contents: [
842
+ {
843
+ uri,
844
+ mimeType: "application/json",
845
+ text: JSON.stringify(payload, null, 2),
846
+ },
847
+ ],
848
+ },
849
+ };
850
+ }
851
+ if (uri === "muxo://context") {
852
+ const runCtx = await engine.getRunContext(ctx);
853
+ return {
854
+ jsonrpc: "2.0",
855
+ id,
856
+ result: {
857
+ contents: [
858
+ {
859
+ uri,
860
+ mimeType: "application/json",
861
+ text: JSON.stringify(runCtx, null, 2),
862
+ },
863
+ ],
864
+ },
865
+ };
866
+ }
867
+ if (uri === "muxo://memory/graph") {
868
+ const graph = await engine.getMemoryGraph(ctx);
869
+ return {
870
+ jsonrpc: "2.0",
871
+ id,
872
+ result: {
873
+ contents: [
874
+ {
875
+ uri,
876
+ mimeType: "application/json",
877
+ text: JSON.stringify(graph, null, 2),
878
+ },
879
+ ],
880
+ },
881
+ };
882
+ }
883
+ if (uri === "muxo://governance/policy") {
884
+ const gov = engine.getGovernanceOverview(ctx);
885
+ return {
886
+ jsonrpc: "2.0",
887
+ id,
888
+ result: {
889
+ contents: [
890
+ {
891
+ uri,
892
+ mimeType: "application/json",
893
+ text: JSON.stringify(gov, null, 2),
894
+ },
895
+ ],
896
+ },
897
+ };
898
+ }
899
+ if (uri === "muxo://receipts/chain") {
900
+ const chain = engine.verifyReceiptChain(ctx);
901
+ return {
902
+ jsonrpc: "2.0",
903
+ id,
904
+ result: {
905
+ contents: [
906
+ {
907
+ uri,
908
+ mimeType: "application/json",
909
+ text: JSON.stringify(chain, null, 2),
910
+ },
911
+ ],
912
+ },
913
+ };
914
+ }
946
915
  const allFiles = getMuxoMcpSkills().flatMap((s) => s.files);
947
916
  const found = allFiles.find((f) => f.uri === uri);
948
917
  if (!found) {
@@ -979,10 +948,7 @@ export async function handleJsonRpcMcpRequest(engine, ctx, rpc) {
979
948
  };
980
949
  }
981
950
  catch (err) {
982
- const errPayload = {
983
- ok: false,
984
- error: String(err?.message || err || "MCP tool execution failed"),
985
- };
951
+ const errPayload = errorPayloadFrom(err, "MCP tool execution failed");
986
952
  return {
987
953
  jsonrpc: "2.0",
988
954
  id,