Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { withRuntime } from "@decocms/runtime";
import { createAssetsAppResource } from "./resources/assets.ts";
import { createCfbBuildVarsAppResource } from "./resources/cfb-build-vars.ts";
import { createCfbBuildsAppResource } from "./resources/cfb-builds.ts";
import { createCfbSecretsAppResource } from "./resources/cfb-secrets.ts";
import { createCfbSetupAppResource } from "./resources/cfb-setup.ts";
import { createCfbVersionsAppResource } from "./resources/cfb-versions.ts";
import { createEnvironmentsAppResource } from "./resources/environments.ts";
import { createFileExplorerAppResource } from "./resources/file-explorer.ts";
import { createIssuesAppResource } from "./resources/issues.ts";
Expand Down Expand Up @@ -118,6 +123,11 @@ export function createApp(opts: CreateAppOptions): Fetcher {
createPullRequestsAppResource(getClientHTML),
createReleasesAppResource(getClientHTML),
createRenderHtmlAppResource(getClientHTML),
createCfbSetupAppResource(getClientHTML),
createCfbSecretsAppResource(getClientHTML),
createCfbBuildVarsAppResource(getClientHTML),
createCfbBuildsAppResource(getClientHTML),
createCfbVersionsAppResource(getClientHTML),
],
});

Expand Down
23 changes: 23 additions & 0 deletions api/resources/cfb-build-vars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createPublicResource } from "@decocms/runtime/tools";
import { CFB_BUILD_VARS_RESOURCE_URI } from "../tools/cfb-build-vars.ts";

const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";

export const createCfbBuildVarsAppResource = (
getClientHTML: () => Promise<string>,
) =>
createPublicResource({
uri: CFB_BUILD_VARS_RESOURCE_URI,
name: "Cloudflare Workers Builds — Build Vars",
description:
"Manage build-time variables on the Cloudflare production trigger for the configured site.",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await getClientHTML();
return {
uri: CFB_BUILD_VARS_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});
23 changes: 23 additions & 0 deletions api/resources/cfb-builds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createPublicResource } from "@decocms/runtime/tools";
import { CFB_BUILDS_RESOURCE_URI } from "../tools/cfb-builds.ts";

const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";

export const createCfbBuildsAppResource = (
getClientHTML: () => Promise<string>,
) =>
createPublicResource({
uri: CFB_BUILDS_RESOURCE_URI,
name: "Cloudflare Workers Builds — Builds",
description:
"List recent Cloudflare Workers Builds, view per-build logs, and trigger new builds.",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await getClientHTML();
return {
uri: CFB_BUILDS_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});
23 changes: 23 additions & 0 deletions api/resources/cfb-secrets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createPublicResource } from "@decocms/runtime/tools";
import { CFB_SECRETS_RESOURCE_URI } from "../tools/cfb-secrets.ts";

const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";

export const createCfbSecretsAppResource = (
getClientHTML: () => Promise<string>,
) =>
createPublicResource({
uri: CFB_SECRETS_RESOURCE_URI,
name: "Cloudflare Workers Builds — Secrets",
description:
"Manage runtime secrets bound to the Cloudflare Worker for the configured site.",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await getClientHTML();
return {
uri: CFB_SECRETS_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});
23 changes: 23 additions & 0 deletions api/resources/cfb-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createPublicResource } from "@decocms/runtime/tools";
import { CFB_SETUP_RESOURCE_URI } from "../tools/cfb-setup.ts";

const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";

export const createCfbSetupAppResource = (
getClientHTML: () => Promise<string>,
) =>
createPublicResource({
uri: CFB_SETUP_RESOURCE_URI,
name: "Cloudflare Workers Builds — Setup",
description:
"One-click onboarding and setup status for a Cloudflare Workers Builds-hosted site.",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await getClientHTML();
return {
uri: CFB_SETUP_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});
23 changes: 23 additions & 0 deletions api/resources/cfb-versions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createPublicResource } from "@decocms/runtime/tools";
import { CFB_VERSIONS_RESOURCE_URI } from "../tools/cfb-versions.ts";

const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";

export const createCfbVersionsAppResource = (
getClientHTML: () => Promise<string>,
) =>
createPublicResource({
uri: CFB_VERSIONS_RESOURCE_URI,
name: "Cloudflare Workers Builds — Versions",
description:
"List recent Cloudflare Worker versions and roll back to a previous version.",
mimeType: RESOURCE_MIME_TYPE,
read: async () => {
const html = await getClientHTML();
return {
uri: CFB_VERSIONS_RESOURCE_URI,
mimeType: RESOURCE_MIME_TYPE,
text: html,
};
},
});
133 changes: 133 additions & 0 deletions api/tools/cfb-build-vars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { createTool } from "@decocms/runtime/tools";
import { z } from "zod";
import { callAdmin, getConfig } from "../lib/admin.ts";

export const CFB_BUILD_VARS_RESOURCE_URI = "ui://mcp-app/cfb-build-vars";

const NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
const NAME_HINT =
"Letters, digits, and underscore only; must start with a letter or underscore; max 64 chars.";

export const buildVarsResultSchema = z.object({
triggerUuid: z.string(),
buildVars: z.record(z.string(), z.string()),
});
export type BuildVarsResult = z.infer<typeof buildVarsResultSchema>;

// ─── cfb_list_build_vars ──────────────────────────────────────────────────────

export const cfbListBuildVarsInputSchema = z.object({});
export type CfbListBuildVarsInput = z.infer<typeof cfbListBuildVarsInputSchema>;

export const cfbListBuildVarsOutputSchema = buildVarsResultSchema;
export type CfbListBuildVarsOutput = z.infer<
typeof cfbListBuildVarsOutputSchema
>;

export const cfbListBuildVarsTool = createTool({
id: "cfb_list_build_vars",
description:
"List Cloudflare build-time variables for the configured site's production trigger. Build vars are visible to anyone with access to the site — for secrets that must stay hidden, use `cfb_set_secret` instead.",
inputSchema: cfbListBuildVarsInputSchema,
outputSchema: cfbListBuildVarsOutputSchema,
_meta: {
ui: { resourceUri: CFB_BUILD_VARS_RESOURCE_URI, visibility: ["app"] },
},
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
execute: async (_input, ctx) => {
const { site, apiKey } = getConfig(ctx);
return (await callAdmin(
"deco-sites/admin/loaders/hosting/cfworkers-builds/vars/list.ts",
{ sitename: site },
apiKey,
)) as CfbListBuildVarsOutput;
},
});

// ─── cfb_set_build_var ────────────────────────────────────────────────────────

export const cfbSetBuildVarInputSchema = z.object({
name: z
.string()
.regex(NAME_REGEX, NAME_HINT)
.describe(`Build var name. ${NAME_HINT}`),
value: z
.string()
.describe("Build var value (plain text, visible after set)."),
});
export type CfbSetBuildVarInput = z.infer<typeof cfbSetBuildVarInputSchema>;

export const cfbSetBuildVarOutputSchema = buildVarsResultSchema;
export type CfbSetBuildVarOutput = z.infer<typeof cfbSetBuildVarOutputSchema>;

export const cfbSetBuildVarTool = createTool({
id: "cfb_set_build_var",
description:
"Create or update a Cloudflare build-time variable on the configured site's production trigger. Overwrites the value if the name already exists. These are NOT runtime secrets — values are plain-text and visible.",
inputSchema: cfbSetBuildVarInputSchema,
outputSchema: cfbSetBuildVarOutputSchema,
_meta: {
ui: { resourceUri: CFB_BUILD_VARS_RESOURCE_URI, visibility: ["app"] },
},
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: true,
openWorldHint: false,
},
execute: async ({ context }, ctx) => {
const { site, apiKey } = getConfig(ctx);
return (await callAdmin(
"deco-sites/admin/actions/hosting/cfworkers-builds/vars/set.ts",
{ sitename: site, name: context.name, value: context.value },
apiKey,
)) as CfbSetBuildVarOutput;
},
});

// ─── cfb_delete_build_var ─────────────────────────────────────────────────────

export const cfbDeleteBuildVarInputSchema = z.object({
name: z
.string()
.regex(NAME_REGEX, NAME_HINT)
.describe("Build var name to remove."),
});
export type CfbDeleteBuildVarInput = z.infer<
typeof cfbDeleteBuildVarInputSchema
>;

export const cfbDeleteBuildVarOutputSchema = buildVarsResultSchema;
export type CfbDeleteBuildVarOutput = z.infer<
typeof cfbDeleteBuildVarOutputSchema
>;

export const cfbDeleteBuildVarTool = createTool({
id: "cfb_delete_build_var",
description:
"Remove a Cloudflare build-time variable from the configured site's production trigger.",
inputSchema: cfbDeleteBuildVarInputSchema,
outputSchema: cfbDeleteBuildVarOutputSchema,
_meta: {
ui: { resourceUri: CFB_BUILD_VARS_RESOURCE_URI, visibility: ["app"] },
},
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: true,
openWorldHint: false,
},
execute: async ({ context }, ctx) => {
const { site, apiKey } = getConfig(ctx);
return (await callAdmin(
"deco-sites/admin/actions/hosting/cfworkers-builds/vars/delete.ts",
{ sitename: site, name: context.name },
apiKey,
)) as CfbDeleteBuildVarOutput;
},
});
Loading
Loading