@zackbart/connecta 0.28.0 → 0.29.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/CHANGELOG.md +961 -5
- package/README.md +62 -39
- package/bin/connecta.mjs +110 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1632 -1509
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +526 -0
- package/dist/auth-elicitation.js +283 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +368 -224
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +631 -0
- package/dist/config.js +503 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +220 -0
- package/dist/connectors/api-connector.js +214 -0
- package/dist/connectors/api.d.ts +8 -71
- package/dist/connectors/api.js +13 -99
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +108 -25
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1780 -351
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +119 -0
- package/dist/downstream-input.js +323 -0
- package/dist/errors.d.ts +97 -20
- package/dist/errors.js +158 -80
- package/dist/execute.js +453 -305
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +24 -9
- package/dist/executors/quickjs-child.js +3 -4
- package/dist/executors/quickjs-runtime.js +147 -59
- package/dist/executors/quickjs.js +29 -35
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +188 -0
- package/dist/guest-types.d.ts +176 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +25 -257
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +230 -73
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +76 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +285 -209
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +117 -0
- package/dist/oauth-partition.js +17 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +55 -18
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/basecamp/index.d.ts +43 -0
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/breeze/index.d.ts +34 -0
- package/dist/providers/breeze/index.js +1446 -0
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/ccb/index.d.ts +103 -0
- package/dist/providers/ccb/index.js +1725 -0
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/overflow/index.d.ts +60 -0
- package/dist/providers/overflow/index.js +1535 -0
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/planning-center/index.d.ts +59 -0
- package/dist/providers/planning-center/index.js +2199 -0
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/tithely/index.d.ts +49 -0
- package/dist/providers/tithely/index.js +1003 -0
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +108 -171
- package/dist/registry.js +513 -925
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +100 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +356 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +136 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +52 -0
- package/dist/sent-secrets.js +474 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +406 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +166 -0
- package/dist/storage/keys.js +428 -0
- package/dist/storage/memory.js +7 -0
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +534 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +320 -54
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +137 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +434 -0
- package/documentation/architecture.md +665 -230
- package/documentation/auth.md +962 -458
- package/documentation/code-mode.md +501 -312
- package/documentation/meta-tools.md +449 -200
- package/documentation/operator-tests.md +93 -0
- package/documentation/provider-migration-0.29.md +60 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +286 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +125 -35
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +133 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- package/templates/node/src/file-activity.ts +0 -182
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { skill } from "./skill.generated.js";
|
|
1
2
|
/**
|
|
2
3
|
* No official `cloudflare` SDK on purpose. What the SDK sells — typed request
|
|
3
4
|
* wrappers and pagination helpers — is what this connection replaces: an agent
|
|
@@ -6,14 +7,17 @@
|
|
|
6
7
|
* optional peer, an install step, and an import that never belongs in the root
|
|
7
8
|
* graph. Cloudflare's v4 API is authenticated `fetch` over a uniform
|
|
8
9
|
* `{ success, errors, messages, result, result_info }` envelope, so Web APIs
|
|
9
|
-
* alone keep this provider Workers-clean. `test/package-surface.test.ts` pins
|
|
10
|
+
* alone keep this provider Workers-clean. `test/package-surface.node.test.ts` pins
|
|
10
11
|
* it: no `cloudflare` package in any dependency field, every import relative.
|
|
11
12
|
*/
|
|
12
|
-
import { api
|
|
13
|
-
import { remoteMcp, withCredentialDefaults
|
|
14
|
-
import {
|
|
15
|
-
import { guardedFetch, retryAfterMs, } from "
|
|
16
|
-
import { ConnectorCallError } from "
|
|
13
|
+
import { apiConnector as api } from "../../connectors/api-connector.js";
|
|
14
|
+
import { remoteMcp, withCredentialDefaults } from "../../connectors/remote-mcp.js";
|
|
15
|
+
import { reviewedCatalog } from "../../catalog-drift.js";
|
|
16
|
+
import { guardedFetch, retryAfterMs, } from "../../connectors/guarded-fetch.js";
|
|
17
|
+
import { ConnectorCallError } from "../../errors.js";
|
|
18
|
+
import { keys, optionsOf, variants } from "../../config-schema.js";
|
|
19
|
+
import { CREDENTIAL, PROVIDER_COMMON, REMOTE_MCP_AUTH } from "../../connectors/option-shapes.js";
|
|
20
|
+
import { defineProvider } from "../../provider.js";
|
|
17
21
|
/** Cloudflare's v4 REST base. Override only for a proxy or a test double. */
|
|
18
22
|
export const CLOUDFLARE_API_BASE = "https://api.cloudflare.com/client/v4";
|
|
19
23
|
/** Cloudflare's official whole-API hosted MCP endpoint. */
|
|
@@ -92,7 +96,7 @@ function admissionPolicy(maxConcurrency) {
|
|
|
92
96
|
}
|
|
93
97
|
const API_TOKEN_CREDENTIAL = {
|
|
94
98
|
label: "Cloudflare API token",
|
|
95
|
-
description:
|
|
99
|
+
description: 'A scoped API token (My Profile → API Tokens → Create Token), not a Global API Key. Grant only the permissions the deployment needs: zone-scoped "Zone Read", "Zone Settings Write", "DNS Write", "Cache Purge", and the phase-specific Rules product Read permissions as needed; account-scoped "Workers Scripts Read/Write", "Workers KV Storage Read/Write", "Workers R2 Storage Read/Write", or "Cloudflare Pages Read/Write" for the platform tools.',
|
|
96
100
|
placeholder: "Paste API token",
|
|
97
101
|
};
|
|
98
102
|
const GLOBAL_API_KEY_CREDENTIAL = {
|
|
@@ -137,9 +141,7 @@ function credentialConfig(authentication, override) {
|
|
|
137
141
|
return credential;
|
|
138
142
|
}
|
|
139
143
|
function asRecord(value) {
|
|
140
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
141
|
-
? value
|
|
142
|
-
: {};
|
|
144
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
143
145
|
}
|
|
144
146
|
function asArray(value) {
|
|
145
147
|
return Array.isArray(value) ? value : [];
|
|
@@ -222,9 +224,12 @@ function failureFor(status, headers, errors) {
|
|
|
222
224
|
{ retryAfterMs: wait ?? 300_000 });
|
|
223
225
|
}
|
|
224
226
|
const authCoded = [...codes].some((code) => AUTH_ERROR_CODES.has(code));
|
|
225
|
-
if (status === 401 ||
|
|
227
|
+
if (status === 401 || authCoded) {
|
|
226
228
|
return new ConnectorCallError("auth_required", `Cloudflare rejected the configured credential (HTTP ${status}). ${detail} Check that it is valid and has permission to access this resource.`);
|
|
227
229
|
}
|
|
230
|
+
if (status === 403) {
|
|
231
|
+
return new ConnectorCallError("provider_permission_denied", `Cloudflare refused access to this resource (HTTP 403). ${detail} Verify the configured credential first; if valid, ask the account administrator to grant the required resource permission and token scope.`);
|
|
232
|
+
}
|
|
228
233
|
if (status === 400 || status === 409 || status === 422) {
|
|
229
234
|
return new ConnectorCallError("invalid_args", `Cloudflare rejected the request (HTTP ${status}). ${detail}`);
|
|
230
235
|
}
|
|
@@ -286,24 +291,20 @@ function cloudflareTransport(baseUrl, authentication) {
|
|
|
286
291
|
async function callCloudflare(send, spec, ctx) {
|
|
287
292
|
return await send(spec, ctx, async (response) => {
|
|
288
293
|
const parsed = await response.jsonResult();
|
|
289
|
-
const envelope = "value" in parsed
|
|
290
|
-
? parsed.value
|
|
291
|
-
: undefined;
|
|
294
|
+
const envelope = "value" in parsed ? parsed.value : undefined;
|
|
292
295
|
if (envelope === undefined) {
|
|
293
296
|
// A gateway error page or an empty body, not an envelope: the status is
|
|
294
297
|
// the only real signal left.
|
|
298
|
+
// No cause: the parser's error quotes the body it could not read.
|
|
295
299
|
throw response.ok
|
|
296
|
-
? new ConnectorCallError("unavailable", "Cloudflare returned a non-JSON body for a successful status."
|
|
300
|
+
? new ConnectorCallError("unavailable", "Cloudflare returned a non-JSON body for a successful status.")
|
|
297
301
|
: failureFor(response.status, response.headers, []);
|
|
298
302
|
}
|
|
299
303
|
const errors = Array.isArray(envelope.errors) ? envelope.errors : [];
|
|
300
304
|
if (!response.ok || envelope.success === false) {
|
|
301
305
|
throw failureFor(response.status, response.headers, errors);
|
|
302
306
|
}
|
|
303
|
-
const isV4Envelope = "success" in envelope ||
|
|
304
|
-
"result" in envelope ||
|
|
305
|
-
"result_info" in envelope ||
|
|
306
|
-
"messages" in envelope;
|
|
307
|
+
const isV4Envelope = "success" in envelope || "result" in envelope || "result_info" in envelope || "messages" in envelope;
|
|
307
308
|
return {
|
|
308
309
|
// `/graphql` and a small number of product APIs return ordinary JSON
|
|
309
310
|
// instead of the standard v4 envelope. Preserve that document whole so
|
|
@@ -338,10 +339,7 @@ async function callCloudflareContent(send, spec, ctx, responseType) {
|
|
|
338
339
|
let envelope;
|
|
339
340
|
try {
|
|
340
341
|
const parsed = await response.jsonResult();
|
|
341
|
-
envelope =
|
|
342
|
-
"value" in parsed
|
|
343
|
-
? parsed.value
|
|
344
|
-
: undefined;
|
|
342
|
+
envelope = "value" in parsed ? parsed.value : undefined;
|
|
345
343
|
}
|
|
346
344
|
catch {
|
|
347
345
|
// Content reads classify an already-failed status even when its error
|
|
@@ -369,9 +367,7 @@ function pageInfo(info) {
|
|
|
369
367
|
return undefined;
|
|
370
368
|
// A cursor-only result_info carries no page counters; inventing them would
|
|
371
369
|
// report `hasMore: false` on a listing that has more.
|
|
372
|
-
if (info.page === undefined &&
|
|
373
|
-
info.total_pages === undefined &&
|
|
374
|
-
info.count === undefined) {
|
|
370
|
+
if (info.page === undefined && info.total_pages === undefined && info.count === undefined) {
|
|
375
371
|
return undefined;
|
|
376
372
|
}
|
|
377
373
|
const page = typeof info.page === "number" ? info.page : 1;
|
|
@@ -392,9 +388,7 @@ function pagedList(key, project) {
|
|
|
392
388
|
});
|
|
393
389
|
}
|
|
394
390
|
function cursorResult(cursor) {
|
|
395
|
-
return typeof cursor === "string" && cursor !== ""
|
|
396
|
-
? { nextCursor: cursor }
|
|
397
|
-
: {};
|
|
391
|
+
return typeof cursor === "string" && cursor !== "" ? { nextCursor: cursor } : {};
|
|
398
392
|
}
|
|
399
393
|
function projectAccount(value) {
|
|
400
394
|
const account = asRecord(value);
|
|
@@ -409,9 +403,7 @@ function projectZone(value) {
|
|
|
409
403
|
const zone = asRecord(value);
|
|
410
404
|
const account = asRecord(zone["account"]);
|
|
411
405
|
const plan = asRecord(zone["plan"]);
|
|
412
|
-
const nameServers = Array.isArray(zone["name_servers"])
|
|
413
|
-
? zone["name_servers"]
|
|
414
|
-
: undefined;
|
|
406
|
+
const nameServers = Array.isArray(zone["name_servers"]) ? zone["name_servers"] : undefined;
|
|
415
407
|
return compact({
|
|
416
408
|
id: zone["id"],
|
|
417
409
|
name: zone["name"],
|
|
@@ -438,9 +430,7 @@ function projectZoneSetting(value) {
|
|
|
438
430
|
function projectDnsRecord(value) {
|
|
439
431
|
const record = asRecord(value);
|
|
440
432
|
const comment = record["comment"] ? record["comment"] : undefined;
|
|
441
|
-
const tags = Array.isArray(record["tags"]) && record["tags"].length > 0
|
|
442
|
-
? record["tags"]
|
|
443
|
-
: undefined;
|
|
433
|
+
const tags = Array.isArray(record["tags"]) && record["tags"].length > 0 ? record["tags"] : undefined;
|
|
444
434
|
return compact({
|
|
445
435
|
id: record["id"],
|
|
446
436
|
name: record["name"],
|
|
@@ -491,13 +481,6 @@ function projectKvBulkValues(value) {
|
|
|
491
481
|
const result = asRecord(value);
|
|
492
482
|
return compact({ values: result["values"] });
|
|
493
483
|
}
|
|
494
|
-
function projectKvBulkResult(value) {
|
|
495
|
-
const result = asRecord(value);
|
|
496
|
-
return compact({
|
|
497
|
-
successfulKeyCount: result["successful_key_count"],
|
|
498
|
-
unsuccessfulKeys: result["unsuccessful_keys"],
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
484
|
function projectR2Bucket(value) {
|
|
502
485
|
const bucket = asRecord(value);
|
|
503
486
|
return compact({
|
|
@@ -582,9 +565,7 @@ function projectRuleset(value) {
|
|
|
582
565
|
function projectPagesProject(value) {
|
|
583
566
|
const project = asRecord(value);
|
|
584
567
|
const latest = asRecord(project["latest_deployment"]);
|
|
585
|
-
const domains = Array.isArray(project["domains"])
|
|
586
|
-
? project["domains"]
|
|
587
|
-
: undefined;
|
|
568
|
+
const domains = Array.isArray(project["domains"]) ? project["domains"] : undefined;
|
|
588
569
|
const latestDeployment = latest["id"] === undefined
|
|
589
570
|
? undefined
|
|
590
571
|
: compact({
|
|
@@ -636,9 +617,7 @@ const RAW_INPUT_PROPERTY = {
|
|
|
636
617
|
*/
|
|
637
618
|
function pagingInputProperties(minPerPage, maxPerPage, options = {}) {
|
|
638
619
|
const { defaultPerPage, bounds = "cloudflare" } = options;
|
|
639
|
-
const defaultNote = defaultPerPage === undefined
|
|
640
|
-
? " Cloudflare chooses the default."
|
|
641
|
-
: ` Defaults to ${defaultPerPage}.`;
|
|
620
|
+
const defaultNote = defaultPerPage === undefined ? " Cloudflare chooses the default." : ` Defaults to ${defaultPerPage}.`;
|
|
642
621
|
const boundsNote = bounds === "clamped"
|
|
643
622
|
? ` The ${maxPerPage} ceiling is this connection's cap, not Cloudflare's limit.`
|
|
644
623
|
: bounds === "undocumented"
|
|
@@ -768,9 +747,7 @@ function scopeRequired(kind, fallback) {
|
|
|
768
747
|
}
|
|
769
748
|
function optionalString(args, key) {
|
|
770
749
|
const value = args[key];
|
|
771
|
-
return typeof value === "string" && value.trim() !== ""
|
|
772
|
-
? value.trim()
|
|
773
|
-
: undefined;
|
|
750
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
|
|
774
751
|
}
|
|
775
752
|
function optionalNumber(args, key) {
|
|
776
753
|
const value = args[key];
|
|
@@ -782,17 +759,6 @@ function requireString(args, key) {
|
|
|
782
759
|
return value;
|
|
783
760
|
throw new ConnectorCallError("invalid_args", `${key} must not be blank.`);
|
|
784
761
|
}
|
|
785
|
-
function encodeObjectKey(value) {
|
|
786
|
-
return value
|
|
787
|
-
.split("/")
|
|
788
|
-
.map((segment) => {
|
|
789
|
-
if (segment === "." || segment === "..") {
|
|
790
|
-
throw new ConnectorCallError("invalid_args", "objectKey cannot contain '.' or '..' path segments because URL normalization would change the target resource.");
|
|
791
|
-
}
|
|
792
|
-
return encodeURIComponent(segment);
|
|
793
|
-
})
|
|
794
|
-
.join("/");
|
|
795
|
-
}
|
|
796
762
|
function cloudflareApiPath(value) {
|
|
797
763
|
if (typeof value !== "string") {
|
|
798
764
|
throw new ConnectorCallError("invalid_args", "path must be a string.");
|
|
@@ -864,7 +830,11 @@ function headersFromArgs(value) {
|
|
|
864
830
|
if (forbidden.has(name.toLowerCase())) {
|
|
865
831
|
throw new ConnectorCallError("invalid_args", `The raw Cloudflare tools do not allow the ${name} header. Authentication and request framing are connector-owned; use contentType for a raw upload body.`);
|
|
866
832
|
}
|
|
867
|
-
|
|
833
|
+
const value = String(entry["value"]);
|
|
834
|
+
if (name.toLowerCase() === "cf-r2-storage-class" && value !== "Standard" && value !== "InfrequentAccess") {
|
|
835
|
+
throw new ConnectorCallError("invalid_args", "cf-r2-storage-class must be Standard or InfrequentAccess.");
|
|
836
|
+
}
|
|
837
|
+
headers[name] = value;
|
|
868
838
|
}
|
|
869
839
|
return headers;
|
|
870
840
|
}
|
|
@@ -875,6 +845,32 @@ function rawSpec(args) {
|
|
|
875
845
|
headers: headersFromArgs(args["headers"]),
|
|
876
846
|
});
|
|
877
847
|
}
|
|
848
|
+
// The hosted helper cannot send R2 jurisdiction or bucket-edit storage headers.
|
|
849
|
+
// Ordinary headers such as Accept are not a reason to restore JSON duplicates.
|
|
850
|
+
function needsMutationHeaders(method, spec) {
|
|
851
|
+
const headers = Object.entries(spec.headers ?? {});
|
|
852
|
+
if (method === "PATCH" &&
|
|
853
|
+
/^\/accounts\/[^/]+\/r2\/buckets\/[^/]+\/?$/.test(spec.path) &&
|
|
854
|
+
headers.some(([name, value]) => name.toLowerCase() === "cf-r2-storage-class" && (value === "Standard" || value === "InfrequentAccess")))
|
|
855
|
+
return true;
|
|
856
|
+
return (/^\/accounts\/[^/]+\/r2\/buckets(?:\/|$)/.test(spec.path) &&
|
|
857
|
+
headers.some(([name, value]) => name.toLowerCase() === "cf-r2-jurisdiction" && typeof value === "string" && value.trim().length > 0));
|
|
858
|
+
}
|
|
859
|
+
// Reviewed raw-body families, rather than a Content-Type assertion that could
|
|
860
|
+
// send an ordinary JSON DNS/configuration mutation through the upload tool.
|
|
861
|
+
function isUploadEndpoint(method, path) {
|
|
862
|
+
const match = /^\/accounts\/[^/]+(\/.*)$/.exec(path);
|
|
863
|
+
if (!match)
|
|
864
|
+
return false;
|
|
865
|
+
const accountPath = match[1];
|
|
866
|
+
if (method === "PUT") {
|
|
867
|
+
return /^(?:\/workers\/scripts\/[^/]+|\/storage\/kv\/namespaces\/[^/]+\/values\/.+|\/r2\/buckets\/[^/]+\/objects\/.+)\/?$/.test(accountPath);
|
|
868
|
+
}
|
|
869
|
+
if (method === "POST") {
|
|
870
|
+
return /^(?:\/workers\/scripts\/[^/]+\/versions|\/images\/v1|\/stream|\/pages\/assets\/upload|\/pages\/projects\/[^/]+\/deployments)\/?$/.test(accountPath);
|
|
871
|
+
}
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
878
874
|
function r2Headers(args) {
|
|
879
875
|
return { "cf-r2-jurisdiction": optionalString(args, "jurisdiction") };
|
|
880
876
|
}
|
|
@@ -884,7 +880,9 @@ function bytesFromBase64(value) {
|
|
|
884
880
|
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
885
881
|
}
|
|
886
882
|
catch (cause) {
|
|
887
|
-
throw new ConnectorCallError("invalid_args", "base64Body and multipart file base64 values must be valid base64.", {
|
|
883
|
+
throw new ConnectorCallError("invalid_args", "base64Body and multipart file base64 values must be valid base64.", {
|
|
884
|
+
cause,
|
|
885
|
+
});
|
|
888
886
|
}
|
|
889
887
|
}
|
|
890
888
|
function uploadBody(args) {
|
|
@@ -917,7 +915,9 @@ function uploadBody(args) {
|
|
|
917
915
|
if (Number(text !== undefined) + Number(base64 !== undefined) !== 1) {
|
|
918
916
|
throw new ConnectorCallError("invalid_args", "Each multipart file needs exactly one of text or base64.");
|
|
919
917
|
}
|
|
920
|
-
const blob = new Blob([text ?? bytesFromBase64(base64)], {
|
|
918
|
+
const blob = new Blob([text ?? bytesFromBase64(base64)], {
|
|
919
|
+
type: String(file["contentType"] ?? "application/octet-stream"),
|
|
920
|
+
});
|
|
921
921
|
form.append(String(file["name"]), blob, String(file["fileName"]));
|
|
922
922
|
}
|
|
923
923
|
return { rawBody: form };
|
|
@@ -1007,13 +1007,6 @@ const KV_BULK_VALUES_SCHEMA = {
|
|
|
1007
1007
|
},
|
|
1008
1008
|
required: ["values"],
|
|
1009
1009
|
};
|
|
1010
|
-
const KV_BULK_RESULT_SCHEMA = {
|
|
1011
|
-
type: "object",
|
|
1012
|
-
properties: {
|
|
1013
|
-
successfulKeyCount: { type: "number" },
|
|
1014
|
-
unsuccessfulKeys: { type: "array", items: { type: "string" } },
|
|
1015
|
-
},
|
|
1016
|
-
};
|
|
1017
1010
|
const R2_CORS_SCHEMA = {
|
|
1018
1011
|
type: "object",
|
|
1019
1012
|
properties: {
|
|
@@ -1083,7 +1076,7 @@ const QUERY_INPUT_PROPERTY = {
|
|
|
1083
1076
|
// cloudflare_api_upload's compact input past the 1,024-byte discovery budget.
|
|
1084
1077
|
const HEADERS_INPUT_PROPERTY = {
|
|
1085
1078
|
type: "array",
|
|
1086
|
-
description: "Endpoint headers as name/value pairs, e.g. cf-r2-jurisdiction or Range. Connector-owned headers are refused.",
|
|
1079
|
+
description: "Endpoint headers as name/value pairs, e.g. cf-r2-jurisdiction, cf-r2-storage-class (Standard or InfrequentAccess), or Range. Connector-owned headers are refused.",
|
|
1087
1080
|
items: {
|
|
1088
1081
|
type: "object",
|
|
1089
1082
|
properties: {
|
|
@@ -1099,11 +1092,6 @@ const R2_JURISDICTION_PROPERTY = {
|
|
|
1099
1092
|
enum: ["default", "eu", "us", "fedramp"],
|
|
1100
1093
|
description: "Bucket jurisdiction. Omit for ordinary buckets; set eu, us, or fedramp for jurisdictional buckets.",
|
|
1101
1094
|
};
|
|
1102
|
-
const KV_JURISDICTION_PROPERTY = {
|
|
1103
|
-
type: "string",
|
|
1104
|
-
enum: ["eu", "fedramp", "us"],
|
|
1105
|
-
description: "Creation-only namespace jurisdiction. Omit for an ordinary namespace; it cannot be changed by rename_kv_namespace.",
|
|
1106
|
-
};
|
|
1107
1095
|
const R2_BUCKET_NAME_PROPERTY = {
|
|
1108
1096
|
type: "string",
|
|
1109
1097
|
minLength: 3,
|
|
@@ -1140,26 +1128,6 @@ const WORKER_DEPLOYMENT_ID_PROPERTY = {
|
|
|
1140
1128
|
minLength: 1,
|
|
1141
1129
|
description: "Deployment id from list_worker_deployments.",
|
|
1142
1130
|
};
|
|
1143
|
-
const RETRY_DEPLOYMENT_ID_PROPERTY = {
|
|
1144
|
-
type: "string",
|
|
1145
|
-
minLength: 1,
|
|
1146
|
-
description: "Deployment id to retry.",
|
|
1147
|
-
};
|
|
1148
|
-
const ROLLBACK_DEPLOYMENT_ID_PROPERTY = {
|
|
1149
|
-
type: "string",
|
|
1150
|
-
minLength: 1,
|
|
1151
|
-
description: "Previous deployment id to promote.",
|
|
1152
|
-
};
|
|
1153
|
-
const DELETE_DEPLOYMENT_ID_PROPERTY = {
|
|
1154
|
-
type: "string",
|
|
1155
|
-
minLength: 1,
|
|
1156
|
-
description: "Deployment id to delete.",
|
|
1157
|
-
};
|
|
1158
|
-
const DELETE_PROJECT_NAME_PROPERTY = {
|
|
1159
|
-
type: "string",
|
|
1160
|
-
minLength: 1,
|
|
1161
|
-
description: "Pages project name to delete.",
|
|
1162
|
-
};
|
|
1163
1131
|
const SETTING_ID_PROPERTY = {
|
|
1164
1132
|
type: "string",
|
|
1165
1133
|
minLength: 1,
|
|
@@ -1206,9 +1174,7 @@ function cfTool(name, description, annotations, scopeKind, scopeFallback, proper
|
|
|
1206
1174
|
...properties,
|
|
1207
1175
|
}
|
|
1208
1176
|
: properties,
|
|
1209
|
-
required: scopeKind
|
|
1210
|
-
? [...scopeRequired(scopeKind, scopeFallback), ...required]
|
|
1211
|
-
: required,
|
|
1177
|
+
required: scopeKind ? [...scopeRequired(scopeKind, scopeFallback), ...required] : required,
|
|
1212
1178
|
additionalProperties: false,
|
|
1213
1179
|
},
|
|
1214
1180
|
outputSchema,
|
|
@@ -1221,13 +1187,6 @@ function getResult(send, request, project = (result) => result) {
|
|
|
1221
1187
|
return project(result, args);
|
|
1222
1188
|
};
|
|
1223
1189
|
}
|
|
1224
|
-
function deleteAck(send, key, value, request) {
|
|
1225
|
-
return async (args, ctx) => {
|
|
1226
|
-
const id = value(args);
|
|
1227
|
-
await callCloudflare(send, request(args, id), ctx);
|
|
1228
|
-
return { deleted: true, [key]: id };
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
1190
|
function buildTools(scope, authentication) {
|
|
1232
1191
|
const { send } = scope;
|
|
1233
1192
|
const zoneArg = (args) => requireScope(args["zoneId"], scope.zoneId, "zoneId");
|
|
@@ -1241,7 +1200,7 @@ function buildTools(scope, authentication) {
|
|
|
1241
1200
|
id: { type: "string" },
|
|
1242
1201
|
status: {
|
|
1243
1202
|
type: "string",
|
|
1244
|
-
description: "
|
|
1203
|
+
description: '"active" for a usable token.',
|
|
1245
1204
|
},
|
|
1246
1205
|
notBefore: { type: "string" },
|
|
1247
1206
|
expiresOn: { type: "string" },
|
|
@@ -1264,7 +1223,7 @@ function buildTools(scope, authentication) {
|
|
|
1264
1223
|
email: { type: "string" },
|
|
1265
1224
|
status: {
|
|
1266
1225
|
type: "string",
|
|
1267
|
-
description: "
|
|
1226
|
+
description: '"active" when Cloudflare accepts the email and key.',
|
|
1268
1227
|
},
|
|
1269
1228
|
},
|
|
1270
1229
|
required: ["email", "status"],
|
|
@@ -1285,7 +1244,7 @@ function buildTools(scope, authentication) {
|
|
|
1285
1244
|
type: "string",
|
|
1286
1245
|
enum: ["json", "text", "base64"],
|
|
1287
1246
|
description: "How to read a successful response. Defaults to json; use text or base64 for object, log, script, and media downloads.",
|
|
1288
|
-
}
|
|
1247
|
+
},
|
|
1289
1248
|
}, ["path"], {
|
|
1290
1249
|
type: "object",
|
|
1291
1250
|
properties: {
|
|
@@ -1318,7 +1277,7 @@ function buildTools(scope, authentication) {
|
|
|
1318
1277
|
resultInfo,
|
|
1319
1278
|
});
|
|
1320
1279
|
}),
|
|
1321
|
-
cfTool("cloudflare_api_mutate", "Call
|
|
1280
|
+
cfTool("cloudflare_api_mutate", "Call JSON mutations for Global API Key identity or R2 jurisdiction/storage-class header gaps. Ordinary API-token writes use hosted execute. Bucket PATCH accepts cf-r2-storage-class: Standard or InfrequentAccess; no uploads.", { readOnlyHint: false, destructiveHint: true }, undefined, undefined, {
|
|
1322
1281
|
method: {
|
|
1323
1282
|
type: "string",
|
|
1324
1283
|
enum: ["POST", "PUT", "PATCH", "DELETE"],
|
|
@@ -1334,7 +1293,7 @@ function buildTools(scope, authentication) {
|
|
|
1334
1293
|
body: {
|
|
1335
1294
|
type: ["object", "array", "string", "number", "boolean", "null"],
|
|
1336
1295
|
description: "JSON request body exactly as documented by Cloudflare. Omit for endpoints with no body.",
|
|
1337
|
-
}
|
|
1296
|
+
},
|
|
1338
1297
|
}, ["method", "path"], {
|
|
1339
1298
|
type: "object",
|
|
1340
1299
|
properties: {
|
|
@@ -1350,6 +1309,9 @@ function buildTools(scope, authentication) {
|
|
|
1350
1309
|
}, async (args, ctx) => {
|
|
1351
1310
|
const method = String(args["method"]);
|
|
1352
1311
|
const spec = rawSpec(args);
|
|
1312
|
+
if (authentication === "apiToken" && !needsMutationHeaders(method, spec)) {
|
|
1313
|
+
throw new ConnectorCallError("invalid_args", "Use the Cloudflare MCP execute tool for JSON mutations with an API token. This REST tool is reserved for Global API Key identity, R2 bucket operations requiring cf-r2-jurisdiction, or bucket PATCH with cf-r2-storage-class set to Standard or InfrequentAccess.");
|
|
1314
|
+
}
|
|
1353
1315
|
const { result, resultInfo } = await callCloudflare(send, compact({
|
|
1354
1316
|
method,
|
|
1355
1317
|
...spec,
|
|
@@ -1416,7 +1378,7 @@ function buildTools(scope, authentication) {
|
|
|
1416
1378
|
required: ["name", "fileName", "contentType"],
|
|
1417
1379
|
additionalProperties: false,
|
|
1418
1380
|
},
|
|
1419
|
-
}
|
|
1381
|
+
},
|
|
1420
1382
|
}, ["method", "path"], {
|
|
1421
1383
|
type: "object",
|
|
1422
1384
|
properties: {
|
|
@@ -1427,6 +1389,9 @@ function buildTools(scope, authentication) {
|
|
|
1427
1389
|
required: ["result"],
|
|
1428
1390
|
}, async (args, ctx) => {
|
|
1429
1391
|
const spec = rawSpec(args);
|
|
1392
|
+
if (authentication === "apiToken" && !isUploadEndpoint(args["method"], spec.path)) {
|
|
1393
|
+
throw new ConnectorCallError("invalid_args", "Use the Cloudflare MCP execute tool for this mutation. REST uploads are confined to Workers, KV values, R2 objects, Images, Stream and Pages upload endpoints.");
|
|
1394
|
+
}
|
|
1430
1395
|
const upload = uploadBody(args);
|
|
1431
1396
|
const { result } = await callCloudflare(send, compact({
|
|
1432
1397
|
method: String(args["method"]),
|
|
@@ -1444,7 +1409,7 @@ function buildTools(scope, authentication) {
|
|
|
1444
1409
|
description: "Filter by exact account name.",
|
|
1445
1410
|
},
|
|
1446
1411
|
...pagingInputProperties(5, 50, { defaultPerPage: 20 }),
|
|
1447
|
-
raw: RAW_INPUT_PROPERTY
|
|
1412
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1448
1413
|
}, [], listOutputSchema("accounts", ACCOUNT_SCHEMA), async (args, ctx) => {
|
|
1449
1414
|
const { result, resultInfo } = await callCloudflare(send, {
|
|
1450
1415
|
method: "GET",
|
|
@@ -1472,7 +1437,7 @@ function buildTools(scope, authentication) {
|
|
|
1472
1437
|
description: "Filter by zone status.",
|
|
1473
1438
|
},
|
|
1474
1439
|
...pagingInputProperties(5, 50, { defaultPerPage: 20 }),
|
|
1475
|
-
raw: RAW_INPUT_PROPERTY
|
|
1440
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1476
1441
|
}, [], listOutputSchema("zones", ZONE_SCHEMA), async (args, ctx) => {
|
|
1477
1442
|
const { result, resultInfo } = await callCloudflare(send, {
|
|
1478
1443
|
method: "GET",
|
|
@@ -1493,8 +1458,8 @@ function buildTools(scope, authentication) {
|
|
|
1493
1458
|
return pagedList("zones", projectZone)(result, resultInfo, args["raw"] === true);
|
|
1494
1459
|
}),
|
|
1495
1460
|
cfTool("get_zone", "Fetch one zone's settings summary by id: status, plan, name servers, and owning account.", readOnly, "zoneId", scope.zoneId, {
|
|
1496
|
-
raw: RAW_INPUT_PROPERTY
|
|
1497
|
-
}, [], ZONE_SCHEMA, getResult(send, (args) => ({ method: "GET", path: `/zones/${encodeURIComponent(zoneArg(args))}` }), (result, args) => args["raw"] === true ? result : projectZone(result))),
|
|
1461
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1462
|
+
}, [], ZONE_SCHEMA, getResult(send, (args) => ({ method: "GET", path: `/zones/${encodeURIComponent(zoneArg(args))}` }), (result, args) => (args["raw"] === true ? result : projectZone(result)))),
|
|
1498
1463
|
// No bulk `list_zone_settings` on purpose (#361): Cloudflare's published
|
|
1499
1464
|
// document marks GET /zones/{zoneId}/settings and its PATCH sibling
|
|
1500
1465
|
// deprecated with no bulk replacement, and the tool projected nothing while
|
|
@@ -1504,26 +1469,11 @@ function buildTools(scope, authentication) {
|
|
|
1504
1469
|
// the caller's risk rather than promised by connecta's catalog.
|
|
1505
1470
|
cfTool("get_zone_setting", "Get one zone setting by its Cloudflare setting id, such as ssl, always_use_https, min_tls_version, brotli, or development_mode.", readOnly, "zoneId", scope.zoneId, {
|
|
1506
1471
|
settingId: SETTING_ID_PROPERTY,
|
|
1507
|
-
raw: RAW_INPUT_PROPERTY
|
|
1472
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1508
1473
|
}, ["settingId"], ZONE_SETTING_SCHEMA, getResult(send, (args) => ({
|
|
1509
1474
|
method: "GET",
|
|
1510
1475
|
path: `/zones/${encodeURIComponent(zoneArg(args))}/settings/${encodeURIComponent(requireString(args, "settingId"))}`,
|
|
1511
|
-
}), (result, args) => args["raw"] === true ? result : projectZoneSetting(result))),
|
|
1512
|
-
cfTool("update_zone_setting", "Set one editable zone setting. Read it first: allowed value types and plan restrictions differ by setting.", { readOnlyHint: false, destructiveHint: true }, "zoneId", scope.zoneId, {
|
|
1513
|
-
settingId: SETTING_ID_PROPERTY,
|
|
1514
|
-
value: {
|
|
1515
|
-
type: ["string", "number", "boolean", "array"],
|
|
1516
|
-
description: "New setting value in the type returned by get_zone_setting. Arrays must contain strings.",
|
|
1517
|
-
items: { type: "string" },
|
|
1518
|
-
}
|
|
1519
|
-
}, ["settingId", "value"], ZONE_SETTING_SCHEMA, async (args, ctx) => {
|
|
1520
|
-
const { result } = await callCloudflare(send, {
|
|
1521
|
-
method: "PATCH",
|
|
1522
|
-
path: `/zones/${encodeURIComponent(zoneArg(args))}/settings/${encodeURIComponent(requireString(args, "settingId"))}`,
|
|
1523
|
-
body: { value: args["value"] },
|
|
1524
|
-
}, ctx);
|
|
1525
|
-
return projectZoneSetting(result);
|
|
1526
|
-
}),
|
|
1476
|
+
}), (result, args) => (args["raw"] === true ? result : projectZoneSetting(result)))),
|
|
1527
1477
|
cfTool("list_zone_rulesets", "List zone rulesets for WAF, redirects, transforms, cache rules, configuration rules, and other Ruleset Engine phases.", readOnly, "zoneId", scope.zoneId, {
|
|
1528
1478
|
perPage: {
|
|
1529
1479
|
type: "integer",
|
|
@@ -1531,7 +1481,7 @@ function buildTools(scope, authentication) {
|
|
|
1531
1481
|
maximum: 50,
|
|
1532
1482
|
description: "Rulesets per request, 1 to 50.",
|
|
1533
1483
|
},
|
|
1534
|
-
cursor: CURSOR_INPUT_PROPERTY
|
|
1484
|
+
cursor: CURSOR_INPUT_PROPERTY,
|
|
1535
1485
|
}, [], {
|
|
1536
1486
|
type: "object",
|
|
1537
1487
|
properties: {
|
|
@@ -1559,7 +1509,7 @@ function buildTools(scope, authentication) {
|
|
|
1559
1509
|
type: "string",
|
|
1560
1510
|
minLength: 1,
|
|
1561
1511
|
description: "Ruleset id from list_zone_rulesets.",
|
|
1562
|
-
}
|
|
1512
|
+
},
|
|
1563
1513
|
}, ["rulesetId"], RULESET_SCHEMA, getResult(send, (args) => ({
|
|
1564
1514
|
method: "GET",
|
|
1565
1515
|
path: `/zones/${encodeURIComponent(zoneArg(args))}/rulesets/${encodeURIComponent(requireString(args, "rulesetId"))}`,
|
|
@@ -1595,7 +1545,7 @@ function buildTools(scope, authentication) {
|
|
|
1595
1545
|
defaultPerPage: 100,
|
|
1596
1546
|
bounds: "clamped",
|
|
1597
1547
|
}),
|
|
1598
|
-
raw: RAW_INPUT_PROPERTY
|
|
1548
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1599
1549
|
}, [], listOutputSchema("records", DNS_RECORD_SCHEMA), async (args, ctx) => {
|
|
1600
1550
|
const { result, resultInfo } = await callCloudflare(send, {
|
|
1601
1551
|
method: "GET",
|
|
@@ -1614,13 +1564,13 @@ function buildTools(scope, authentication) {
|
|
|
1614
1564
|
}),
|
|
1615
1565
|
cfTool("get_dns_record", "Fetch one DNS record by its record id.", readOnly, "zoneId", scope.zoneId, {
|
|
1616
1566
|
recordId: RECORD_ID_PROPERTY,
|
|
1617
|
-
raw: RAW_INPUT_PROPERTY
|
|
1567
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1618
1568
|
}, ["recordId"], DNS_RECORD_SCHEMA, getResult(send, (args) => ({
|
|
1619
1569
|
method: "GET",
|
|
1620
1570
|
path: `/zones/${encodeURIComponent(zoneArg(args))}/dns_records/${encodeURIComponent(String(args["recordId"]))}`,
|
|
1621
|
-
}), (result, args) => args["raw"] === true ? result : projectDnsRecord(result))),
|
|
1571
|
+
}), (result, args) => (args["raw"] === true ? result : projectDnsRecord(result)))),
|
|
1622
1572
|
cfTool("list_worker_scripts", "List Workers scripts deployed in an account, with their last-modified times.", readOnly, "accountId", scope.accountId, {
|
|
1623
|
-
raw: RAW_INPUT_PROPERTY
|
|
1573
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1624
1574
|
}, [], listOutputSchema("scripts", {
|
|
1625
1575
|
type: "object",
|
|
1626
1576
|
properties: {
|
|
@@ -1639,52 +1589,32 @@ function buildTools(scope, authentication) {
|
|
|
1639
1589
|
}),
|
|
1640
1590
|
cfTool("get_worker_settings", "Get a Worker's compatibility date and flags, bindings, limits, observability, placement, usage model, and other script settings.", readOnly, "accountId", scope.accountId, {
|
|
1641
1591
|
scriptName: SCRIPT_NAME_PROPERTY,
|
|
1642
|
-
raw: RAW_INPUT_PROPERTY
|
|
1592
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1643
1593
|
}, ["scriptName"], WORKER_SETTINGS_SCHEMA, getResult(send, (args) => ({
|
|
1644
1594
|
method: "GET",
|
|
1645
1595
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/settings`,
|
|
1646
|
-
}), (result, args) => args["raw"] === true ? result : projectWorkerSettings(result))),
|
|
1596
|
+
}), (result, args) => (args["raw"] === true ? result : projectWorkerSettings(result)))),
|
|
1647
1597
|
cfTool("list_worker_deployments", "List deployments of a Worker script, including version traffic allocations and deployment strategy.", readOnly, "accountId", scope.accountId, {
|
|
1648
|
-
scriptName: SCRIPT_NAME_PROPERTY
|
|
1598
|
+
scriptName: SCRIPT_NAME_PROPERTY,
|
|
1649
1599
|
}, ["scriptName"], listOutputSchema("deployments", WORKER_DEPLOYMENT_SCHEMA), async (args, ctx) => {
|
|
1650
1600
|
const { result } = await callCloudflare(send, {
|
|
1651
1601
|
method: "GET",
|
|
1652
1602
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/deployments`,
|
|
1653
1603
|
}, ctx);
|
|
1654
1604
|
const record = asRecord(result);
|
|
1655
|
-
const deployments = Array.isArray(result)
|
|
1656
|
-
? result
|
|
1657
|
-
: asArray(record["deployments"]);
|
|
1605
|
+
const deployments = Array.isArray(result) ? result : asArray(record["deployments"]);
|
|
1658
1606
|
return { deployments: deployments.map(projectWorkerDeployment) };
|
|
1659
1607
|
}),
|
|
1660
1608
|
cfTool("get_worker_deployment", "Get one Worker deployment and its version traffic allocations.", readOnly, "accountId", scope.accountId, {
|
|
1661
1609
|
scriptName: SCRIPT_NAME_PROPERTY,
|
|
1662
|
-
deploymentId: WORKER_DEPLOYMENT_ID_PROPERTY
|
|
1610
|
+
deploymentId: WORKER_DEPLOYMENT_ID_PROPERTY,
|
|
1663
1611
|
}, ["scriptName", "deploymentId"], WORKER_DEPLOYMENT_SCHEMA, getResult(send, (args) => ({
|
|
1664
1612
|
method: "GET",
|
|
1665
1613
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}`,
|
|
1666
1614
|
}), projectWorkerDeployment)),
|
|
1667
|
-
cfTool("delete_worker_script", "Delete a Worker script and stop traffic served by that script. This cannot be undone from the API.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1668
|
-
scriptName: SCRIPT_NAME_PROPERTY,
|
|
1669
|
-
force: {
|
|
1670
|
-
type: "boolean",
|
|
1671
|
-
description: "Pass Cloudflare's force=true option when the script has dependencies that permit forced removal.",
|
|
1672
|
-
}
|
|
1673
|
-
}, ["scriptName"], {
|
|
1674
|
-
type: "object",
|
|
1675
|
-
properties: {
|
|
1676
|
-
deleted: { type: "boolean" },
|
|
1677
|
-
scriptName: { type: "string" },
|
|
1678
|
-
},
|
|
1679
|
-
required: ["deleted", "scriptName"],
|
|
1680
|
-
}, deleteAck(send, "scriptName", (args) => requireString(args, "scriptName"), (args, scriptName) => ({
|
|
1681
|
-
method: "DELETE",
|
|
1682
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(scriptName)}`,
|
|
1683
|
-
query: { force: typeof args["force"] === "boolean" ? args["force"] : undefined },
|
|
1684
|
-
}))),
|
|
1685
1615
|
cfTool("list_kv_namespaces", "List Workers KV namespaces in an account, with the namespace ids bindings refer to.", readOnly, "accountId", scope.accountId, {
|
|
1686
1616
|
...pagingInputProperties(1, 1000, { defaultPerPage: 20 }),
|
|
1687
|
-
raw: RAW_INPUT_PROPERTY
|
|
1617
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1688
1618
|
}, [], listOutputSchema("namespaces", {
|
|
1689
1619
|
type: "object",
|
|
1690
1620
|
properties: {
|
|
@@ -1706,61 +1636,11 @@ function buildTools(scope, authentication) {
|
|
|
1706
1636
|
return pagedList("namespaces", projectKvNamespace)(result, resultInfo, args["raw"] === true);
|
|
1707
1637
|
}),
|
|
1708
1638
|
cfTool("get_kv_namespace", "Get one Workers KV namespace by id.", readOnly, "accountId", scope.accountId, {
|
|
1709
|
-
namespaceId: NAMESPACE_ID_PROPERTY
|
|
1639
|
+
namespaceId: NAMESPACE_ID_PROPERTY,
|
|
1710
1640
|
}, ["namespaceId"], KV_NAMESPACE_SCHEMA, getResult(send, (args) => ({
|
|
1711
1641
|
method: "GET",
|
|
1712
1642
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}`,
|
|
1713
1643
|
}), projectKvNamespace)),
|
|
1714
|
-
cfTool("create_kv_namespace", "Create a Workers KV namespace.", { readOnlyHint: false }, "accountId", scope.accountId, {
|
|
1715
|
-
title: {
|
|
1716
|
-
type: "string",
|
|
1717
|
-
minLength: 1,
|
|
1718
|
-
maxLength: 512,
|
|
1719
|
-
description: "Human-readable namespace title.",
|
|
1720
|
-
},
|
|
1721
|
-
jurisdiction: KV_JURISDICTION_PROPERTY
|
|
1722
|
-
}, ["title"], KV_NAMESPACE_SCHEMA, async (args, ctx) => {
|
|
1723
|
-
const { result } = await callCloudflare(send, {
|
|
1724
|
-
method: "POST",
|
|
1725
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces`,
|
|
1726
|
-
body: compact({
|
|
1727
|
-
title: requireString(args, "title"),
|
|
1728
|
-
jurisdiction: args["jurisdiction"],
|
|
1729
|
-
}),
|
|
1730
|
-
}, ctx);
|
|
1731
|
-
return projectKvNamespace(result);
|
|
1732
|
-
}),
|
|
1733
|
-
cfTool("rename_kv_namespace", "Rename an existing Workers KV namespace without changing its id or keys.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1734
|
-
namespaceId: NAMESPACE_ID_PROPERTY,
|
|
1735
|
-
title: {
|
|
1736
|
-
type: "string",
|
|
1737
|
-
minLength: 1,
|
|
1738
|
-
maxLength: 512,
|
|
1739
|
-
description: "Replacement namespace title.",
|
|
1740
|
-
}
|
|
1741
|
-
}, ["namespaceId", "title"], KV_NAMESPACE_SCHEMA, async (args, ctx) => {
|
|
1742
|
-
const { result } = await callCloudflare(send, {
|
|
1743
|
-
method: "PUT",
|
|
1744
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}`,
|
|
1745
|
-
body: { title: requireString(args, "title") },
|
|
1746
|
-
}, ctx);
|
|
1747
|
-
return result
|
|
1748
|
-
? projectKvNamespace(result)
|
|
1749
|
-
: { renamed: true, namespaceId: args["namespaceId"] };
|
|
1750
|
-
}),
|
|
1751
|
-
cfTool("delete_kv_namespace", "Permanently delete a Workers KV namespace and every key stored in it.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1752
|
-
namespaceId: NAMESPACE_ID_PROPERTY
|
|
1753
|
-
}, ["namespaceId"], {
|
|
1754
|
-
type: "object",
|
|
1755
|
-
properties: {
|
|
1756
|
-
deleted: { type: "boolean" },
|
|
1757
|
-
namespaceId: { type: "string" },
|
|
1758
|
-
},
|
|
1759
|
-
required: ["deleted", "namespaceId"],
|
|
1760
|
-
}, deleteAck(send, "namespaceId", (args) => requireString(args, "namespaceId"), (args, namespaceId) => ({
|
|
1761
|
-
method: "DELETE",
|
|
1762
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(namespaceId)}`,
|
|
1763
|
-
}))),
|
|
1764
1644
|
cfTool("list_kv_keys", "List keys and metadata in a Workers KV namespace by prefix, using cursor pagination.", readOnly, "accountId", scope.accountId, {
|
|
1765
1645
|
namespaceId: NAMESPACE_ID_PROPERTY,
|
|
1766
1646
|
prefix: {
|
|
@@ -1773,7 +1653,7 @@ function buildTools(scope, authentication) {
|
|
|
1773
1653
|
maximum: 1000,
|
|
1774
1654
|
description: "Keys per request, 10 to 1000. Defaults to 1000.",
|
|
1775
1655
|
},
|
|
1776
|
-
cursor: CURSOR_INPUT_PROPERTY
|
|
1656
|
+
cursor: CURSOR_INPUT_PROPERTY,
|
|
1777
1657
|
}, ["namespaceId"], {
|
|
1778
1658
|
type: "object",
|
|
1779
1659
|
properties: {
|
|
@@ -1825,7 +1705,7 @@ function buildTools(scope, authentication) {
|
|
|
1825
1705
|
type: "string",
|
|
1826
1706
|
enum: ["text", "json"],
|
|
1827
1707
|
description: "Return strings as stored, or parse JSON values before returning them.",
|
|
1828
|
-
}
|
|
1708
|
+
},
|
|
1829
1709
|
}, ["namespaceId", "keys"], KV_BULK_VALUES_SCHEMA, async (args, ctx) => {
|
|
1830
1710
|
const { result } = await callCloudflare(send, {
|
|
1831
1711
|
method: "POST",
|
|
@@ -1838,74 +1718,6 @@ function buildTools(scope, authentication) {
|
|
|
1838
1718
|
}, ctx);
|
|
1839
1719
|
return projectKvBulkValues(result);
|
|
1840
1720
|
}),
|
|
1841
|
-
cfTool("bulk_write_kv_values", "Create or replace multiple Workers KV values, with optional expirations and JSON metadata.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1842
|
-
namespaceId: NAMESPACE_ID_PROPERTY,
|
|
1843
|
-
entries: {
|
|
1844
|
-
type: "array",
|
|
1845
|
-
minItems: 1,
|
|
1846
|
-
maxItems: 10_000,
|
|
1847
|
-
description: "Key/value entries to write, up to Cloudflare's 10,000-key bulk limit.",
|
|
1848
|
-
items: {
|
|
1849
|
-
type: "object",
|
|
1850
|
-
properties: {
|
|
1851
|
-
key: {
|
|
1852
|
-
type: "string",
|
|
1853
|
-
minLength: 1,
|
|
1854
|
-
maxLength: 512,
|
|
1855
|
-
description: "Key name, up to Cloudflare's 512 bytes.",
|
|
1856
|
-
},
|
|
1857
|
-
value: {
|
|
1858
|
-
type: "string",
|
|
1859
|
-
maxLength: 26_214_400,
|
|
1860
|
-
description: "Value, up to Cloudflare's 25 MiB.",
|
|
1861
|
-
},
|
|
1862
|
-
expiration: {
|
|
1863
|
-
type: "number",
|
|
1864
|
-
description: "Absolute expiry as a Unix timestamp in seconds.",
|
|
1865
|
-
},
|
|
1866
|
-
expiration_ttl: {
|
|
1867
|
-
type: "number",
|
|
1868
|
-
minimum: 60,
|
|
1869
|
-
description: "Relative expiry in seconds; Cloudflare's floor is 60.",
|
|
1870
|
-
},
|
|
1871
|
-
metadata: {
|
|
1872
|
-
type: ["object", "array", "string", "number", "boolean", "null"],
|
|
1873
|
-
description: "JSON metadata returned beside the key by list_kv_keys.",
|
|
1874
|
-
},
|
|
1875
|
-
base64: {
|
|
1876
|
-
type: "boolean",
|
|
1877
|
-
description: "Treat value as base64 and store the decoded bytes.",
|
|
1878
|
-
},
|
|
1879
|
-
},
|
|
1880
|
-
required: ["key", "value"],
|
|
1881
|
-
additionalProperties: false,
|
|
1882
|
-
},
|
|
1883
|
-
}
|
|
1884
|
-
}, ["namespaceId", "entries"], KV_BULK_RESULT_SCHEMA, async (args, ctx) => {
|
|
1885
|
-
const { result } = await callCloudflare(send, {
|
|
1886
|
-
method: "PUT",
|
|
1887
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}/bulk`,
|
|
1888
|
-
body: args["entries"],
|
|
1889
|
-
}, ctx);
|
|
1890
|
-
return projectKvBulkResult(result);
|
|
1891
|
-
}),
|
|
1892
|
-
cfTool("bulk_delete_kv_values", "Permanently delete multiple keys from a Workers KV namespace.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1893
|
-
namespaceId: NAMESPACE_ID_PROPERTY,
|
|
1894
|
-
keys: {
|
|
1895
|
-
type: "array",
|
|
1896
|
-
minItems: 1,
|
|
1897
|
-
maxItems: 10_000,
|
|
1898
|
-
items: { type: "string", minLength: 1, maxLength: 512 },
|
|
1899
|
-
description: "Key names to delete, up to Cloudflare's 10,000-key bulk limit.",
|
|
1900
|
-
}
|
|
1901
|
-
}, ["namespaceId", "keys"], KV_BULK_RESULT_SCHEMA, async (args, ctx) => {
|
|
1902
|
-
const { result } = await callCloudflare(send, {
|
|
1903
|
-
method: "POST",
|
|
1904
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}/bulk/delete`,
|
|
1905
|
-
body: args["keys"],
|
|
1906
|
-
}, ctx);
|
|
1907
|
-
return projectKvBulkResult(result);
|
|
1908
|
-
}),
|
|
1909
1721
|
cfTool("list_r2_buckets", "List R2 buckets in an account, with location and storage class.", readOnly, "accountId", scope.accountId, {
|
|
1910
1722
|
nameContains: {
|
|
1911
1723
|
type: "string",
|
|
@@ -1919,7 +1731,7 @@ function buildTools(scope, authentication) {
|
|
|
1919
1731
|
},
|
|
1920
1732
|
cursor: CURSOR_INPUT_PROPERTY,
|
|
1921
1733
|
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
1922
|
-
raw: RAW_INPUT_PROPERTY
|
|
1734
|
+
raw: RAW_INPUT_PROPERTY,
|
|
1923
1735
|
}, [], {
|
|
1924
1736
|
type: "object",
|
|
1925
1737
|
properties: {
|
|
@@ -1954,72 +1766,12 @@ function buildTools(scope, authentication) {
|
|
|
1954
1766
|
}),
|
|
1955
1767
|
cfTool("get_r2_bucket", "Get one R2 bucket's location, jurisdiction, storage class, and creation time.", readOnly, "accountId", scope.accountId, {
|
|
1956
1768
|
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
1957
|
-
jurisdiction: R2_JURISDICTION_PROPERTY
|
|
1769
|
+
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
1958
1770
|
}, ["bucketName"], R2_BUCKET_SCHEMA, getResult(send, (args) => ({
|
|
1959
1771
|
method: "GET",
|
|
1960
1772
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(requireString(args, "bucketName"))}`,
|
|
1961
1773
|
headers: r2Headers(args),
|
|
1962
1774
|
}), projectR2Bucket)),
|
|
1963
|
-
cfTool("create_r2_bucket", "Create an R2 bucket with an optional location hint and default storage class.", { readOnlyHint: false }, "accountId", scope.accountId, {
|
|
1964
|
-
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
1965
|
-
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
1966
|
-
locationHint: {
|
|
1967
|
-
type: "string",
|
|
1968
|
-
enum: ["apac", "eeur", "enam", "weur", "wnam", "oc"],
|
|
1969
|
-
description: "Optional placement hint for the new bucket.",
|
|
1970
|
-
},
|
|
1971
|
-
storageClass: {
|
|
1972
|
-
type: "string",
|
|
1973
|
-
enum: ["Standard", "InfrequentAccess"],
|
|
1974
|
-
description: "Default storage class for new objects.",
|
|
1975
|
-
}
|
|
1976
|
-
}, ["bucketName"], R2_BUCKET_SCHEMA, async (args, ctx) => {
|
|
1977
|
-
const { result } = await callCloudflare(send, {
|
|
1978
|
-
method: "POST",
|
|
1979
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets`,
|
|
1980
|
-
headers: r2Headers(args),
|
|
1981
|
-
body: compact({
|
|
1982
|
-
name: requireString(args, "bucketName"),
|
|
1983
|
-
locationHint: args["locationHint"],
|
|
1984
|
-
storageClass: args["storageClass"],
|
|
1985
|
-
}),
|
|
1986
|
-
}, ctx);
|
|
1987
|
-
return projectR2Bucket(result);
|
|
1988
|
-
}),
|
|
1989
|
-
cfTool("update_r2_bucket", "Change the default storage class used for newly uploaded objects in an R2 bucket.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
1990
|
-
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
1991
|
-
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
1992
|
-
storageClass: {
|
|
1993
|
-
type: "string",
|
|
1994
|
-
enum: ["Standard", "InfrequentAccess"],
|
|
1995
|
-
description: "New default storage class for future uploads.",
|
|
1996
|
-
}
|
|
1997
|
-
}, ["bucketName", "storageClass"], R2_BUCKET_SCHEMA, async (args, ctx) => {
|
|
1998
|
-
const { result } = await callCloudflare(send, {
|
|
1999
|
-
method: "PATCH",
|
|
2000
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(requireString(args, "bucketName"))}`,
|
|
2001
|
-
headers: {
|
|
2002
|
-
...r2Headers(args),
|
|
2003
|
-
"cf-r2-storage-class": String(args["storageClass"]),
|
|
2004
|
-
},
|
|
2005
|
-
}, ctx);
|
|
2006
|
-
return projectR2Bucket(result);
|
|
2007
|
-
}),
|
|
2008
|
-
cfTool("delete_r2_bucket", "Permanently delete an empty R2 bucket and all of its configuration. Cloudflare refuses non-empty buckets.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2009
|
-
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
2010
|
-
jurisdiction: R2_JURISDICTION_PROPERTY
|
|
2011
|
-
}, ["bucketName"], {
|
|
2012
|
-
type: "object",
|
|
2013
|
-
properties: {
|
|
2014
|
-
deleted: { type: "boolean" },
|
|
2015
|
-
bucketName: { type: "string" },
|
|
2016
|
-
},
|
|
2017
|
-
required: ["deleted", "bucketName"],
|
|
2018
|
-
}, deleteAck(send, "bucketName", (args) => requireString(args, "bucketName"), (args, bucketName) => ({
|
|
2019
|
-
method: "DELETE",
|
|
2020
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(bucketName)}`,
|
|
2021
|
-
headers: r2Headers(args),
|
|
2022
|
-
}))),
|
|
2023
1775
|
cfTool("list_r2_objects", "List object keys and metadata in an R2 bucket by prefix, with delimiter grouping and cursor pagination.", readOnly, "accountId", scope.accountId, {
|
|
2024
1776
|
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
2025
1777
|
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
@@ -2043,7 +1795,7 @@ function buildTools(scope, authentication) {
|
|
|
2043
1795
|
maximum: 1000,
|
|
2044
1796
|
description: "Objects per request, 1 to 1000.",
|
|
2045
1797
|
},
|
|
2046
|
-
cursor: CURSOR_INPUT_PROPERTY
|
|
1798
|
+
cursor: CURSOR_INPUT_PROPERTY,
|
|
2047
1799
|
}, ["bucketName"], {
|
|
2048
1800
|
type: "object",
|
|
2049
1801
|
properties: {
|
|
@@ -2069,33 +1821,11 @@ function buildTools(scope, authentication) {
|
|
|
2069
1821
|
const cursor = resultInfo?.cursor;
|
|
2070
1822
|
return {
|
|
2071
1823
|
objects: asArray(result).map(projectR2Object),
|
|
2072
|
-
...(Array.isArray(resultInfo?.delimited)
|
|
2073
|
-
? { commonPrefixes: resultInfo.delimited }
|
|
2074
|
-
: {}),
|
|
1824
|
+
...(Array.isArray(resultInfo?.delimited) ? { commonPrefixes: resultInfo.delimited } : {}),
|
|
2075
1825
|
...cursorResult(cursor),
|
|
2076
1826
|
truncated: resultInfo?.is_truncated === true,
|
|
2077
1827
|
};
|
|
2078
1828
|
}),
|
|
2079
|
-
cfTool("delete_r2_object", "Permanently delete one object from an R2 bucket by key.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2080
|
-
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
2081
|
-
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
2082
|
-
objectKey: {
|
|
2083
|
-
type: "string",
|
|
2084
|
-
minLength: 1,
|
|
2085
|
-
description: "Exact object key. Slashes are preserved as path separators.",
|
|
2086
|
-
}
|
|
2087
|
-
}, ["bucketName", "objectKey"], {
|
|
2088
|
-
type: "object",
|
|
2089
|
-
properties: {
|
|
2090
|
-
deleted: { type: "boolean" },
|
|
2091
|
-
objectKey: { type: "string" },
|
|
2092
|
-
},
|
|
2093
|
-
required: ["deleted", "objectKey"],
|
|
2094
|
-
}, deleteAck(send, "objectKey", (args) => requireString(args, "objectKey"), (args, objectKey) => ({
|
|
2095
|
-
method: "DELETE",
|
|
2096
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(requireString(args, "bucketName"))}/objects/${encodeObjectKey(objectKey)}`,
|
|
2097
|
-
headers: r2Headers(args),
|
|
2098
|
-
}))),
|
|
2099
1829
|
// No `get_r2_metrics`, `set_r2_cors`, or `delete_r2_cors` on purpose (#350).
|
|
2100
1830
|
// A named tool is a permanent line item in every deployment's catalog, and
|
|
2101
1831
|
// these lost the comparison against the escape hatches: `get_r2_metrics`
|
|
@@ -2110,7 +1840,7 @@ function buildTools(scope, authentication) {
|
|
|
2110
1840
|
// PUT/DELETE /accounts/{accountId}/r2/buckets/{bucketName}/cors.
|
|
2111
1841
|
cfTool("get_r2_cors", "Get the browser CORS rules configured on an R2 bucket.", readOnly, "accountId", scope.accountId, {
|
|
2112
1842
|
bucketName: R2_BUCKET_NAME_PROPERTY,
|
|
2113
|
-
jurisdiction: R2_JURISDICTION_PROPERTY
|
|
1843
|
+
jurisdiction: R2_JURISDICTION_PROPERTY,
|
|
2114
1844
|
}, ["bucketName"], R2_CORS_SCHEMA, getResult(send, (args) => ({
|
|
2115
1845
|
method: "GET",
|
|
2116
1846
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(requireString(args, "bucketName"))}/cors`,
|
|
@@ -2118,7 +1848,7 @@ function buildTools(scope, authentication) {
|
|
|
2118
1848
|
}), projectR2Cors)),
|
|
2119
1849
|
cfTool("list_pages_projects", "List Cloudflare Pages projects in an account, with their production branch and latest deployment.", readOnly, "accountId", scope.accountId, {
|
|
2120
1850
|
...pagingInputProperties(1, 100, { bounds: "undocumented" }),
|
|
2121
|
-
raw: RAW_INPUT_PROPERTY
|
|
1851
|
+
raw: RAW_INPUT_PROPERTY,
|
|
2122
1852
|
}, [], listOutputSchema("projects", PAGES_PROJECT_SCHEMA), async (args, ctx) => {
|
|
2123
1853
|
const { result, resultInfo } = await callCloudflare(send, {
|
|
2124
1854
|
method: "GET",
|
|
@@ -2132,11 +1862,11 @@ function buildTools(scope, authentication) {
|
|
|
2132
1862
|
}),
|
|
2133
1863
|
cfTool("get_pages_project", "Get one Pages project, including build configuration, deployment configuration, domains, and latest deployment.", readOnly, "accountId", scope.accountId, {
|
|
2134
1864
|
projectName: PROJECT_NAME_PROPERTY,
|
|
2135
|
-
raw: RAW_INPUT_PROPERTY
|
|
1865
|
+
raw: RAW_INPUT_PROPERTY,
|
|
2136
1866
|
}, ["projectName"], PAGES_PROJECT_SCHEMA, getResult(send, (args) => ({
|
|
2137
1867
|
method: "GET",
|
|
2138
1868
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}`,
|
|
2139
|
-
}), (result, args) => args["raw"] === true ? result : projectPagesProject(result))),
|
|
1869
|
+
}), (result, args) => (args["raw"] === true ? result : projectPagesProject(result)))),
|
|
2140
1870
|
cfTool("list_pages_deployments", "List production and preview deployments for a Pages project.", readOnly, "accountId", scope.accountId, {
|
|
2141
1871
|
projectName: PROJECT_NAME_PROPERTY,
|
|
2142
1872
|
env: {
|
|
@@ -2144,7 +1874,7 @@ function buildTools(scope, authentication) {
|
|
|
2144
1874
|
enum: ["production", "preview"],
|
|
2145
1875
|
description: "Optional deployment environment filter.",
|
|
2146
1876
|
},
|
|
2147
|
-
...pagingInputProperties(1, 100, { bounds: "undocumented" })
|
|
1877
|
+
...pagingInputProperties(1, 100, { bounds: "undocumented" }),
|
|
2148
1878
|
}, ["projectName"], listOutputSchema("deployments", PAGES_DEPLOYMENT_SCHEMA), async (args, ctx) => {
|
|
2149
1879
|
const { result, resultInfo } = await callCloudflare(send, {
|
|
2150
1880
|
method: "GET",
|
|
@@ -2163,40 +1893,13 @@ function buildTools(scope, authentication) {
|
|
|
2163
1893
|
cfTool("get_pages_deployment", "Get one Pages deployment including its environment, URLs, stages, source, and build configuration.", readOnly, "accountId", scope.accountId, {
|
|
2164
1894
|
projectName: PROJECT_NAME_PROPERTY,
|
|
2165
1895
|
deploymentId: DEPLOYMENT_ID_PROPERTY,
|
|
2166
|
-
raw: RAW_INPUT_PROPERTY
|
|
1896
|
+
raw: RAW_INPUT_PROPERTY,
|
|
2167
1897
|
}, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, getResult(send, (args) => ({
|
|
2168
1898
|
method: "GET",
|
|
2169
1899
|
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}`,
|
|
2170
|
-
}), (result, args) => args["raw"] === true ? result : projectPagesDeployment(result))),
|
|
2171
|
-
cfTool("retry_pages_deployment", "Retry a failed or cancelled Pages deployment using its existing source and build configuration.", { readOnlyHint: false }, "accountId", scope.accountId, {
|
|
2172
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2173
|
-
deploymentId: RETRY_DEPLOYMENT_ID_PROPERTY
|
|
2174
|
-
}, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, async (args, ctx) => {
|
|
2175
|
-
const { result } = await callCloudflare(send, {
|
|
2176
|
-
method: "POST",
|
|
2177
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}/retry`,
|
|
2178
|
-
}, ctx);
|
|
2179
|
-
return projectPagesDeployment(result);
|
|
2180
|
-
}),
|
|
2181
|
-
cfTool("rollback_pages_deployment", "Promote a previous Pages deployment to production, replacing the currently served production deployment.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2182
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2183
|
-
deploymentId: ROLLBACK_DEPLOYMENT_ID_PROPERTY
|
|
2184
|
-
}, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, async (args, ctx) => {
|
|
2185
|
-
const { result } = await callCloudflare(send, {
|
|
2186
|
-
method: "POST",
|
|
2187
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}/rollback`,
|
|
2188
|
-
}, ctx);
|
|
2189
|
-
return projectPagesDeployment(result);
|
|
2190
|
-
}),
|
|
2191
|
-
cfTool("delete_pages_deployment", "Permanently delete a Pages deployment and its immutable deployment URL.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2192
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2193
|
-
deploymentId: DELETE_DEPLOYMENT_ID_PROPERTY
|
|
2194
|
-
}, ["projectName", "deploymentId"], { type: "object", properties: { deleted: { type: "boolean" }, deploymentId: { type: "string" } }, required: ["deleted", "deploymentId"] }, deleteAck(send, "deploymentId", (args) => requireString(args, "deploymentId"), (args, deploymentId) => ({
|
|
2195
|
-
method: "DELETE",
|
|
2196
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(deploymentId)}`,
|
|
2197
|
-
}))),
|
|
1900
|
+
}), (result, args) => (args["raw"] === true ? result : projectPagesDeployment(result)))),
|
|
2198
1901
|
cfTool("list_pages_domains", "List custom domains attached to a Pages project and their validation status.", readOnly, "accountId", scope.accountId, {
|
|
2199
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY
|
|
1902
|
+
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2200
1903
|
}, ["projectName"], listOutputSchema("domains", PAGES_DOMAIN_SCHEMA), async (args, ctx) => {
|
|
2201
1904
|
const { result } = await callCloudflare(send, {
|
|
2202
1905
|
method: "GET",
|
|
@@ -2204,275 +1907,6 @@ function buildTools(scope, authentication) {
|
|
|
2204
1907
|
}, ctx);
|
|
2205
1908
|
return { domains: asArray(result).map(projectPagesDomain) };
|
|
2206
1909
|
}),
|
|
2207
|
-
cfTool("add_pages_domain", "Attach a custom domain to a Pages project. DNS ownership and validation still apply.", { readOnlyHint: false }, "accountId", scope.accountId, {
|
|
2208
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2209
|
-
domain: { type: "string", minLength: 1, description: "Fully qualified custom domain to attach." }
|
|
2210
|
-
}, ["projectName", "domain"], PAGES_DOMAIN_SCHEMA, async (args, ctx) => {
|
|
2211
|
-
const { result } = await callCloudflare(send, {
|
|
2212
|
-
method: "POST",
|
|
2213
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/domains`,
|
|
2214
|
-
body: { name: requireString(args, "domain") },
|
|
2215
|
-
}, ctx);
|
|
2216
|
-
return projectPagesDomain(result);
|
|
2217
|
-
}),
|
|
2218
|
-
cfTool("delete_pages_domain", "Detach a custom domain from a Pages project.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2219
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY,
|
|
2220
|
-
domain: { type: "string", minLength: 1, description: "Custom domain to detach." }
|
|
2221
|
-
}, ["projectName", "domain"], { type: "object", properties: { deleted: { type: "boolean" }, domain: { type: "string" } }, required: ["deleted", "domain"] }, deleteAck(send, "domain", (args) => requireString(args, "domain"), (args, domain) => ({
|
|
2222
|
-
method: "DELETE",
|
|
2223
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/domains/${encodeURIComponent(domain)}`,
|
|
2224
|
-
}))),
|
|
2225
|
-
cfTool("purge_pages_build_cache", "Clear a Pages project's build cache so its next deployment rebuilds dependencies and artifacts from scratch.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2226
|
-
projectName: PAGES_PROJECT_NAME_PROPERTY
|
|
2227
|
-
}, ["projectName"], { type: "object", properties: { purged: { type: "boolean" } }, required: ["purged"] }, async (args, ctx) => {
|
|
2228
|
-
await callCloudflare(send, {
|
|
2229
|
-
method: "POST",
|
|
2230
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/purge_build_cache`,
|
|
2231
|
-
}, ctx);
|
|
2232
|
-
return { purged: true };
|
|
2233
|
-
}),
|
|
2234
|
-
cfTool("delete_pages_project", "Permanently delete a Pages project, its deployments, and project configuration.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
|
|
2235
|
-
projectName: DELETE_PROJECT_NAME_PROPERTY
|
|
2236
|
-
}, ["projectName"], { type: "object", properties: { deleted: { type: "boolean" }, projectName: { type: "string" } }, required: ["deleted", "projectName"] }, deleteAck(send, "projectName", (args) => requireString(args, "projectName"), (args, projectName) => ({
|
|
2237
|
-
method: "DELETE",
|
|
2238
|
-
path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(projectName)}`,
|
|
2239
|
-
}))),
|
|
2240
|
-
cfTool(
|
|
2241
|
-
// Additive: brings a record into being and destroys nothing, so
|
|
2242
|
-
// `destructiveHint` stays unset. `readOnlyHint: false` already routes it
|
|
2243
|
-
// through call_destructive_tool.
|
|
2244
|
-
"create_dns_record", "Create a content-based DNS record in a zone; the type enum lists the creatable types. Check list_dns_records first — Cloudflare rejects a duplicate rather than replacing it. Structured types like SRV and CAA are readable but not creatable.", { readOnlyHint: false }, "zoneId", scope.zoneId, {
|
|
2245
|
-
type: {
|
|
2246
|
-
type: "string",
|
|
2247
|
-
enum: [...CLOUDFLARE_CONTENT_DNS_RECORD_TYPES],
|
|
2248
|
-
description: "Record type.",
|
|
2249
|
-
},
|
|
2250
|
-
name: {
|
|
2251
|
-
type: "string",
|
|
2252
|
-
description: "Record name. Use the apex domain for the root, or a fully qualified subdomain, e.g. www.example.com.",
|
|
2253
|
-
},
|
|
2254
|
-
content: {
|
|
2255
|
-
type: "string",
|
|
2256
|
-
description: "Record value: an IPv4 address for A, IPv6 for AAAA, a hostname for CNAME/MX/NS, or the text body for TXT.",
|
|
2257
|
-
},
|
|
2258
|
-
ttl: {
|
|
2259
|
-
type: "integer",
|
|
2260
|
-
minimum: 1,
|
|
2261
|
-
maximum: 86400,
|
|
2262
|
-
description: "Time to live in seconds. 1 means automatic, which is what a proxied record must use; any other value must be at least 60 (30 on Enterprise zones). Defaults to 1.",
|
|
2263
|
-
},
|
|
2264
|
-
proxied: {
|
|
2265
|
-
type: "boolean",
|
|
2266
|
-
description: "Route through Cloudflare's proxy. Only A, AAAA, and CNAME records are proxiable. Defaults to false.",
|
|
2267
|
-
},
|
|
2268
|
-
priority: {
|
|
2269
|
-
type: "integer",
|
|
2270
|
-
minimum: 0,
|
|
2271
|
-
maximum: 65535,
|
|
2272
|
-
description: "Mail-server preference. MX records only.",
|
|
2273
|
-
},
|
|
2274
|
-
comment: {
|
|
2275
|
-
type: "string",
|
|
2276
|
-
description: "Operator-facing note stored with the record.",
|
|
2277
|
-
},
|
|
2278
|
-
tags: {
|
|
2279
|
-
type: "array",
|
|
2280
|
-
items: { type: "string" },
|
|
2281
|
-
description: "Custom tags, available on paid plans.",
|
|
2282
|
-
}
|
|
2283
|
-
}, ["type", "name", "content"], DNS_RECORD_SCHEMA, async (args, ctx) => {
|
|
2284
|
-
const { result } = await callCloudflare(send, {
|
|
2285
|
-
method: "POST",
|
|
2286
|
-
path: `/zones/${encodeURIComponent(zoneArg(args))}/dns_records`,
|
|
2287
|
-
body: compact({
|
|
2288
|
-
type: args["type"],
|
|
2289
|
-
name: args["name"],
|
|
2290
|
-
content: args["content"],
|
|
2291
|
-
ttl: optionalNumber(args, "ttl") ?? 1,
|
|
2292
|
-
proxied: args["proxied"],
|
|
2293
|
-
priority: args["priority"],
|
|
2294
|
-
comment: args["comment"],
|
|
2295
|
-
tags: args["tags"],
|
|
2296
|
-
}),
|
|
2297
|
-
}, ctx);
|
|
2298
|
-
return projectDnsRecord(result);
|
|
2299
|
-
}),
|
|
2300
|
-
cfTool(
|
|
2301
|
-
// Destructive: it overwrites what a record already resolves to.
|
|
2302
|
-
"update_dns_record", "Update fields on an existing DNS record. Only the supplied fields change; everything else keeps its current value. Changing content on a live record repoints traffic immediately.", { readOnlyHint: false, destructiveHint: true }, "zoneId", scope.zoneId, {
|
|
2303
|
-
recordId: RECORD_ID_PROPERTY,
|
|
2304
|
-
type: {
|
|
2305
|
-
type: "string",
|
|
2306
|
-
enum: [...CLOUDFLARE_CONTENT_DNS_RECORD_TYPES],
|
|
2307
|
-
description: "Record type. Send it whenever content changes; Cloudflare treats type and content as a pair.",
|
|
2308
|
-
},
|
|
2309
|
-
name: { type: "string", description: "Fully qualified record name." },
|
|
2310
|
-
content: { type: "string", description: "New record value." },
|
|
2311
|
-
ttl: {
|
|
2312
|
-
type: "integer",
|
|
2313
|
-
minimum: 1,
|
|
2314
|
-
maximum: 86400,
|
|
2315
|
-
description: "Seconds; 1 means automatic, otherwise at least 60 (30 on Enterprise zones).",
|
|
2316
|
-
},
|
|
2317
|
-
proxied: {
|
|
2318
|
-
type: "boolean",
|
|
2319
|
-
description: "Route through Cloudflare's proxy. Only A, AAAA, and CNAME records are proxiable, and a proxied record must use ttl 1.",
|
|
2320
|
-
},
|
|
2321
|
-
priority: {
|
|
2322
|
-
type: "integer",
|
|
2323
|
-
minimum: 0,
|
|
2324
|
-
maximum: 65535,
|
|
2325
|
-
description: "Mail-server preference. MX records only.",
|
|
2326
|
-
},
|
|
2327
|
-
comment: {
|
|
2328
|
-
type: "string",
|
|
2329
|
-
description: "Operator-facing note stored with the record. Replaces the existing note.",
|
|
2330
|
-
},
|
|
2331
|
-
tags: {
|
|
2332
|
-
type: "array",
|
|
2333
|
-
items: { type: "string" },
|
|
2334
|
-
description: "Custom tags, available on paid plans. Replaces the existing tag set rather than adding to it.",
|
|
2335
|
-
}
|
|
2336
|
-
}, ["recordId"], DNS_RECORD_SCHEMA, async (args, ctx) => {
|
|
2337
|
-
const body = {};
|
|
2338
|
-
for (const key of [
|
|
2339
|
-
"type",
|
|
2340
|
-
"name",
|
|
2341
|
-
"content",
|
|
2342
|
-
"ttl",
|
|
2343
|
-
"proxied",
|
|
2344
|
-
"priority",
|
|
2345
|
-
"comment",
|
|
2346
|
-
"tags",
|
|
2347
|
-
]) {
|
|
2348
|
-
if (args[key] !== undefined)
|
|
2349
|
-
body[key] = args[key];
|
|
2350
|
-
}
|
|
2351
|
-
if (Object.keys(body).length === 0) {
|
|
2352
|
-
throw new ConnectorCallError("invalid_args", "update_dns_record needs at least one field to change besides zoneId and recordId.", {
|
|
2353
|
-
validation: {
|
|
2354
|
-
issues: [
|
|
2355
|
-
{
|
|
2356
|
-
path: "/",
|
|
2357
|
-
code: "anyOf",
|
|
2358
|
-
expected: "at least one of type, name, content, ttl, proxied, priority, comment, tags",
|
|
2359
|
-
},
|
|
2360
|
-
],
|
|
2361
|
-
},
|
|
2362
|
-
});
|
|
2363
|
-
}
|
|
2364
|
-
const { result } = await callCloudflare(send, {
|
|
2365
|
-
method: "PATCH",
|
|
2366
|
-
path: `/zones/${encodeURIComponent(zoneArg(args))}/dns_records/${encodeURIComponent(String(args["recordId"]))}`,
|
|
2367
|
-
body,
|
|
2368
|
-
}, ctx);
|
|
2369
|
-
return projectDnsRecord(result);
|
|
2370
|
-
}),
|
|
2371
|
-
cfTool("delete_dns_record", "Delete a DNS record by id. The record stops resolving immediately and Cloudflare keeps no undo.", { readOnlyHint: false, destructiveHint: true }, "zoneId", scope.zoneId, {
|
|
2372
|
-
recordId: RECORD_ID_PROPERTY
|
|
2373
|
-
}, ["recordId"], {
|
|
2374
|
-
type: "object",
|
|
2375
|
-
properties: {
|
|
2376
|
-
deleted: { type: "boolean" },
|
|
2377
|
-
recordId: { type: "string" },
|
|
2378
|
-
},
|
|
2379
|
-
required: ["deleted", "recordId"],
|
|
2380
|
-
}, deleteAck(send, "recordId", (args) => String(args["recordId"]), (args, recordId) => ({
|
|
2381
|
-
method: "DELETE",
|
|
2382
|
-
path: `/zones/${encodeURIComponent(zoneArg(args))}/dns_records/${encodeURIComponent(recordId)}`,
|
|
2383
|
-
}))),
|
|
2384
|
-
cfTool("purge_cache", "Purge Cloudflare's edge cache for a zone. Prefer files, tags, hosts, or prefixes; everything discards the entire zone cache and sends every subsequent request to the origin until the cache refills.", { readOnlyHint: false, destructiveHint: true }, "zoneId", scope.zoneId, {
|
|
2385
|
-
everything: {
|
|
2386
|
-
type: "boolean",
|
|
2387
|
-
description: "Purge the entire zone cache. Mutually exclusive with the targeted options below, and a real load event for the origin.",
|
|
2388
|
-
},
|
|
2389
|
-
files: {
|
|
2390
|
-
type: "array",
|
|
2391
|
-
items: { type: "string" },
|
|
2392
|
-
minItems: 1,
|
|
2393
|
-
maxItems: 100,
|
|
2394
|
-
description: "Absolute URLs to purge, e.g. https://example.com/style.css. Up to 100 per request (500 on Enterprise).",
|
|
2395
|
-
},
|
|
2396
|
-
tags: {
|
|
2397
|
-
type: "array",
|
|
2398
|
-
items: { type: "string" },
|
|
2399
|
-
minItems: 1,
|
|
2400
|
-
maxItems: 100,
|
|
2401
|
-
description: "Cache-Tag values to purge. Up to 100 per request; available on every plan.",
|
|
2402
|
-
},
|
|
2403
|
-
hosts: {
|
|
2404
|
-
type: "array",
|
|
2405
|
-
items: { type: "string" },
|
|
2406
|
-
minItems: 1,
|
|
2407
|
-
maxItems: 100,
|
|
2408
|
-
description: "Hostnames to purge. Up to 100 per request; available on every plan.",
|
|
2409
|
-
},
|
|
2410
|
-
prefixes: {
|
|
2411
|
-
type: "array",
|
|
2412
|
-
items: { type: "string" },
|
|
2413
|
-
minItems: 1,
|
|
2414
|
-
maxItems: 100,
|
|
2415
|
-
description: "URL prefixes to purge, e.g. example.com/assets. Up to 100 per request; available on every plan.",
|
|
2416
|
-
}
|
|
2417
|
-
}, [], {
|
|
2418
|
-
type: "object",
|
|
2419
|
-
properties: {
|
|
2420
|
-
purged: { type: "boolean" },
|
|
2421
|
-
zoneId: { type: "string" },
|
|
2422
|
-
scope: {
|
|
2423
|
-
type: "string",
|
|
2424
|
-
description: "Which variant ran: everything, files, tags, hosts, or prefixes.",
|
|
2425
|
-
},
|
|
2426
|
-
},
|
|
2427
|
-
required: ["purged", "zoneId", "scope"],
|
|
2428
|
-
}, async (args, ctx) => {
|
|
2429
|
-
const zoneId = zoneArg(args);
|
|
2430
|
-
const targeted = ["files", "tags", "hosts", "prefixes"].filter((key) => Array.isArray(args[key]) && args[key].length > 0);
|
|
2431
|
-
const everything = args["everything"] === true;
|
|
2432
|
-
// One variant per call is this connection's contract, not a
|
|
2433
|
-
// documented API restriction: Cloudflare's schema models the body as
|
|
2434
|
-
// `anyOf`, which does not forbid combining. Refusing locally gives an
|
|
2435
|
-
// agent `invalid_args` naming the conflict instead of a purge whose
|
|
2436
|
-
// actual scope is ambiguous. Combined purging would be a deliberate
|
|
2437
|
-
// change here.
|
|
2438
|
-
if (everything && targeted.length > 0) {
|
|
2439
|
-
throw new ConnectorCallError("invalid_args", "purge_cache takes either everything: true or one targeted list, never both.", {
|
|
2440
|
-
validation: {
|
|
2441
|
-
issues: [
|
|
2442
|
-
{
|
|
2443
|
-
path: "/everything",
|
|
2444
|
-
code: "oneOf",
|
|
2445
|
-
expected: "everything: true alone, or exactly one of files, tags, hosts, prefixes",
|
|
2446
|
-
},
|
|
2447
|
-
],
|
|
2448
|
-
},
|
|
2449
|
-
});
|
|
2450
|
-
}
|
|
2451
|
-
if (!everything && targeted.length !== 1) {
|
|
2452
|
-
throw new ConnectorCallError("invalid_args", targeted.length === 0
|
|
2453
|
-
? "purge_cache needs everything: true or one of files, tags, hosts, or prefixes."
|
|
2454
|
-
: `purge_cache takes exactly one targeted list; received ${targeted.join(", ")}.`, {
|
|
2455
|
-
validation: {
|
|
2456
|
-
issues: [
|
|
2457
|
-
{
|
|
2458
|
-
path: "/",
|
|
2459
|
-
code: "oneOf",
|
|
2460
|
-
expected: "everything: true, or exactly one of files, tags, hosts, prefixes",
|
|
2461
|
-
},
|
|
2462
|
-
],
|
|
2463
|
-
},
|
|
2464
|
-
});
|
|
2465
|
-
}
|
|
2466
|
-
const variant = everything ? "everything" : targeted[0];
|
|
2467
|
-
await callCloudflare(send, {
|
|
2468
|
-
method: "POST",
|
|
2469
|
-
path: `/zones/${encodeURIComponent(zoneId)}/purge_cache`,
|
|
2470
|
-
body: everything
|
|
2471
|
-
? { purge_everything: true }
|
|
2472
|
-
: { [variant]: args[variant] },
|
|
2473
|
-
}, ctx);
|
|
2474
|
-
return { purged: true, zoneId, scope: variant };
|
|
2475
|
-
}),
|
|
2476
1910
|
];
|
|
2477
1911
|
return tools;
|
|
2478
1912
|
}
|
|
@@ -2485,66 +1919,43 @@ function apiUsageGuide(purpose, scope, instructions, authentication) {
|
|
|
2485
1919
|
? `It defaults to account \`${scope.accountId}\`; omit \`accountId\` unless the request names a different account.`
|
|
2486
1920
|
: "It declares no default account. `list_accounts` supplies the `accountId` the Workers, KV, R2, and Pages tools need.";
|
|
2487
1921
|
const authenticationLine = authentication === "apiToken"
|
|
2488
|
-
? "The API token is operator-managed and scoped by permission. An `auth_required` failure means the token is missing
|
|
2489
|
-
: "The Global API Key and account email are operator-managed. The key has the same access as its Cloudflare user. An `auth_required` failure means one field is missing
|
|
1922
|
+
? "The API token is operator-managed and scoped by permission. An `auth_required` failure means the token is missing or invalid. A `provider_permission_denied` failure asks an administrator to grant resource permission and token scope. Call `verify_api_token` first."
|
|
1923
|
+
: "The Global API Key and account email are operator-managed. The key has the same access as its Cloudflare user. An `auth_required` failure means one field is missing or the pair is invalid. A `provider_permission_denied` failure asks an administrator to grant the user access. Call `verify_global_api_key` first.";
|
|
2490
1924
|
return `# Cloudflare usage
|
|
2491
1925
|
|
|
2492
1926
|
Account purpose: ${purpose}
|
|
2493
1927
|
|
|
2494
1928
|
- ${zoneLine}
|
|
2495
|
-
- ${accountLine}
|
|
2496
|
-
- Prefer a named tool: its schema is complete, projected, and enough to call it without provider documentation. For an operation without a named tool, use \`cloudflare_api_get\` for GET, \`cloudflare_api_mutate\` for JSON POST/PUT/PATCH/DELETE, or \`cloudflare_api_upload\` for raw and multipart content. Raw tools take a path below \`/client/v4\`; their argument schemas are complete, but endpoint-specific query, header, and body fields come from Cloudflare's API reference. Use \`headers\` for endpoint-specific controls such as \`cf-r2-jurisdiction\`, \`Range\`, \`If-None-Match\`, and Cloudflare product metadata. \`Authorization\`, \`Cookie\`, \`Host\`, \`Content-Length\`, \`Content-Type\`, and \`Transfer-Encoding\` are connector-owned and refused: authentication, host, content type, and request framing are not the caller's to set.
|
|
2497
|
-
- The raw tools cover the wider control plane without weakening routing: GET is explicitly read-only; every mutation and upload is destructive and must cross the host's approval boundary. The configured Cloudflare credential remains the hard provider-side permission boundary. Absolute URLs, traversal, and query strings embedded in \`path\` are refused locally.
|
|
2498
|
-
- Useful raw paths include \`/accounts/{accountId}/images/v1\` (Images), \`/accounts/{accountId}/stream\` (Stream), \`/zones/{zoneId}/email/routing/rules\` (Email Routing), \`/accounts/{accountId}/d1/database\` (D1), and \`/accounts/{accountId}/queues\` (Queues). On GET, use \`responseType: "text"\` or \`"base64"\` for non-JSON content. Direct-upload endpoints can issue upload URLs; \`cloudflare_api_upload\` can also send explicit text, base64 bytes, or multipart fields/files.
|
|
2499
|
-
- Three areas are deliberately unnamed. Read a bucket's CORS policy with \`get_r2_cors\`, then change it with \`cloudflare_api_mutate\` — \`PUT\` or \`DELETE /accounts/{accountId}/r2/buckets/{bucketName}/cors\`, rule fields per Cloudflare's reference — and read account storage totals with \`cloudflare_api_get\` at \`/accounts/{accountId}/r2/metrics\`. Zone settings are read one at a time with \`get_zone_setting\`: Cloudflare deprecated the bulk \`/zones/{zoneId}/settings\` read and published no replacement for it, so reach for the whole set through \`cloudflare_api_get\` only when one setting genuinely will not do.
|
|
2500
|
-
- Lists paginate with \`page\` and \`perPage\` and return a \`page\` object; request the next page only when \`page.hasMore\` is true. \`list_zone_rulesets\`, \`list_r2_buckets\`, \`list_r2_objects\`, and \`list_kv_keys\` page by cursor instead: pass \`cursor\`, continue while \`nextCursor\` is present, and expect no \`page\` object. Their schemas say so too. \`list_worker_scripts\` is unpaginated.
|
|
2501
|
-
- Results are projected to the fields that identify and describe a resource. Pass \`raw: true\` on a read when you genuinely need a field the projection drops.
|
|
2502
|
-
- ${authenticationLine}
|
|
2503
|
-
- A \`rate_limited\` failure carries the wait window. Cloudflare's limit is 1,200 requests per five minutes per user, counted across the dashboard and every token, so do not fan out speculatively; filter server-side with \`name\`, \`type\`, and \`content\` instead of listing everything and filtering locally.
|
|
2504
|
-
- Named creates that only add a resource are write-routed without claiming destruction. Updates, overwrites, deletes, rollbacks, cache purges, \`cloudflare_api_mutate\`, and \`cloudflare_api_upload\` are destructive. Read current state before changing it, and prefer a targeted \`purge_cache\` over \`everything\`.
|
|
2505
|
-
${accountInstructions
|
|
2506
|
-
? `\n## Account instructions\n\n${accountInstructions}\n`
|
|
2507
|
-
: ""}`;
|
|
1929
|
+
- ${accountLine}${skill.fragments.guide_0}${authenticationLine}${skill.fragments.guide_1}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
|
|
2508
1930
|
}
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
1931
|
+
/**
|
|
1932
|
+
* Reviewed in #705's provider audit against https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/.
|
|
1933
|
+
* Retains the release-reviewed inventory, including names absent from today's
|
|
1934
|
+
* public reference. Live annotations were not reverified without credentials.
|
|
1935
|
+
* No schema digest is asserted without a captured schema to review.
|
|
1936
|
+
*/
|
|
1937
|
+
const CLOUDFLARE_MCP_CLASSIFICATION = {
|
|
1938
|
+
tools: {
|
|
1939
|
+
"search": {
|
|
1940
|
+
"verdict": "read",
|
|
1941
|
+
"reason": "Searches the Cloudflare OpenAPI contract without executing API methods.",
|
|
1942
|
+
},
|
|
1943
|
+
"execute": {
|
|
1944
|
+
"verdict": "destructive",
|
|
1945
|
+
"reason": "Can mix HTTP methods across the Cloudflare API; no input schema proves a program only reads.",
|
|
1946
|
+
},
|
|
1947
|
+
},
|
|
1948
|
+
};
|
|
2516
1949
|
function mcpUsageGuide(purpose, instructions) {
|
|
2517
1950
|
const accountInstructions = instructions?.trim();
|
|
2518
1951
|
return `# Cloudflare MCP usage
|
|
2519
1952
|
|
|
2520
|
-
Official whole-API MCP interface: ${purpose}
|
|
2521
|
-
|
|
2522
|
-
- The catalog contains \`search\` and \`execute\`. Search runs code against
|
|
2523
|
-
Cloudflare's OpenAPI document. Execute runs code that may call any authorized
|
|
2524
|
-
Cloudflare API endpoint.
|
|
2525
|
-
- Use \`search\` to find the exact method, path, and fields before writing an
|
|
2526
|
-
execute program. Do not guess an endpoint from product naming.
|
|
2527
|
-
- Connecta routes every \`execute\` call through approval because the tool can
|
|
2528
|
-
mix GET, POST, PUT, PATCH, and DELETE requests inside one program. The MCP
|
|
2529
|
-
schema cannot establish that arbitrary code is read-only.
|
|
2530
|
-
- Keep returned values small. Filter and project inside the Cloudflare MCP
|
|
2531
|
-
program, then reduce again inside Connecta's \`execute_code\` when several
|
|
2532
|
-
calls must be joined.
|
|
2533
|
-
- OAuth and API-token permissions remain the provider-side boundary. An
|
|
2534
|
-
\`auth_required\` failure needs authorization or a token with the required
|
|
2535
|
-
Cloudflare permission.
|
|
2536
|
-
${accountInstructions
|
|
2537
|
-
? `\n## Account instructions\n\n${accountInstructions}\n`
|
|
2538
|
-
: ""}`;
|
|
1953
|
+
Official whole-API MCP interface: ${purpose}${skill.fragments.guide_2}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
|
|
2539
1954
|
}
|
|
2540
|
-
function cloudflareMcp(id, purpose, options) {
|
|
1955
|
+
function cloudflareMcp(id, purpose, options, provider) {
|
|
2541
1956
|
const connector = remoteMcp(id, {
|
|
2542
1957
|
url: CLOUDFLARE_MCP_ENDPOINT,
|
|
2543
|
-
...
|
|
2544
|
-
authScope: options.authScope,
|
|
2545
|
-
callAdmission: options.callAdmission,
|
|
2546
|
-
maxResultBytes: options.maxResultBytes,
|
|
2547
|
-
}),
|
|
1958
|
+
...provider.connectorOptions,
|
|
2548
1959
|
title: options.title ?? "Cloudflare (MCP)",
|
|
2549
1960
|
description: `Cloudflare's official whole-API MCP interface: ${purpose}`,
|
|
2550
1961
|
auth: withCredentialDefaults(options.auth ?? { type: "oauth" }, {
|
|
@@ -2555,13 +1966,14 @@ function cloudflareMcp(id, purpose, options) {
|
|
|
2555
1966
|
},
|
|
2556
1967
|
}),
|
|
2557
1968
|
requireHttps: true,
|
|
1969
|
+
classify: provider.classify,
|
|
2558
1970
|
usageGuide: {
|
|
2559
1971
|
content: mcpUsageGuide(purpose, options.instructions),
|
|
2560
|
-
summary: "Official whole-API MCP. Search the OpenAPI document
|
|
1972
|
+
summary: "Official whole-API MCP. Search the OpenAPI document; execute programs always classify as writes.",
|
|
2561
1973
|
required: true,
|
|
2562
1974
|
},
|
|
2563
1975
|
});
|
|
2564
|
-
return
|
|
1976
|
+
return connector;
|
|
2565
1977
|
}
|
|
2566
1978
|
function cloudflareApi(id, purpose, options) {
|
|
2567
1979
|
const maxConcurrency = options.maxConcurrency ?? 6;
|
|
@@ -2595,9 +2007,7 @@ function cloudflareApi(id, purpose, options) {
|
|
|
2595
2007
|
// so forcing the guide into context before every operation would spend
|
|
2596
2008
|
// tokens on a sequence the schemas already express.
|
|
2597
2009
|
},
|
|
2598
|
-
...(options.maxResultBytes !== undefined
|
|
2599
|
-
? { maxResultBytes: options.maxResultBytes }
|
|
2600
|
-
: {}),
|
|
2010
|
+
...(options.maxResultBytes !== undefined ? { maxResultBytes: options.maxResultBytes } : {}),
|
|
2601
2011
|
tools: buildTools(scope, authentication),
|
|
2602
2012
|
...(authentication === "apiToken"
|
|
2603
2013
|
? {
|
|
@@ -2621,7 +2031,7 @@ function cloudflareApi(id, purpose, options) {
|
|
|
2621
2031
|
return await testCloudflareCredential(scope.send, { method: "GET", path: "/user" }, {
|
|
2622
2032
|
...ctx,
|
|
2623
2033
|
credential: {
|
|
2624
|
-
get: async (field) => field ? values[field] ?? null : null,
|
|
2034
|
+
get: async (field) => (field ? (values[field] ?? null) : null),
|
|
2625
2035
|
getAll: async () => values,
|
|
2626
2036
|
},
|
|
2627
2037
|
}, (result) => ({
|
|
@@ -2632,13 +2042,36 @@ function cloudflareApi(id, purpose, options) {
|
|
|
2632
2042
|
}),
|
|
2633
2043
|
});
|
|
2634
2044
|
}
|
|
2045
|
+
/** The closed options cloudflare() accepts; see `assertKnownOptions`. */
|
|
2046
|
+
const CLOUDFLARE_OPTIONS = variants("surface", {
|
|
2047
|
+
api: optionsOf()({
|
|
2048
|
+
...keys("title", "authScope", "purpose", "instructions", "maxResultBytes"),
|
|
2049
|
+
...keys("surface", "accountId", "zoneId", "baseUrl", "authentication", "maxConcurrency"),
|
|
2050
|
+
credential: CREDENTIAL,
|
|
2051
|
+
}).shape,
|
|
2052
|
+
mcp: optionsOf()({
|
|
2053
|
+
...PROVIDER_COMMON,
|
|
2054
|
+
...keys("surface"),
|
|
2055
|
+
auth: REMOTE_MCP_AUTH,
|
|
2056
|
+
}).shape,
|
|
2057
|
+
}, "mcp");
|
|
2635
2058
|
/** A maintained Cloudflare connection using the selected provider interface. */
|
|
2636
|
-
export
|
|
2059
|
+
export const cloudflare = defineProvider({
|
|
2060
|
+
name: "cloudflare",
|
|
2061
|
+
title: "Cloudflare",
|
|
2062
|
+
kind: "composed",
|
|
2063
|
+
readme: "Cloudflare",
|
|
2064
|
+
bundle: { "baselineGzip": 151186, "maxGzip": 211186 },
|
|
2065
|
+
skill,
|
|
2066
|
+
options: CLOUDFLARE_OPTIONS,
|
|
2067
|
+
classify: CLOUDFLARE_MCP_CLASSIFICATION,
|
|
2068
|
+
create: cloudflareConnector,
|
|
2069
|
+
});
|
|
2070
|
+
function cloudflareConnector(id, options, provider) {
|
|
2637
2071
|
const purpose = options.purpose.trim();
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
return options.surface === "mcp"
|
|
2642
|
-
? cloudflareMcp(id, purpose, options)
|
|
2643
|
-
: cloudflareApi(id, purpose, options);
|
|
2072
|
+
return options.surface === "api"
|
|
2073
|
+
? cloudflareApi(id, purpose, options)
|
|
2074
|
+
: cloudflareMcp(id, purpose, options, provider);
|
|
2644
2075
|
}
|
|
2076
|
+
/** @deprecated Read `cloudflare.definition.classify` instead. Kept for existing imports. */
|
|
2077
|
+
export const CLOUDFLARE_MCP_VETTED_CATALOG = reviewedCatalog(cloudflare.definition.classify, 'defineProvider("cloudflare")');
|