@typeroll/mcp-server 0.45.103 → 0.45.105
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 +10 -1
- package/README.md +5 -3
- package/dist/bundled-content.js +5 -5
- package/dist/tools/domain.js +4 -4
- package/dist/tools/settings.js +1 -0
- package/dist/tools/sites.js +14 -4
- package/dist/tools/workflows.js +20 -8
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/tr-header-footer.md +8 -0
- package/skills/tr-migrate-multisite.md +2 -2
- package/skills/tr-responsive.md +10 -0
package/dist/tools/domain.js
CHANGED
|
@@ -24,9 +24,9 @@ export const domainTools = [
|
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
name: 'guide_publishing_domain_change',
|
|
27
|
-
description: 'Guide a site domain move. Start with check: returns hosting, zone, nameserver, certificate, permission, publishing, redirect capacity, candidate_noindex and candidate checks, current phase, next action and an explicit switch summary. candidate_noindex blocks prepare and approve while site settings, the last publication or the candidate tell search engines not to index or follow the site (next_action resolve_noindex): the temporary address is already blocked from indexing by Typeroll, so prepare with confirm_disable_noindex: true to turn it off and build an indexable candidate in one step, or pass allow_noindex_launch: true to launch hidden on purpose. Saving future hosts is inert. Prepare republishes the last public content on main with the new origins, replacing the current site before DNS changes; newer unpublished CMS edits are excluded. Later normal publications retain the new origins. Approve changes DNS for the same main artifact without another build. Adding redirect hosts preserves the main artifact. Approve requires explicit user approval of the switch summary and any validation interruption. Automatic DNS is journaled and rolled back after a failed check or the agreed deadline; later external edits require manual attention. Rollback requests restoration through the serialized publication chain. External DNS remains the caller’s responsibility.',
|
|
27
|
+
description: 'Guide a site domain move. Start with check: returns hosting, zone, nameserver, certificate, permission, publishing, redirect capacity, candidate_noindex and candidate checks, current phase, next action and an explicit switch summary. candidate_noindex blocks prepare and approve while site settings, the last publication or the candidate tell search engines not to index or follow the site (next_action resolve_noindex): the temporary address is already blocked from indexing by Typeroll, so prepare with confirm_disable_noindex: true to turn it off and build an indexable candidate in one step, or pass allow_noindex_launch: true to launch hidden on purpose. Saving future hosts is inert. Prepare republishes the last public content on main with the new origins, replacing the current site before DNS changes; newer unpublished CMS edits are excluded. Later normal publications retain the new origins. Approve changes DNS for the same main artifact without another build. Adding redirect hosts preserves the main artifact. Approve requires explicit user approval of the switch summary and any validation interruption. Automatic DNS is journaled and rolled back after a failed check or the agreed deadline; later external edits require manual attention. Rollback requests restoration through the serialized publication chain. After go-live, Typeroll re-checks who serves the website and redirect hosts at about 2, 10 and 30 minutes; next_action remove_other_host (with traffic_live false and a serving check) means another provider answers the host, typically a previous host\'s Cloudflare for SaaS hostname that outranks the customer\'s DNS: remove the domain from that host\'s dashboard, then check again. Live website hosts are then checked daily. A switch goes live only when the website host\'s Cloudflare Pages custom domain is active; otherwise it fails with pages_domain_not_active and automatic DNS is restored. Before approval, a check previous_host_saas:<host> (host_checks warning previous_host_saas_hostname, also in switch_summary.previous_host) means the current host (for example Kinsta) still holds the domain as a Cloudflare for SaaS hostname, which blocks Pages validation: tell the user to remove the domain there right before or right after the switch, inside the validation window. After go-live, next_action retry_validation (check pages_domain:<host>, traffic_live false) means the Pages custom domain is not active (pending or deactivated, visitors typically get HTTP 522): make sure the previous host released the domain, then call action retry_validation. It is idempotent: it re-checks the host and asks Cloudflare to retry validation (never a DNS change), at most once a minute. Previous website addresses (such as the temporary sites address) get a 301 through one Single Redirect rule per new website host in their zone; check reports host_checks warnings redirect_rule_quota (the zone\'s rule quota is full, Free plan: 10) or redirect_permission_missing with a remedy before approval. A refused write never blocks or rolls back the switch: the old address keeps noindex, previous_hosts records the issue code, and next_action repair_previous_host_redirects re-creates missing redirects without a build or DNS change once the remedy is applied (idempotent; safe to repeat). External DNS remains the caller’s responsibility.',
|
|
28
28
|
inputSchema: {
|
|
29
|
-
action: z.enum(['check', 'preview', 'save', 'prepare', 'approve', 'rollback']),
|
|
29
|
+
action: z.enum(['check', 'preview', 'save', 'prepare', 'approve', 'rollback', 'retry_validation', 'repair_previous_host_redirects']),
|
|
30
30
|
revision: z.string().optional(), candidate_id: z.string().optional(),
|
|
31
31
|
website_host: z.string().nullable().optional(), media_host: z.string().nullable().optional(), media_path_prefix: z.string().optional(),
|
|
32
32
|
redirect_hosts: z.array(z.string()).max(4).optional(), dns_mode: z.enum(['automatic', 'external']).optional(),
|
|
@@ -215,7 +215,7 @@ export const domainTools = [
|
|
|
215
215
|
},
|
|
216
216
|
{
|
|
217
217
|
name: 'approve_publishing_domain_cutover',
|
|
218
|
-
description: 'Approve switching DNS to the current verified main publication, without another Git push, build or upload. Read the latest candidate_id; older receipts are rejected. Read publishing domains first and review DNS requirements, certificate readiness and redirect_preparations. Existing traffic is preserved until validation succeeds. With automatic DNS, redirect hosts switch after the website host: Typeroll ensures their zone redirect rule, then changes their reviewed record to a proxied placeholder. The publication goes live only after every redirect host answers 301 to the website host with the same path and query. When preparation.validation_blocker.resolution is accept_validation_window, Cloudflare can validate the website host only after its one existing record points at Pages: approving with accept_validation_window: true lets Typeroll change that record, and the host does not answer until Cloudflare validates it (Cloudflare does not document how long; previous_records holds the rollback). Get the user\'s explicit go-ahead for that window and choose a quiet time. External DNS management remains the caller’s responsibility.',
|
|
218
|
+
description: 'Approve switching DNS to the current verified main publication, without another Git push, build or upload. Read the latest candidate_id; older receipts are rejected. Read publishing domains first and review DNS requirements, certificate readiness and redirect_preparations. Existing traffic is preserved until validation succeeds. With automatic DNS, redirect hosts switch after the website host: Typeroll ensures their zone redirect rule, then changes their reviewed record to a proxied placeholder. The publication goes live only after every redirect host answers 301 to the website host with the same path and query. When preparation.validation_blocker.resolution is accept_validation_window, Cloudflare can validate the website host only after its one existing record points at Pages: approving with accept_validation_window: true lets Typeroll change that record, and the host does not answer until Cloudflare validates it (Cloudflare does not document how long; previous_records holds the rollback). Get the user\'s explicit go-ahead for that window and choose a quiet time. The website host goes live only when its Cloudflare Pages custom domain is active: Typeroll retries validation while it is pending or deactivated, and a domain that is blocked or not active by the deadline fails the switch with pages_domain_not_active (automatic DNS is restored). If host_checks warns previous_host_saas_hostname, the user must remove the domain from the previous host right before or right after approving. External DNS management remains the caller’s responsibility.',
|
|
219
219
|
inputSchema: {
|
|
220
220
|
revision: z.string(), candidate_id: z.string(),
|
|
221
221
|
validation_timeout_minutes: z.number().int().min(5).max(45).optional(),
|
|
@@ -226,7 +226,7 @@ export const domainTools = [
|
|
|
226
226
|
},
|
|
227
227
|
{
|
|
228
228
|
name: 'read_publishing_domains',
|
|
229
|
-
description: 'Read the desired and active website, redirect and media hosts, retained media aliases, DNS management mode and domain configuration revision. host_checks lists each future host with its Cloudflare zone and structured blockers and warnings (code, host, message), for example apex_zone_required (an apex such as example.com needs an active Cloudflare zone in the hosting account), zone_not_active (the zone is pending until its nameservers change) or redirect_zone_required. Resolve blockers before preparing. preparation and redirect_preparations hold DNS records, the zone redirect rule and certificate state after preparation. Saving intent does not switch traffic. published identifies the addresses embedded in main, separately from active (verified traffic). Saving desired hosts is inert. prepare_publishing_domain_change explicitly replaces main with the new origins; later normal publication retains them and refreshes the DNS approval receipt. candidate.sitewide_noindex describes the frozen candidate, not current settings. Prepare and approve reject an authored noindex launch with candidate_noindex unless allow_noindex_launch is true.',
|
|
229
|
+
description: 'Read the desired and active website, redirect and media hosts, retained media aliases, DNS management mode and domain configuration revision. host_checks lists each future host with its Cloudflare zone and structured blockers and warnings (code, host, message), for example apex_zone_required (an apex such as example.com needs an active Cloudflare zone in the hosting account), zone_not_active (the zone is pending until its nameservers change) or redirect_zone_required. Resolve blockers before preparing. preparation and redirect_preparations hold DNS records, the zone redirect rule and certificate state after preparation. Saving intent does not switch traffic. published identifies the addresses embedded in main, separately from active (verified traffic). Saving desired hosts is inert. prepare_publishing_domain_change explicitly replaces main with the new origins; later normal publication retains them and refreshes the DNS approval receipt. candidate.sitewide_noindex describes the frozen candidate, not current settings. Prepare and approve reject an authored noindex launch with candidate_noindex unless allow_noindex_launch is true. serving_check reports read-only follow-up checks about 2, 10 and 30 minutes after the website host went live: status pending, serving, inconclusive (a transport or edge error, never an alarm), other_host (issue code domain_served_by_other_host, with observed.provider_hint and remedy) or other_publication (domain_serving_other_publication). Checks continue daily while the host is live. serving_check.pages_domain is the latest read of the website host\'s Cloudflare Pages custom domain (status, validation, retried_at); serving_check.pages_issue (code pages_domain_not_active, with status, remedy and retryable) stands while it is not active, for example deactivated after a previous host\'s Cloudflare for SaaS hostname blocked validation. Checks retry validation automatically when the host points at the Pages project; to retry now, call guide_publishing_domain_change with action retry_validation. host_checks warning previous_host_saas_hostname means the current host still holds the domain as a Cloudflare for SaaS hostname: remove it there around the switch. An alarm stands until a later check succeeds; reads re-check it. Inconclusive reads never raise or clear an alarm. Typeroll never changes DNS or rolls back because of it.',
|
|
230
230
|
inputSchema: {},
|
|
231
231
|
handler: withErrorBoundary(async (_args, { client, siteId }) => ok(await client.get(siteId, 'publishing/domains'))),
|
|
232
232
|
},
|
package/dist/tools/settings.js
CHANGED
|
@@ -66,6 +66,7 @@ export const settingsTools = [
|
|
|
66
66
|
language: z.string().optional().describe('BCP-47 tag (e.g. "en", "sv", "en-GB"). Drives <html lang> on the rendered site.'),
|
|
67
67
|
robots_txt: z.string().optional(),
|
|
68
68
|
ai_crawler_policy: z.enum(['allow_all', 'no_training', 'block_all']).nullable().optional().describe('AI crawler preference, written as Cloudflare-compatible Content Signals in robots.txt and the Content-Signal response header. `allow_all` (default, writes nothing); `no_training` (search=yes, ai-input=yes, ai-train=no, and Disallow groups for training-only crawlers such as GPTBot, ClaudeBot and Google-Extended); `block_all` (also disallows AI search and user agents such as OAI-SearchBot, ChatGPT-User and PerplexityBot). Googlebot, Bingbot and Applebot are never blocked. An explicit group for an agent in robots_txt wins. A Cloudflare zone AI bot policy is enforced at the edge and can override this; `null` resets to the default.'),
|
|
69
|
+
header_behavior: z.enum(['static', 'sticky', 'reveal_on_scroll_up']).nullable().optional().describe('Site header while scrolling. `static` (default, writes nothing) scrolls with the page; `sticky` stays at the top; `reveal_on_scroll_up` hides while scrolling down and returns as a compact header on the first scroll up, with the navigation menu toggle at every width. The compact state carries `data-header-compact` for site CSS. null clears.'),
|
|
69
70
|
sitewide_noindex: z.boolean().optional().describe('Exclude public pages from search indexing; following links remains a separate setting.'),
|
|
70
71
|
external_routes: z.array(z.object({ path: z.string().min(2).max(2048), owner: z.string().min(1).max(200) }).strict()).max(1000).optional().describe('Exact same-origin paths owned by an independent deployment, e.g. [{path:"/docs/",owner:"Documentation"}]. No wildcards. Does not configure hosting or verify remote availability. Verify each declared public URL separately. Local routes cannot be exempted.'),
|
|
71
72
|
seo_review: z.object({ forbidden_markers: z.array(z.string().min(1).max(500)).max(100).optional(), claims: z.array(z.object({ phrase: z.string().min(1).max(500), guidance: z.string().min(1).max(500) })).max(100).optional(), notes: z.array(z.string().min(1).max(500)).max(100).optional() }).optional().describe('Editorial review rules checked on all built pages, including unchanged pages. Warnings require human review; no copy is rewritten.'),
|
package/dist/tools/sites.js
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
// check as the corresponding portal action.
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { ok, withErrorBoundary } from './helpers.js';
|
|
6
|
+
/** Optional fields every site-creating tool accepts (POST /api/v1/sites and the create-and-* routes). */
|
|
7
|
+
export const newSiteFields = {
|
|
8
|
+
id: z.string().optional().describe('Optional site id: 3-48 lowercase letters, digits and "-" (e.g. "acme-studio"). Used exactly; 409 site_id_taken when the organization has it. Default: the kebab-case name.'),
|
|
9
|
+
language: z.string().optional().describe('Optional site content language as a BCP 47 tag (e.g. "en", "sv", "nl-BE"). Default "en". Drives <html lang>; change it later with update_site_settings.'),
|
|
10
|
+
};
|
|
11
|
+
/** The arguments that were given: an omitted optional field is not sent. */
|
|
12
|
+
export function definedFields(args) {
|
|
13
|
+
return Object.fromEntries(Object.entries(args).filter(([, value]) => value !== undefined));
|
|
14
|
+
}
|
|
6
15
|
export const siteTools = [
|
|
7
16
|
{
|
|
8
17
|
name: 'read_organization_access',
|
|
@@ -26,17 +35,18 @@ export const siteTools = [
|
|
|
26
35
|
},
|
|
27
36
|
{
|
|
28
37
|
name: 'create_site',
|
|
29
|
-
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`
|
|
38
|
+
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). Accepts exactly `name`, optional `id`, `domain` and `language`; any other field is refused. Without `id` the site id is the kebab-case `name` (with a random suffix when taken); with `id` that exact id is used, or 409 site_id_taken. `language` is the site's BCP 47 content language (e.g. \"nl-BE\"; default \"en\"), saved at creation so <html lang> is right from the first build. Pass `domain` to kick off the \"point your DNS\" flow (never written as a live domain). Returns the new site's id, language + 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.",
|
|
30
39
|
noSite: true,
|
|
31
40
|
inputSchema: {
|
|
32
|
-
name: z.string().min(1).describe('Display name. Slugified into the site id.'),
|
|
41
|
+
name: z.string().min(1).describe('Display name. Slugified into the site id unless `id` is given.'),
|
|
42
|
+
...newSiteFields,
|
|
33
43
|
domain: z
|
|
34
44
|
.string()
|
|
35
45
|
.optional()
|
|
36
46
|
.describe('Optional real hostname e.g. "example.com". Starts DNS setup; not set live until DNS verifies.'),
|
|
37
47
|
},
|
|
38
48
|
handler: withErrorBoundary(async (args, { client }) => {
|
|
39
|
-
const res = await client.rootPost('sites',
|
|
49
|
+
const res = await client.rootPost('sites', definedFields(args));
|
|
40
50
|
return ok(res);
|
|
41
51
|
}),
|
|
42
52
|
},
|
|
@@ -69,7 +79,7 @@ export const siteTools = [
|
|
|
69
79
|
},
|
|
70
80
|
{
|
|
71
81
|
name: 'check_site_indexing',
|
|
72
|
-
description: 'Probe the site\'s recorded fallback and live production origins and report indexing safety. Keeps X-Robots-Tag, HTML robots meta, and robots.txt crawl policy separate. expectation_reason identifies fallback_protection, platform_robots_blocked, sitewide_noindex or public_site. Customer publishing without a future website host intentionally blocks indexing even when sitewide_noindex is false; this is expected, not an error. Fallback URLs must expose the documented edge noindex header. Use before launch and after changing domains or indexing settings.',
|
|
82
|
+
description: 'Probe the site\'s recorded fallback and live production origins and report indexing safety. Keeps X-Robots-Tag, HTML robots meta, and robots.txt crawl policy separate. expectation_reason identifies fallback_protection, platform_robots_blocked, sitewide_noindex or public_site. Customer publishing without a future website host intentionally blocks indexing even when sitewide_noindex is false; this is expected, not an error. Fallback URLs must expose the documented edge noindex header. Each target also records whose page was read: serving_publication (the X-Typeroll-Publication header, else /.well-known/typeroll/publication.json), serving_typeroll and provider_hint (a likely previous host named by a well-known header such as x-kinsta-cache). For customer publishing the current publication is expected; when another host or another publication answers, serving_typeroll is false, matches_expected is false and an issue explains it, because the robots findings then describe that other host. A previous host using Cloudflare for SaaS (for example Kinsta) outranks the customer\'s own DNS until the domain is removed from that host\'s dashboard. Use before launch and after changing domains or indexing settings.',
|
|
73
83
|
handler: withErrorBoundary(async (_args, { client, siteId }) => {
|
|
74
84
|
const res = await client.get(siteId, 'indexing-diagnostics');
|
|
75
85
|
return ok(res);
|
package/dist/tools/workflows.js
CHANGED
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
// Site together with its first workflow.
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { ok, versionParam, withErrorBoundary } from './helpers.js';
|
|
7
|
+
import { definedFields, newSiteFields } from './sites.js';
|
|
7
8
|
// Run by the portal with the Organization's own AI key; without access for the
|
|
8
9
|
// Site the run fails with failure_code ai_not_enabled. The agent then does the
|
|
9
10
|
// work itself with the named recipe instead of retrying.
|
|
10
11
|
const AI_WORKFLOWS = 'AI workflows — site_planning, content_generation, content_improvement and schema_markup — call the model with the Organization\'s own AI key and need AI access for this Site; without it the run fails with failure_code "ai_not_enabled" (failure_reason: the AI assistant is not enabled for this site). Do not retry or work around it: you are an AI agent, so do the same work yourself and tell the user you did — site_planning: tr-new-site (propose the page structure, get approval, then build); content_generation: tr-content-write (draft page); content_improvement: tr-content-write on the weakest published pages (thin text, missing seo_title/seo_description, stale), as unsaved drafts for review; schema_markup: tr-seo step 5 (add_faq_schema, add_recipe_schema, add_event_schema or json_ld). seo_audit still runs without AI and returns its issue list unprioritized. Enabling the portal AI is the Organization owner\'s or admin\'s choice, never a prerequisite for you.';
|
|
12
|
+
// Runs execute in the portal process; a restart (a deploy) stops them. Reads
|
|
13
|
+
// close a run with no heartbeat for 10 minutes as workflow_interrupted.
|
|
14
|
+
const INTERRUPTED = 'failure_code "workflow_interrupted" means the run stopped making progress (no heartbeat for over 10 minutes, usually because the service restarted) and will not continue: tell the user, then start_workflow again; work saved before it stopped stays saved. A run that is still running keeps a recent heartbeat_at, however slowly it progresses.';
|
|
11
15
|
const WORKFLOW_TYPES = [
|
|
12
16
|
'migration', 'site_planning', 'seo_audit', 'content_improvement', 'link_check',
|
|
13
17
|
'performance_audit', 'content_generation', 'schema_markup', 'url_parity', 'rebuild_deploy',
|
|
@@ -15,7 +19,7 @@ const WORKFLOW_TYPES = [
|
|
|
15
19
|
export const workflowTools = [
|
|
16
20
|
{
|
|
17
21
|
name: 'list_workflows',
|
|
18
|
-
description: 'List the workflow types this Site can run (label, description, steps, required_permission) and its most recent runs with status. Read only. Migration, site planning and URL parity pause for review; check get_workflow for paused_for_review. Site planning, content generation, content improvement and schema markup need the Organization\'s AI key for this Site (see start_workflow).',
|
|
22
|
+
description: 'List the workflow types this Site can run (label, description, steps, required_permission) and its most recent runs with status. Read only. Migration, site planning and URL parity pause for review; check get_workflow for paused_for_review. A run left running after a service restart is reported failed with failure_code workflow_interrupted. Site planning, content generation, content improvement and schema markup need the Organization\'s AI key for this Site (see start_workflow).',
|
|
19
23
|
inputSchema: { limit: z.number().int().min(1).max(100).optional() },
|
|
20
24
|
handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.get(siteId, 'workflows', args.limit ? { limit: args.limit } : undefined))),
|
|
21
25
|
},
|
|
@@ -31,7 +35,7 @@ export const workflowTools = [
|
|
|
31
35
|
},
|
|
32
36
|
{
|
|
33
37
|
name: 'get_workflow',
|
|
34
|
-
description: 'Read one workflow run: status (pending | running | paused_for_review | completed | failed), current step, progress, log, review_message/review_data when paused, results, failure_reason and failure_code (newer Core; older Core reports failure_reason only). Credential config is masked. failure_code "ai_not_enabled" (or a failure_reason saying the AI assistant is not enabled for this site) means the Site has no portal AI access: do the work yourself with the recipe named in start_workflow instead of retrying.',
|
|
38
|
+
description: 'Read one workflow run: status (pending | running | paused_for_review | completed | failed | cancelled), current step, progress, log, review_message/review_data when paused, results, failure_reason and failure_code (newer Core; older Core reports failure_reason only). Credential config is masked. failure_code "ai_not_enabled" (or a failure_reason saying the AI assistant is not enabled for this site) means the Site has no portal AI access: do the work yourself with the recipe named in start_workflow instead of retrying. ' + INTERRUPTED,
|
|
35
39
|
inputSchema: { workflow_id: z.string() },
|
|
36
40
|
handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.get(siteId, `workflows/${encodeURIComponent(args.workflow_id)}`))),
|
|
37
41
|
},
|
|
@@ -41,25 +45,33 @@ export const workflowTools = [
|
|
|
41
45
|
inputSchema: { workflow_id: z.string() },
|
|
42
46
|
handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.post(siteId, `workflows/${encodeURIComponent(args.workflow_id)}/approve`))),
|
|
43
47
|
},
|
|
48
|
+
{
|
|
49
|
+
name: 'cancel_workflow',
|
|
50
|
+
description: 'Cancel a run that is pending, running or paused_for_review; it is recorded as status cancelled and continues no further (a step already in flight may finish its current work, but nothing more is recorded; changes it already saved stay). Use it when the user wants to stop a run or start over. Needs the permission that starting the type needs (write; admin for rebuild_deploy). A finished run (completed, failed, cancelled) returns 409. Returns the cancelled run.',
|
|
51
|
+
inputSchema: { workflow_id: z.string() },
|
|
52
|
+
handler: withErrorBoundary(async (args, { client, siteId }) => ok(await client.post(siteId, `workflows/${encodeURIComponent(args.workflow_id)}/cancel`))),
|
|
53
|
+
},
|
|
44
54
|
{
|
|
45
55
|
name: 'create_site_and_migrate',
|
|
46
56
|
noSite: true,
|
|
47
|
-
description: 'Create a new Site in the Organization and start a WordPress migration into it, like "Migrate from WordPress" on the portal\'s New site page. Requires an organization API key and verified organization import storage (409 import_storage_required otherwise — nothing is created). Returns site and workflow ids; poll get_workflow with that site_id. Run get_migration_readiness on the new Site if you need the preflight first.',
|
|
57
|
+
description: 'Create a new Site in the Organization and start a WordPress migration into it, like "Migrate from WordPress" on the portal\'s New site page. Requires an organization API key and verified organization import storage (409 import_storage_required otherwise — nothing is created). Returns site and workflow ids; poll get_workflow with that site_id. Run get_migration_readiness on the new Site if you need the preflight first. Optional `id` and `language` work as in create_site; any other field is refused.',
|
|
48
58
|
inputSchema: {
|
|
49
|
-
name: z.string().min(1).describe('Site display name; slugified into the Site id.'),
|
|
59
|
+
name: z.string().min(1).describe('Site display name; slugified into the Site id unless `id` is given.'),
|
|
60
|
+
...newSiteFields,
|
|
50
61
|
wp_url: z.string().url().describe('Public WordPress address, e.g. https://oldsite.example.'),
|
|
51
62
|
helper_api_key: z.string().optional().describe('Typeroll Helper plugin key from the WordPress admin, if installed. Stored for the run and never returned.'),
|
|
52
63
|
},
|
|
53
|
-
handler: withErrorBoundary(async (args, { client }) => ok(await client.rootPost('sites/create-and-migrate', args))),
|
|
64
|
+
handler: withErrorBoundary(async (args, { client }) => ok(await client.rootPost('sites/create-and-migrate', definedFields(args)))),
|
|
54
65
|
},
|
|
55
66
|
{
|
|
56
67
|
name: 'create_site_and_plan',
|
|
57
68
|
noSite: true,
|
|
58
|
-
description: 'Create a new Site in the Organization and start AI site planning from a business description, like "Plan a new site with AI" on the New site page. Requires an organization API key. Needs the Organization\'s own AI key with site access "all" (read_organization_ai_settings); otherwise it answers 403 ai_not_enabled and creates nothing — then create_site a blank Site and plan it yourself with tr-new-site (propose the pages, get the user\'s approval, build), and say that you did; enabling the portal AI is the owner\'s or admin\'s choice, not a prerequisite. The plan pauses for review: read it with get_workflow and approve_workflow only after the user agrees.',
|
|
69
|
+
description: 'Create a new Site in the Organization and start AI site planning from a business description, like "Plan a new site with AI" on the New site page. Requires an organization API key. Needs the Organization\'s own AI key with site access "all" (read_organization_ai_settings); otherwise it answers 403 ai_not_enabled and creates nothing — then create_site a blank Site and plan it yourself with tr-new-site (propose the pages, get the user\'s approval, build), and say that you did; enabling the portal AI is the owner\'s or admin\'s choice, not a prerequisite. The plan pauses for review: read it with get_workflow and approve_workflow only after the user agrees. Optional `id` and `language` work as in create_site; any other field is refused.',
|
|
59
70
|
inputSchema: {
|
|
60
|
-
name: z.string().min(1),
|
|
71
|
+
name: z.string().min(1).describe('Site display name; slugified into the Site id unless `id` is given.'),
|
|
72
|
+
...newSiteFields,
|
|
61
73
|
business_description: z.string().min(1).describe('What the business does, for whom, and what sets it apart.'),
|
|
62
74
|
},
|
|
63
|
-
handler: withErrorBoundary(async (args, { client }) => ok(await client.rootPost('sites/create-and-plan', args))),
|
|
75
|
+
handler: withErrorBoundary(async (args, { client }) => ok(await client.rootPost('sites/create-and-plan', definedFields(args)))),
|
|
64
76
|
},
|
|
65
77
|
];
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typeroll/mcp-server",
|
|
3
3
|
"mcpName": "io.github.Typeroll/typeroll",
|
|
4
|
-
"version": "0.45.
|
|
4
|
+
"version": "0.45.105",
|
|
5
5
|
"description": "Typeroll CMS MCP server \u2013 connect AI agents to the REST API to manage content and publish static websites.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -121,6 +121,14 @@ desktop 1280, wide 1536); do not independently hide all links at the menu bounda
|
|
|
121
121
|
Verify 1023/1024 px, Tab/Shift-Tab, Enter/Space, Escape returning focus,
|
|
122
122
|
visible focus, long labels, no-JavaScript links and no horizontal overflow.
|
|
123
123
|
|
|
124
|
+
To divide the mobile panel into groups, put one `core/navigation_links` per
|
|
125
|
+
group in the second slot and give each a `group_label` (render version 13),
|
|
126
|
+
for example `"group_label": "Product"`. The label is shown above the links,
|
|
127
|
+
names the list for screen readers and takes the site's Eyebrow style (or
|
|
128
|
+
`group_label_style_id`). Do not insert Text blocks or headings as group titles
|
|
129
|
+
or style them with site CSS. Read `read_site_settings` → `render.version`
|
|
130
|
+
first; below 13, raise it with `tr-upgrade-rendering`.
|
|
131
|
+
|
|
124
132
|
Each entry in `links` (`core/navigation_links` and `core/navigation`) may set
|
|
125
133
|
`link_rel`, for example `nofollow sponsored` on an affiliate or partner link.
|
|
126
134
|
A `core/tabs` choice with a direct `href` accepts `link_rel` and `new_tab` too,
|
|
@@ -100,10 +100,10 @@ you when you're done, and it stops you discovering an untouched 400-URL blog
|
|
|
100
100
|
in week three.
|
|
101
101
|
|
|
102
102
|
For each source site, create the target site first (the inventory lives on
|
|
103
|
-
it):
|
|
103
|
+
it), in its language so `<html lang>` is right from the first build:
|
|
104
104
|
|
|
105
105
|
```
|
|
106
|
-
create_site name="Example DE"
|
|
106
|
+
create_site name="Example DE" id="example-de" language="de-DE"
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Then walk the source and post what you find:
|
package/skills/tr-responsive.md
CHANGED
|
@@ -212,6 +212,16 @@ when it is below 12, raise it with `tr-upgrade-rendering` instead of working
|
|
|
212
212
|
around it in content. Rows, and containers that become rows at some
|
|
213
213
|
breakpoint, are unchanged.
|
|
214
214
|
|
|
215
|
+
## Long words on small screens (render version 13)
|
|
216
|
+
|
|
217
|
+
From render version 13 (Core 0.2.140), a container that is a column at every
|
|
218
|
+
breakpoint keeps its children on one line, and Text and Heading blocks break
|
|
219
|
+
a word that does not fit. A long word, URL or inline code span then no longer
|
|
220
|
+
makes every child of the container, and the page, wider than a 375 px screen.
|
|
221
|
+
Below 13, raise the version with `tr-upgrade-rendering` instead of adding site
|
|
222
|
+
CSS such as `.intro > * { min-width: 0; max-width: 100% }`. Rows and
|
|
223
|
+
fixed-width children are unchanged.
|
|
224
|
+
|
|
215
225
|
## Native image framing and body heading scales (Core 0.2.35+)
|
|
216
226
|
|
|
217
227
|
Use `core/image.scale_percent` (100–200, responsive) for deliberate horizontal
|