@muxoai/platform 1.3.3 → 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 +7 -5
  5. package/dist/cli.js +393 -13
  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 +538 -8
  39. package/dist/sdk.js +377 -10
  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 +212 -5
  44. package/dist/ui/console-html.d.ts +10 -1
  45. package/dist/ui/console-html.js +1188 -462
  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
@@ -0,0 +1,1076 @@
1
+ export const MCP_TOOLS_OAUTH_SCOPE = "mcp:tools";
2
+ /** Workspace-bound tools require an OAuth bearer token (or workspace API key). */
3
+ export const DEFAULT_TOOL_SECURITY_SCHEMES = [
4
+ { type: "oauth2", scopes: [MCP_TOOLS_OAUTH_SCOPE] },
5
+ ];
6
+ /** Catalog discovery tools work anonymously and also accept OAuth. */
7
+ export const PUBLIC_TOOL_SECURITY_SCHEMES = [
8
+ { type: "noauth" },
9
+ { type: "oauth2", scopes: [MCP_TOOLS_OAUTH_SCOPE] },
10
+ ];
11
+ export const PUBLIC_MCP_TOOL_NAMES = new Set([
12
+ "search_tools",
13
+ "inspect_tool",
14
+ "search",
15
+ "fetch",
16
+ ]);
17
+ /** Stable per-workspace agent identity returned at agent signup on both runtimes. */
18
+ export function workspaceAgentDid(workspaceId) {
19
+ return `did:agent:muxo:${workspaceId}`;
20
+ }
21
+ /** JSON-RPC methods that anonymous MCP clients may call for discovery. */
22
+ export const PUBLIC_MCP_METHODS = new Set([
23
+ "initialize",
24
+ "ping",
25
+ "tools/list",
26
+ "resources/list",
27
+ "resources/read",
28
+ "resources/templates/list",
29
+ "prompts/list",
30
+ ]);
31
+ /** True when a single JSON-RPC MCP request only needs public discovery access. */
32
+ export function isPublicMcpRequest(rpc) {
33
+ if (!rpc || typeof rpc !== "object" || Array.isArray(rpc))
34
+ return false;
35
+ const message = rpc;
36
+ const method = String(message.method || "");
37
+ if (method.startsWith("notifications/") || PUBLIC_MCP_METHODS.has(method))
38
+ return true;
39
+ if (method === "tools/call") {
40
+ const params = (message.params || {});
41
+ return PUBLIC_MCP_TOOL_NAMES.has(String(params.name || ""));
42
+ }
43
+ return false;
44
+ }
45
+ export function securitySchemesForTool(name) {
46
+ return PUBLIC_MCP_TOOL_NAMES.has(name)
47
+ ? PUBLIC_TOOL_SECURITY_SCHEMES
48
+ : DEFAULT_TOOL_SECURITY_SCHEMES;
49
+ }
50
+ /** Maximum in-turn polling window for wait_for_connection and get_plan(wait_for_approval). */
51
+ export const MAX_MCP_WAIT_SECONDS = 120;
52
+ export const DEFAULT_MCP_WAIT_SECONDS = 15;
53
+ export function clampWaitSeconds(raw, fallback = DEFAULT_MCP_WAIT_SECONDS, max = MAX_MCP_WAIT_SECONDS) {
54
+ const n = raw === undefined || raw === null || raw === "" ? fallback : Number(raw);
55
+ if (!Number.isFinite(n))
56
+ return Math.min(fallback, max);
57
+ return Math.max(0, Math.min(max, n));
58
+ }
59
+ /** Matches explicit catalog slugs (e.g. 'app.github.create_issue') as opposed to natural-language requests. */
60
+ export function looksLikeToolSlug(raw) {
61
+ return /^[a-z0-9_-]+(\.[a-z0-9_-]+)+$/i.test(String(raw || "").trim());
62
+ }
63
+ /**
64
+ * Picks the live Composio search hit for a requested `app.<toolkit>.<action>` slug: an exact
65
+ * slug/upstream match, else a same-toolkit tool whose slug contains every action word. Returns
66
+ * null rather than an unrelated top search result.
67
+ */
68
+ export function matchAppToolSlug(requestedSlug, candidates) {
69
+ const clean = String(requestedSlug || "").trim();
70
+ const parts = clean.split(".");
71
+ if (parts[0] !== "app" || parts.length < 3)
72
+ return null;
73
+ const toolkit = parts[1].toLowerCase();
74
+ const action = parts.slice(2).join("_").toLowerCase();
75
+ const upstream = `${toolkit}_${action}`.toUpperCase();
76
+ const exact = candidates.find((c) => c.slug === clean || c.upstreamSlug.toUpperCase() === upstream);
77
+ if (exact)
78
+ return exact;
79
+ const words = action.split(/[_\s]+/).filter(Boolean);
80
+ if (words.length === 0)
81
+ return null;
82
+ return (candidates.find((c) => c.providerSlug.toLowerCase() === toolkit &&
83
+ words.every((w) => c.slug.toLowerCase().includes(w))) || null);
84
+ }
85
+ export const DEFAULT_MCP_SKILL_NAME = "muxo";
86
+ /**
87
+ * SEP-2640 `skills/get` lookup. A `uri` takes precedence over `name`, and a miss returns
88
+ * `skill: undefined` so callers answer with JSON-RPC -32602 rather than a default skill.
89
+ */
90
+ export function findMcpSkill(skills, params) {
91
+ const requestedUri = String(params.uri || "").trim();
92
+ if (requestedUri) {
93
+ return { skill: skills.find((s) => s.uri === requestedUri), requested: requestedUri };
94
+ }
95
+ const requestedName = String(params.name || "").trim() || DEFAULT_MCP_SKILL_NAME;
96
+ return { skill: skills.find((s) => s.name === requestedName), requested: requestedName };
97
+ }
98
+ export const APPROVED_PLAN_STATUSES = new Set([
99
+ "approved",
100
+ "auto_approved",
101
+ "executed",
102
+ ]);
103
+ export const GET_RUN_CONTEXT_ACTIONS = [
104
+ "inspect",
105
+ "remember",
106
+ "recall",
107
+ "forget",
108
+ "memory_graph",
109
+ "set_guardrail",
110
+ "governance_status",
111
+ "scan_context",
112
+ "list_workspaces",
113
+ "switch_workspace",
114
+ "onboard_team",
115
+ ];
116
+ /** Error carrying a structured MCP/REST payload (merged into structuredContent / JSON body). */
117
+ export class MuxoToolError extends Error {
118
+ code;
119
+ statusCode;
120
+ payload;
121
+ constructor(message, options) {
122
+ super(message);
123
+ this.name = "MuxoToolError";
124
+ this.code = options.code;
125
+ this.statusCode = options.statusCode ?? 400;
126
+ this.payload = { code: options.code, ...(options.payload || {}) };
127
+ }
128
+ }
129
+ export function unknownToolError(slug) {
130
+ const clean = String(slug || "").trim();
131
+ const keyword = clean.split(".").filter(Boolean).slice(-1)[0] || clean;
132
+ const message = clean
133
+ ? `Tool not found: '${clean}' is not in the Muxo catalog. Call search_tools with a keyword (e.g. query "${keyword}") to find a valid tool slug, then call inspect_tool or plan_action with that slug.`
134
+ : "tool_slug is required. Call search_tools to find a valid tool slug, then call inspect_tool or plan_action with that slug.";
135
+ return new MuxoToolError(message, {
136
+ code: "tool_not_found",
137
+ statusCode: 404,
138
+ payload: {
139
+ toolSlug: clean || null,
140
+ recovery: {
141
+ summary: "Search the catalog for a valid slug, then retry with it.",
142
+ nextToolCalls: [
143
+ {
144
+ tool: "search_tools",
145
+ input: { query: keyword || "" },
146
+ when: "To find the correct tool slug",
147
+ },
148
+ ],
149
+ },
150
+ },
151
+ });
152
+ }
153
+ export function buildApprovalUrl(baseUrl, planId) {
154
+ return `${baseUrl.replace(/\/$/, "")}/approve/${encodeURIComponent(planId)}`;
155
+ }
156
+ /** Structured response returned when execute_<risk> is called on a plan still awaiting approval. */
157
+ export function buildApprovalRequiredPayload(baseUrl, plan) {
158
+ const approvalUrl = buildApprovalUrl(baseUrl, plan.id);
159
+ return {
160
+ approvalRequired: true,
161
+ planId: plan.id,
162
+ toolSlug: plan.toolSlug,
163
+ riskLevel: plan.riskLevel,
164
+ approvalStatus: plan.approvalStatus,
165
+ approvalUrl,
166
+ humanHandoff: {
167
+ kind: "approval",
168
+ url: approvalUrl,
169
+ ctaLabel: "Review & approve",
170
+ headline: `Muxo needs your approval to run ${plan.toolSlug}`,
171
+ instructions: `Open ${approvalUrl} to review and approve this ${plan.riskLevel}-risk action with one click (or run \`muxo approve ${plan.id}\`). Nothing runs until you approve.`,
172
+ planId: plan.id,
173
+ },
174
+ polling: {
175
+ tool: "get_plan",
176
+ input: { plan_id: plan.id, wait_for_approval: true, timeout_seconds: 30 },
177
+ restUrl: `${baseUrl.replace(/\/$/, "")}/api/v1/plans/${encodeURIComponent(plan.id)}/wait?timeout_seconds=30`,
178
+ },
179
+ llmGuidance: {
180
+ summary: `Plan ${plan.id} is awaiting human approval. Share ${approvalUrl} with the user, poll get_plan(wait_for_approval: true), then call execute_${plan.riskLevel} once approved.`,
181
+ nextToolCalls: [
182
+ {
183
+ tool: "get_plan",
184
+ input: { plan_id: plan.id, wait_for_approval: true, timeout_seconds: 30 },
185
+ when: `After sharing ${approvalUrl} with the user, to wait in-turn until they click Approve`,
186
+ },
187
+ {
188
+ tool: `execute_${plan.riskLevel}`,
189
+ input: { plan_id: plan.id },
190
+ when: "Only after get_plan reports approved: true",
191
+ },
192
+ ],
193
+ },
194
+ };
195
+ }
196
+ export function approvalRequiredError(baseUrl, plan) {
197
+ const approvalUrl = buildApprovalUrl(baseUrl, plan.id);
198
+ return new MuxoToolError(`Plan '${plan.id}' (${plan.riskLevel}) is awaiting human approval. Open ${approvalUrl} to approve it (or run 'muxo approve ${plan.id}'), then poll get_plan with wait_for_approval: true before calling execute_${plan.riskLevel}.`, {
199
+ code: "approval_required",
200
+ statusCode: 409,
201
+ payload: buildApprovalRequiredPayload(baseUrl, plan),
202
+ });
203
+ }
204
+ export function errorPayloadFrom(err, fallback = "Tool execution failed") {
205
+ const message = String(err?.message || err || fallback);
206
+ return err instanceof MuxoToolError
207
+ ? { ok: false, error: message, ...err.payload }
208
+ : { ok: false, error: message };
209
+ }
210
+ /**
211
+ * MCP onboard_team never mints credentials in-band; it returns the human handoff
212
+ * (Console / CLI / REST) that issues a Team API key so secrets stay out of agent transcripts.
213
+ */
214
+ export function buildOnboardTeamGuide(input) {
215
+ const base = input.baseUrl.replace(/\/$/, "");
216
+ const teamName = (input.teamName || "").trim() || "Engineering Team";
217
+ return {
218
+ ok: true,
219
+ action: "onboard_team",
220
+ workspaceId: input.workspaceId,
221
+ workspaceName: input.workspaceName,
222
+ teamName,
223
+ consoleUrl: `${base}/keys`,
224
+ onboardingEndpoint: {
225
+ method: "POST",
226
+ url: `${base}/api/v1/workspaces/onboard-team`,
227
+ body: { teamName, mode: "shared_workspace", role: "operator" },
228
+ },
229
+ cli: {
230
+ onboard: `muxo workspace onboard-team --team "${teamName}"`,
231
+ join: "muxo workspace join --api-key <team_key>",
232
+ },
233
+ instructions: "Generate a shared Team API Key in the Muxo Console (API Keys & Access), via `muxo workspace onboard-team`, or POST /api/v1/workspaces/onboard-team; teammates then join with `muxo workspace join --api-key <key>`.",
234
+ workspaces: input.workspaces || [],
235
+ };
236
+ }
237
+ /**
238
+ * Concise server instructions (<512 chars) per OpenAI Plugin MCP Server specification:
239
+ * https://developers.openai.com/plugins/build/mcp-server
240
+ */
241
+ export const MUXO_MCP_SERVER_INSTRUCTIONS = "Muxo governs SaaS actions (app.*), Instant tools (instant.*), Cloud Infrastructure (resource.*), Memory, and Guardrails. Workflow: 1) search_tools & inspect_tool. 2) plan_action to get a plan_*. 3) If authHandoff.required, show humanHandoff.url and call wait_for_connection. 4) If approvalStatus is pending_approval, send humanHandoff.url or call get_plan(wait_for_approval:true). 5) Execute via execute_<risk>. 6) Manage memory/guardrails via get_run_context.";
242
+ export const MUXO_MCP_TOOLS = [
243
+ {
244
+ name: "get_profile",
245
+ title: "Get Authenticated Profile",
246
+ description: "Get the authenticated actor profile, user ID, email, workspace ID, and subscription tier.",
247
+ inputSchema: {
248
+ type: "object",
249
+ properties: {},
250
+ additionalProperties: false,
251
+ },
252
+ outputSchema: {
253
+ $schema: "https://json-schema.org/draft/2020-12/schema",
254
+ type: "object",
255
+ properties: {
256
+ id: {
257
+ type: "string",
258
+ minLength: 1,
259
+ pattern: "\\S",
260
+ description: "Unique identifier for the user.",
261
+ },
262
+ name: {
263
+ type: "string",
264
+ description: "Full name of the user.",
265
+ },
266
+ email: {
267
+ type: "string",
268
+ description: "Email address of the user.",
269
+ },
270
+ nickname: {
271
+ type: "string",
272
+ description: "Handle or username of the user.",
273
+ },
274
+ workspaceId: {
275
+ type: "string",
276
+ description: "Active workspace ID.",
277
+ },
278
+ workspaceName: {
279
+ type: "string",
280
+ description: "Active workspace name.",
281
+ },
282
+ tier: {
283
+ type: "string",
284
+ description: "Workspace subscription tier.",
285
+ },
286
+ authType: {
287
+ type: "string",
288
+ description: "Authentication type (session or api_key).",
289
+ },
290
+ actorId: {
291
+ type: "string",
292
+ description: "Actor identifier.",
293
+ },
294
+ user: {
295
+ type: "object",
296
+ description: "User profile record.",
297
+ },
298
+ },
299
+ required: ["id"],
300
+ additionalProperties: false,
301
+ },
302
+ annotations: {
303
+ readOnlyHint: true,
304
+ destructiveHint: false,
305
+ openWorldHint: false,
306
+ },
307
+ _meta: {
308
+ "openai/profile": true,
309
+ },
310
+ },
311
+ {
312
+ name: "get_organization",
313
+ title: "Get Organization & Billing Summary",
314
+ description: "Get workspace governance policy, plain-English guardrails, monthly action usage, credit balance, workspace memberships, and active connection/resource counts.",
315
+ inputSchema: {
316
+ type: "object",
317
+ properties: {},
318
+ additionalProperties: false,
319
+ },
320
+ annotations: {
321
+ readOnlyHint: true,
322
+ destructiveHint: false,
323
+ openWorldHint: false,
324
+ },
325
+ },
326
+ {
327
+ name: "search_tools",
328
+ title: "Search Unified Tool Catalog",
329
+ description: "Search the unified Muxo catalog across Connected Apps (app.*), Instant Tools (instant.*), Billing (billing.*), and Cloud Infrastructure (resource.*).",
330
+ inputSchema: {
331
+ type: "object",
332
+ properties: {
333
+ query: {
334
+ type: "string",
335
+ description: "Search keywords (e.g. 'postgres', 'github issue', 'web search', 'seo audit', 'stripe refund', 'redis')",
336
+ },
337
+ lane: {
338
+ type: "string",
339
+ enum: ["all", "composio_sdk", "composio_instant", "stripe_projects"],
340
+ default: "all",
341
+ },
342
+ risk_level: {
343
+ type: "string",
344
+ enum: [
345
+ "read",
346
+ "write",
347
+ "admin",
348
+ "financial",
349
+ "provisioning",
350
+ "destructive",
351
+ ],
352
+ },
353
+ limit: { type: "number", default: 20 },
354
+ },
355
+ additionalProperties: false,
356
+ },
357
+ annotations: {
358
+ readOnlyHint: true,
359
+ destructiveHint: false,
360
+ openWorldHint: true,
361
+ },
362
+ },
363
+ {
364
+ name: "inspect_tool",
365
+ title: "Inspect Tool Schema & Risk",
366
+ description: "Inspect a tool's full input JSON schema, risk classification, provider lane, LLM context URL, and credit cost before planning.",
367
+ inputSchema: {
368
+ type: "object",
369
+ required: ["tool_slug"],
370
+ properties: {
371
+ tool_slug: {
372
+ type: "string",
373
+ description: "Canonical Muxo tool slug (e.g. 'instant.seo.audit', 'app.gmail.send_email', 'billing.stripe.create_refund', or 'resource.turso.database')",
374
+ },
375
+ },
376
+ additionalProperties: false,
377
+ },
378
+ annotations: {
379
+ readOnlyHint: true,
380
+ destructiveHint: false,
381
+ openWorldHint: false,
382
+ },
383
+ },
384
+ {
385
+ name: "connection_status",
386
+ title: "Check Connection Status",
387
+ description: "Check connection status across Connected Apps, Instant Tools, and linked Cloud Infrastructure providers.",
388
+ inputSchema: {
389
+ type: "object",
390
+ properties: {
391
+ provider: {
392
+ type: "string",
393
+ description: "Optional provider filter (e.g. 'github', 'gmail', 'slack', 'neon', 'turso')",
394
+ },
395
+ sync_live: {
396
+ type: "boolean",
397
+ default: true,
398
+ description: "Whether to sync live connection status from upstream providers",
399
+ },
400
+ },
401
+ additionalProperties: false,
402
+ },
403
+ annotations: {
404
+ readOnlyHint: true,
405
+ destructiveHint: false,
406
+ openWorldHint: true,
407
+ },
408
+ },
409
+ {
410
+ name: "start_connection",
411
+ title: "Start OAuth Connection Handoff",
412
+ description: "Initiate a managed OAuth connection handoff for a Connected App or link a Cloud Infrastructure provider.",
413
+ inputSchema: {
414
+ type: "object",
415
+ required: ["provider"],
416
+ properties: {
417
+ provider: {
418
+ type: "string",
419
+ description: "Provider or toolkit slug (e.g. 'github', 'gmail', 'slack', 'neon')",
420
+ },
421
+ lane: {
422
+ type: "string",
423
+ enum: ["composio_sdk", "stripe_projects"],
424
+ description: "Provider lane (defaults to composio_sdk unless prefixed with resource.)",
425
+ },
426
+ callback_url: {
427
+ type: "string",
428
+ description: "Optional OAuth callback URL",
429
+ },
430
+ },
431
+ additionalProperties: false,
432
+ },
433
+ annotations: {
434
+ readOnlyHint: false,
435
+ destructiveHint: false,
436
+ openWorldHint: true,
437
+ },
438
+ },
439
+ {
440
+ name: "wait_for_connection",
441
+ title: "Wait for OAuth Connection Handoff",
442
+ description: "Poll and wait for an external user's pending OAuth connection handoff to become active before resuming a planned operation.",
443
+ inputSchema: {
444
+ type: "object",
445
+ required: ["provider"],
446
+ properties: {
447
+ provider: {
448
+ type: "string",
449
+ description: "Provider or toolkit slug (e.g. 'github', 'gmail', 'slack', 'notion', 'linear')",
450
+ },
451
+ timeout_seconds: {
452
+ type: "number",
453
+ default: 15,
454
+ description: "Maximum seconds to poll for OAuth completion (0-120, default 15)",
455
+ },
456
+ },
457
+ additionalProperties: false,
458
+ },
459
+ annotations: {
460
+ readOnlyHint: true,
461
+ destructiveHint: false,
462
+ openWorldHint: true,
463
+ },
464
+ },
465
+ {
466
+ name: "plan_action",
467
+ title: "Create Governed Action Plan",
468
+ 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', 'app.gmail.send_email', 'billing.stripe.create_refund', 'resource.turso.database') or a natural-language instruction. Evaluates workspace policy, conditional parameter guardrails, risk level, Workspace Memory recall, BYOK vs Muxo-funded mode, and credit balance.",
469
+ inputSchema: {
470
+ type: "object",
471
+ required: ["tool_slug"],
472
+ properties: {
473
+ tool_slug: {
474
+ type: "string",
475
+ description: "Muxo tool slug (e.g. 'instant.seo.audit', 'billing.stripe.create_refund') or natural-language request",
476
+ },
477
+ input: {
478
+ type: "object",
479
+ description: "Arguments matching the tool's inputSchema (auto-extracted when tool_slug is natural language)",
480
+ },
481
+ reason: {
482
+ type: "string",
483
+ description: "Audit reason explaining why this action is being planned",
484
+ },
485
+ },
486
+ additionalProperties: false,
487
+ },
488
+ annotations: {
489
+ readOnlyHint: false,
490
+ destructiveHint: false,
491
+ openWorldHint: false,
492
+ },
493
+ },
494
+ {
495
+ name: "get_plan",
496
+ title: "Get Action Plan",
497
+ description: "Inspect the status, risk level, governance decision record, and approval state of a planned action. Set wait_for_approval: true to poll in-turn while a human approves the plan at /approve/<plan_id>.",
498
+ inputSchema: {
499
+ type: "object",
500
+ required: ["plan_id"],
501
+ properties: {
502
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
503
+ wait_for_approval: {
504
+ type: "boolean",
505
+ description: "If true, wait in-turn (up to timeout_seconds) until the plan transitions out of pending_approval.",
506
+ },
507
+ timeout_seconds: {
508
+ type: "number",
509
+ description: "Maximum seconds to wait when wait_for_approval is true (default 15, max 60).",
510
+ },
511
+ },
512
+ additionalProperties: false,
513
+ },
514
+ annotations: {
515
+ readOnlyHint: true,
516
+ destructiveHint: false,
517
+ openWorldHint: false,
518
+ },
519
+ },
520
+ {
521
+ name: "get_run_context",
522
+ title: "Get & Manage Workspace Context, Memory & Guardrails",
523
+ description: "Get or manage the workspace runtime context, Supermemory v5 contextual brain (profile, hybrid search recall, remember/forget, bi-temporal knowledge graph), conditional Guardrails (natural language or structured parameter_rules compiled by your LLM harness), workspace switching, and active provisioned resources.",
524
+ inputSchema: {
525
+ type: "object",
526
+ properties: {
527
+ query: {
528
+ type: "string",
529
+ description: "Optional semantic search query to recall relevant workspace memories or filter the bi-temporal knowledge graph",
530
+ },
531
+ action: {
532
+ type: "string",
533
+ enum: [
534
+ "inspect",
535
+ "remember",
536
+ "recall",
537
+ "forget",
538
+ "memory_graph",
539
+ "set_guardrail",
540
+ "governance_status",
541
+ "scan_context",
542
+ "list_workspaces",
543
+ "switch_workspace",
544
+ "onboard_team",
545
+ ],
546
+ description: "Control-plane operation: 'inspect' (default), 'remember' (save fact/preference), 'recall' (list memories), 'forget' (delete matching memories), 'memory_graph' (bi-temporal entity/relationship lineage), 'set_guardrail' (apply plain-English or structured parameter_rules guardrail), 'governance_status', 'scan_context' (OWASP ASI-06 check), 'list_workspaces', 'switch_workspace', or 'onboard_team'",
547
+ },
548
+ prompt: {
549
+ type: "string",
550
+ description: "Natural-language instruction when action is 'remember', 'set_guardrail', or 'scan_context' (e.g. 'Only allow sending emails to @muxo.ai' or 'Require approval for Stripe refunds over $50, auto-approve under $50')",
551
+ },
552
+ parameter_rules: {
553
+ type: "array",
554
+ description: "Optional structured conditional parameter guardrail rules compiled by the caller LLM harness when action='set_guardrail'. Each item: { toolPattern, parameter, operator, value, unit?, action, elseAction?, description }",
555
+ items: {
556
+ type: "object",
557
+ properties: {
558
+ id: { type: "string" },
559
+ toolPattern: {
560
+ type: "string",
561
+ description: "Tool slug or wildcard pattern (e.g. 'app.gmail.send_email', '*refund*', '*email*')",
562
+ },
563
+ parameter: {
564
+ type: "string",
565
+ description: "Parameter name or comma-separated aliases (e.g. 'to', 'amount', 'channel')",
566
+ },
567
+ operator: {
568
+ type: "string",
569
+ enum: [
570
+ "equals",
571
+ "must_equal",
572
+ "not_equals",
573
+ "contains",
574
+ "not_contains",
575
+ "starts_with",
576
+ "must_start_with",
577
+ "ends_with",
578
+ "must_end_with",
579
+ "domain_in",
580
+ "domain_not_in",
581
+ "max_number",
582
+ "min_number",
583
+ "gt",
584
+ "gte",
585
+ "lt",
586
+ "lte",
587
+ "in",
588
+ "not_in",
589
+ "regex",
590
+ ],
591
+ },
592
+ value: {
593
+ description: "Target value (string, number, or array of strings)",
594
+ },
595
+ unit: {
596
+ type: "string",
597
+ enum: ["usd", "cents", "credits", "raw"],
598
+ },
599
+ action: {
600
+ type: "string",
601
+ enum: ["block", "require_approval", "allow", "auto_approve"],
602
+ },
603
+ elseAction: {
604
+ type: "string",
605
+ enum: ["block", "require_approval", "allow", "auto_approve"],
606
+ },
607
+ description: { type: "string" },
608
+ },
609
+ },
610
+ },
611
+ workspace_id: {
612
+ type: "string",
613
+ description: "Target workspace ID when action='switch_workspace'",
614
+ },
615
+ team_name: {
616
+ type: "string",
617
+ description: "Team name when action='onboard_team'",
618
+ },
619
+ title: {
620
+ type: "string",
621
+ description: "Optional memory title when saving a fact via action='remember'",
622
+ },
623
+ content: {
624
+ type: "string",
625
+ description: "Optional memory content or text to scan",
626
+ },
627
+ include_graph: {
628
+ type: "boolean",
629
+ description: "If true, attach the Bi-Temporal Knowledge Graph (nodes, activeEdges, historicalEdges, mermaid) to the context response",
630
+ },
631
+ plan_id: {
632
+ type: "string",
633
+ description: "Optional plan ID to inspect context for",
634
+ },
635
+ run_id: {
636
+ type: "string",
637
+ description: "Optional run ID to inspect context for",
638
+ },
639
+ },
640
+ additionalProperties: false,
641
+ },
642
+ annotations: {
643
+ readOnlyHint: true,
644
+ destructiveHint: false,
645
+ openWorldHint: false,
646
+ },
647
+ },
648
+ {
649
+ name: "execute_read",
650
+ title: "Execute Read Plan",
651
+ description: "Execute an approved plan with riskLevel = 'read'.",
652
+ inputSchema: {
653
+ type: "object",
654
+ required: ["plan_id"],
655
+ properties: {
656
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
657
+ },
658
+ additionalProperties: false,
659
+ },
660
+ annotations: {
661
+ readOnlyHint: true,
662
+ destructiveHint: false,
663
+ openWorldHint: true,
664
+ },
665
+ },
666
+ {
667
+ name: "execute_write",
668
+ title: "Execute Write Plan",
669
+ description: "Execute an approved plan with riskLevel = 'write'.",
670
+ inputSchema: {
671
+ type: "object",
672
+ required: ["plan_id"],
673
+ properties: {
674
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
675
+ },
676
+ additionalProperties: false,
677
+ },
678
+ annotations: {
679
+ readOnlyHint: false,
680
+ destructiveHint: false,
681
+ openWorldHint: true,
682
+ },
683
+ },
684
+ {
685
+ name: "execute_admin",
686
+ title: "Execute Admin Plan",
687
+ description: "Execute an approved plan with riskLevel = 'admin'.",
688
+ inputSchema: {
689
+ type: "object",
690
+ required: ["plan_id"],
691
+ properties: {
692
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
693
+ },
694
+ additionalProperties: false,
695
+ },
696
+ annotations: {
697
+ readOnlyHint: false,
698
+ destructiveHint: false,
699
+ openWorldHint: true,
700
+ },
701
+ },
702
+ {
703
+ name: "execute_financial",
704
+ title: "Execute Financial Plan",
705
+ description: "Execute an approved plan with riskLevel = 'financial'.",
706
+ inputSchema: {
707
+ type: "object",
708
+ required: ["plan_id"],
709
+ properties: {
710
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
711
+ },
712
+ additionalProperties: false,
713
+ },
714
+ annotations: {
715
+ readOnlyHint: false,
716
+ destructiveHint: false,
717
+ openWorldHint: true,
718
+ },
719
+ },
720
+ {
721
+ name: "execute_provisioning",
722
+ title: "Execute Infrastructure Provisioning Plan",
723
+ description: "Execute an approved infrastructure provisioning plan with riskLevel = 'provisioning' via Stripe Projects.",
724
+ inputSchema: {
725
+ type: "object",
726
+ required: ["plan_id"],
727
+ properties: {
728
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
729
+ },
730
+ additionalProperties: false,
731
+ },
732
+ annotations: {
733
+ readOnlyHint: false,
734
+ destructiveHint: false,
735
+ openWorldHint: true,
736
+ },
737
+ },
738
+ {
739
+ name: "execute_destructive",
740
+ title: "Execute Destructive Plan",
741
+ description: "Execute an approved plan with riskLevel = 'destructive'.",
742
+ inputSchema: {
743
+ type: "object",
744
+ required: ["plan_id"],
745
+ properties: {
746
+ plan_id: { type: "string", description: "Plan ID (plan_*)" },
747
+ },
748
+ additionalProperties: false,
749
+ },
750
+ annotations: {
751
+ readOnlyHint: false,
752
+ destructiveHint: true,
753
+ openWorldHint: true,
754
+ },
755
+ },
756
+ {
757
+ name: "get_run",
758
+ title: "Get Execution Run",
759
+ description: "Get the execution status, output, duration, and metered cost of a run (run_*).",
760
+ inputSchema: {
761
+ type: "object",
762
+ required: ["run_id"],
763
+ properties: {
764
+ run_id: { type: "string", description: "Run ID (run_*)" },
765
+ },
766
+ additionalProperties: false,
767
+ },
768
+ annotations: {
769
+ readOnlyHint: true,
770
+ destructiveHint: false,
771
+ openWorldHint: false,
772
+ },
773
+ },
774
+ {
775
+ name: "cancel_run",
776
+ title: "Cancel Execution Run",
777
+ description: "Cancel a run (status becomes 'cancelled') and issue a signed cancellation receipt. Completed runs cannot be cancelled.",
778
+ inputSchema: {
779
+ type: "object",
780
+ required: ["run_id"],
781
+ properties: {
782
+ run_id: { type: "string", description: "Run ID (run_*)" },
783
+ reason: {
784
+ type: "string",
785
+ description: "Optional audit reason recorded on the cancellation receipt",
786
+ },
787
+ },
788
+ additionalProperties: false,
789
+ },
790
+ annotations: {
791
+ readOnlyHint: false,
792
+ destructiveHint: true,
793
+ openWorldHint: false,
794
+ },
795
+ },
796
+ {
797
+ name: "get_receipt",
798
+ title: "Verify Execution Receipt",
799
+ description: "Fetch and cryptographically verify the HMAC-SHA256 + portable Ed25519 AgenticReceipt + Microsoft Governance DecisionRecord for a run (or pass receipt_id='latest' or 'chain' / verify_chain=true to audit the full workspace hash chain).",
800
+ inputSchema: {
801
+ type: "object",
802
+ properties: {
803
+ receipt_id: {
804
+ type: "string",
805
+ description: "Receipt ID (rcpt_*), Run ID (run_*), 'latest', or 'chain'. Provide receipt_id or run_id.",
806
+ },
807
+ run_id: {
808
+ type: "string",
809
+ description: "Run ID (run_*) whose receipt should be returned",
810
+ },
811
+ verify_chain: {
812
+ type: "boolean",
813
+ description: "If true, also verify the entire workspace receipt SHA-256 + Ed25519 hash chain from genesis to head",
814
+ },
815
+ },
816
+ additionalProperties: false,
817
+ },
818
+ annotations: {
819
+ readOnlyHint: true,
820
+ destructiveHint: false,
821
+ openWorldHint: false,
822
+ },
823
+ },
824
+ ];
825
+ /**
826
+ * OpenAI Company Knowledge standard `search` and `fetch` tool definitions
827
+ * per https://developers.openai.com/plugins/build/mcp-server#company-knowledge-compatibility
828
+ */
829
+ export const OPENAI_COMPANY_KNOWLEDGE_TOOLS = [
830
+ {
831
+ name: "search",
832
+ title: "Search Muxo Tools & Workspace Memory",
833
+ description: "Search across Muxo tools, provisioned cloud resources, and Supermemory v5 workspace knowledge.",
834
+ inputSchema: {
835
+ type: "object",
836
+ required: ["query"],
837
+ properties: {
838
+ query: { type: "string", description: "Search query string." },
839
+ },
840
+ additionalProperties: false,
841
+ },
842
+ annotations: {
843
+ readOnlyHint: true,
844
+ destructiveHint: false,
845
+ openWorldHint: false,
846
+ },
847
+ },
848
+ {
849
+ name: "fetch",
850
+ title: "Fetch Muxo Tool or Memory Record",
851
+ description: "Retrieve complete details for a Muxo tool, resource, or workspace memory record by ID.",
852
+ inputSchema: {
853
+ type: "object",
854
+ required: ["id"],
855
+ properties: {
856
+ id: {
857
+ type: "string",
858
+ description: "Identifier returned by search (e.g. 'tool:instant.seo.audit' or 'memory:mem_123').",
859
+ },
860
+ },
861
+ additionalProperties: false,
862
+ },
863
+ annotations: {
864
+ readOnlyHint: true,
865
+ destructiveHint: false,
866
+ openWorldHint: false,
867
+ },
868
+ },
869
+ ];
870
+ /**
871
+ * Enriches any MCP tool output object with structured `llmGuidance` so agent harnesses
872
+ * (Claude Code, Cursor, Codex, OpenAI MCP, Windsurf) always know the exact next tool call.
873
+ */
874
+ export function attachMcpHarnessGuidance(toolName, toolArgs, output) {
875
+ if (!output || typeof output !== "object" || Array.isArray(output)) {
876
+ return output;
877
+ }
878
+ const obj = output;
879
+ if (obj.llmGuidance) {
880
+ return output;
881
+ }
882
+ let guidance = null;
883
+ switch (toolName) {
884
+ case "get_profile":
885
+ case "get_organization":
886
+ guidance = {
887
+ summary: "Workspace identity verified. Call get_run_context to load memory & guardrails, or search_tools to discover capabilities.",
888
+ nextToolCalls: [
889
+ {
890
+ tool: "get_run_context",
891
+ input: { action: "inspect" },
892
+ when: "Before planning actions, to load active memory defaults and guardrails",
893
+ },
894
+ {
895
+ tool: "search_tools",
896
+ input: { query: "" },
897
+ when: "To discover available Instant, Connected App, and Cloud Infrastructure tools",
898
+ },
899
+ ],
900
+ };
901
+ break;
902
+ case "search_tools": {
903
+ const firstSlug = Array.isArray(obj.tools) && obj.tools[0]?.slug
904
+ ? String(obj.tools[0].slug)
905
+ : "<tool_slug>";
906
+ guidance = {
907
+ summary: `Found ${Array.isArray(obj.tools) ? obj.tools.length : 0} matching tools. Call inspect_tool to check inputSchema or plan_action to create an execution plan.`,
908
+ nextToolCalls: [
909
+ {
910
+ tool: "inspect_tool",
911
+ input: { tool_slug: firstSlug },
912
+ when: "To inspect required parameters and risk level before planning",
913
+ },
914
+ {
915
+ tool: "plan_action",
916
+ input: {
917
+ tool_slug: firstSlug,
918
+ input: {},
919
+ reason: "Execute user request",
920
+ },
921
+ when: "When you have the required input parameters ready",
922
+ },
923
+ ],
924
+ };
925
+ break;
926
+ }
927
+ case "inspect_tool": {
928
+ const slug = String(obj.slug || toolArgs.tool_slug || "<tool_slug>");
929
+ guidance = {
930
+ summary: `Inspected ${slug} (risk=${String(obj.riskLevel || "read")}). Call plan_action with input matching inputSchema.`,
931
+ nextToolCalls: [
932
+ {
933
+ tool: "plan_action",
934
+ input: {
935
+ tool_slug: slug,
936
+ input: {},
937
+ reason: `Execute ${slug}`,
938
+ },
939
+ when: "Next, to evaluate workspace guardrails and obtain a plan_id",
940
+ },
941
+ ],
942
+ };
943
+ break;
944
+ }
945
+ case "start_connection": {
946
+ const provider = String(obj.providerSlug || toolArgs.provider || "<provider>");
947
+ guidance = {
948
+ summary: obj.redirectUrl
949
+ ? `Share ${String(obj.redirectUrl)} with the user so they can authorize ${provider}, then call wait_for_connection.`
950
+ : `Connection status for ${provider}: ${String(obj.status || "active")}.`,
951
+ nextToolCalls: [
952
+ {
953
+ tool: "wait_for_connection",
954
+ input: { provider, timeout_seconds: 30 },
955
+ when: "While the user completes the browser OAuth flow",
956
+ },
957
+ ],
958
+ };
959
+ break;
960
+ }
961
+ case "wait_for_connection": {
962
+ const provider = String(obj.provider || toolArgs.provider || "<provider>");
963
+ guidance = obj.connected
964
+ ? {
965
+ summary: `${provider} is connected and active. Proceed to plan_action or execute_<riskLevel>.`,
966
+ nextToolCalls: [
967
+ {
968
+ tool: "plan_action",
969
+ input: {
970
+ tool_slug: `app.${provider}.`,
971
+ input: {},
972
+ reason: "Execute connected app action",
973
+ },
974
+ when: "Now that OAuth connection is active",
975
+ },
976
+ ],
977
+ }
978
+ : {
979
+ summary: `Still awaiting user OAuth completion for ${provider}. Ask the user to open ${String(obj.redirectUrl || "the authorization URL")} and call wait_for_connection again.`,
980
+ nextToolCalls: [
981
+ {
982
+ tool: "wait_for_connection",
983
+ input: { provider, timeout_seconds: 30 },
984
+ when: "After the user finishes authorizing in their browser",
985
+ },
986
+ ],
987
+ };
988
+ break;
989
+ }
990
+ case "get_plan": {
991
+ const plan = obj.plan || obj;
992
+ const planId = String(plan?.id || toolArgs.plan_id || "<plan_id>");
993
+ const risk = String(plan?.riskLevel || "read");
994
+ const status = String(obj.approvalStatus || plan?.approvalStatus || "auto_approved");
995
+ guidance =
996
+ status === "approved" || status === "auto_approved"
997
+ ? {
998
+ summary: `Plan ${planId} is ${status}. Call execute_${risk} to run it now.`,
999
+ nextToolCalls: [
1000
+ {
1001
+ tool: `execute_${risk}`,
1002
+ input: { plan_id: planId },
1003
+ when: "Immediately; plan is approved",
1004
+ },
1005
+ ],
1006
+ }
1007
+ : {
1008
+ summary: `Plan ${planId} is ${status}. Share the approval link with the user and wait for approval before executing.`,
1009
+ nextToolCalls: [
1010
+ {
1011
+ tool: "get_plan",
1012
+ input: {
1013
+ plan_id: planId,
1014
+ wait_for_approval: true,
1015
+ timeout_seconds: 25,
1016
+ },
1017
+ when: "While waiting for the workspace owner to click Approve",
1018
+ },
1019
+ ],
1020
+ };
1021
+ break;
1022
+ }
1023
+ case "execute_read":
1024
+ case "execute_write":
1025
+ case "execute_admin":
1026
+ case "execute_financial":
1027
+ case "execute_provisioning":
1028
+ case "execute_destructive": {
1029
+ const runId = String(obj.run?.id || obj.receipt?.runId || obj.receipt?.id || "<run_id>");
1030
+ guidance = {
1031
+ summary: `Execution completed (${String(obj.run?.status || "succeeded")}). Call get_receipt to verify the cryptographic Ed25519 receipt if needed.`,
1032
+ nextToolCalls: [
1033
+ {
1034
+ tool: "get_receipt",
1035
+ input: { receipt_id: runId },
1036
+ when: "To verify the signed receipt and governance decision record",
1037
+ },
1038
+ ],
1039
+ };
1040
+ break;
1041
+ }
1042
+ case "get_run_context":
1043
+ case "set_guardrail":
1044
+ case "configure_guardrails": {
1045
+ guidance = {
1046
+ summary: "Workspace context, memory defaults, and guardrails updated/loaded. Use plan_action to propose governed actions or get_run_context with action='set_guardrail'|'remember'|'forget' to update workspace state.",
1047
+ nextToolCalls: [
1048
+ {
1049
+ tool: "search_tools",
1050
+ input: { query: "" },
1051
+ when: "To find tools matching the user's goal",
1052
+ },
1053
+ {
1054
+ tool: "plan_action",
1055
+ input: {
1056
+ tool_slug: "<tool_slug>",
1057
+ input: {},
1058
+ reason: "Planned action under active workspace guardrails",
1059
+ },
1060
+ when: "To evaluate guardrails and prepare an action for execution",
1061
+ },
1062
+ ],
1063
+ };
1064
+ break;
1065
+ }
1066
+ default:
1067
+ break;
1068
+ }
1069
+ if (guidance) {
1070
+ return {
1071
+ ...obj,
1072
+ llmGuidance: guidance,
1073
+ };
1074
+ }
1075
+ return output;
1076
+ }