@typeroll/mcp-server 0.43.16 → 0.44.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/dist/client.js CHANGED
@@ -103,4 +103,7 @@ export class TyperollClient {
103
103
  rootPost(path, body) {
104
104
  return this.request('POST', this.rootUrl(path), body);
105
105
  }
106
+ rootPut(path, body) {
107
+ return this.request('PUT', this.rootUrl(path), body);
108
+ }
106
109
  }
@@ -16,6 +16,64 @@
16
16
  import { z } from 'zod';
17
17
  import { ok, withErrorBoundary } from './helpers.js';
18
18
  export const domainTools = [
19
+ {
20
+ name: 'prepare_publishing_domain_change',
21
+ description: 'Prepare future website and media hosts using only the last successfully published snapshot. Saved CMS changes stay unpublished. Requires the current domain revision. Poll read_publishing_domains for certificate and DNS requirements, then explicitly approve the verified cutover.',
22
+ inputSchema: { revision: z.string() },
23
+ handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.post(siteId, 'publishing/prepare', args))),
24
+ },
25
+ {
26
+ name: 'read_organization_media_migration',
27
+ description: 'Read progress and actionable failures while original media moves to the organization Cloudflare account. Requires an organization API key.',
28
+ inputSchema: {},
29
+ handler: withErrorBoundary(async (_args, { client }) => ok(await client.rootGet('publishing/media-migration'))),
30
+ },
31
+ {
32
+ name: 'retry_organization_media_migration',
33
+ description: 'Resume verified media migration after fixing account, R2 or domain setup. Source files remain readable; pointer changes require matching hashes. Requires an organization API key.',
34
+ inputSchema: {},
35
+ handler: withErrorBoundary(async (_args, { client }) => ok(await client.rootPost('publishing/media-migration', {}))),
36
+ },
37
+ {
38
+ name: 'read_publishing_readiness',
39
+ description: 'Check required publishing connections and domains for the selected site. Returns actionable setup requirements. Editing and temporary previews remain available before publishing is configured.',
40
+ inputSchema: {},
41
+ handler: withErrorBoundary(async (_args, { client, siteId }) => ok(await client.get(siteId, 'publishing'))),
42
+ },
43
+ {
44
+ name: 'approve_publishing_domain_cutover',
45
+ description: 'Approve switching website traffic to the verified frozen deployment. Read publishing domains first and review DNS requirements and certificate readiness. Existing traffic is preserved until validation succeeds. External DNS management remains the caller’s responsibility.',
46
+ inputSchema: { revision: z.string(), candidate_id: z.string() },
47
+ handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.post(siteId, 'publishing/cutover', args))),
48
+ },
49
+ {
50
+ name: 'read_publishing_domains',
51
+ description: 'Read the desired and active website and media hosts, retained media aliases, DNS management mode and domain configuration revision. Saving intent does not switch traffic.',
52
+ inputSchema: {},
53
+ handler: withErrorBoundary(async (_args, { client, siteId }) => ok(await client.get(siteId, 'publishing/domains'))),
54
+ },
55
+ {
56
+ name: 'set_publishing_domains',
57
+ description: 'Save future website and media hosts before preparing a deployment. Requires the current revision from read_publishing_domains. This does not publish content or change traffic DNS. Choose external DNS when your agent manages Cloudflare independently.',
58
+ inputSchema: {
59
+ revision: z.string(), website_host: z.string().nullable(), media_host: z.string().nullable(),
60
+ media_path_prefix: z.string().optional().describe('Empty on a separate media host; /media when using the website host.'),
61
+ dns_mode: z.enum(['automatic', 'external']),
62
+ },
63
+ handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.put(siteId, 'publishing/domains', args))),
64
+ },
65
+ {
66
+ name: 'read_organization_publishing_domains',
67
+ description: 'Read the organization default domain. Requires an organization API key; site keys cannot access organization publishing settings.',
68
+ inputSchema: {},
69
+ handler: withErrorBoundary(async (_args, { client }) => ok(await client.rootGet('publishing/domains'))),
70
+ },
71
+ {
72
+ name: 'set_organization_publishing_domains',
73
+ description: 'Save the organization default domain used for demos and site versions. Requires an organization API key and the current settings revision. Does not modify DNS or replace an existing active domain.',
74
+ inputSchema: { revision: z.string(), default_domain: z.string().nullable(), dns_mode: z.enum(['automatic', 'external']) },
75
+ handler: withErrorBoundary(async (args, { client }) => ok(await client.rootPut('publishing/domains', args))),
76
+ },
19
77
  {
20
78
  name: 'read_domain',
21
79
  description: "Read the current state of the site's custom domain. Returns " +
@@ -100,6 +100,12 @@ async function uploadFromUrl(args, deps) {
100
100
  };
101
101
  }
102
102
  export const mediaTools = [
103
+ {
104
+ name: 'read_private_media_url',
105
+ description: 'Get a 60-second read URL for a private media original. Use it for authorized image inspection; never store it in page content or generated source. Use the stable media URL or ID in content.',
106
+ inputSchema: { media_id: z.string() },
107
+ handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.get(siteId, `media/${encodeURIComponent(args.media_id)}/content`))),
108
+ },
103
109
  {
104
110
  name: 'list_media',
105
111
  description: 'List uploaded media items (CDN URLs, alt text, mime). Newest first, cursor-paginated.',
@@ -240,11 +246,12 @@ export const mediaTools = [
240
246
  },
241
247
  {
242
248
  name: 'update_media',
243
- description: 'Patch a media item\'s alt_text or filename. Other fields are immutable.',
249
+ description: 'Patch a media item\'s alt text, filename or public path. A public path change is applied at the next publication.',
244
250
  inputSchema: {
245
251
  media_id: z.string(),
246
252
  alt_text: z.string().optional(),
247
253
  filename: z.string().optional(),
254
+ public_path: z.string().nullable().optional().describe('Optional stable path such as /wp-content/uploads/2023/photo.jpg. Applied at the next build; existing public image URLs stay available.'),
248
255
  },
249
256
  handler: withErrorBoundary(async (args, { client, siteId }) => {
250
257
  const { media_id, ...body } = args;
@@ -4,9 +4,20 @@ function v(version) {
4
4
  return version ? { version } : undefined;
5
5
  }
6
6
  export const previewTools = [
7
+ {
8
+ name: 'revoke_preview_link',
9
+ description: 'Revoke one previously issued preview link. Page access stops immediately; any media read URLs already issued expire within 60 seconds. Does not affect other preview links.',
10
+ inputSchema: { preview_url: z.string() },
11
+ handler: withErrorBoundary(async (args, { client, siteId }) => {
12
+ const token = new URL(args.preview_url).searchParams.get('t');
13
+ if (!token)
14
+ throw new Error('Expected a signed preview URL.');
15
+ return ok(await client.post(siteId, 'preview-link/revoke', { token }));
16
+ }),
17
+ },
7
18
  {
8
19
  name: 'get_preview_link',
9
- description: 'Mint a signed URL the user (or your own browser tool) can open to SEE the rendered preview. Renders LIVE from the database with NO build — this is the PREFERRED way to preview design/content changes as you iterate; reach for this, not trigger_deploy, when previewing. BUFFER MODEL: your edits are unsaved drafts, so for the iteration loop mint the link with include_working_copy:true (drafts visible); a plain link shows SAVED content only — right for stakeholders reviewing what will deploy. Mint ONCE and REUSE that single URL across edits — internal links keep the token so it navigates the whole branch, and it stays valid until the TTL lapses (24h default and max). Target a page (page_id), a collection item (collection_name + item_id), or a raw slug; omit all for the home page. (For a permanently-bookmarkable link to the COMPILED static site, deploy and share the {branch}.{project}.pages.dev alias instead.)',
20
+ description: 'Mint a signed URL the user (or your own browser tool) can open to SEE the rendered preview. Renders LIVE from the database with NO build — this is the PREFERRED way to preview design/content changes as you iterate; reach for this, not trigger_deploy, when previewing. BUFFER MODEL: your edits are unsaved drafts, so for the iteration loop mint the link with include_working_copy:true (drafts visible); a plain link shows SAVED content only — right for stakeholders reviewing what will deploy. Mint ONCE and REUSE that single URL across edits — internal links keep the token so it navigates the whole branch, and it stays valid until the TTL lapses (24h default and max). Target a page (page_id), a collection item (collection_name + item_id), or a raw slug; omit all for the home page. (For a permanent public link, complete Publishing setup and wait for a verified deployment on the organization or site domain.)',
10
21
  inputSchema: {
11
22
  page_id: z.string().optional(),
12
23
  slug: z.string().optional(),
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  //
9
9
  // Keep it in lockstep with package.json: tests/version.test.ts asserts
10
10
  // VERSION === package.json.version, so a bump that forgets this line fails CI.
11
- export const VERSION = '0.43.16';
11
+ export const VERSION = '0.44.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeroll/mcp-server",
3
- "version": "0.43.16",
3
+ "version": "0.44.0",
4
4
  "description": "Model Context Protocol server for the Typeroll public API. Use with Claude Code or any MCP-compatible client to manage a Typeroll site.",
5
5
  "license": "MIT",
6
6
  "repository": {