@desplega.ai/agent-swarm 1.113.0 → 1.115.0
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/README.md +2 -2
- package/dist/{actions-q4n7cz6e.js → actions-17ya5wde.js} +8 -9
- package/dist/{app-es4nzc71.js → app-4f718yk0.js} +6 -6
- package/dist/{assistant-0x8ey0vs.js → assistant-ah7csnjz.js} +19 -18
- package/dist/{boot-reembed-69agkhv6.js → boot-reembed-4jpxhb25.js} +6 -6
- package/dist/{boot-reembed-p0ny05t8.js → boot-reembed-qata34xa.js} +5 -5
- package/dist/{boot-scrub-logs-yybrkmvr.js → boot-scrub-logs-tv48nn3z.js} +4 -4
- package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-3csn5bks.js} +3 -3
- package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
- package/dist/cli-0pygq9r1.js +429 -0
- package/dist/{cli-hsetkkd3.js → cli-12vb0xg6.js} +33 -9
- package/dist/{cli-ncfgsqbd.js → cli-15y7qhzp.js} +262 -33
- package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
- package/dist/{cli-36ymmpmp.js → cli-3samkyap.js} +2 -2
- package/dist/cli-52fg7s7x.js +269 -0
- package/dist/{cli-hjhvekf4.js → cli-65ekje01.js} +11 -8
- package/dist/{cli-h3k622d0.js → cli-6aq8xhvm.js} +90 -3
- package/dist/{cli-f3qa069v.js → cli-7xje5amz.js} +1 -1
- package/dist/cli-86fdnerz.js +405 -0
- package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
- package/dist/{cli-c3frqf65.js → cli-b23axgz4.js} +3 -3
- package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
- package/dist/{cli-bnzbn8j8.js → cli-beea4a3y.js} +73 -24
- package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
- package/dist/{cli-pwc5e83c.js → cli-cchksf5q.js} +12 -7
- package/dist/{cli-30bbaveh.js → cli-cmw9rzy5.js} +2 -2
- package/dist/{cli-y6mrptcn.js → cli-cnwssmsr.js} +1 -1
- package/dist/{cli-r5g6ngtn.js → cli-dcca6j8m.js} +46 -5
- package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
- package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
- package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
- package/dist/{cli-4xyj9jtq.js → cli-hrhye2rm.js} +1062 -478
- package/dist/cli-jkhwmmgg.js +136 -0
- package/dist/{cli-y4ycrnjc.js → cli-k3y4z3h5.js} +1 -1
- package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
- package/dist/{cli-2fc97xm5.js → cli-mnbgv3w7.js} +4 -4
- package/dist/{cli-trmapn9k.js → cli-pet3aev6.js} +95 -10
- package/dist/{cli-z46pnksz.js → cli-q1rx7g0d.js} +175 -28
- package/dist/{cli-qwgtacd6.js → cli-r9f6ngrf.js} +1244 -336
- package/dist/{cli-gtkqc144.js → cli-shvaxw27.js} +13 -7
- package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
- package/dist/cli-t0vqevnm.js +393 -0
- package/dist/{cli-tbw13sx8.js → cli-tece6zgm.js} +1 -1
- package/dist/{cli-bgvskydy.js → cli-tffvrh6j.js} +1 -1
- package/dist/cli-wh91zby6.js +187222 -0
- package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
- package/dist/{cli-mq580e06.js → cli-zsrdty74.js} +18 -18
- package/dist/cli.js +32 -15
- package/dist/{codex-adapter-5cmy858w.js → codex-adapter-de3w0nch.js} +10 -10
- package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-bnw8cysk.js} +10 -10
- package/dist/{commands-z5dbwta3.js → commands-hch4e2k1.js} +4 -4
- package/dist/{db-bbgahh4z.js → db-p3h2j06x.js} +14 -4
- package/dist/{handlers-6b44317z.js → handlers-9er4zx9q.js} +17 -31
- package/dist/{hook-sbp5fmps.js → hook-4axs756z.js} +7 -7
- package/dist/{http-2xz43gz3.js → http-809fvtz2.js} +1934 -886
- package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
- package/dist/{index-nhat35em.js → index-47em3d2n.js} +14 -11
- package/dist/{index-5ghxn8s6.js → index-9fqaktjr.js} +12 -9
- package/dist/{index-0gzmqj4k.js → index-9ht8gr56.js} +13 -10
- package/dist/{index-vfedgdw6.js → index-rm85cfdx.js} +368 -40
- package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
- package/dist/{keepalive-62gfj91d.js → keepalive-3cps6e3e.js} +7 -6
- package/dist/{lead-ag0akn0v.js → lead-fkk95wgq.js} +36 -32
- package/dist/{maintenance-xxrrzk5x.js → maintenance-fweqh0yj.js} +6 -6
- package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
- package/dist/oauth-refresh-sweep-sycqtbph.js +114 -0
- package/dist/{onboard-64zyfcbs.js → onboard-cy0rkgvx.js} +2 -2
- package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
- package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
- package/dist/{otel-impl-b86qseaa.js → otel-impl-wbns8hf7.js} +1 -1
- package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-05sck1ds.js} +17 -109
- package/dist/{pricing-refresh-cgtkffpa.js → pricing-refresh-0hvazmkf.js} +6 -6
- package/dist/rbac-roles-kfesjy9y.js +28 -0
- package/dist/rbac-roles-mwcwhbxc.js +283 -0
- package/dist/{seed-pricing-1r1y1xkq.js → seed-pricing-h2kdq4cq.js} +5 -5
- package/dist/{setup-mkcgkjf7.js → setup-8506q97w.js} +2 -2
- package/dist/{worker-351sze63.js → worker-4r5c6zyb.js} +36 -32
- package/openapi.json +1327 -20
- package/package.json +3 -3
- package/src/agentmail/handlers.ts +16 -6
- package/src/agentmail/templates.ts +25 -5
- package/src/be/audit-user.ts +28 -4
- package/src/be/db-queries/oauth.ts +42 -0
- package/src/be/db.ts +314 -28
- package/src/be/identity.ts +79 -0
- package/src/be/mcp-proxy.ts +132 -0
- package/src/be/migrations/109_rbac_roles.sql +79 -0
- package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
- package/src/be/migrations/112_script_connections_graphql.sql +96 -0
- package/src/be/migrations/113_task_routing_affinity.sql +9 -0
- package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
- package/src/be/modelsdev-cache.json +135 -0
- package/src/be/oauth-credential-bindings.ts +35 -0
- package/src/be/oauth-refresh-sweep.ts +159 -0
- package/src/be/rbac-audit.ts +52 -13
- package/src/be/rbac-roles.ts +424 -0
- package/src/be/script-connections.ts +459 -40
- package/src/be/script-credential-broker.ts +29 -3
- package/src/be/scripts/typecheck.ts +51 -7
- package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
- package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
- package/src/be/users.ts +24 -0
- package/src/cli.tsx +17 -0
- package/src/github/handlers.ts +10 -9
- package/src/github/templates.ts +45 -9
- package/src/gitlab/handlers.ts +20 -8
- package/src/gitlab/templates.ts +18 -6
- package/src/heartbeat/heartbeat.ts +143 -21
- package/src/http/all-routes.ts +3 -0
- package/src/http/approval-requests.ts +12 -0
- package/src/http/config.ts +44 -10
- package/src/http/core.ts +30 -3
- package/src/http/favorites.ts +1 -5
- package/src/http/index.ts +25 -1
- package/src/http/mcp-oauth.ts +2 -0
- package/src/http/mcp-servers.ts +44 -3
- package/src/http/oauth-generic.ts +105 -0
- package/src/http/poll.ts +20 -3
- package/src/http/script-connection-proxy.ts +116 -0
- package/src/http/script-connections.ts +1657 -0
- package/src/http/scripts.ts +27 -7
- package/src/http/skills.ts +11 -0
- package/src/http/tasks.ts +27 -13
- package/src/http/x.ts +6 -2
- package/src/integrations/kapso/inbound.ts +23 -6
- package/src/jira/sync.ts +111 -17
- package/src/jira/templates.ts +10 -2
- package/src/mcp-client/http-client.ts +194 -0
- package/src/oauth/app-validation.ts +16 -0
- package/src/oauth/ensure-token.ts +69 -14
- package/src/oauth/mcp-wrapper.ts +15 -0
- package/src/oauth/wrapper.ts +48 -20
- package/src/prompts/session-templates.ts +3 -3
- package/src/providers/codex-models.ts +100 -30
- package/src/providers/modelsdev-reasoning.json +51 -0
- package/src/providers/pi-mono-mcp-client.ts +2 -133
- package/src/providers/reasoning-effort.ts +11 -5
- package/src/rbac/admission.ts +68 -0
- package/src/rbac/index.ts +2 -0
- package/src/rbac/legacy-policy.ts +12 -0
- package/src/rbac/permissions.ts +48 -0
- package/src/scheduler/scheduler.ts +9 -1
- package/src/scripts-runtime/api-client.ts +151 -19
- package/src/scripts-runtime/api-types.ts +38 -6
- package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
- package/src/scripts-runtime/credential-broker/types.ts +8 -0
- package/src/scripts-runtime/ctx.ts +11 -1
- package/src/scripts-runtime/eval-harness.ts +5 -1
- package/src/scripts-runtime/executors/types.ts +2 -1
- package/src/scripts-runtime/loader.ts +3 -1
- package/src/scripts-runtime/mcp-client.ts +87 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +6 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +19 -0
- package/src/server-user.ts +114 -59
- package/src/server.ts +12 -0
- package/src/slack/assistant.ts +14 -6
- package/src/slack/enrich.ts +17 -0
- package/src/slack/handlers.ts +8 -22
- package/src/slack/responses.ts +91 -1
- package/src/slack/thread-buffer.ts +6 -3
- package/src/slack/watcher.ts +9 -6
- package/src/tasks/worker-follow-up.ts +100 -3
- package/src/tests/agentmail-handlers.test.ts +32 -3
- package/src/tests/approval-requests.test.ts +61 -0
- package/src/tests/audit-user.test.ts +47 -1
- package/src/tests/codex-adapter.test.ts +46 -23
- package/src/tests/credential-broker.test.ts +5 -2
- package/src/tests/delete-page-tool.test.ts +197 -0
- package/src/tests/github-handlers.test.ts +28 -2
- package/src/tests/gitlab-handlers.test.ts +125 -0
- package/src/tests/heartbeat.test.ts +48 -3
- package/src/tests/identity.test.ts +117 -0
- package/src/tests/jira-sync.test.ts +99 -1
- package/src/tests/kapso-inbound.test.ts +7 -0
- package/src/tests/mcp-tools-user.test.ts +60 -6
- package/src/tests/model-control.test.ts +8 -2
- package/src/tests/oauth-credential-bindings.test.ts +490 -0
- package/src/tests/oauth-refresh-sweep.test.ts +160 -0
- package/src/tests/pool-affinity.test.ts +401 -0
- package/src/tests/prompt-template-remaining.test.ts +2 -2
- package/src/tests/rbac-admission-e2e.test.ts +386 -0
- package/src/tests/rbac-admission.test.ts +492 -0
- package/src/tests/rbac-e2e-helpers.ts +3 -0
- package/src/tests/rbac-engine.test.ts +50 -0
- package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
- package/src/tests/rbac-roles.test.ts +328 -0
- package/src/tests/reasoning-effort.test.ts +15 -2
- package/src/tests/schedule-target-type.test.ts +50 -0
- package/src/tests/scheduled-tasks.test.ts +40 -0
- package/src/tests/script-apis-mcp.test.ts +37 -13
- package/src/tests/script-connections-http.test.ts +1158 -0
- package/src/tests/script-connections-mcp.test.ts +894 -0
- package/src/tests/script-connections.test.ts +754 -6
- package/src/tests/scripts-external-api.test.ts +49 -1
- package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
- package/src/tests/scripts-runtime.test.ts +291 -0
- package/src/tests/seed-scripts.test.ts +36 -0
- package/src/tests/slack-identity-resolution.test.ts +37 -3
- package/src/tests/slack-inline-output.test.ts +65 -0
- package/src/tests/slack-thread-buffer.test.ts +28 -0
- package/src/tests/tool-annotations.test.ts +1 -0
- package/src/tests/user-token-rest-auth.test.ts +140 -1
- package/src/tests/workflow-swarm-script.test.ts +44 -0
- package/src/tests/workflow-triggers-v2.test.ts +300 -1
- package/src/tools/credential-bindings/tool.ts +277 -18
- package/src/tools/delete-page.ts +145 -0
- package/src/tools/mcp-servers/mcp-server-delete.ts +7 -4
- package/src/tools/request-human-input.ts +2 -0
- package/src/tools/resolve-user.ts +77 -27
- package/src/tools/script-apis.ts +62 -3
- package/src/tools/script-connections/tool.ts +275 -31
- package/src/tools/send-task.ts +15 -1
- package/src/tools/task-action.ts +34 -2
- package/src/tools/templates.ts +53 -1
- package/src/tools/tool-config.ts +2 -1
- package/src/tools/utils.ts +2 -0
- package/src/tools/workflows/create-workflow.ts +8 -1
- package/src/tools/workflows/update-workflow.ts +11 -2
- package/src/types.ts +90 -11
- package/src/utils/scoped-resource.ts +25 -0
- package/src/workflows/executors/human-in-the-loop.ts +1 -0
- package/src/workflows/executors/swarm-script.ts +7 -1
- package/src/workflows/triggers.ts +146 -18
- package/templates/skills/swarm-scripts/content.md +33 -8
- package/dist/cli-bgef578c.js +0 -771
- package/dist/cli-c9mtm09b.js +0 -43
- package/dist/cli-ceewqajw.js +0 -1698
- package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
- package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
- package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
- package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
- package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
- package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
- package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
- package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
- package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
|
@@ -1,39 +1,153 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { getAgentById } from "@/be/db";
|
|
4
|
+
import { upsertOAuthApp } from "@/be/db-queries/oauth";
|
|
5
|
+
import {
|
|
6
|
+
getOAuthBindingTokenStatus,
|
|
7
|
+
getOAuthProviderConfig,
|
|
8
|
+
type OAuthBindingTokenStatus,
|
|
9
|
+
} from "@/be/oauth-credential-bindings";
|
|
4
10
|
import {
|
|
5
11
|
disableCredentialBinding,
|
|
6
12
|
importLegacyCredentialBindings,
|
|
7
13
|
listRelationalCredentialBindings,
|
|
14
|
+
type ScriptCredentialBindingRecord,
|
|
8
15
|
upsertCredentialBinding,
|
|
9
16
|
} from "@/be/script-connections";
|
|
17
|
+
import { assertOAuthAppUrlsSafe, assertOAuthProviderIsNotReserved } from "@/oauth/app-validation";
|
|
18
|
+
import { buildAuthorizationUrl } from "@/oauth/wrapper";
|
|
10
19
|
import { can } from "@/rbac";
|
|
11
20
|
import {
|
|
12
21
|
CredentialBindingSchema,
|
|
13
22
|
placeholderForConfigKey,
|
|
14
23
|
} from "@/scripts-runtime/credential-broker";
|
|
15
24
|
import { createToolRegistrar } from "@/tools/utils";
|
|
25
|
+
import { getPublicMcpBaseUrl } from "@/utils/constants";
|
|
26
|
+
import { resolveScopedResourceId, scopedResourceScopeIdSchema } from "@/utils/scoped-resource";
|
|
27
|
+
|
|
28
|
+
const providerSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.min(1)
|
|
31
|
+
.max(255)
|
|
32
|
+
.regex(/^[A-Za-z0-9_-]+$/);
|
|
33
|
+
const tokenStatusSchema = z.enum(["ok", "expiring", "missing"]);
|
|
34
|
+
const credentialBindingToolBindingSchema = CredentialBindingSchema.and(
|
|
35
|
+
z.object({
|
|
36
|
+
id: z.string().optional(),
|
|
37
|
+
source: z.enum(["default", "user", "migration"]).optional(),
|
|
38
|
+
createdAt: z.string().optional(),
|
|
39
|
+
updatedAt: z.string().optional(),
|
|
40
|
+
createdBy: z.string().nullable().optional(),
|
|
41
|
+
updatedBy: z.string().nullable().optional(),
|
|
42
|
+
tokenStatus: tokenStatusSchema.optional(),
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
16
45
|
|
|
17
46
|
const credentialBindingsOutputSchema = z.object({
|
|
18
47
|
yourAgentId: z.string().uuid().optional(),
|
|
19
48
|
success: z.boolean(),
|
|
20
49
|
message: z.string(),
|
|
21
|
-
|
|
50
|
+
provider: z.string().optional(),
|
|
51
|
+
authorizeUrl: z.string().optional(),
|
|
52
|
+
redirectUri: z.string().optional(),
|
|
53
|
+
bindings: z.array(credentialBindingToolBindingSchema),
|
|
22
54
|
});
|
|
23
55
|
|
|
24
56
|
const credentialBindingsInputSchema = z.object({
|
|
25
57
|
action: z
|
|
26
|
-
.enum(["list", "upsert", "disable", "import-legacy"])
|
|
27
|
-
.describe(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
.enum(["list", "upsert", "disable", "import-legacy", "oauth-app-upsert", "oauth-authorize-url"])
|
|
59
|
+
.describe(
|
|
60
|
+
"List, add/update, disable, import legacy JSON bindings, or register/authorize OAuth apps.",
|
|
61
|
+
),
|
|
62
|
+
id: z
|
|
63
|
+
.string()
|
|
64
|
+
.uuid()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Existing credential binding ID for update or disable."),
|
|
67
|
+
configKey: z
|
|
68
|
+
.string()
|
|
69
|
+
.min(1)
|
|
70
|
+
.max(255)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("Swarm config key whose secret value is injected through templates."),
|
|
73
|
+
allowedHosts: z
|
|
74
|
+
.array(z.string().min(1))
|
|
75
|
+
.min(1)
|
|
76
|
+
.optional()
|
|
77
|
+
.describe("Allowed outbound hostnames for this binding."),
|
|
78
|
+
headerTemplate: z
|
|
79
|
+
.string()
|
|
80
|
+
.min(1)
|
|
81
|
+
.optional()
|
|
82
|
+
.describe("Header template containing the config-key placeholder."),
|
|
83
|
+
queryTemplate: z
|
|
84
|
+
.string()
|
|
85
|
+
.min(1)
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("Query parameter template containing the config-key placeholder."),
|
|
88
|
+
scope: z
|
|
89
|
+
.enum(["global", "agent", "repo"])
|
|
90
|
+
.default("global")
|
|
91
|
+
.optional()
|
|
92
|
+
.describe("Binding visibility scope."),
|
|
93
|
+
scopeId: scopedResourceScopeIdSchema
|
|
94
|
+
.nullable()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe("Agent UUID for agent scope or repo id (owner/name) for repo scope."),
|
|
97
|
+
authKind: z
|
|
98
|
+
.enum(["config", "oauth"])
|
|
99
|
+
.default("config")
|
|
100
|
+
.optional()
|
|
101
|
+
.describe("Use config for stored swarm config secrets or oauth for OAuth token resolution."),
|
|
102
|
+
oauthProvider: providerSchema
|
|
103
|
+
.optional()
|
|
104
|
+
.describe("OAuth provider slug required when authKind is oauth."),
|
|
105
|
+
provider: providerSchema
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("OAuth provider slug for oauth-app-upsert and oauth-authorize-url."),
|
|
108
|
+
clientId: z.string().min(1).optional().describe("OAuth client ID for oauth-app-upsert."),
|
|
109
|
+
clientSecret: z.string().min(1).optional().describe("OAuth client secret for oauth-app-upsert."),
|
|
110
|
+
authorizeUrl: z
|
|
111
|
+
.string()
|
|
112
|
+
.url()
|
|
113
|
+
.optional()
|
|
114
|
+
.describe("OAuth authorization URL for oauth-app-upsert."),
|
|
115
|
+
tokenUrl: z.string().url().optional().describe("OAuth token URL for oauth-app-upsert."),
|
|
116
|
+
scopes: z.array(z.string().min(1)).optional().describe("OAuth scopes for oauth-app-upsert."),
|
|
117
|
+
extraParams: z
|
|
118
|
+
.record(z.string(), z.string())
|
|
119
|
+
.optional()
|
|
120
|
+
.describe("Extra OAuth authorization parameters stored with the OAuth app."),
|
|
121
|
+
tokenAuthStyle: z
|
|
122
|
+
.enum(["body", "basic"])
|
|
123
|
+
.optional()
|
|
124
|
+
.describe(
|
|
125
|
+
"How client credentials reach the token endpoint: body params (default) or HTTP Basic auth (required by e.g. Notion).",
|
|
126
|
+
),
|
|
127
|
+
tokenBodyFormat: z
|
|
128
|
+
.enum(["form", "json"])
|
|
129
|
+
.optional()
|
|
130
|
+
.describe(
|
|
131
|
+
"Token request body encoding: form-urlencoded (default) or JSON (required by e.g. Notion).",
|
|
132
|
+
),
|
|
35
133
|
});
|
|
36
134
|
|
|
135
|
+
type BindingWithTokenStatus = ScriptCredentialBindingRecord & {
|
|
136
|
+
tokenStatus?: OAuthBindingTokenStatus;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function genericOAuthRedirectUri(provider: string): string {
|
|
140
|
+
return `${getPublicMcpBaseUrl()}/api/oauth/${encodeURIComponent(provider)}/callback`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function decorateBindings(bindings: ScriptCredentialBindingRecord[]): BindingWithTokenStatus[] {
|
|
144
|
+
return bindings.map((binding) =>
|
|
145
|
+
binding.authKind === "oauth" && binding.oauthProvider
|
|
146
|
+
? { ...binding, tokenStatus: getOAuthBindingTokenStatus(binding.oauthProvider) }
|
|
147
|
+
: binding,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
37
151
|
export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
38
152
|
createToolRegistrar(server)(
|
|
39
153
|
"credential-bindings",
|
|
@@ -80,7 +194,133 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
80
194
|
};
|
|
81
195
|
}
|
|
82
196
|
|
|
83
|
-
const
|
|
197
|
+
const currentBindings = () =>
|
|
198
|
+
decorateBindings(listRelationalCredentialBindings({ includeInactive: true }));
|
|
199
|
+
const bindings = currentBindings();
|
|
200
|
+
|
|
201
|
+
if (args.action === "oauth-app-upsert") {
|
|
202
|
+
if (
|
|
203
|
+
!args.provider ||
|
|
204
|
+
!args.clientId ||
|
|
205
|
+
!args.clientSecret ||
|
|
206
|
+
!args.authorizeUrl ||
|
|
207
|
+
!args.tokenUrl ||
|
|
208
|
+
!args.scopes
|
|
209
|
+
) {
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: "provider, clientId, clientSecret, authorizeUrl, tokenUrl, and scopes are required for oauth-app-upsert.",
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
structuredContent: {
|
|
218
|
+
yourAgentId: requestInfo.agentId,
|
|
219
|
+
success: false,
|
|
220
|
+
message:
|
|
221
|
+
"provider, clientId, clientSecret, authorizeUrl, tokenUrl, and scopes are required for oauth-app-upsert.",
|
|
222
|
+
bindings,
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
assertOAuthProviderIsNotReserved(args.provider);
|
|
229
|
+
assertOAuthAppUrlsSafe({
|
|
230
|
+
authorizeUrl: args.authorizeUrl,
|
|
231
|
+
tokenUrl: args.tokenUrl,
|
|
232
|
+
});
|
|
233
|
+
} catch (err) {
|
|
234
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
235
|
+
return {
|
|
236
|
+
content: [{ type: "text", text: message }],
|
|
237
|
+
structuredContent: {
|
|
238
|
+
yourAgentId: requestInfo.agentId,
|
|
239
|
+
success: false,
|
|
240
|
+
message,
|
|
241
|
+
bindings,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const redirectUri = genericOAuthRedirectUri(args.provider);
|
|
247
|
+
upsertOAuthApp(args.provider, {
|
|
248
|
+
clientId: args.clientId,
|
|
249
|
+
clientSecret: args.clientSecret,
|
|
250
|
+
authorizeUrl: args.authorizeUrl,
|
|
251
|
+
tokenUrl: args.tokenUrl,
|
|
252
|
+
redirectUri,
|
|
253
|
+
scopes: args.scopes.join(","),
|
|
254
|
+
...(args.extraParams || args.tokenAuthStyle || args.tokenBodyFormat
|
|
255
|
+
? {
|
|
256
|
+
metadata: JSON.stringify({
|
|
257
|
+
...(args.extraParams ? { extraParams: args.extraParams } : {}),
|
|
258
|
+
...(args.tokenAuthStyle ? { tokenAuthStyle: args.tokenAuthStyle } : {}),
|
|
259
|
+
...(args.tokenBodyFormat ? { tokenBodyFormat: args.tokenBodyFormat } : {}),
|
|
260
|
+
}),
|
|
261
|
+
}
|
|
262
|
+
: {}),
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: "text",
|
|
269
|
+
text: `OAuth app ${args.provider} saved. Redirect URI: ${redirectUri}`,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
structuredContent: {
|
|
273
|
+
yourAgentId: requestInfo.agentId,
|
|
274
|
+
success: true,
|
|
275
|
+
message: `OAuth app ${args.provider} saved.`,
|
|
276
|
+
provider: args.provider,
|
|
277
|
+
redirectUri,
|
|
278
|
+
bindings: currentBindings(),
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (args.action === "oauth-authorize-url") {
|
|
284
|
+
if (!args.provider) {
|
|
285
|
+
return {
|
|
286
|
+
content: [{ type: "text", text: "provider is required for oauth-authorize-url." }],
|
|
287
|
+
structuredContent: {
|
|
288
|
+
yourAgentId: requestInfo.agentId,
|
|
289
|
+
success: false,
|
|
290
|
+
message: "provider is required for oauth-authorize-url.",
|
|
291
|
+
bindings,
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const config = getOAuthProviderConfig(args.provider);
|
|
297
|
+
if (!config) {
|
|
298
|
+
return {
|
|
299
|
+
content: [{ type: "text", text: `OAuth app ${args.provider} is not configured.` }],
|
|
300
|
+
structuredContent: {
|
|
301
|
+
yourAgentId: requestInfo.agentId,
|
|
302
|
+
success: false,
|
|
303
|
+
message: `OAuth app ${args.provider} is not configured.`,
|
|
304
|
+
provider: args.provider,
|
|
305
|
+
bindings,
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const result = await buildAuthorizationUrl(config);
|
|
311
|
+
return {
|
|
312
|
+
content: [{ type: "text", text: result.url }],
|
|
313
|
+
structuredContent: {
|
|
314
|
+
yourAgentId: requestInfo.agentId,
|
|
315
|
+
success: true,
|
|
316
|
+
message: `OAuth authorization URL generated for ${args.provider}.`,
|
|
317
|
+
provider: args.provider,
|
|
318
|
+
authorizeUrl: result.url,
|
|
319
|
+
redirectUri: config.redirectUri,
|
|
320
|
+
bindings,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
84
324
|
|
|
85
325
|
if (args.action === "list") {
|
|
86
326
|
return {
|
|
@@ -107,7 +347,7 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
107
347
|
|
|
108
348
|
if (args.action === "import-legacy") {
|
|
109
349
|
const imported = importLegacyCredentialBindings();
|
|
110
|
-
const nextBindings =
|
|
350
|
+
const nextBindings = currentBindings();
|
|
111
351
|
return {
|
|
112
352
|
content: [{ type: "text", text: `Imported ${imported} legacy credential binding(s).` }],
|
|
113
353
|
structuredContent: {
|
|
@@ -133,7 +373,7 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
133
373
|
};
|
|
134
374
|
}
|
|
135
375
|
|
|
136
|
-
const nextBindings =
|
|
376
|
+
const nextBindings = currentBindings();
|
|
137
377
|
return {
|
|
138
378
|
content: [{ type: "text", text: `Credential binding ${disabled.configKey} disabled.` }],
|
|
139
379
|
structuredContent: {
|
|
@@ -158,14 +398,17 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
158
398
|
}
|
|
159
399
|
|
|
160
400
|
const scope = args.scope ?? "global";
|
|
161
|
-
|
|
162
|
-
|
|
401
|
+
let scopeId: string | null;
|
|
402
|
+
try {
|
|
403
|
+
scopeId = resolveScopedResourceId(scope, args.scopeId, "bindings");
|
|
404
|
+
} catch (err) {
|
|
405
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
163
406
|
return {
|
|
164
|
-
content: [{ type: "text", text:
|
|
407
|
+
content: [{ type: "text", text: message }],
|
|
165
408
|
structuredContent: {
|
|
166
409
|
yourAgentId: requestInfo.agentId,
|
|
167
410
|
success: false,
|
|
168
|
-
message
|
|
411
|
+
message,
|
|
169
412
|
bindings,
|
|
170
413
|
},
|
|
171
414
|
};
|
|
@@ -189,6 +432,18 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
189
432
|
};
|
|
190
433
|
}
|
|
191
434
|
|
|
435
|
+
if ((args.authKind ?? "config") === "oauth" && !args.oauthProvider) {
|
|
436
|
+
return {
|
|
437
|
+
content: [{ type: "text", text: "oauthProvider is required for oauth bindings." }],
|
|
438
|
+
structuredContent: {
|
|
439
|
+
yourAgentId: requestInfo.agentId,
|
|
440
|
+
success: false,
|
|
441
|
+
message: "oauthProvider is required for oauth bindings.",
|
|
442
|
+
bindings,
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
192
447
|
const placeholder = placeholderForConfigKey(args.configKey);
|
|
193
448
|
if (args.headerTemplate && !args.headerTemplate.includes(placeholder)) {
|
|
194
449
|
return {
|
|
@@ -221,6 +476,8 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
221
476
|
scope,
|
|
222
477
|
scopeId,
|
|
223
478
|
active: true,
|
|
479
|
+
authKind: args.authKind ?? "config",
|
|
480
|
+
oauthProvider: args.oauthProvider,
|
|
224
481
|
});
|
|
225
482
|
|
|
226
483
|
upsertCredentialBinding({
|
|
@@ -232,8 +489,10 @@ export const registerCredentialBindingsTool = (server: McpServer) => {
|
|
|
232
489
|
scope: nextBinding.scope,
|
|
233
490
|
scopeId: nextBinding.scopeId ?? null,
|
|
234
491
|
active: true,
|
|
492
|
+
authKind: nextBinding.authKind,
|
|
493
|
+
oauthProvider: nextBinding.oauthProvider ?? null,
|
|
235
494
|
});
|
|
236
|
-
const nextBindings =
|
|
495
|
+
const nextBindings = currentBindings();
|
|
237
496
|
|
|
238
497
|
return {
|
|
239
498
|
content: [{ type: "text", text: `Credential binding ${args.configKey} saved.` }],
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { deletePage, getAgentById, getPage, getPageBySlug } from "@/be/db";
|
|
4
|
+
import { can } from "@/rbac";
|
|
5
|
+
import { createToolRegistrar } from "@/tools/utils";
|
|
6
|
+
|
|
7
|
+
export const registerDeletePageTool = (server: McpServer) => {
|
|
8
|
+
createToolRegistrar(server)(
|
|
9
|
+
"delete-page",
|
|
10
|
+
{
|
|
11
|
+
title: "Delete Page",
|
|
12
|
+
description:
|
|
13
|
+
"Permanently delete one page by pageId, or by slug in the caller's page namespace. Only the lead or the page owner can delete a page.",
|
|
14
|
+
annotations: { destructiveHint: true },
|
|
15
|
+
inputSchema: z.object({
|
|
16
|
+
pageId: z.string().min(1).optional().describe("Page ID to delete."),
|
|
17
|
+
slug: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(1)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(
|
|
22
|
+
"Page slug to delete from the caller's own (agentId, slug) namespace. Alternative to pageId.",
|
|
23
|
+
),
|
|
24
|
+
}),
|
|
25
|
+
outputSchema: z.object({
|
|
26
|
+
yourAgentId: z.string().optional(),
|
|
27
|
+
success: z.boolean(),
|
|
28
|
+
message: z.string(),
|
|
29
|
+
deletedPage: z
|
|
30
|
+
.object({
|
|
31
|
+
id: z.string(),
|
|
32
|
+
slug: z.string(),
|
|
33
|
+
title: z.string(),
|
|
34
|
+
})
|
|
35
|
+
.optional(),
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
async ({ pageId, slug }, requestInfo, _meta) => {
|
|
39
|
+
if (!requestInfo.agentId) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text", text: 'Agent ID not found. Set the "X-Agent-ID" header.' }],
|
|
42
|
+
structuredContent: {
|
|
43
|
+
success: false,
|
|
44
|
+
message: 'Agent ID not found. Set the "X-Agent-ID" header.',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!pageId && !slug) {
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: "Either pageId or slug must be provided." }],
|
|
52
|
+
structuredContent: {
|
|
53
|
+
yourAgentId: requestInfo.agentId,
|
|
54
|
+
success: false,
|
|
55
|
+
message: "Either pageId or slug must be provided.",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const caller = getAgentById(requestInfo.agentId);
|
|
61
|
+
if (!caller) {
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: "Agent not found." }],
|
|
64
|
+
structuredContent: {
|
|
65
|
+
yourAgentId: requestInfo.agentId,
|
|
66
|
+
success: false,
|
|
67
|
+
message: "Agent not found.",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const page = pageId
|
|
73
|
+
? getPage(pageId)
|
|
74
|
+
: slug
|
|
75
|
+
? getPageBySlug(requestInfo.agentId, slug)
|
|
76
|
+
: null;
|
|
77
|
+
if (!page) {
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: "Page not found." }],
|
|
80
|
+
structuredContent: {
|
|
81
|
+
yourAgentId: requestInfo.agentId,
|
|
82
|
+
success: false,
|
|
83
|
+
message: "Page not found.",
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const decision = can({
|
|
89
|
+
principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead },
|
|
90
|
+
verb: "page.delete.any",
|
|
91
|
+
resource: { kind: "owned", ownerAgentId: page.agentId },
|
|
92
|
+
source: "mcp",
|
|
93
|
+
});
|
|
94
|
+
if (!decision.allow) {
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: "Only the lead or page owner can delete pages." }],
|
|
97
|
+
structuredContent: {
|
|
98
|
+
yourAgentId: requestInfo.agentId,
|
|
99
|
+
success: false,
|
|
100
|
+
message: "Only the lead or page owner can delete pages.",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const deleted = deletePage(page.id);
|
|
107
|
+
if (!deleted) {
|
|
108
|
+
return {
|
|
109
|
+
content: [{ type: "text", text: "Failed to delete page." }],
|
|
110
|
+
structuredContent: {
|
|
111
|
+
yourAgentId: requestInfo.agentId,
|
|
112
|
+
success: false,
|
|
113
|
+
message: "Failed to delete page.",
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const deletedPage = {
|
|
119
|
+
id: page.id,
|
|
120
|
+
slug: page.slug,
|
|
121
|
+
title: page.title,
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
content: [{ type: "text", text: `Deleted page "${page.title}".` }],
|
|
125
|
+
structuredContent: {
|
|
126
|
+
yourAgentId: requestInfo.agentId,
|
|
127
|
+
success: true,
|
|
128
|
+
message: `Deleted page "${page.title}".`,
|
|
129
|
+
deletedPage,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
} catch (error) {
|
|
133
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
134
|
+
return {
|
|
135
|
+
content: [{ type: "text", text: `Failed to delete page: ${message}` }],
|
|
136
|
+
structuredContent: {
|
|
137
|
+
yourAgentId: requestInfo.agentId,
|
|
138
|
+
success: false,
|
|
139
|
+
message: `Failed to delete page: ${message}`,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
};
|
|
@@ -64,18 +64,21 @@ export const registerMcpServerDeleteTool = (server: McpServer) => {
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const result = deleteMcpServer(args.id);
|
|
68
|
+
const message = result.deleted
|
|
69
|
+
? `Deleted MCP server "${existing.name}" and ${result.deletedScriptConnectionCount} script connection(s).`
|
|
70
|
+
: "Delete failed.";
|
|
68
71
|
return {
|
|
69
72
|
content: [
|
|
70
73
|
{
|
|
71
74
|
type: "text",
|
|
72
|
-
text:
|
|
75
|
+
text: message,
|
|
73
76
|
},
|
|
74
77
|
],
|
|
75
78
|
structuredContent: {
|
|
76
79
|
yourAgentId: requestInfo.agentId,
|
|
77
|
-
success: deleted,
|
|
78
|
-
message
|
|
80
|
+
success: result.deleted,
|
|
81
|
+
message,
|
|
79
82
|
},
|
|
80
83
|
};
|
|
81
84
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
+
import { resolveTaskAuditUserId } from "@/be/audit-user";
|
|
3
4
|
import { createApprovalRequest, getAgentCurrentTask } from "@/be/db";
|
|
4
5
|
import { createToolRegistrar } from "@/tools/utils";
|
|
5
6
|
import { getAppUrl } from "@/utils/constants";
|
|
@@ -93,6 +94,7 @@ export const registerRequestHumanInputTool = (server: McpServer) => {
|
|
|
93
94
|
approvers: { policy: "any" },
|
|
94
95
|
sourceTaskId: sourceTaskId ?? undefined,
|
|
95
96
|
timeoutSeconds,
|
|
97
|
+
createdBy: resolveTaskAuditUserId(sourceTaskId, requestInfo.agentId) ?? undefined,
|
|
96
98
|
});
|
|
97
99
|
|
|
98
100
|
const appUrl = getAppUrl();
|