MCP Sentinel provides a security and governance layer for Drupal sites that allow AI agents to interact with content. It controls what AI agents can access, hides sensitive fields, logs all actions in a tamper-evident log, limits data retrieval, and protects content being edited by humans. It also includes a dashboard for monitoring these activities.
MCP Sentinel is the governance layer for Drupal sites that expose content to AI agents over the Model Context Protocol (MCP), JSON:API, and GraphQL. It decides what an agent may touch, hides what it must not see, records everything it does, and protects content people are editing — so you don't have to build that control yourself.
It sits on top of MCP Server and the Tool API and adds only the governance those projects leave to the site builder. It does not reimplement the protocol, OAuth, or the tool system.
How governance triggers. It applies to traffic on the validated OAuth agent channel — a designated consumer, or an agent scope on the request's token, checked server-side and never from a header. Your public frontend and your own cookie-session admin work are untouched. Each agent's role selects a policy profile, and every action is attributed to its account.
What it does not cover. A policy profile governs requests that reach Drupal through the MCP server's entity-API path. It cannot govern channels that bypass that API — raw SQL, most Drush commands, direct file access, or programmatic entity loads in custom code. drush sql:query is the clearest case: it declares a bootstrap ceiling below the level at which module command files are discovered, so no hook or policy check in any Drupal module can fire for it. That is a property of Drush, not a gap this module can close. The boundary for those paths is who can reach the host: shell and database credentials sit outside this module's threat model and must be controlled separately. Stating this makes the guarantee stronger, because it becomes checkable.
What it does
- Policy profiles per role — gates, redaction, limits, quotas, and IP rules live on a reusable config entity; the agent's role selects which profile applies.
- Operation gates — a master switch plus independent read, write, delete, and GraphQL-mutation toggles.
- Open-redirect guard — stop an agent from pointing a redirect off-domain (secure by default, with a per-profile host allowlist).
- Entity allow / deny lists — restrict agents to specific entity types, or block sensitive ones (users are blocked by default). Enforced through Drupal's own access system, so JSON:API and GraphQL honour it automatically.
- Field redaction — hide fields like
mailorpassfrom agent requests: stripped from JSON:API/REST, returned as[REDACTED]in GraphQL, and cached separately so nothing leaks across the boundary. - PII redaction (opt-in) — scan field values for emails, phone numbers, SSNs, and card numbers and mask the matches. A pattern may declare a classification label (2.11.0): a hit can only lower the egress ceiling, never raise or invent one.
- Audit log — every operation and GraphQL query recorded with user, IP, time, and payload metadata; filterable, exportable to CSV or JSON, with automatic retention pruning.
- Escape-hatch permission assertions — a profile declares permissions its governed roles must not hold (
bypass node access,administer usersand similar), so a role cannot quietly step around the policy it appears to be under. Violations surface on the status report and throughdrush mcp-sentinel:role-audit; deliberate grants are recorded in config asrole_id:permission, optionally scoped withrole_id:permission@environment(environment from$settings['mcp_sentinel.environment']in settings.php — never from exported config; fails closed when unset). - Governed raw SQL (opt-in, off by default) — where an agent genuinely needs to read with SQL,
drush mcp-sentinel:sql-queryruns it inside Drupal behind a fail-closed check, so deny lists, redaction and the audit chain still apply. Gated on a per-profileallow_raw_sqlflag that ships FALSE. - Tamper-evident trail — every entry is hash-chained (HMAC-SHA256 when keyed via a Key entity) by Audit Chain, so an inserted, deleted or edited row is detectable rather than merely discouraged.
drush audit-chain:verifychecks it. Optional at-rest encryption and SIEM streaming. - Change diffs — updates record which fields changed; redacted fields never enter the trail.
- Rate limits and quotas — throttle agent traffic per profile, keyed on the resolved user ID so one token can't saturate the server.
- Exfiltration guards — finite-by-default read budgets (2.7.0) cap result counts, response bytes, requests, and collection pages per window across Tool, JSON:API, and GraphQL responses, so neither a single call nor a pagination loop can bulk-export your content.
- Evidence-required actions — mark action classes (2.8.0) whose governed mutations execute only when their evidence can commit to the keyed audit chain: the precommit lands in the same transaction as the mutation so both are durable together or neither is, uncertain receipts are refused and reconciled instead of reported as success, and unkeyed logging never satisfies the class.
- Classification labels and egress ceilings — label data by configuration (2.9.0): an ordered site vocabulary assigned by entity type, bundle or field, plus a ceiling per policy profile for each governed surface — Tool, context, JSON:API, GraphQL and the governed drush SQL command. Data above a surface’s ceiling is refused or redacted before it leaves, with the stable code
classification_egress_deniedand bounded evidence that names labels, never values. A northbound declaration can only narrow a ceiling, never widen it. Ships inert: label nothing, set no ceilings, and no read decision changes. - Secure-install verifier —
drush mcp-sentinel:verifyproduces an evidence document that this install carries the secure, tenant-neutral floor (2.10.0). Posture checks always run.--liveadds hostile-input probes without writing content. A skipped check fails the run; residuals (prompt injection, operator trust) are recorded as managed. - Portable policy bundles — a versioned, HMAC-sealed artifact (2.11.0) that can be verified, activated (with last-known-good rollback), simulated, revoked, or used to arm emergency deny. Denials apply on the live access path since 2.12.0 — the entity, create, config and JSON:API-filter checks, the context schema document, GraphQL query and mutation gates, and the governed drush SQL command — refusing with the stable code
policy_bundle_denied. A bundle can only tighten: local deny cannot be widened by an upstream allow, an attested digest whose document will not verify (expired, revoked, tampered, or missing key) fails closed, and cached allows do not outlive the attested document's remaining TTL. Every audit row cites the attested digest when a bundle is active. - IP allowlisting — restrict agent connections to specific addresses or CIDR blocks (trusted-proxy aware).
- Anomaly detection — cron rules over the audit log raise alerts by log, email, or webhook, with per-rule debounce. Rules can fire on a count threshold, off-hours governed activity, or a complete/near-complete bulk read (2.11.0). No rules are enabled by default.
- Content locks — stop agents from overwriting content a person is editing, with TTL expiry.
- Webhooks — queue-backed, HTTPS-only, HMAC-signed delivery with retries, an SSRF guard, and one-click replay.
- Context endpoint —
/drupal-mcp/contextexposes your content model so agents can discover it before acting;/drupal-mcp/healthremains the public uptime probe; authenticatedGET /drupal-mcp/readinessreports whether the fail-closed governed source contract is ready (contract_readyplus a stable non-secret reason) without claiming policy effectiveness or overall posture, and anonymous callers are refused (403). - Governed Tool plugins — ready-made tools for content, media, workflow transitions, bulk actions, and schema discovery, each run through the same checks.
- Dashboard — a read-only console at
/admin/reports/mcp-sentinelwith posture, alerts, top agents, and denied-by-policy panels. The hero never reports all-clear until audit-chain evidence is verified (2.11.0).
Submodules
- Server (
mcp_sentinel_server) — registers the Tool plugins with MCP Server and wires per-tool OAuth scopes. - GraphQL (
mcp_sentinel_graphql) — extends gating, auditing, and redaction to the GraphQL Compose endpoint. - Approval (
mcp_sentinel_approval) — queues destructive operations for human approval bound to one HMAC-sealed action manifest (2.11.0). The requester cannot approve their own request; the form shows the sealed action against the live target. Includes time-boxed break-glass elevation into a shipped non-adminmcp_adminrole (single-use sealed grant; uid 1 and standingis_adminrefused; elevation cannot promote policy or lift the no-agent-publish floor).
Requirements
- Drupal 10.6+ or 11.3+, PHP 8.3+
- Tool API, Key, Simple OAuth with Consumers, and Encrypt
- Audit Chain — required since 2.0.0. The tamper-evident chain was extracted into its own project so sites can use it without an MCP write-plane.
- Recommended: MCP Server, which exposes the tools to MCP clients
- Optional: GraphQL Compose for the GraphQL submodule
Audit, redaction, content locks, and webhooks all work without MCP Server installed.
Quick start
composer require drupal/mcp_sentinel drupal/mcp_server drupal/simple_oauth drush en mcp_sentinel mcp_sentinel_server mcp_server_tool_bridge -y drush mcp-sentinel:setup
Configure at Configuration → Web services → MCP Sentinel, and review activity at Reports → MCP Sentinel.
Companion connector
drupal-mcp-connector is a Node.js MCP connector (multi-site, JSON:API + GraphQL, Drush bridge) that pairs with MCP Sentinel and appears by its X-MCP-Client label in the audit log.
Security
Not covered by Drupal's security advisory policy. Report vulnerabilities privately as described in SECURITY.md on the project repository; do not open a public issue for an exploitable flaw. General bugs go through the project issue queue.
Maintainers
Maintained by Jeremy Michael Cerda, sponsored by Wilkes & Liberty, LLC.
Depends on
Dependencies of the latest stable release
- Audit Chain
- Consumers
- Encrypt
- Key
- Simple OAuth (OAuth2) & OpenID Connect
- Tool API
- jsonapi Drupal core
- node Drupal core
- user Drupal core
Required by
Tracked projects that depend on this one
No tracked projects depend on this one yet.
Activity
Release Timeline
Releases
| Version | Type | Core | Notes | Release date | |
|---|---|---|---|---|---|
| 2.14.0 | Stable | 10–11 | client_id/azp on site-issued tokens; JSON 401 refusal on /drupal-mcp/* | Aug 27, 2026 | |
| 2.13.2 | Stable | 10–11 | Readiness anonymous deny is 403 JSON. | Aug 26, 2026 | |
| 2.13.1 | Stable | 10–11 | Readiness refuses anonymous callers. | Aug 26, 2026 | |
| 2.13.0 | Stable | 10–11 | Postcondition receipts, live bulk-read channels, and DLP path tests. | Aug 25, 2026 | |
| 2.12.0 | Stable | 10–11 | Portable policy bundles now deny on the live access path, not only in simulate. Tightening only. | Aug 18, 2026 | |
| 2.11.0 | Stable | 10–11 | Sealed approvals, evidence dashboard, DLP classification, anomaly signals, portable policy bundles. | Aug 17, 2026 | |
| 2.10.0 | Stable | 10–11 | Never-persist secure-install verifier (drush mcp-sentinel:verify). | Aug 16, 2026 | |
| 2.9.0 | Stable | 10–11 | Classification labels and per-surface egress ceilings: which data classes may leave through which governed surface, enforced before egress. | Aug 15, 2026 | |
| 2.8.0 | Stable | 10–11 | Evidence-required action veto: governed mutations execute only when their evidence can commit to the keyed audit chain. | Aug 15, 2026 | |
| 2.7.0 | Stable | 10–11 | Aug 15, 2026 | ||
| 2.6.0 | Stable | 10–11 | Token-capable agent provisioning; declared-principal reconcile command | Aug 14, 2026 | |
| 2.5.0 | Stable | 10–11 | Aug 14, 2026 | ||
| 2.4.0 | Stable | 10–11 | Aug 13, 2026 | ||
| 2.3.0 | Stable | 10–11 | Break-glass conduct audit, live-grant posture revalidation, People Roles warning, dual-edit docs. | Aug 1, 2026 | |
| 2.2.0 | Stable | 10–11 | Seals the break-glass role: enumerated permissions, a grant-time ceiling, and drift reporting. | Jul 31, 2026 | |
| 2.1.0 | Stable | 10–11 | Jul 31, 2026 | ||
| 2.0.1 | Stable | 10–11 | Jul 30, 2026 | ||
| 2.0.0 | Stable | 10–11 | Jul 30, 2026 | ||
| 1.13.0 | Stable | 10–11 | A declared signing key that cannot be resolved now refuses delivery (failed_key) instead of silently sending unsigned; status report pre-flights endpoint keys. | Jul 26, 2026 | |
| 1.12.1 | Stable | 10–11 | Regression fix: the in-place publish-gate refusal now fires on JSON:API PATCHes that omit moderation_state. Update from 1.12.0 promptly. | Jul 26, 2026 | |
| 1.12.0 | Stable | 10–11 | Webhook delivery hardening (no redirects, stale-claim reclaim, failure visibility); publish gate denies in-place edits of published content. | Jul 26, 2026 | |
| 1.x-dev | Dev | 10–11 | Jul 23, 2026 | ||
| 1.11.0 | Stable | 10–11 | Paragraph publish-gate redirect-to-draft (governance fix); settings page now links to the dashboard and audit log. | Jul 23, 2026 | |
| 1.10.0 | Stable | 10–11 | Jul 22, 2026 | ||
| 1.9.0 | Stable | 10–11 | Jul 16, 2026 | ||
| 1.8.0 | Stable | 10–11 | Jul 15, 2026 | ||
| 1.7.0 | Stable | 10–11 | Jul 14, 2026 | ||
| 1.6.1 | Stable | 10–11 | Jul 6, 2026 | ||
| 1.6.0 | Stable | 10–11 | Jul 5, 2026 | ||
| 1.5.1 | Stable | 10–11 | Jul 4, 2026 | ||
| 1.5.0 | Stable | 10–11 | Jul 4, 2026 | ||
| 1.4.0 | Stable | 10–11 | Jun 29, 2026 | ||
| 1.3.0 | Stable | 10–11 | Jun 29, 2026 | ||
| 1.2.0 | Stable | 10–11 | Jun 27, 2026 | ||
| 1.1.0 | Stable | 10–11 | Jun 27, 2026 | ||
| 1.0.0 | Stable | 10–11 | Jun 26, 2026 | ||
| 1.0.0-beta6 | Pre-release | 10–11 | Jun 26, 2026 | ||
| 1.0.0-beta5 | Pre-release | 10–11 | Jun 26, 2026 | ||
| 1.0.0-beta4 | Pre-release | 10–11 | Jun 23, 2026 | ||
| 1.0.x-dev | Dev | 10–11 | Jun 3, 2026 | ||
| 1.0.0-beta3 | Pre-release | 10–11 | Enterprise governance for AI-agent access to Drupal — policy profiles, field redaction, DLP, tamper-evident audit logging, and reliable webhooks over MCP / JSON:API / GraphQL. | Jun 3, 2026 | |
| 1.0.0-beta2 | Pre-release | 10–11 | Enterprise governance for AI-agent access to Drupal — policy profiles, field redaction, DLP, tamper-evident audit logging, and reliable webhooks over MCP / JSON:API / GraphQL. | Jun 3, 2026 | |
| 1.0.0-beta1 | Pre-release | 10–11 | Jun 2, 2026 | ||
| 1.0.0-alpha1 | Pre-release | 10–11 | Initial release | Jun 1, 2026 |