@tuskcms/mcp
A Model Context Protocol server for Tusk CMS. Connect Claude Code or Codex to a Tusk studio and manage sites headlessly — create a site, learn its schema, scan pages into editable fields, publish, check the deploy — without clicking through the dashboard. It is the fast path that complements the public guide at https://tuskcms.com/llms-full.txt.
Every tool is a thin call to an existing Tusk REST endpoint, authenticated with a personal access token. Tusk stays the single source of truth; this server adds no business logic of its own.
Install
Until this package is published to npm, run it from the repo:
cd packages/tusk-mcp
pnpm install
pnpm build
That gives you a runnable CLI at packages/tusk-mcp/bin/tusk-mcp.mjs. Once published you will be able to npx @tuskcms/mcp instead.
Log in (the bootstrap flow)
The server authenticates with a token that begins tusk_pat_…. You never type or paste it: pair the machine in your browser, and the CLI collects the token for you.
node bin/tusk-mcp.mjs login
This prints a URL and a short pairing code:
Open this URL in a browser where you are signed in to Tusk, and approve:
https://tuskcms.com/api/studio/pat/pair?code=ABCD-EF23
(pairing code ABCD-EF23)
Waiting for approval …
Open the URL in a browser where you are already signed in to Tusk as your studio, click Approve, and the CLI receives the freshly minted token and saves it to a credentials file with owner-only permissions:
- macOS/Linux:
~/.config/tusk/credentials.json
- Windows:
%APPDATA%\tusk\credentials.json
Confirm it worked:
node bin/tusk-mcp.mjs whoami
node bin/tusk-mcp.mjs logout
Least privilege: bind the token to one site (recommended)
To connect a single site, pair a token that can act on only that site:
node bin/tusk-mcp.mjs login --site my-site --scopes scan,fields,content,publish,deploy
The browser approval screen then shows exactly what you are granting — the one site, and the listed actions — and states plainly that it does not create or change your website. A token minted this way can reach that one site and no other, and can only do the actions it names (a token without publish can't publish, without deploy can't rotate the build token, and none of them can mint another token). It can never touch your code or hosting on its own.
Capabilities: read, scan, fields, content, publish, deploy, tokens. A full connect uses scan,fields,content,publish,deploy.
Omit --site for a studio-wide token (able to edit and publish every site in your studio) — the default. Either way the token only ever does what a signed-in studio member can do, and you can revoke it any time with the revoke_token tool, from the dashboard, or by pairing a replacement.
Configuration (env)
TUSK_URL | https://tuskcms.com | The Tusk instance to talk to. |
TUSK_PAT | — | An access token, if you would rather pass it than run login. |
TUSK_CONFIG_DIR | OS default (see above) | Where the credentials file is read/written. |
Precedence: an explicit flag/env value wins over the saved credentials file. If you set TUSK_PAT, you do not need to run login.
Add it to Claude Code
Add a server to your project's .mcp.json (adjust the path to wherever this package lives):
{
"mcpServers": {
"tusk": {
"command": "node",
"args": ["./packages/tusk-mcp/bin/tusk-mcp.mjs", "serve"],
"env": { "TUSK_URL": "https://tuskcms.com" }
}
}
}
The saved credentials file supplies the token, so it stays out of .mcp.json. If you prefer an explicit token instead of login, add "TUSK_PAT": "tusk_pat_…" to env (and keep that file out of git).
Add it to Codex
In ~/.codex/config.toml:
[mcp_servers.tusk]
command = "node"
args = ["/abs/path/to/packages/tusk-mcp/bin/tusk-mcp.mjs", "serve"]
env = { TUSK_URL = "https://tuskcms.com" }
Tools
whoami | The studio user this token belongs to, and the sites it can see. Call first. |
list_sites | Every site in the studio with slug, domain, pages, clients, publish/deploy state. |
create_site | Create a site (name required; domain, previewUrl, deployHook recommended). |
get_site | Full detail for one site: pages, fields, clients, project, files, invoices, events. |
get_setup | The connection checklist and the next step to do. |
get_schema | The site's editable schema (pages, fields, binds). |
get_instruction | A connect instruction tailored to this site (build token, pull, apply). |
get_connect_guide | The public integration guide (the data-tusk grammar). No token needed. |
scan_site | Scan live page URLs to discover editable content into the schema. |
save_fields | Define or curate a site's fields by hand. |
rotate_build_token | Rotate the site's build token (for @tuskcms/sdk / tusk pull). Returned once. |
publish | Publish pages, write the snapshot, and (in hook mode) trigger the host rebuild. |
deploy_status | Where the host's rebuild stands after a publish. |
list_tokens | This studio's access tokens (labels + masked previews only). |
create_token | Mint another access token (for a CI job or a second machine). Returned once. |
revoke_token | Revoke an access token by id, effective immediately. |
Two different secrets, easily confused: the access token (tusk_pat_…) authenticates this MCP server as a studio member; the build token from rotate_build_token is what a build passes to @tuskcms/sdk to fetch the published snapshot. rotate_build_token returns the build token, not the access token.
Connect a site end to end
A recipe an agent can follow with these tools: whoami to confirm the token → get_connect_guide to learn the data-tusk grammar → create_site with the live domain and a reachable previewUrl → scan_site on the site's page URLs to pull its text and images into an editable schema → get_schema (or get_setup) to review what became editable and what's left → publish to write the first snapshot → deploy_status to confirm the host rebuilt. Then rotate_build_token and follow get_instruction to wire the site's build to @tuskcms/sdk so it renders the published content.
Notes
- The access token is never printed or logged — only saved to the credentials file, and only ever sent in the
Authorization header.
serve writes nothing but MCP protocol to stdout; all human/diagnostic output goes to stderr, so it is safe as a stdio server.
- Local
pnpm build of the main Tusk app is unrelated; this package builds on its own with pnpm build (tsc -p .).