{"id":51666918,"url":"https://github.com/danielgnh/statamic-mcp","last_synced_at":"2026-07-14T21:01:09.668Z","repository":{"id":371150107,"uuid":"1294255465","full_name":"danielgnh/statamic-mcp","owner":"danielgnh","description":null,"archived":false,"fork":false,"pushed_at":"2026-07-13T17:05:46.000Z","size":575,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-13T18:20:54.428Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielgnh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-08T21:20:14.000Z","updated_at":"2026-07-13T17:05:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/danielgnh/statamic-mcp","commit_stats":null,"previous_names":["danielgnh/statamic-mcp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/danielgnh/statamic-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielgnh%2Fstatamic-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielgnh%2Fstatamic-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielgnh%2Fstatamic-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielgnh%2Fstatamic-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielgnh","download_url":"https://codeload.github.com/danielgnh/statamic-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielgnh%2Fstatamic-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35478764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-14T02:00:06.603Z","response_time":114,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-14T21:00:41.484Z","updated_at":"2026-07-14T21:01:09.625Z","avatar_url":"https://github.com/danielgnh.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Statamic MCP\n\n[![Latest Version](https://img.shields.io/packagist/v/danielgnh/statamic-mcp)](https://packagist.org/packages/danielgnh/statamic-mcp)\n[![Tests](https://github.com/danielgnh/statamic-mcp/actions/workflows/tests.yml/badge.svg)](https://github.com/danielgnh/statamic-mcp/actions/workflows/tests.yml)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)\n\nThis package presents a remote  **MCP server for Statamic v6**, which makes it possible to manage your content (entries,\ntaxonomy terms, globals, and assets) via any AI provider. Statamic's permission system is deciding\nwho may do what. Built on the first-party [`laravel/mcp`](https://laravel.com/docs/mcp) package.\n\n## Requirements\n\n- PHP ^8.3\n- Statamic ^6.0 (Laravel 12 or 13)\n- For OAuth mode only: `laravel/passport` + a database for Passport's own tables\n  (your users stay wherever they are — file users work)\n\n## Installation\n\n```bash\ncomposer require danielgnh/statamic-mcp\n```\n\nThat's it — no config publishing required.\n\nThe connected user needs the **Access MCP** permission (or super). Grant it in the\nControl Panel under the role's permissions — `mcp:token` warns you at issuance if\nthe user doesn't have it yet.\n\nPrefer a guided setup? One interactive command handles either auth mode — including\nevery OAuth prerequisite — and finishes by running `mcp:doctor` as proof:\n\n```bash\nphp please mcp:setup\n```\n\nIt's scriptable too — `--oauth --yes` (or `--token --user=you@site.com --yes`) runs\nunattended, which is what the bundled [Laravel Boost](https://laravel.com/docs/boost)\nguidelines teach AI coding agents to use. Boost users get them automatically on\n`boost:install`.\n\n## Token vs. OAuth mode\n\n| Client                                                  | Token mode                           | OAuth mode |\n|---------------------------------------------------------|--------------------------------------|------------|\n| Claude Code / Cursor                                    | ✅                                    | ✅          |\n| claude.ai / Claude Desktop connectors (individual plan) | ❌ no static headers                  | ✅          |\n| Claude Team/Enterprise connectors                       | ⚠️ org-admin-configured headers only | ✅          |\n| ChatGPT connectors                                      | ❌ OAuth or no-auth only              | ✅          |\n\n## What Statamic MCP can do?\n\n19 tools across five areas — every agent session is starting with `statamic_overview`,\nwhich reports the sites, resources, and capabilities visible to the acting user:\n\n- **Discovery** — `statamic_overview`, `blueprints_get` (fields + a valid example payload for writes)\n- **Entries** — `entries_list`, `entries_get`, `entries_create`, `entries_update`, `entries_delete`\n- **Taxonomy terms** — `terms_list`, `terms_get`, `terms_create`, `terms_update`, `terms_delete`\n- **Globals** — `globals_get`, `globals_update`\n- **Assets** — `assets_list`, `assets_get`, `assets_upload`, `assets_update`, `assets_delete`\n\nThe write semantics are deliberately conservative:\n\n- Entry creates and updates save **drafts by default** — agents draft, humans publish.\n- On revision-enabled collections, edits become **working copies** through the same\n  mechanism the CP uses; the live entry is never touched.\n- Delete tools aren't even registered unless you opt in (`deletes` config).\n- Every write response states the resulting liveness (\"saved as draft — not live\",\n  \"working copy created — live entry unchanged\", …) and links the CP edit page.\n\nSee **[docs/tools.md](docs/tools.md)** for the full per-tool reference, including\nupload limits and the SSRF policy for URL-based asset uploads.\n\n## Authentication\n\n### Token mode (default)\n\nWorks on **every** install, including file-based users. Tokens are stored\nSHA-256-hashed in `storage/statamic/mcp/tokens.yaml` — no database, no migrations —\nand shown exactly once at issuance. A token authenticates as the Statamic user it\nwas issued for; delete the user and the token dies with them.\n\n```bash\nphp please mcp:token you@site.com --name=\"Claude\" --expires-days=90   # issue\nphp please mcp:tokens                                                 # list\nphp please mcp:token:revoke {tokenId}                                 # revoke\n```\n\nUsers can also issue and revoke their own tokens in the Control Panel at\n**Tools → Utilities → MCP Access** — grant the **Access MCP Tokens utility**\npermission to enable it. Super admins see (and can revoke) everyone's tokens.\n\n### OAuth mode\n\nFor claude.ai, Claude Desktop, and ChatGPT connectors. Client registration, PKCE,\ndiscovery, and consent are delegated to `laravel/mcp` + Laravel Passport — and\n**your users stay exactly where they are, file users included**. The addon brings\nits own guard: bearers are validated by Passport's ResourceServer, and the token's\nuser resolves through the Statamic repository. No user migration, no `HasApiTokens`\ntrait, no `config/auth.php` edit. Passport just needs a database for its *own*\ntables (sqlite is fine) and its encryption keys.\n\nThe easy path is the wizard:\n\n```bash\nphp please mcp:setup\n```\n\nIt installs Passport, generates keys, flips `STATAMIC_MCP_AUTH=oauth`, and runs the\nmigrations (including the addon's user_id conversion — Statamic ids are UUIDs,\nPassport's stock columns are bigint) — never editing a file without showing the\nchange first. The manual steps, the deploy recipe (keys via `PASSPORT_PRIVATE_KEY` /\n`PASSPORT_PUBLIC_KEY` env vars), and the CP panel for viewing and disconnecting\nOAuth connections are in **[docs/oauth.md](docs/oauth.md)**.\n\nIf any prerequisite is missing, the MCP endpoint answers **503 with the exact\nremedy** — the rest of your site is untouched.\n\n## Configuration\n\n```bash\nphp artisan vendor:publish --tag=statamic-mcp-config   # → config/statamic/mcp.php\n```\n\n| Key                        | Default                            | What it does                                                                                                            |\n|----------------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------------|\n| `enabled`                  | `true` (`STATAMIC_MCP_ENABLED`)    | Kill switch. When `false` the MCP route is never registered.                                                            |\n| `route`                    | `mcp/statamic`                     | Where the streamable-HTTP endpoint mounts.                                                                              |\n| `auth`                     | `token` (`STATAMIC_MCP_AUTH`)      | `token` or `oauth`.                                                                                                     |\n| `middleware`               | `['throttle:60,1']`                | Prepended to the auth middleware on the MCP route. Plain Laravel.                                                       |\n| `read_only`                | `false` (`STATAMIC_MCP_READ_ONLY`) | Hides every write/delete tool from the server entirely.                                                                 |\n| `deletes`                  | `false` (`STATAMIC_MCP_DELETES`)   | Delete tools are not even registered unless `true`.                                                                     |\n| `resources`                | all `true`                         | Exposure allowlist per type: `true` = all handles, or an array like `'collections' =\u003e ['blog', 'pages']`.               |\n| `per_page`                 | `25`                               | Default page size for list tools (hard-capped at 100).                                                                  |\n| `uploads.max_size`         | `10240`                            | Per-upload cap in **kilobytes** for `assets_upload`.                                                                    |\n| `uploads.source_allowlist` | `null`                             | Exact-host allowlist for `assets_upload` URLs. `null` = any public host; private/reserved addresses are always blocked. |\n\n\u003e Upgrading from v1.0? Re-publish the config or add `'asset_containers' =\u003e true`\n\u003e to `resources` — a published config **without** the key exposes no containers\n\u003e (safe by default).\n\n## Security model: the token is the user\n\nThere are no API scopes and no parallel ACL. Every MCP request authenticates as a\nreal Statamic user, and authorization is always Statamic's native permission\nsystem — the same roles UI you already use:\n\n1. **Read-only switch** — `read_only` hides all write/delete tools.\n2. **Exposure allowlist** — `resources` decides what exists as far as MCP is concerned.\n3. **Native permissions on every call** — `view/edit/create/delete {handle} entries`\n   (and term/global equivalents), publish permissions for publish-state changes,\n   site permissions on multi-site. Denials name the missing permission and the remedy.\n4. **Deletes off by default** — both the config flag and the role permission must open.\n\nA restricted agent is just a dedicated Statamic user with a restricted role.\nReady-made recipes — drafting agent, read-only analyst, publishing agent, site\nscoping — are in **[docs/permissions.md](docs/permissions.md)**.\n\n## Troubleshooting\n\n```bash\nphp please mcp:doctor\n```\n\nOne command answers \"why doesn't my MCP endpoint work?\" — it runs every check\nwithout short-circuiting and names each problem with the exact remedy.\n\n| Response                       | Meaning                                                                               |\n|--------------------------------|---------------------------------------------------------------------------------------|\n| `401`                          | Missing, malformed, expired, or revoked token — deliberately identical in every case. |\n| `403` \"requires 'access mcp'…\" | Authenticated fine, but the user lacks the `Access MCP` permission.                   |\n| `503` + `remedy` (OAuth mode)  | An OAuth prerequisite is missing; the body names the exact fix.                       |\n| `404` on the endpoint          | MCP is disabled, or failed to mount — run `mcp:doctor`.                               |\n\nDetails on every doctor check, and the MCP Inspector, are in\n**[docs/troubleshooting.md](docs/troubleshooting.md)**.\n\n## Testing\n\n```bash\ncomposer test     # Pest\ncomposer format   # Pint\n```\n\n## License\n\nMIT — see [LICENSE.md](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielgnh%2Fstatamic-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielgnh%2Fstatamic-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielgnh%2Fstatamic-mcp/lists"}