MCP Prompts
MCP prompts are reusable, operator-authored templates that AI clients discover via prompts/list and invoke via prompts/get. Each prompt lives as an object in the mcp-prompt reserved collection. The body is a Twig template — the full cms.* function library is available alongside declared argument values.
Use prompts when you want to ship a starting workflow to an AI agent — a house-style blog scaffold, a brand-voice rewrite template, or a site-wide content audit outline. For data retrieval, use Saved-Query Tools instead.
| Prompts | Saved-Query Tools | |
|---|---|---|
| Returns | Rendered text (one user-role message) | Filtered collection data |
| AI agent uses it as | A starting point or instruction | A data query |
| Defined in | mcp-prompt collection | Collection schema MCP tab |
| Twig in body | Yes — full cms.* available | No |
Quick start
Section titled “Quick start”- In the admin, open MCP → Prompts and click Add Prompt.
- Fill in Name (snake_case, e.g.
draft_blog_post), Description, and Body. - Save. The prompt appears in
prompts/listimmediately — no rebuild, no restart.
Name: draft_blog_postDescription: Draft a new blog post in our house style.Body: Write a {{ args.tone | default('professional') }} blog post titled "{{ args.title }}". Use H2 subheadings, keep paragraphs under 5 sentences, and end with a call to action.Args: title (required), tone (optional)An AI client invokes it as:
{ "method": "prompts/get", "params": { "name": "draft_blog_post", "arguments": { "title": "10 Tips for Summer Photography", "tone": "conversational" } }}The server renders the Twig body with the supplied arguments and returns one user-role message.
Worked examples
Section titled “Worked examples”House-style scaffold
Section titled “House-style scaffold”Return a structured writing brief that matches editorial standards:
You are writing for {{ cms.config('displayName') }}.
Write a {{ args.format | default('long-form') }} article titled: {{ args.title }}
House rules:- Sentences: ≤ 25 words.- Tone: {{ args.tone | default('professional') }}.- Always include a tldr summary in the opening paragraph.- End with a bulleted "Key Takeaways" section.
Begin the article now.Args: title (required), format (optional), tone (optional).
Object-aware workflow
Section titled “Object-aware workflow”Pull live collection data into the prompt body using cms.object():
{% set post = cms.object(args.post_id, 'blog') %}You are editing an existing blog post.
Title: {{ post.title }}Published: {{ post.date }}Current body:{{ post.body | striptags }}
Rewrite the body in a {{ args.tone | default('professional') }} tone.Keep the same structure. Return only the rewritten body, no title.Args: post_id (required), tone (optional).
The agent passes the post’s ID; the prompt fetches the live record and injects it. Editors can trigger a rewrite by invoking prompts/get from Claude Desktop, Cursor, or any MCP client.
Site-wide aggregation
Section titled “Site-wide aggregation”Give the agent a cross-collection overview to answer high-level questions:
Site: {{ cms.config('displayName') }}Date: {{ "now" | date("Y-m-d") }}
Content summary:{% for collection in cms.collections %}- {{ collection.labelPlural }}: {{ collection.count }} objects{% endfor %}
Your task: {{ args.task }}
Focus on any content gaps, outdated objects (older than {{ args.months | default(6) }} months),or collections with fewer than 5 objects.Args: task (required), months (optional).
Twig context reference
Section titled “Twig context reference”The body template receives these variables at render time:
| Variable | Type | Notes |
|---|---|---|
args.* | string (or typed if declared) | Caller-supplied argument values. Only declared args are injected — undeclared keys are silently dropped. |
cms.* | object | Full T3 Twig adapter: cms.object(), cms.collection(), cms.config(), cms.collections, cms.env, etc. |
| Twig builtins | — | All Twig filters and functions: date, default, striptags, upper, for, if, etc. |
Arguments with required: true are validated before rendering. If a required argument is absent, the server returns a JSON-RPC error — the body template is never called.
Access model
Section titled “Access model”Each prompt has an Access setting:
| Setting | Who can call the prompt |
|---|---|
(inherit from collection) | Inherits the target collection’s MCP access. Blank targetCollection defaults to admin. |
Admin only | API-key authenticated callers only. |
Authenticated | OAuth Bearer token callers (and admin). |
Public | Anonymous AI agents (and all above). |
Persona enforcement runs at two points:
prompts/list— inaccessible prompts are filtered out entirely. A public caller never sees anadminprompt in the list.prompts/get— the handler re-checks access at call time. A caller who guesses an admin prompt name receives a JSON-RPC error, not the rendered content.
Argument declaration
Section titled “Argument declaration”Arguments declared in the Arguments card field are typed and validated:
| Field | Notes |
|---|---|
| Name | Snake_case (^[a-z][a-z0-9_]*$). Referenced in the body as {{ args.name }}. |
| Description | Shown to AI agents in the prompts/list response so they know what to pass. |
| Required | Toggle. Missing required args return a JSON-RPC error before the body renders. |
Optional arguments with no default in the body render as an empty string when absent. Use Twig’s default filter: {{ args.tone | default('professional') }}.
Only declared argument names are injected into the template context. Extra keys passed by the caller are silently dropped.
Code-defined prompts (extensions)
Section titled “Code-defined prompts (extensions)”Extensions can ship code-defined prompts alongside the collection-stored ones this page covers. They share the same prompts/list and prompts/get surface; the difference is authoring path — PHP in an extension vs. JSON object in the admin.
See Extending MCP → Registering code-defined prompts for the full guide: signature, when-to-use comparison vs. collection-stored, worked examples, access tiers, and collision policy.
ID field and snake_case
Section titled “ID field and snake_case”The id field on the mcp-prompt schema is readonly and auto-generated from the Name you enter. It follows the snakeCase ID setting — see ID Field for details. The name field is the canonical identifier AI clients use to call the prompt; keep it stable once published.
Limitations (v1)
Section titled “Limitations (v1)”- Single user-role message. Each prompt returns one
user-rolePromptMessage. Multi-turn scaffolds (system + user) are a v2 target. - Synchronous render. The body is rendered inline during
prompts/get. Long-runningcms.*calls (e.g. fetching many objects) block the response. Keep the body lightweight. - No per-prompt persona override. Access is set at the prompt level. Collection inheritance is coarse-grained — there is no field-level or argument-level access control.
- No listChanged push in v1. Clients that have called
prompts/listare not notified when a new prompt is added until they re-list (e.g. on reconnect).
Reference
Section titled “Reference”- MCP Server — personas, transport, core tool catalog, collection MCP settings.
- Saved-Query Tools — parameterised data queries; the right tool when you need filtered collection content rather than a workflow template.
- Extending MCP —
registerMcpPrompt()in the full context of the extension MCP API surface.