@typeroll/mcp-server 0.20.0 → 0.21.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/AGENTS.md CHANGED
@@ -13,6 +13,16 @@ advertises its own step-by-step playbook (`tr-new-site`, `tr-migrate-wp`,
13
13
  `tr-brand`, …). Then `read_skill name=…` loads the full recipe. These are
14
14
  local reads; no API key or site context required.
15
15
 
16
+ **Branch first for anything larger than a small edit.** Before a redesign,
17
+ a multi-page change, or trying out a new design direction, run
18
+ `create_branch name="…"` and pass the returned id as `version=<id>` on every
19
+ subsequent read/write. The work stays off the live `main` version until you
20
+ `merge_branch` it — nothing ships until you decide it should. Branches default
21
+ `robots_blocked:true` and get their own deploy URL for stakeholder review.
22
+ It's the cheapest insurance there is; when in doubt, branch. The
23
+ `tr-redesign-branch` skill walks the whole flow. (Small, low-risk single edits
24
+ can go straight to main.)
25
+
16
26
  ## What this is
17
27
 
18
28
  Typeroll is a static-site CMS: content lives in a database, the user
@@ -216,6 +226,13 @@ goes through the MCP:
216
226
  You usually want at least #1 + #2 + a sampling from #3 before
217
227
  proposing any design change, so you mirror the conventions in use.
218
228
 
229
+ **Don't have a site yet?** With an org-scoped key you can `create_site
230
+ name="Acme"` — it bootstraps settings + a draft Home page + a published
231
+ header/footer and returns the new site id. Use that id as `site_id`
232
+ (hosted) / `TYPEROLL_SITE_ID` (stdio) for follow-ups, then run
233
+ `list_skills` → `read_skill tr-new-site` to design it. A site-scoped key
234
+ can't create sites (it's bound to one) and gets a 403.
235
+
219
236
  ## Common operations
220
237
 
221
238
  ### "Replace this string across the whole site"
@@ -578,7 +595,7 @@ stakeholder review.
578
595
  | Family | Tools |
579
596
  |---|---|
580
597
  | **Skills (playbook)** | `list_skills`, `read_skill` — the bundled `tr-*.md` recipes, advertised at runtime. Call `list_skills` first when a task looks like "build / migrate / redesign a site", then `read_skill name=…`. No API key or site context needed. |
581
- | **Discovery** | `get_site`, `update_site`, `list_versions`, `read_site_settings` |
598
+ | **Discovery** | `get_site`, `create_site` (org-scoped key only — see below), `update_site`, `list_versions`, `read_site_settings` |
582
599
  | **Pages — reads** | `list_pages`, `read_page`, `batch_read_pages` |
583
600
  | **Pages — writes** | `create_page`, `update_page`, `replace_page`, `batch_update_pages`, `delete_page`, `clone_page` |
584
601
  | **Pages — blocks** | `get_page_blocks`, `add_block`, `update_block`, `move_block`, `remove_block`, `set_page_mode`, `convert_page_to_blocks` |
package/README.md CHANGED
@@ -107,7 +107,8 @@ the full reference + concrete operation recipes.
107
107
  migrate / redesign a site, then `read_skill name=tr-new-site` for the
108
108
  full markdown. Pure local reads — no API key or site context needed, so
109
109
  they work identically on the hosted connector and over stdio.
110
- - **Discovery** — `get_site`, `update_site` (name/slug/domain), `list_versions`,
110
+ - **Discovery** — `get_site`, `create_site` (bootstrap a new site — org-scoped
111
+ key only), `update_site` (name/slug/domain), `list_versions`,
111
112
  `read_site_settings`, `update_site_settings`.
112
113
  - **Pages** — list, read, batch-read, create, update (PATCH), replace
113
114
  (PUT), batch-update, delete, clone, get-preview, `set_page_mode`
package/dist/client.js CHANGED
@@ -100,4 +100,7 @@ export class TyperollClient {
100
100
  rootGet(path) {
101
101
  return this.request('GET', this.rootUrl(path));
102
102
  }
103
+ rootPost(path, body) {
104
+ return this.request('POST', this.rootUrl(path), body);
105
+ }
103
106
  }
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import { runInitCli } from './init.js';
18
18
  import { runInstallSkillsCli } from './install-skills.js';
19
19
  import { resolveSiteId } from './resolve-site-id.js';
20
20
  import { buildServer } from './server.js';
21
- const VERSION = '0.7.12';
21
+ const VERSION = '0.21.0';
22
22
  function bail(message) {
23
23
  console.error(`typeroll-mcp: ${message}`);
24
24
  process.exit(1);
package/dist/server.js CHANGED
@@ -48,7 +48,37 @@ function effectFor(name) {
48
48
  }
49
49
  return 'write';
50
50
  }
51
- const DEFAULT_INFO = { name: 'typeroll', version: '0.7.12' };
51
+ const DEFAULT_INFO = { name: 'typeroll', version: '0.21.0' };
52
+ /**
53
+ * Server-level instructions — returned in the MCP `initialize` response and
54
+ * surfaced to the model by every client (Claude Code stdio AND the hosted
55
+ * Desktop/claude.ai connector) with zero user setup. This is the one channel
56
+ * that reaches every consumer automatically, so it carries the highest-value
57
+ * conventions and POINTS at the deeper, on-demand content (the bundled skills,
58
+ * reachable via list_skills/read_skill) rather than duplicating it.
59
+ */
60
+ export const SERVER_INSTRUCTIONS = `
61
+ Typeroll MCP — operating manual. You're managing a Typeroll site (a static-site
62
+ CMS: database content compiles to a fast static site on a deploy). The full
63
+ playbook ships with this server — use it:
64
+
65
+ 1. When the task is "build / migrate / redesign / brand a site", call
66
+ list_skills FIRST, then read_skill <name> for the step-by-step recipe
67
+ (tr-new-site, tr-migrate-wp, tr-brand, tr-blog, …). These are the canonical
68
+ how-to; don't improvise what a skill already covers.
69
+ 2. Discover before you write: get_site, read_site_settings, list_pages,
70
+ list_block_types. Never hardcode block ids or field names — they're per-site.
71
+ 3. Branch first for anything larger than a small edit: create_branch, pass
72
+ version=<id> on every subsequent call, merge_branch once approved. Nothing
73
+ touches the live site until then.
74
+ 4. Pages default to block mode. Build with add_block/update_block; make layouts
75
+ responsive per breakpoint with set_block_responsive (grid columns, icon-box
76
+ layout, … take { mobile, tablet, laptop, desktop, wide } values).
77
+ 5. No site yet? With an org-scoped key, create_site bootstraps one.
78
+
79
+ If anything here conflicts with what a tool returns, trust the tool. Every
80
+ tool's own description carries its specifics.
81
+ `.trim();
52
82
  export function buildServer(options) {
53
83
  if (!options.fixedSiteId && !options.allowedSites) {
54
84
  throw new Error('buildServer: either fixedSiteId or allowedSites must be provided');
@@ -58,6 +88,7 @@ export function buildServer(options) {
58
88
  }
59
89
  const server = new McpServer(options.info ?? DEFAULT_INFO, {
60
90
  capabilities: { tools: {} },
91
+ instructions: SERVER_INSTRUCTIONS,
61
92
  });
62
93
  const allTools = [
63
94
  ...skillTools,
@@ -92,7 +92,7 @@ export const blockTypeTools = [
92
92
  // audit + UI distinguish agent-authored types.
93
93
  {
94
94
  name: 'create_block_type',
95
- description: "Create a new custom block type usable on this site. Origin is stamped 'ai' automatically. The block ships immediately to every page editor + the renderer's registry. Custom JS via `script` is accepted under your API key's authority (audit-logged; the response carries a notice) — review before deploy. Returns the created BlockType.",
95
+ description: "Create a new custom block type usable on this site. Origin is stamped 'ai' automatically. The block ships immediately to every page editor + the renderer's registry. Custom JS via `script` is accepted under your API key's authority (audit-logged; the response carries a notice) — review before deploy. Returns the created BlockType. Responsive fields: mark a schema field `responsive: true` and expose it as style=\"--{field}:{{field}}\" on the outermost element so it can vary per breakpoint. If the value is directly usable CSS, read var(--{field}); if it's a token that maps to CSS (e.g. layout 'icon-left' → flex-direction:row) add a `responsive_css` map on the field ({ 'icon-left': '--dir: row;' }), otherwise per-breakpoint overrides won't take effect.",
96
96
  inputSchema: {
97
97
  name: z.string().describe('Machine name (lowercase kebab/underscore, 1-64 chars). Becomes the id.'),
98
98
  label: z.string().optional().describe('Display label (defaults to name).'),
@@ -2,6 +2,22 @@
2
2
  import { z } from 'zod';
3
3
  import { ok, withErrorBoundary } from './helpers.js';
4
4
  export const siteTools = [
5
+ {
6
+ name: 'create_site',
7
+ description: "Create + bootstrap a NEW site in your org. Seeds default settings, a draft Home page, and a published header/footer so it renders immediately. Requires an ORG-scoped key (a site-scoped key is bound to one existing site and can't mint new ones; you'll get a 403). `name` drives a kebab-case site id; pass `domain` to kick off the \"point your DNS\" flow (never written as a live domain). Returns the new site's id + urls — use that id as `site_id`/`TYPEROLL_SITE_ID` for follow-up calls. After creating, run list_skills → read_skill tr-new-site to bootstrap the design.",
8
+ noSite: true,
9
+ inputSchema: {
10
+ name: z.string().min(1).describe('Display name. Slugified into the site id.'),
11
+ domain: z
12
+ .string()
13
+ .optional()
14
+ .describe('Optional real hostname e.g. "example.com". Starts DNS setup; not set live until DNS verifies.'),
15
+ },
16
+ handler: withErrorBoundary(async (args, { client }) => {
17
+ const res = await client.rootPost('sites', { name: args.name, domain: args.domain });
18
+ return ok(res);
19
+ }),
20
+ },
5
21
  {
6
22
  name: 'get_site',
7
23
  description: 'Read this site\'s metadata (id, name, slug, domain, active version) + a urls object covering the production / fallback / preview_base URLs. Useful as a first call to confirm the key is wired up and to learn what URLs the site is reachable at.',
@@ -12,7 +12,7 @@ export const versionTools = [
12
12
  },
13
13
  {
14
14
  name: 'create_branch',
15
- description: 'Create a copy-on-write branch from main (or the version passed in `base`). New branches default to robots_blocked:true. Pass the new branch\'s id as ?version= on subsequent calls to read/write against it.',
15
+ description: "Create a copy-on-write branch from main (or the version passed in `base`) — the RECOMMENDED first step for any larger or experimental change (redesigns, multi-page edits, trying a new design direction). Work lands on the branch, never on the live main version, until you merge_branch it. New branches default to robots_blocked:true (a half-finished design can't be indexed) and get their own deploy URL ({branch}.{project}.pages.dev) for stakeholder review. Pass the returned id as ?version= on every subsequent read/write. When in doubt, branch — it's cheap and keeps the live site safe. The tr-redesign-branch skill (read_skill) walks the full flow.",
16
16
  inputSchema: {
17
17
  name: z.string().min(1),
18
18
  base: z.string().optional().describe('Source version id; defaults to main.'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeroll/mcp-server",
3
- "version": "0.20.0",
3
+ "version": "0.21.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": {