bnomei/kirby-mcp
A CLI-first MCP server for Kirby CMS
Maintainers
Requires
- php: ^8.2
- firebase/php-jwt: ^7.0
- getkirby/cli: ^1.0
- guzzlehttp/psr7: ^2.8
- mcp/sdk: ^0.6.0
- symfony/finder: ^7.3
- symfony/process: ^7.0
- symfony/yaml: ^7.0
Requires (Dev)
- getkirby/cms: ^5.2
- larastan/larastan: ^3.0
- laravel/pint: ^1.26
- pestphp/pest: ^4.0
- pestphp/pest-plugin-type-coverage: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
MIT aa1203c65986c76602e7d5c2ca6017292c06b769
README
π Kirby 5
π PHP 8.2
π Release
π Downloads
π Unittests
π PHPStan
π Discord
π Buymecoffee
CLI-first MCP server for Composer-based Kirby CMS projects. It lets an IDE or agent inspect your Kirby project (blueprints, templates, plugins, docs) and interact with a real Kirby runtime. It ships with a local knowledge base of Kirby concepts and tasks. For agent-specific install steps (Claude Code, Codex CLI) and Skill sync, see Client setup.
It can also run as a projectless global reference MCP (kirby-mcp --global) for always-on Kirby docs/KB research. Global reference mode is intentionally separate from project-local MCP servers and cannot inspect, render, update, or run commands in a Kirby project.
Warning
Prompt injection is a serious security threat, especially when used with documents retrieved from the internet. You might not see it happen when observing the conversation with the agent!
Quickstart
From your Kirby project root:
composer require bnomei/kirby-mcp --dev vendor/bin/kirby-mcp install vendor/bin/kirby-mcp
This quickstart is for a local stdio MCP server. If you want Kirby to serve a production HTTP
/mcp route, install bnomei/kirby-mcp as a normal Composer dependency instead of --dev; see
HTTP transport below.
Then configure your MCP client (Cursor/Claude Code/Codex CLI) using the examples in Client setup and copy the bundled Skills as described below.
See Client setup β Claude Code and Client setup β Codex CLI for per-agent install and Skill sync steps.
Global Reference Mode
Install once with Composer and run the global reference MCP anywhere:
composer global require bnomei/kirby-mcp kirby-mcp --global
Use this mode for always-available Kirby research: bundled KB search, glossary, Panel field/section reference, hooks, extensions, update-schema guides, official docs search, and plugin directory search.
Global reference mode is projectless by design:
- It does not auto-detect or accept
--project. - It does not expose project/runtime tools such as
kirby_roots,kirby_info,kirby_render_page, content updates, eval/query, runtime install, or IDE helper generation. - If you need project context or mutations, add a separate project-local MCP server with
vendor/bin/kirby-mcp.
Copy-paste request examples
Use these once your MCP client is connected to the server.
Planning & content
Tip
"Use the Kirby MCP to make a plan to..." is a reliable way to get your agent to use the tools and resources this MCP server provides. If you ask it to take action, it tends to edit files directly based on its training and skills.
Use the Kirby MCP to make a plan to... build a contact form page.
kirby_roots, kirby_blueprint_read, kirby_templates_index, kirby_snippets_index, kirby_controllers_index, kirby_render_page, kirby_dump_log_tail, kirby://config/{option}
Show me the fields available on the home page blueprint and what they do using the MCP.
kirby_blueprint_read, kirby_blueprints_index
Show me the current content of the about page.
kirby_read_page_content
Append " with AI" to the title of the home page with Kirby MCP.
kirby_read_page_content, kirby_update_page_content, kirby://field/text/update-schema
Resource shortcuts
Tip
Either on its own or with a request, the resources can be used to quickly bring knowledge and runtime information into the current context of your agent.
kirby://glossary/collection
kirby://glossary/{term}
What is the kirby://config/debug for production?
kirby://config/{option}
Search & docs
Tip
The MCP server ships with a local knowledge base about Kirby. It consists of a glossary, common tasks, and update guides for content fields. This reduces the need to rely on external resources and is very fast.
kirby search for collection filtering
kirby_search
Tip
But sometimes you or your agent needs to dig deeper. That is why the MCP server also provides a fallback to the official Kirby search and docs (not including the forum). You can trigger it by mentioning search online in your request.
kirby search online for panel permissions
kirby_online
Tip
When you need to discover third-party plugins, you can also search the official Kirby plugin directory and fetch details from each plugin page.
kirby search plugins online for e-commerce cart
kirby_online_plugins
Tip
Your agent will use the next tool under the hood itself, but you can use it as well to quickly check what the MCP server knows about a given topic.
What mcp tool should I use to... list plugins?
kirby_tool_suggest
Inventory (runtime + filesystem)
list blueprints, templates, snippets, collections, controllers, models, plugins, routes, roots
kirby_blueprints_loaded, kirby_blueprints_index, kirby_templates_index, kirby_snippets_index, kirby_collections_index, kirby_controllers_index, kirby_models_index, kirby_plugins_index, kirby_routes_index, kirby_roots
Debug, tinker/eval and running commands
Important
The kirby_eval tool is disabled by default and CLI commands are protected by an allowlist/denylist, see config and security below.
kirby MCP tinker $site->index()->count()
kirby_eval
kirby MCP check query site.find('notes').unlisted.count
kirby MCP check query page.siblings.count (model: notes)
kirby_query_dot
run kirby cli command uuid:populate
kirby_run_cli_command
My home page renders incorrectly. Help me debug it with mcp_dump() to return the current $page object.
kirby_render_page, kirby_dump_log_tail, kirby_templates_index, kirby_snippets_index, kirby_controllers_index, kirby_models_index
Capabilities
[!INFO]
kirby_initis required once per session before calling any other tool or resource but the agent should figure this out automatically. Some capabilities require the runtime wrappers because they query Kirby at runtime. Installing/updating them should happen automatically as well.
At initialization, the server tells the agent which tools/resources to use. The knowledge base cross-references them so the agent can find the next step.
Current inventory: 37 tools, 15 resources, 15 resource templates, 216 KB articles.
In global reference mode (kirby-mcp --global), the exposed surface is intentionally smaller: kirby_init, kirby_search, kirby_online, kirby_online_plugins, kirby_tool_suggest, and static reference resources/templates (kirby://kb, glossary, fields/sections, hooks, extensions, and update schemas).
Skills
Bundled Skills live in vendor/bnomei/kirby-mcp/skills after installation. Copy them into your agentβs local skills folder using the Client setup instructions below.
kirby-project-tourβ Project inventory and orientation (roots, blueprints, plugins) with next-step recommendations.kirby-content-migrationβ Safe content migrations with runtime read/update tools and update schemas.kirby-scaffold-page-typeβ Scaffold a page type (blueprint + template + optional controller/model) using project conventions.kirby-routing-and-representationsβ Custom routes, redirects, and content representations (.json/.xml/.rss).kirby-collections-and-navigationβ Listings, pagination, search, filtering/sorting/grouping, and navigation menus.kirby-panel-and-blueprintsβ Blueprint design, Panel UX,extends, and custom areas/fields/sections.kirby-plugin-developmentβ Reusable plugins with hooks/extensions, KirbyTags, blocks, and shared controllers/templates.kirby-headless-apiβ Headless API setup with Kirby API, KQL, and JSON representations.kirby-i18n-workflowsβ Language config, translation keys, localized labels, and import/export workflows.kirby-security-and-authβ Login/roles/permissions, access restriction, and protected downloads.kirby-performance-and-mediaβ Cache tuning, CDN/media routing, responsive images, and lazy loading.kirby-debugging-and-tracingβ Render reproduction, runtime tracing withmcp_dump, and code-path discovery.kirby-ide-supportβ IDE helper status plus minimal PHPDoc/type-hint improvements.kirby-upgrade-and-maintenanceβ Safe Kirby upgrades with composer audit, plugin checks, and verification.kirby-forms-and-frontend-actionsβ Contact forms, uploads, emails, and frontend page creation with validation/CSRF.
Client setup
Note
The --project flag is optional when you run the server from the Kirby project root.
Use it (or KIRBY_MCP_PROJECT_ROOT) only for project-local MCP servers that should inspect a specific Kirby project.
Command-based stdio is the default and recommended setup for local IDE/agent use.
kirby-mcp --global is a separate projectless reference server and must not be combined with --project.
Cursor
Add to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"kirby-reference": {
"command": "kirby-mcp",
"args": ["--global"]
},
"kirby-project": {
"command": "/absolute/path/to/kirby-project/vendor/bin/kirby-mcp"
}
}
}
Use kirby-reference for docs/KB research that is always available. Use kirby-project only when that specific Kirby project should be inspectable or mutable.
Claude Code
From the Kirby project directory:
claude mcp add kirby -- vendor/bin/kirby-mcp
Global reference server:
claude mcp add kirby-reference -- kirby-mcp --global
Or explicitly:
claude mcp add kirby -- vendor/bin/kirby-mcp --project=/absolute/path/to/kirby-project
Copy bundled Skills (personal scope):
mkdir -p ~/.claude/skills rsync -a vendor/bnomei/kirby-mcp/skills/ ~/.claude/skills/
Restart Claude Code after copying (use .claude/skills/ instead for repo-scoped skills).
Codex CLI
From the Kirby project directory:
codex mcp add kirby -- vendor/bin/kirby-mcp
Global reference server:
codex mcp add kirby-reference -- kirby-mcp --global
Or explicitly:
codex mcp add kirby -- vendor/bin/kirby-mcp --project=/absolute/path/to/kirby-project
Copy bundled Skills (user scope):
mkdir -p ~/.codex/skills rsync -a vendor/bnomei/kirby-mcp/skills/ ~/.codex/skills/
Restart Codex CLI after copying.
Manual
Start the server (point it at a composer-based Kirby project):
- From the Kirby project root:
vendor/bin/kirby-mcp - Or explicitly:
vendor/bin/kirby-mcp --project=/absolute/path/to/kirby-project - Or as the projectless global reference server:
kirby-mcp --global
HTTP transport (optional)
HTTP is disabled by default. vendor/bin/kirby-mcp continues to run stdio unless you add the Kirby
route and set "http.enabled": true in .kirby-mcp/mcp.json or environment variables.
Note
Remote HTTP follows the standard MCP pattern: HTTPS /mcp, Bearer/OAuth auth, and MCP metadata
discovery. Claude Code and Claude Desktop/Claude.ai custom connectors are the primary tested
targets. Other MCP-compatible clients may work if they support remote HTTP MCP and the configured
auth mode. OpenAI/ChatGPT uses MCP through Responses API tools and ChatGPT Apps/MCP Apps, not the
Claude custom-connector URL flow documented here.
Use one auth mode:
| Mode | Use for |
|---|---|
shared-token |
Local loopback development with a client on the same host. |
remote-token |
Public HTTPS routes for clients that can send Bearer tokens. |
oauth |
Claude Desktop/Claude.ai custom connectors or OAuth clients. |
For a Kirby route, install this package as a production dependency:
composer require bnomei/kirby-mcp
Do not install it with composer require --dev if your /mcp route should work in production;
the production PHP runtime must be able to autoload Bnomei\KirbyMcp\Mcp\KirbyMcpRoutes.
Add these routes to your Kirby config, usually site/config/config.php:
<?php use Bnomei\KirbyMcp\Mcp\KirbyMcpRoutes; return [ 'routes' => [ ...KirbyMcpRoutes::routes(), ], ];
If your config already defines routes, spread these entries into the existing routes array
instead of replacing it. No special Nginx location or vendor/bin/kirby-mcp proxy is required.
The route helper adds /mcp plus the optional OAuth metadata, registration, authorize/token, JWKS,
and login routes. If you change http.path, pass the same path to the route helper:
'routes' => [ ...KirbyMcpRoutes::routes('/custom-mcp'), ],
If you also change the built-in OAuth provider path, pass it as a named argument:
'routes' => [ ...KirbyMcpRoutes::routes('/custom-mcp', oauthPath: '/custom-mcp/oauth'), ],
Put the JSON examples below in your Kirby projectβs MCP config file:.kirby-mcp/mcp.json.
Warning
All /mcp requests require Authorization: Bearer ...; query-string credentials are rejected.
Public route requests require HTTPS, requests with an Origin header must match
http.allowedOrigins, and every operation is scope-checked. If the route is registered but
http.enabled is false, it returns 404.
Local loopback token
Use shared-token only for local development from the same machine:
{
"http": {
"enabled": true,
"path": "/mcp",
"allowedOrigins": ["http://127.0.0.1:3000"],
"auth": {
"mode": "shared-token",
"token": "replace-with-a-long-random-secret",
"scopes": ["kirby-mcp:read", "kirby-mcp:runtime", "kirby-mcp:write", "kirby-mcp:execute", "kirby-mcp:admin"]
}
}
}
The Kirby route rejects shared-token requests unless PHP reports REMOTE_ADDR as loopback and the request host is a real loopback host (localhost, ::1, or a valid IPv4 literal in 127.0.0.0/8).
Remote bearer token (recommended)
Use remote-token for public HTTPS routes when the client can send a static Bearer token:
{
"http": {
"enabled": true,
"path": "/mcp",
"allowedOrigins": [],
"auth": {
"mode": "remote-token",
"tokens": [
{
"id": "claude-code",
"hash": "sha256:replace-with-sha256-token-hash",
"scopes": ["kirby-mcp:read", "kirby-mcp:runtime", "kirby-mcp:write", "kirby-mcp:execute", "kirby-mcp:admin"]
}
]
}
}
}
Local CLI clients usually send no Origin header, so omit allowedOrigins or leave it empty. Add
exact origins only for browser or webview clients that send Origin, for example
http://localhost:5173.
Generate the token hash:
php -r 'echo "sha256:" . hash("sha256", $argv[1]) . PHP_EOL;' 'replace-with-a-long-random-secret'
Or provide the raw token through the environment:
KIRBY_MCP_HTTP_AUTH_MODE=remote-token KIRBY_MCP_HTTP_REMOTE_TOKEN=replace-with-a-long-random-secret KIRBY_MCP_HTTP_REMOTE_TOKEN_ID=claude-code KIRBY_MCP_HTTP_REMOTE_TOKEN_SCOPES=kirby-mcp:read,kirby-mcp:runtime
Use OAuth instead for Claude Desktop/Claude.ai custom connectors.
OAuth auth (for Claude Desktop/Ai)
Use oauth for Claude Desktop/Claude.ai custom connectors. No separate OAuth server package is
required for the built-in Claude flow.
- Register
KirbyMcpRoutes::routes(). - Enable the config below.
- Add a Claude custom connector with MCP server URL
https://example.com/mcp. - Add the consent snippet only if you want a custom approval screen.
{
"http": {
"enabled": true,
"path": "/mcp",
"allowedOrigins": ["https://claude.ai"],
"auth": {
"mode": "oauth",
"scopes": ["kirby-mcp:read", "kirby-mcp:runtime", "kirby-mcp:write", "kirby-mcp:execute", "kirby-mcp:admin"]
},
"oauthProvider": {
"enabled": true,
"path": "/mcp/oauth",
"consent": "snippet",
"role": "admin"
}
}
}
With oauthProvider.enabled=true, the route derives issuer, audience/resource, and JWKS URL from
the incoming HTTPS request unless you set http.auth.issuer, http.auth.audience, or
http.auth.jwksUri. Provider state is stored under .kirby-mcp/oauth, not in Kirby cache.
Important
Consent defaults to snippet. A logged-in Kirby user must approve or deny the client before Claude
gets a token. If the user is not logged in, Kirby MCP stores the authorize request under
.kirby-mcp/oauth/sessions, redirects through /mcp/oauth/login, and resumes the OAuth flow
after login. Use auto only for trusted private deployments.
For a custom approval screen, create a new snippet. The default snippet name is kirby-mcp/oauth-consent, which maps to site/snippets/kirby-mcp/oauth-consent.php in a Kirby project. The snippet receives client, scopes, user, approveUrl, denyUrl, and error:
<?php $clientName = (string) ($client['client_name'] ?? $client['client_id'] ?? 'OAuth client'); $userEmail = (string) ($user?->email() ?? 'Kirby user'); ?> <?php if ($error !== null): ?> <p><?= esc((string) $error) ?></p> <?php endif ?> <form method="post" action="<?= esc((string) $approveUrl, 'attr') ?>"> <h1>Authorize <?= esc($clientName) ?></h1> <p><?= esc($userEmail) ?></p> <ul> <?php foreach ($scopes as $scope): ?> <li><?= esc((string) $scope) ?></li> <?php endforeach ?> </ul> <input type="hidden" name="csrf" value="<?= esc((string) csrf(), 'attr') ?>"> <button type="submit" name="approve" value="1">Approve</button> <button type="submit" name="deny" value="1" formaction="<?= esc((string) $denyUrl, 'attr') ?>">Deny</button> </form>
The snippet must submit POST back to the provided authorize URL, include a csrf field generated
by Kirby's csrf() helper, and submit either approve=1 or deny=1.
Custom OAuth/OIDC issuer
If you already have, or want to build, a separate OAuth/OIDC authorization server, keep
oauthProvider.enabled false and configure the issuer, audience/resource, and JWKS URI yourself:
{
"http": {
"enabled": true,
"path": "/mcp",
"allowedOrigins": ["https://client.example"],
"auth": {
"mode": "oauth",
"issuer": "https://auth.example.test",
"audience": "https://example.test/mcp",
"jwksUri": "https://auth.example.test/.well-known/jwks.json",
"scopes": ["kirby-mcp:read", "kirby-mcp:runtime", "kirby-mcp:write", "kirby-mcp:execute", "kirby-mcp:admin"]
}
}
}
OAuth mode validates JWT access tokens by issuer, audience/resource, JWKS signature, expiry, and
operation scopes. Kirby MCP validates the resulting JWTs for this mode; it does not run your custom
authorization server for you. A package such as league/oauth2-server can be useful if you build
that issuer yourself, but it is not used by the built-in Claude OAuth provider.
HTTP tokens are scope-checked per operation. Available scope names are:
kirby-mcp:readfor read-only tools and resources.kirby-mcp:runtimefor runtime inspection that executes Kirby CLI wrappers.kirby-mcp:writefor content/file/user/site mutations, still requiring confirmation.kirby-mcp:executefor query/eval-style operations, still requiring enablement and confirmation.kirby-mcp:adminfor administrative runtime actions.
Composer installs the HTTP/JWT runtime libraries needed by Kirby MCP itself as direct package
dependencies; upgrading this package is enough for consumers unless your deployment pins Composer
with --no-update.
IDE helpers (optional, for humans)
The agent can both check and generate IDE helpers for your project: kirby_ide_helpers_status and kirby_generate_ide_helpers. You can also use the CLI commands yourself.
- Check baseline + freshness:
vendor/bin/kirby-mcp ide:status(use--detailsand--limit=Nfor more output) - Generate regeneratable helper files:
vendor/bin/kirby-mcp ide:generate(default is--dry-run; add--writeto create files) - JSON output:
--json(MCP markers) or--raw-json(plain JSON)
What the MCP server does (and doesnβt)
- Provides MCP tools/resources for project inspection (blueprints, templates/snippets/collections, controllers/models, plugins, routes, roots).
- Fetches official Kirby reference docs and ships a local Markdown knowledge base (
kb/) for fast lookups. - Doesnβt modify your content by default; write-capable actions run by the MCP are guarded and require explicit opt-in/confirmation. But your agent still can do whatever you allow it to!
- Only supports composer-based Kirby projects (Kirby CLI is used for many capabilities).
Security model
kirby_run_cli_commandis guarded by an allowlist; extend it via.kirby-mcp/mcp.json(cli.allow,cli.allowWrite) and block viacli.deny.- Write-capable actions require explicit opt-in (e.g.
allowWrite=trueorconfirm=true, depending on the tool). kirby_evalis disabled by default; enable viaKIRBY_MCP_ENABLE_EVAL=1or.kirby-mcp/mcp.json({"eval":{"enabled":true}}) and still requires per-call confirmation (confirm=trueor client-side elicitation).kirby_query_dotis enabled by default; disable via.kirby-mcp/mcp.json({"query":{"enabled":false}}) and still requires per-call confirmation (confirm=trueor client-side elicitation).- HTTP transport is disabled by default and must never be exposed without Bearer-token authorization.
- HTTP shared-token auth is limited to local development. Keep the token outside source control; the Kirby route rejects shared-token requests when
REMOTE_ADDRis not loopback or the request host is not a real loopback host. - HTTP remote-token auth is explicit public bearer-token auth for header-capable clients. Store hashes in config, keep raw tokens in environment/secret storage, require HTTPS for non-loopback route requests, and scope tokens tightly.
- OAuth remains the preferred production path for clients that need an interactive auth flow, including Claude Desktop and Claude.ai custom connectors. The optional built-in provider is disabled by default and writes only to
.kirby-mcp/oauth. - HTTP validates
Originbefore MCP protocol handling and rejects missing, malformed, expired, invalid, or insufficient-scope tokens before tool/resource side effects. - HTTP exposes only the configured MCP route path,
/mcpby default, for MCP traffic.
What install / update change in your project
vendor/bin/kirby-mcp install:
- Creates
.kirby-mcp/mcp.jsonif neither.kirby-mcp/mcp.jsonnor.kirby-mcp/config.jsonexist. - Copies runtime command wrappers into the projectβs Kirby commands root (usually
site/commands/mcp/). - Use
--forceto overwrite existing wrapper files.
vendor/bin/kirby-mcp update:
- Overwrites the runtime wrappers (use after upgrading this package).
- Creates
.kirby-mcp/mcp.jsononly if missing; it wonβt overwrite an existing config.
To remove everything:
- Delete the runtime wrappers folder (
site/commands/mcp/in most projects). - Optionally delete
.kirby-mcp/(config + caches + optional helper files).
Debug dumps (mcp_dump)
This package provides a lightweight mcp_dump() helper that appends JSONL to .kirby-mcp/dumps.jsonl in the project root.
Secret redaction: By default, dump output is scanned for sensitive data (API keys, tokens, passwords, IPs) and redacted before writing. This protects against accidentally leaking secrets. Configure via dumps.secretPatterns in .kirby-mcp/mcp.json:
{
"dumps": {
"secretPatterns": []
}
}
- Omit
secretPatternsβ use built-in patterns (OpenAI/Anthropic/GitHub/Stripe/AWS keys, JWTs, Bearer tokens, IPs, etc.) - Set to
[]β disable redaction entirely - Set to
["/pattern1/", "/pattern2/"]β use only your custom regex patterns
Typical workflow for your coding agent:
- Add
mcp_dump($anything)(optionally chain->green(),->label('...'),->caller(),->trace(),->pass($value)) anywhere in templates/snippets/controllers. - Call
kirby_render_page(it returns atraceId). - Call
kirby_dump_log_tail(traceId=...)to retrieve the captured dump events for that render.
Configuration
Project config lives in .kirby-mcp/mcp.json (or .kirby-mcp/config.json) in the Kirby project root.
It is created by vendor/bin/kirby-mcp install if missing.
Kirby host selection:
- By default, Kirby CLI runs with no
KIRBY_HOSToverride. - To use host-specific Kirby config, set
KIRBY_MCP_HOST(orKIRBY_HOST) when starting the MCP server, or setkirby.hostin.kirby-mcp/mcp.json:{"kirby":{"host":"localhost"}}
| Option | Type | Default | Description |
|---|---|---|---|
cache.ttlSeconds |
int |
60 |
In-memory cache TTL (seconds) for read-only resources like kirby://commands and kirby://cli/command/{command} plus a few internal caches (roots inspection, completions); set to 0 to disable caching. |
docs.ttlSeconds |
int |
86400 |
In-memory cache TTL (seconds) for fetched getkirby.com markdown docs (e.g. kirby://field/{type} and kirby://section/{type}); set to 0 to disable caching. |
cli.allow |
string[] |
[] |
Additional allowlist patterns for kirby_run_cli_command (supports * wildcard, e.g. plugin:*). |
cli.allowWrite |
string[] |
[] |
Additional allowlist patterns for write-capable commands; requires allowWrite=true when calling kirby_run_cli_command (supports *). |
cli.deny |
string[] |
[] |
Deny patterns that always block commands, even if allowlisted (supports *). |
dumps.enabled |
bool |
true |
Enable/disable mcp_dump() writes to .kirby-mcp/dumps.jsonl. |
dumps.maxBytes |
int |
2097152 |
Max size for .kirby-mcp/dumps.jsonl written by mcp_dump(). When the next write would exceed it, the log is compacted by keeping the newest half of lines, then the new entry is appended. |
dumps.secretPatterns |
string[] |
(defaults) | Regex patterns for secret redaction in dump logs. Omit to use defaults (API keys, tokens, IPs, etc.), set to [] to disable masking, or provide custom patterns. |
ide.typeHintScanBytes |
int |
16384 |
Max bytes to read from controller/model files when detecting Kirby IDE baseline type hints (see kirby_ide_helpers_status). |
kirby.host |
string |
null |
Default Kirby host to pass as KIRBY_HOST to the Kirby CLI (affects host-specific config like config.{host}.php). |
eval.enabled |
bool |
false |
Enable kirby_eval / kirby mcp:eval (still requires explicit confirmation per call). |
query.enabled |
bool |
true |
Enable kirby_query_dot / kirby mcp:query:dot (still requires explicit confirmation per call). |
http.enabled |
bool |
false |
Enable the optional Streamable HTTP MCP transport. Stdio remains the default when this is false or unset. |
http.host |
string |
127.0.0.1 |
Bind host for the low-level HTTP listener/config check. Shared-token mode requires a real loopback host; the Kirby route adapter separately rejects shared-token auth unless both REMOTE_ADDR and the request host are loopback. |
http.port |
int |
8765 |
Bind port for the low-level HTTP listener/config check. The Kirby route adapter does not use this field. |
http.path |
string |
/mcp |
Single MCP endpoint path for Streamable HTTP requests. Match this with the copied Kirby route pattern. |
http.allowedOrigins |
string[] |
[] |
Allowed browser origins for HTTP mode. Configure the exact client origins you expect. |
http.auth.mode |
string |
null |
Required when HTTP is enabled: oauth for JWT validation, remote-token for public bearer-token clients that can send headers, or shared-token for loopback local development. |
http.auth.token |
string |
null |
Shared-token secret for local development. Prefer KIRBY_MCP_HTTP_TOKEN so secrets stay out of source control. |
http.auth.tokens |
array |
[] |
Remote-token records for remote-token mode. Each record needs id, hash (sha256:<64-hex>), and optional per-token scopes. |
http.auth.issuer |
string |
null |
OAuth issuer expected in JWT access tokens. |
http.auth.audience |
string |
null |
OAuth audience/resource expected in JWT access tokens, usually the MCP resource URL. |
http.auth.jwksUri |
string |
null |
OAuth JWKS URI used to verify access-token signatures. |
http.auth.scopes |
string[] |
[] |
Accepted operation scopes such as kirby-mcp:read, kirby-mcp:runtime, kirby-mcp:write, kirby-mcp:execute, and kirby-mcp:admin. |
http.oauthProvider.enabled |
bool |
false |
Enable the built-in OAuth authorization server for Claude Desktop/Claude.ai custom connectors. |
http.oauthProvider.path |
string |
/mcp/oauth |
Built-in OAuth provider route prefix. Match this with the fourth argument to KirbyMcpRoutes::routes() if you customize it. |
http.oauthProvider.consent |
string |
snippet |
Consent mode: snippet, always, remember, or auto. auto skips explicit consent for logged-in Kirby users and should only be used for trusted private deployments. |
http.oauthProvider.consentSnippet |
string |
kirby-mcp/oauth-consent |
Kirby snippet used when consent is snippet. |
http.oauthProvider.role |
string |
admin |
Panel role required to authorize MCP OAuth clients. A logged-in user without this role is denied (access_denied), so low-privilege accounts cannot mint tokens. Use * to allow any authenticated Panel user (loopback/dev only). |
Environment variables:
| Env var | Description |
|---|---|
KIRBY_MCP_PROJECT_ROOT |
Project root (overrides auto-detection). |
KIRBY_MCP_KIRBY_BIN |
Path to vendor/bin/kirby (overrides binary resolution). |
KIRBY_MCP_PHP_BINARY |
PHP binary for wrapped Kirby CLI calls; useful when PHP_BINARY points to PHP-FPM. |
KIRBY_MCP_HOST / KIRBY_HOST |
Kirby host override (takes precedence over config). |
KIRBY_MCP_DUMPS_ENABLED |
Override dumps.enabled (1/0, true/false, on/off). |
KIRBY_MCP_ENABLE_EVAL |
Enable eval override (takes precedence over config; still needs confirmation). |
KIRBY_MCP_ENABLE_QUERY |
Enable query eval override (takes precedence over config; still needs confirmation). |
KIRBY_MCP_HTTP_ENABLED |
Enable optional HTTP transport (1/0, true/false, on/off). |
KIRBY_MCP_HTTP_HOST |
HTTP bind host for the low-level listener/config check; defaults to 127.0.0.1. |
KIRBY_MCP_HTTP_PORT |
HTTP bind port for the low-level listener/config check; defaults to 8765. |
KIRBY_MCP_HTTP_PATH |
HTTP MCP endpoint path; defaults to /mcp; match this with the Kirby route pattern. |
KIRBY_MCP_HTTP_ALLOWED_ORIGINS |
Comma-separated allowed origins for HTTP requests. |
KIRBY_MCP_HTTP_AUTH_MODE |
HTTP auth mode: oauth, remote-token, or shared-token. |
KIRBY_MCP_HTTP_TOKEN |
Shared-token bearer secret for loopback local development. |
KIRBY_MCP_HTTP_REMOTE_TOKEN |
Raw remote-token bearer secret for public HTTPS routes; prefer secret storage. |
KIRBY_MCP_HTTP_REMOTE_TOKEN_HASH |
Remote-token hash in sha256:<64-hex> format. |
KIRBY_MCP_HTTP_REMOTE_TOKEN_ID |
Remote-token identifier used in auth metadata; defaults to env. |
KIRBY_MCP_HTTP_REMOTE_TOKEN_SCOPES |
Comma-separated scopes for the environment remote token. |
KIRBY_MCP_HTTP_OAUTH_ISSUER |
OAuth JWT issuer. |
KIRBY_MCP_HTTP_OAUTH_AUDIENCE |
OAuth JWT audience/resource. |
KIRBY_MCP_HTTP_OAUTH_JWKS_URI |
OAuth JWKS URI for JWT signature validation. |
KIRBY_MCP_HTTP_OAUTH_PROVIDER_ENABLED |
Enable the built-in OAuth provider (1/0, true/false, on/off). |
KIRBY_MCP_HTTP_OAUTH_PROVIDER_PATH |
Built-in OAuth provider route prefix; defaults to /mcp/oauth. |
KIRBY_MCP_HTTP_OAUTH_PROVIDER_CONSENT |
Built-in OAuth provider consent mode: auto, remember, always, or snippet. |
KIRBY_MCP_HTTP_OAUTH_PROVIDER_CONSENT_SNIPPET |
Kirby snippet used when provider consent mode is snippet. |
KIRBY_MCP_HTTP_SCOPES |
Comma-separated accepted operation scopes. |
Troubleshooting
- βUnable to determine Kirby project rootβ: run from the Kirby project root or pass
--project=/absolute/path(or setKIRBY_MCP_PROJECT_ROOT). - Runtime-only tools fail: run
vendor/bin/kirby-mcp installand checkkirby_runtime_status. - CLI command blocked: add patterns to
.kirby-mcp/mcp.json(cli.allow/cli.allowWrite) or block withcli.deny. - Runtime CLI commands fail behind PHP-FPM with exit code 126: set
KIRBY_MCP_PHP_BINARYto the PHP CLI binary path, e.g./opt/php-x.x/bin/php. - Host-specific config not applied: set
KIRBY_MCP_HOST/KIRBY_HOSTor configure{"kirby":{"host":"..."}}. - Docs resources are slow/failing: confirm network access or adjust
docs.ttlSeconds(set to0to disable caching). - No dump output: ensure
dumps.enabled=true, a.kirby-mcp/dumps.jsonlexists, and use the correcttraceIdwithkirby_dump_log_tail. - HTTP client gets 401/403: confirm Bearer auth, token audience/resource, scopes, and
Originmatch the configured HTTP settings. - Claude custom connector cannot connect: confirm the public URL is the MCP endpoint (
https://example.com/mcp), the route helper is registered,http.enabled=true,http.auth.mode=oauth,http.oauthProvider.enabled=true, and non-loopback requests reach Kirby over HTTPS.
Development
- Install deps:
composer install - Run tests:
composer test - Run static analysis:
composer analyse
Disclaimer
This MCP server is provided "as is" with no guarantee. Use it at your own risk and always test it yourself before using it in a production environment. If you find any issues, please create a new issue.
License
It is discouraged to use this MCP server in any project that promotes racism, sexism, homophobia, animal abuse, violence or any other form of hate speech.
