Part of the MCP ecosystem · 11 projects
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, checked server-side and never from a header. From 3.0, a governed Tool call fails closed unless the access token has already been accepted by the site and names the issuer, the subject, the client, and the tenant. An agent scope or a designated consumer is not enough on its own. 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.
How it differs from similar projects
MCP Server (mcp_server) exposes Drupal tools to MCP clients; it is the transport/tooling layer. MCP Sentinel does not replace it — it governs what those tools (and JSON:API/GraphQL requests from the same agents) are allowed to do, and records evidence of what they did. MCP Server is a recommended companion.
Drupal AI (ai) integrates LLM providers inside Drupal (automators, assistants, guardrails for site-initiated AI). MCP Sentinel addresses the opposite direction: external agents acting on the site. The two are complementary.
Core permissions and JSON:API access checks are respected and never bypassed. MCP Sentinel layers policy, redaction, budgets, and audit evidence on top of them rather than replacing entity or field access.
Draft translations
Governed clients can create and continue unpublished node translations while preserving the published default language. Version 2.17.0 also supports paragraph field values when paragraph status is translatable, plus image alt and title on a translatable node image field while keeping the same file.
Paragraph updates require the state token from the previous draft read. Stale edits are refused. Shared-status paragraphs and saves requiring new paragraph references return a conflict; the endpoint does not repoint host revisions. These cases remain for human editing. Content-tier callers cannot publish translations.
See the 2.17.0 release notes for the API contract and limits.
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. Content-entity rows stamp
langcode(and translation create/source when a language is added) so a Spanish save is not attributed as English (2.19.0). - 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. When contrib Content Lock is installed, a human's entity-form lock is honoured as the same governed write conflict (2.18.0).
- Translation inventory and shared-state guard —
GET .../mcp-translationsincludes corecontent_translation_outdatedandcontent_translation_sourcewhen those fields exist. A langcode write cannot change untranslatablemoderation_state, so a Spanish draft cannot move the shared workflow (2.19.0). - 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, denied-by-policy panels, and six charts. Charts render as inline SVG; installing Charts with a library submodule (for example charts_chartjs) upgrades them. The hero never reports all-clear until audit-chain evidence is verified (2.11.0). - Admin status strip — the governance dashboard and the settings form show whether the master switch is on, which agent clients are designated, source-governance readiness with the failing gate in plain language, the last whoami or readiness signal, and a link to add an agent client (2.27.0).
- Sealed tokens — Configuration → MCP Sentinel → Sealed tokens mints a short-lived token bound to a designated client. The secret is shown once and is not stored. Tokens can be revoked. From 3.0.1, governed Tool plugins refuse them. Those tools accept only an access token that names the issuer, the subject, the client, and the tenant.
- Denials — a tool or readiness refusal names the policy or rule and says whether widening access would change the result. Widening is never automatic, and the message does not include secrets (2.27.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.2+, with the
intlextension (required since 3.0) - 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
- Optional: Charts with a library submodule (for example charts_chartjs) for interactive dashboard charts. Inline SVG is the default, including when Charts is enabled without a library.
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
The companion Node.js MCP client is the Drupal MCP Connector (source): multi-site, JSON:API + GraphQL, Drush bridge. It 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.
Ask your assistant about MCP Sentinel
Check compatibility with your Drupal and PHP version, maintenance and security coverage, from current release data. How it works
Depends on
Dependencies of the latest stable release
- Audit Chain
- Consumers
- Encrypt
- Key
- Simple OAuth (OAuth2) & OpenID Connect
- Tool API >=1.0.0-beta11
- 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.
More in the MCP ecosystem
Most installed first
Activity
Release Timeline
Releases
| Version | Type | Core | PHP | Release date | |
|---|---|---|---|---|---|
| 2.30.1 | Stable | 10–11 | PHP >=8.2 | Oct 5, 2026 | |
| 2.30.0 | Stable | 10–11 | PHP >=8.2 | Oct 4, 2026 | |
| 2.29.1 | Stable | 10–11 | PHP >=8.2 | Oct 4, 2026 | |
| 2.29.0 | Stable | 10–11 | PHP >=8.2 | Oct 3, 2026 | |
| 2.28.2 | Stable | 10–11 | PHP >=8.2 | Oct 3, 2026 | |
| 2.28.1 | Stable | 10–11 | PHP >=8.2 | Oct 2, 2026 | |
| 2.28.0 | Stable | 10–11 | PHP >=8.2 | Oct 2, 2026 | |
| 2.27.0 | Stable | 10–11 | PHP >=8.2 | Oct 1, 2026 | |
| 2.26.0 | Stable | 10–11 | PHP >=8.2 | Oct 1, 2026 | |
| 2.25.5 | Stable | 10–11 | PHP >=8.2 | Sep 30, 2026 |