npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

drupal-mcp-connector

v5.4.5

Published

MCP server for Drupal: connects MCP clients to one or more sites over JSON:API or GraphQL, with governed writes and an SSH Drush bridge. Hosted HTTPS mode checks every call with the token issuer.

Readme

Drupal MCP Connector

MCP server for Drupal: connects MCP clients to one or more sites over JSON:API or GraphQL, with governed writes and an SSH Drush bridge. Hosted HTTPS mode checks every call with the token issuer.

License: MIT Node.js Drupal MCP

Built by Jeremy Michael Cerda ([email protected]). Maintained by Wilkes & Liberty, LLC.

If the client only shows drupal_list_sites and drupal_governance_status, the secret env vars named in config.json are unset. Confirm they are loaded (config/secrets.map or the shipped example table) and restart the MCP server. See #199.


What It Does

Drupal MCP Connector (drupal-mcp-connector) connects any Model Context Protocol client to one or more Drupal sites. It exposes Drupal content and configuration as a set of MCP tools, resources, and prompts, so an MCP client can read, audit, and (where permitted) write content through structured, governed operations instead of the admin UI:

"Find all articles missing a meta description and list them."
"Show me every user account that hasn't logged in for 90 days."
"Create 10 draft product nodes from this structured data."
"Run an SEO and accessibility audit on the article content type."
"What content types exist on the site and which are barely used?"

The connector speaks two Drupal backends interchangeably — Drupal core's JSON:API and GraphQL (via GraphQL Compose) — selectable per site. It normalizes both into one canonical entity shape, so the same tools work whether a site exposes JSON:API, GraphQL, or both. An optional SSH Drush bridge adds administrative operations the HTTP APIs can't reach.


Dual-Protocol Backends

Drupal modules can also supply their own typed MCP actions through an opt-in module-tool registry. The module owns business rules and schemas; the connector discovers and forwards approved tools under Sentinel and connector policy. Existing built-in tools remain available during migration.

Each site declares which backend(s) it exposes via the api key:

"sites": {
  "main":         { "baseUrl": "https://example.com", "api": "jsonapi" },
  "graphql_only": { "baseUrl": "https://api.example.com", "api": "graphql" },
  "either":       { "baseUrl": "https://example.com", "api": ["graphql", "jsonapi"] }
}
  • api accepts "jsonapi", "graphql", or a priority array like ["graphql","jsonapi"]. Omit it to auto-detect (the connector probes both once and caches the result).
  • One canonical shape. Both backends return entities as { id, entityType, bundle, title, status, langcode, created, changed, url, fields, relationships, _backend }, so tool output is identical regardless of protocol. Every site-addressing response also includes _target: { name, baseUrl, source } so a defaulted call cannot be mistaken for another environment.
  • Capability-aware. Each backend advertises what it supports (read, write, delete, server-side filter/sort, revisions). GraphQL via GraphQL Compose is read-only (no mutations) and has no server-side field filter, so filters are applied client-side over a bounded fetch and flagged approximate/truncated. Write tools against a read-only backend return a clear capability error rather than failing silently.
  • Writes go through JSON:API. Use a JSON:API-enabled site as the write plane; keep GraphQL as a read plane where that suits your architecture.
  • defaultTextFormat sets the body text format used by the body convenience parameter on node writes, e.g. { "baseUrl": "…", "defaultTextFormat": "basic_html" }. Individual calls can override it with format. Field API allowed_formats wins when it can be resolved (from field_config or, for body, base_field_override): a single allowed format is the default, and a format outside the list is refused. Without a resolved list, a create falls back to full_html, which many governed sites deliberately do not define — and which is the most permissive core format, so setting this per site is the safer posture. An update reuses the format already stored on the field instead of that fallback. A text format is Drupal's HTML-filtering boundary, so it is worth choosing deliberately rather than inheriting.

See docs/architecture.md for the backend abstraction and docs/graphql-local-setup.md for the GraphQL specifics.


Features

124 Tools Across 28 Modules

| Module | Tools | |--------|-------| | Nodes | CRUD for any content type with arbitrary field support | | Taxonomy | Vocabulary listing + full term CRUD | | Users | List, get, create, update, block/unblock, role management (PII-gated) | | Media | List types, CRUD, file upload, orphaned-media detection | | GraphQL | Execute a query, schema introspection (mutation-gated) | | Codegen | Optional graphql_compose_codegen inspect/diff/generate (generate is --dry-run text) | | Entities | Generic CRUD for any Drupal entity type (paragraphs, commerce, webforms, …) | | Site | Site info, content-type discovery, configured-site listing | | Reports | Content summary, stale content, field completeness, SEO/accessibility audits, taxonomy usage, user activity, revision hotspots (10 read-only reports) | | Drush | Cache rebuild, cron, config sync, module management, DB updates via SSH | | Revisions | List/get entity revisions; governed revert to a prior revision | | Moderation | Set moderation state; list content by state; observed-state discovery (content_moderation) | | Scheduler | Set publish-on / unpublish-on dates (Scheduler module) | | Fields | Describe a bundle's fields (type/required/cardinality, best-effort) | | References | Resolve a human name/title to an entity UUID for relationship fields | | Bulk | Bulk create/update with per-item partial-failure reporting | | Translations | List, create, and revise published entity translations (revise: true on drupal_create_translation, MCP Sentinel 2.24.0+) | | Paragraphs | Create/update/get Paragraph components for embedding in host fields | | Nested | Governed nested-paragraph draft (drupal_draft_nested_components) — new unpublished children pinned from the host draft | | Structure | Menu links (list/create/update, incl. parent + enabled) + custom blocks (list/create) | | Redirects | Create active URL redirects (301/302) + update/repoint existing redirects (Redirect module) | | Search | Best-effort content search (title match; Search API/Solr-ready) | | Reports (extra) | Orphaned references, unpublished content, missing-field audits | | Reports — Links & 404 | 404-log → redirect candidates, redirect-table health (chains/loops/duplicates), body-link inventory with opt-in live checking, URL-alias coverage, menu-link integrity, embedded-entity scan | | Reports — Config & Health | Config drift, best-practice/security config linter, module audit (dev/debug + security updates), permission audit, Drupal status report, text-format safety, cache posture | | Reports — Content Quality | Duplicate content, workflow bottlenecks, translation coverage, scheduled content, readability (Flesch), orphan pages, PII exposure (masked), structured-meta SEO coverage | | Audit (composite) | drupal_audit_site_health — scored content/links/config dashboard with a roll-up grade | | Config & Governance | Governed config get/list/set via the server-tool bridge; drupal_mcp_whoami tier/capability report |

Preview writes with dryRun. The node and entity create/update/delete tools accept an optional dryRun: true flag that runs the connector's checks and returns a preview of the payload, without committing anything to Drupal. The result's checks block says what was checked. Field access and entity validation are checked only when Sentinel's non-saving draft endpoint ran; see docs/tools-reference.md.

MCP Resources

Browsable, always-fresh context the client can read without calling a tool:

  • drupal://sites — configured site profiles (no credentials)
  • drupal://{site}/content-types — content types with field schemas
  • drupal://{site}/security-policy — the active security configuration

MCP Prompts

Prompts are exposed as slash-commands in any MCP client (Claude, Gemini, Codex, and other MCP-aware agents). Two kinds ship with the connector:

Workflow templates — multi-step guided flows:

  • drupal-content-audit — walk through a full site content audit
  • drupal-full-audit — run the composite content/links/config audit and turn the scored dashboard into a prioritized action plan
  • drupal-create-article — guided article creation with all fields
  • drupal-seo-fix — find and fix SEO gaps
  • drupal-user-cleanup — identify and handle inactive accounts
  • Module-owned workflows (drupal-<namespace>-<workflow>) when serverTools.modules.workflows is enabled — see docs/module-workflows.md

One prompt per tool — every drupal_* tool is also exposed as a drupal-<tool> prompt (e.g. drupal-create-node, drupal-list-nodes, drupal-report-seo-audit), derived automatically from the tool set so it never drifts. Each prompt takes the tool's parameters as arguments and drives a single, governed call to that tool. These are protocol-native, so they work everywhere the prompts capability is supported — the client renders them per its own convention (e.g. Claude Code shows /mcp__drupal__drupal-create-node).

Filesystem slash commands (/drupal-*)

MCP prompts (above) are the protocol-native slash surface. For the literal bare /drupal-<tool> form, the connector ships generated stubs under .agents/commands/ — a harness-agnostic tree, not a vendor rule directory. Clients that scan .agents/commands/ (including Grok Build when this repo is the project) pick them up automatically.

Clients that only scan a vendor home path (Claude Code ~/.claude/commands, Grok ~/.grok/commands, Codex $HOME/.agents/skills) install from that tree into the operator home, so no consuming project has to commit .claude/ or .grok/. Codex uses a skill (drupal-mcp), not deprecated custom prompts:

npm run generate:commands    # refresh .agents/commands/ (from a clone)
npm run install:commands     # copies into ~/.claude/commands, ~/.grok/commands, and ~/.agents/skills/drupal-mcp/
# npm run install:commands -- --clients claude
# npm run install:commands -- --clients codex
# npm run install:commands -- --home /path/to/fake-home   # tests / CI
# npm run install:commands -- --modules   # also write stubs for module-owned tools

Module-owned tools (docs/module-tools.md) get a prompt whenever they are visible to the caller. Their bare /drupal-<namespace>-<alias> stubs are written only with --modules, which discovers them from the sources in config/config.json.

From an npm install, the same files ship at node_modules/drupal-mcp-connector/.agents/commands/. Do not copy them into an application repo's .claude/ or .grok/ directory.

Security Model

Defense-in-depth presets, enforced connector-side and complemented by Drupal-side governance (MCP Sentinel). Default when security is omitted: production-strict (read-only, sensitive types denied). Local development must set "preset": "development" explicitly.

"security": { "preset": "auditor" }

| Preset | What it does | |--------|-------------| | development | Everything allowed, including GraphQL — local development only | | content-editor | Create/edit content + structural entities; no deletes; no publishing; secrets/governance/account types denied | | config-editor | content-editor + site-building config read + governed config write (developer tier) | | auditor | Read-only; secrets/governance/account types denied; user PII redacted when user is allowed | | production-strict | Read-only; same sensitive denylist as auditor; broad PII field redaction (default) | | write-plane | Create/update content set for agents; no deletes; no GraphQL; publish off by default |

Additional connector-side gates (2.1+ / 2.2+):

  • Entity allowlists apply to specialized tools (drupal_*_node, media, taxonomy), not only drupal_entity_*.
  • Publish gate: status: true and moderation_state: "published" require allowPublish. Media create defaults unpublished. Published moderated node updates without a moderation state default to draft (forward revision).
  • Uploads only from MCP_UPLOAD_ROOT (or the process cwd); sensitive paths (.env*, .ssh, connector config.json) are refused.
  • HTTPS: non-loopback binds require an inbound OAuth resource server (auth.issuer + auth.audience + RFC 7662 introspection). Every authenticated network call is introspected at the issuer (no positive cache; issuer down is 503). MCP_AUTH_TOKEN was removed in 4.0.0 (#231); setting it is fatal at startup. MCP_ALLOW_UNAUTHENTICATED=1 is loopback-only; a non-loopback bind with that flag refuses to start. A network request with no resolved identity is 401 before dispatch. GET /health and RFC 9728 protected-resource metadata stay reachable without a token and expose no tool data. Non-loopback TLS defaults to 120 req/min rate limiting (per client address before auth; per verified principal after). X-Forwarded-For is honored only from MCP_TRUSTED_PROXIES / auth.trustedProxies (default: trust none). Inbound JWT scopes (and optional auth.grants) filter which tools, resources, prompts, and sites a principal can discover or invoke.
  • Restricted admission: optional auth.allowedPrincipals limits authenticated access to exact client/subject pairs within auth.issuer, for example [{"clientId":"pilot-client","sub":"pilot-user"}]. Both values must match the verified token; azp and RFC 7662 client_id, when both present, must agree. A valid but unlisted identity receives 403 before session creation or tool dispatch. Omitting the setting preserves normal authentication; an explicit empty array denies all authenticated access. Invalid entries, null and wildcard-only identifiers prevent startup. The policy is snapshotted at startup: update the managed configuration and restart to change membership. Admission does not grant site access or tool scopes, and it does not bypass introspection, revocation or session binding. Keep real membership identifiers in private deployment configuration.
  • Ops listener (mesh-only, off by default): MCP_OPS_LISTEN=<addr:port> or ops.listen starts a second socket for GET /ready and GET /metrics. It has no authentication. It may bind only to loopback or a Tailscale address (100.64.0.0/10, fd7a:115c:a1e0::/48); port 0, 0.0.0.0, ::, and any other public or non-mesh address are fatal. 100.64.0.0/10 is also carrier-grade NAT space — confirm the address is actually Tailscale, and restrict the port with Tailscale ACLs. /ready is 200 only on a 2xx introspection response with an RFC 7662-shaped body plus complete hosted scope table and allowlists (401 / 404 / 5xx are 503); probes are single-flighted and cached for a few seconds. /metrics is Prometheus text (request counts by route and status, deny counts by reason, 401 / 403 / 429, rate-limit buckets, in-flight) with no principals, subjects, client ids, tokens, tenants, or IPs. The public listener does not serve /ready or /metrics (normal 401 or 404). GET /health stays the public liveness probe.
  • GraphQL is off by default. drupal_graphql / introspect require security.allowGraphql (true only on the development preset). Raw GraphQL results still bypass entity allowlists and field redaction — prefer JSON:API entity tools when connector policy must hold. Mutations also need allowGraphqlMutations.
  • Northbound data-flow budgets (2.8+): row, byte, page, request, and chained-action counters keyed by inbound principal + authoritative target (same finite defaults as MCP Sentinel), so pagination, retries, batching, or a new chain id cannot reset them. Governed reads carry the declared-ceiling / declared-destination wire contract; tune with security.declaredCeiling and security.readBudgets.

Full detail: docs/security.md and docs/security-hardening.md.


Requirements

  • Node.js 20+
  • Drupal 10 or 11 (JSON:API ships in core)
  • For the GraphQL backend: GraphQL Compose
  • For token auth (recommended): Simple OAuth
  • For the Drush bridge: SSH key access to the Drupal server

Quick Start

One-liner (recommended for operators)

npx -y drupal-mcp-connector init
# aliases: npx -y drupal-mcp-connector wizard
#          npx -y drupal-mcp-wizard
# CI / dogfood: npx -y drupal-mcp-connector init --yes --json
npx -y drupal-mcp-connector doctor
# CI: npx -y drupal-mcp-connector doctor --json

The wizard prints Cursor (.cursor/mcp.json) and Claude Code mcpServers snippets, optional auth.grants allowlist hints, and a whoami / contract_ready check. It writes files only with --write (never clobbers without confirm unless --yes). Doctor prints one primary failing gate and the exact next fix (exit non-zero on fail; --json is secret-free).

Transport presets

| Preset | URL shape | Notes | |--------|-----------|--------| | Local stdio (--preset local-stdio) | https://drupal.ddev.site | Client launches this connector as a subprocess. Drupal must be reachable from this machine. | | Tailscale VPN (--preset tailscale) | https://drupal.<tailnet>.ts.net | VPN-required. The MCP client host must be on the same tailnet. Not a public internet path. | | Public HTTPS (--preset public-https) | https://mcp.example.com/mcp | Gated / later. Operator-run MCP_TRANSPORT=https + TLS + inbound OAuth. Not required to use the Wilkes & Liberty hosted endpoints below. |

Hosted endpoints

Wilkes & Liberty operates Streamable HTTP endpoints (DEV-817):

| Environment | MCP URL | Protected-resource discovery (RFC 9728) | |-------------|---------|-----------------------------------------| | Production | https://mcp.wilkesliberty.com/mcp | https://mcp.wilkesliberty.com/.well-known/oauth-protected-resource | | Staging | https://mcp.staging.wilkesliberty.com/mcp | https://mcp.staging.wilkesliberty.com/.well-known/oauth-protected-resource |

Both advertise scopes_supported: ["mcp_read"]. /mcp is an OAuth protected resource (no token → 401). Discovery is unauthenticated. The resource-specific path /.well-known/oauth-protected-resource/mcp is also served.

OAuth path per client (mcp_read only):

  • Cursor — public PKCE client cursor-mcp. Register the MCP URL; Cursor completes authorization-code + PKCE against that client.
  • Grok Bot — grok-bot client / gated anonymous registration (keystone#1541). Register the same MCP URL as a remote MCP server.

Hosted /mcp Origin allowlist (DEV-953): https://cursor.com, https://www.cursor.com, https://grok.com, https://console.x.ai. Copy into auth.allowedOrigins / MCP_ALLOWED_ORIGINS. Matching is exact.

stdio is still the default local path: the client launches the connector on your machine and inherits VPN/Tailscale/localhost reachability to Drupal. See docs/mcp-clients.md.

requireGovernance: true remains the listing default for a later marketplace entry — this repo does not submit listings. If the client only shows drupal_list_sites and drupal_governance_status, run doctor.

tools/list and prompts/list walk sites concurrently. The wait does not abort the site chain. Delivery is per session: a notified client's first list waits up to 4s and returns built-ins plus ready snapshots, then list_changed; an unnotified client (stdio 2026 without listen, every modern HTTP 2026 list) waits for the in-flight chain (default 20s). The whole listing — catalog wait plus a parallel 4s governance re-check — is hard-capped at 25s. Order on each site: governance → tools/list → onTools; prompt hops start after governance. See docs/module-tools.md.

Cursor plugin (stdio)

Local skeleton only (.cursor-plugin/plugin.json + root mcp.json): the client launches npx -y drupal-mcp-connector on this machine. The plugin does not ship a remote url.

npx -y drupal-mcp-connector init --preset local-stdio
npx -y drupal-mcp-connector doctor

requireGovernance: true is the listing default. --preset public-https stays gated. Marketplace listing submit is operator-only — this repo does not submit. See PRIVACY.md.

Two-minute happy path

After init and a green doctor, in the MCP client (real tool names):

  1. Who am I? Call drupal_mcp_whoami. Confirm tier, preset, and capabilities.publish (false on production-strict / content-editor).
  2. What can I see? Call drupal_list_sites, then drupal_list_nodes with { "type": "article", "status": false, "limit": 5 } (unpublished only) or drupal_get_node on a staging UUID. Prefer drupal_search_content for a title substring.
  3. Safe unpublished write (optional, non-prod): Preview with drupal_create_node { "type": "article", "title": "MCP draft", "status": false, "dryRun": true }. Commit without dryRun only on staging, still status: false (or moderationState: "draft"). Never set status: true or moderationState: "published" unless drupal_mcp_whoami shows capabilities.publish: true and you intend to go live.

Fail-closed: default production-strict is read-only. A deny is expected when the allowlist or Sentinel profile excludes the type — run doctor and drupal_governance_status; do not auto-widen allowlists.

From npm (recommended for operators)

npm install -g [email protected]
# or: npx -y [email protected]

Point your MCP client at the installed binary (path from which drupal-mcp-connector or node_modules/.bin/drupal-mcp-connector). For multi-site or non-env config, clone the repo (or copy config/config.example.json beside a small launcher) and pass a config path — see docs/getting-started.md.

Before you upgrade

Pin the version you run. Do not point a client you depend on at latest or an unbounded range.

  1. Pin an exact version in the lockfile (package-lock.json or npm-shrinkwrap.json), or in package.json as "drupal-mcp-connector": "5.4.5" (use the version you intend to run).
  2. Confirm the registry checksum before you install. npm view [email protected] dist.integrity prints the integrity npm checks. A lockfile install fails when the tarball does not match.
  3. Read CHANGELOG.md for that version.
  4. Run npm audit --omit=dev against the lockfile and read any advisory before you upgrade. There is no separate scanner to install.

Restart the MCP client after the upgrade. Run drupal-mcp-doctor when the package is on your PATH, or npx -y [email protected] doctor when you launch it with npx.

From a git clone (development)

git clone https://github.com/Wilkes-Liberty/drupal-mcp-connector
cd drupal-mcp-connector
npm install
cp config/config.example.json config/config.json
# Edit config/config.json — baseUrl, api backend, auth, security preset
node src/index.js

Register with an MCP client

Most desktop and CLI MCP clients launch the connector over stdio:

{
  "mcpServers": {
    "drupal": {
      "command": "drupal-mcp-connector",
      "env": {
        "DRUPAL_BASE_URL": "https://mysite.com",
        "DRUPAL_API_TOKEN": "your-token-here"
      }
    }
  }
}

Or with an absolute path to src/index.js / the installed package. For multi-client or remote use, run the HTTPS transport and register the endpoint instead — see docs/getting-started.md and docs/mcp-clients.md.

The same entry point serves current MCP 2026-07-28 clients and 2025-era clients. Current HTTP requests are stateless and never receive Mcp-Session-Id; legacy HTTP clients retain their existing session. Set MCP_LEGACY_TRANSPORT=reject to end the compatibility window deliberately. The /mcp URL does not change.


Companion Drupal Module — MCP Sentinel

The connector works out of the box against Drupal core's JSON:API and a GraphQL Compose schema. For server-side governance, pair it with the MCP Sentinel module (drupal/mcp_sentinel), which enforces policy inside Drupal — independent of any connector configuration:

  • Role-bound policy profiles (operation gates, entity allow/deny, field redaction)
  • Tamper-evident audit log of every governed MCP operation, attributed to the acting account
  • Content locks that prevent edits to content a human is actively editing
  • OAuth scope enforcement (mcp_read / mcp_write / mcp_config) per tool
  • HMAC-signed webhooks on MCP-driven entity changes
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

Governance keys off the authenticated account's role and OAuth scopes — not request headers. The connector sends an X-MCP-Client identity header purely as a log label. See the MCP Sentinel project page for the full contract.

Raw SQL is governed, or it is off

The Drush bridge runs over SSH, which is below everything above: a drush subprocess does not make a request Drupal can govern, and most Drush commands never load Drupal's module system at all. drupal_drush_sql_query used to exploit that without meaning to — it called drush sql:query, so no policy profile, no denied entity type, no field redaction and no audit entry applied to anything it read.

It now calls drush mcp-sentinel:sql-query (mcp_sentinel ≥ 1.14), which runs with Drupal fully bootstrapped and enforces the same profile that governs JSON:API. Two opt-ins, both off by default, are required:

// this connector, per site
"drushSsh": {
  "rawSql": "governed",                          // no other value enables it
  "allowedCommands": ["mcp-sentinel:sql-query"]  // only if you pin this list
}

…plus allow_raw_sql on the policy profile in Drupal. Expect a much narrower tool than before: one SELECT, entity tables only, no expressions, and no SELECT * on a table carrying a redacted column. Every attempt — permitted or refused — lands in the audit chain with its statement text.

The rest of the bridge (sql:cli, sql:dump, php:eval and anything else you reach over SSH) is outside Drupal governance by construction. Treat SSH as an operator channel: keep the agent's credentials off it, and pin allowedCommands per site.


Documentation

| Doc | Description | |-----|-------------| | Getting Started | Full setup: DDEV/Lando, Simple OAuth, multi-site, transports | | MCP Clients | Wire the connector into Claude (Code/Desktop), Grok (Build/API), and OpenAI (Codex/ChatGPT) — copy-paste config per client | | OAuth client_credentials | Production OAuth deploy: scope→role mapping, JSON:API writes, config persistence, secret handling, troubleshooting | | Architecture | Backend abstraction, canonical model, and how to extend it | | GraphQL Setup | GraphQL Compose backend + local TLS notes | | Tools Reference | Full reference for all 124 tools | | Security Guide | Presets, entity access control, field redaction | | Security Hardening | Optional transport, identity, and secrets controls | | Verification | Prove a secure install: static + live checks, negative probes, evidence artefact, managed residuals | | Threat Model | Trust boundaries, threats & mitigations, residual risks, and the security-pass results | | Deployment | Run the HTTPS transport in production: Docker, systemd, launchd, reverse proxy, pre-exposure checklist | | Integration Contract | The connector ↔ Drupal-governance contract (identity, OAuth scopes, compatibility) | | Adapter Contracts | Provider-neutral evaluator / relay / approval / evidence / SoR contracts and the Drupal conformance kit | | Versioning & Stability | Semver policy: the stable surface, deprecation process, MCP protocol + Node support | | Whitepaper | Vision, personas, and use cases |


Contributing

PRs welcome. See CONTRIBUTING.md for guidelines.

Security

Found a vulnerability? See SECURITY.md. Please do not open a public issue.

License

MIT © 2026 Jeremy Michael Cerda and Wilkes & Liberty, LLC