Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
DRUSH_PATHNoPath to Drush binary, may contain arguments (e.g., 'ddev drush')drush
MCP_TRANSPORTNoTransport protocol. One of: stdio, http, sse, streamable-httpstdio
DRUPAL_BASE_URLNoBase URL of the Drupal sitehttp://localhost
DRUPAL_PASSWORDNoPassword for Drupal authentication (used with DRUPAL_USERNAME)
DRUPAL_USERNAMENoUsername for Drupal authentication (used with DRUPAL_PASSWORD)
DRUPAL_API_TOKENNoBearer token for authentication (sent as Authorization: Bearer)
DRUPAL_VERIFY_SSLNoSet to false for self-signed dev certs (DDEV, Lando)true
DEFAULT_AI_PROVIDERNoAI provider to use. One of: ollama, openai, anthropic, nvidia_nim, googleollama
DRUPAL_OAUTH_CLIENT_IDNoOAuth2 client ID (alternative authentication method)
DRUPAL_OAUTH_TOKEN_URLNoOAuth2 token URL (alternative authentication method)
DRUPAL_OAUTH_CLIENT_SECRETNoOAuth2 client secret (alternative authentication method)

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": true
}
resources
{
  "subscribe": false,
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
analyze_d7_siteC

Analyze a Drupal 7 site for D10 upgrade readiness.

analyze_d9_siteC

Analyze a Drupal 9+ site for deprecated code and APIs.

inventory_content_typesC

List all content types on a Drupal site.

inventory_modulesC

List all modules on a Drupal site.

map_modules_d7_to_d10C

Map Drupal 7 modules to D10 equivalents using AI + known mappings.

find_deprecated_codeC

Scan custom modules for deprecated Drupal APIs.

find_entity_referencesA

Find which bundles use reference fields targeting an entity type.

Answers "where are these used?" at the configuration level: for entity_type ("taxonomy_term", "node", "media", ...) it lists every field on every bundle whose storage targets that type, e.g. which content types have a tags or category field. Filter by the referencing bundle or by field_name.

This reads field configuration, not content: it reports where references can live, not which individual rows currently point at which entity. For the data, query the field's table with db_query.

search_entitiesA

Case-insensitive substring search across entity titles and names.

Scans node titles, user names and emails, taxonomy term names, comment subjects, media names, and file names with one read-only LIKE query per type, returning matches grouped by entity type.

Pass entity_types (e.g. ["node", "taxonomy_term"]) to search fewer tables: a LIKE scan reads every row, so keep it narrow on large sites. This does not search node bodies -- for full text use the site's own search or the search_api tools.

find_entity_by_pathA

Resolve a URL path or alias ("/about", "/node/123") to its entity.

Internal routes such as /node/123 are read directly. Anything else is looked up in the path alias table, and the resolved target is parsed the same way. A full URL is accepted; the query string and fragment are ignored. Returns the entity id and a short summary, or found: false when nothing resolves.

generate_migration_yamlD

Generate migration YAML configuration.

generate_module_migrationC

Generate migration module for a custom module with source plugin, process plugins, and migration template.

run_migration_testC

Test migration with limited records.

validate_migrationC

Validate migration configuration.

rollback_migrationC

Rollback a completed migration.

sync_media_filesC

Sync media files between paths.

migrate_taxonomyC

Migrate taxonomy vocabularies and their terms.

create_migration_planC

Create or replace a persisted migration plan.

get_migration_planC

Read a persisted migration plan and its tracked state.

list_migration_plansB

List all persisted migration plans.

migration_statusC

Summarize migration progress for a persisted plan.

migrate_recordsC

Copy a batch of source records into the target Drupal site through JSON:API.

record_migration_resultC

Record the outcome of a manually executed migration operation.

analyze_source_siteC

Analyze a source Drupal JSON:API resource type and optionally store counts in a plan.

username/password authenticate to the source site: JSON:API field access hides attributes (user name/mail, for example) from anonymous requests, so unauthenticated analysis under-reports.

reconcile_migration_countsC

Compare recorded source counts with current target-site counts.

run_migration_waveC

Fetch and migrate one resource type from the plan's source site into the target site.

source_username/source_password authenticate to the source site. Credentials may instead be stored in the plan's source block (username/password), which keeps waves self-contained.

run_migrationB

Run an ordered end-to-end migration for one or all planned entity types.

Waves run in the order given (dependencies first). A failed wave stops the run by default, since a schema or auth problem tends to repeat; set continue_on_error to attempt the remaining types anyway.

create_nodeC

Create a single node of the specified bundle with given fields.

get_nodeB

Get a single node by ID with optional relationship includes.

update_nodeC

Update a single node by ID with given fields.

delete_nodeB

Delete a single node by ID.

query_nodesC

Query nodes with filters, sorts, includes, and pagination.

upload_mediaC

Upload a file to the media library.

create_mediaC

Create media entity from a remote URL (image, video, document, etc.).

clean_nodes_aiC

Clean duplicate or malformed nodes using AI. Requires confirm=True to execute deletions.

map_fields_aiB

Suggest AI-powered field mappings from a source field list to a target bundle.

Reads the target bundle's available fields, then asks the AI provider to map each source field onto the closest target field.

bulk_update_nodesC

Apply the same field updates to every node matching a set of filters.

fix_media_referencesC

Find broken media references across a content type.

Scans nodes of the given type and checks every media relationship, reporting references whose target media entity no longer resolves.

bulk_update_aliasesB

Regenerate URL aliases for a content type.

Alias generation belongs to the Pathauto module, so this runs drush pathauto:generate. The previous implementation ran drush uuri, which is not a Drush command. pattern is not applied here: patterns are pathauto_pattern config objects, which pathauto_pattern_create / pathauto_pattern_update manage.

analyze_content_qualityC

Analyze content quality with AI for specific nodes or an entire type.

generate_test_contentA

Generate sample nodes for a bundle to populate a development site.

config_getC

Get a single configuration object by name.

config_setC

Set a single configuration value.

export_configC

Export Drupal configuration to files.

import_configC

Import Drupal configuration from files.

sync_configC

Sync configuration between environments via Drush.

diff_configB

Show differences in configuration between environments.

split_configC

Split configuration into separate directories for atomic deployment.

Reads from source_dir (exported config) and creates individual config files in output_dir for each specified config object.

config_statusA

Compare active configuration with the exported sync directory.

Read-only: reports how many config objects are the same, differ, exist only in the database (never exported, or changed since), or exist only in the sync directory, with the differing names. This is what drush config:import would act on; nothing is exported, imported, or written here.

An empty sync directory shows everything as "Only in DB" -- export first with drush config:export (or the export_config tool) before expecting a useful comparison.

drush_commandB

Execute any Drush command.

options values are rendered as drush expects them. Drush flags take no value, so {"yes": True} must become --yes and not --yes=True, which drush rejects with "The --yes option does not accept a value". That made every confirmation-answering call fail -- including pm:install, so installing a module reported success while nothing was installed. A False means the caller does not want the flag, so it is omitted rather than spelled --yes=False; that direction was the dangerous one, because it used to pass --yes and silently suppress confirmation on destructive commands.

ddev_setupA

Generate .ddev/config.yaml for a local Drupal environment.

Refuses to overwrite an existing config: calling this with defaults on a working project used to replace the whole file with name: ., which takes the project down.

ddev_startC

Start DDEV project.

ddev_stopC

Stop DDEV project.

ddev_execC

Execute command in DDEV container.

lando_startC

Start Lando project.

lando_stopC

Stop Lando project.

lando_execC

Execute command in Lando container.

lando_setupC

Generate .lando.yml for a local Drupal environment.

acquia_deployC

Deploy to Acquia Cloud via acquia-cli or Drush acquia integration.

Supports both acquia-cli (preferred) and legacy Drush acquia commands.

backup_databaseC

Create database backup via Drush.

cache_rebuildB

Clear and rebuild all Drupal caches via Drush.

composer_installD

Run composer install.

composer_requireC

Require one or more packages via composer.

Several packages may be given at once, space separated, the way composer require itself accepts them. They used to arrive as a single argv token, so composer read "drupal/pathauto" as a version constraint on "drupal/token" and refused the command with "Could not parse version constraint" -- a confusing error for the ordinary request "install these two modules". A package name never contains a space, so the split is unambiguous.

composer_updateC

Run composer update.

drush_cronC

Run cron.

drush_watchdogC

Show recent log entries from watchdog.

cache_clearC

Clear specific cache bins.

drush_updbC

Run database updates.

drush_php_evalC

Execute arbitrary PHP code via Drush.

ai_analyze_content_qualityC

Analyze content quality using AI.

ai_suggest_field_mappingsC

Suggest field mappings using AI.

ai_generate_migration_planD

Generate migration plan using AI.

ai_translate_contentC

Translate content using AI.

create_vocabularyC

Create a taxonomy vocabulary.

get_vocabularyB

Get a taxonomy vocabulary by ID.

update_vocabularyD

Update a taxonomy vocabulary.

delete_vocabularyC

Delete a taxonomy vocabulary.

list_vocabulariesB

List all taxonomy vocabularies.

create_termC

Create a taxonomy term in a vocabulary.

get_termC

Get a taxonomy term by ID.

update_termD

Update a taxonomy term.

delete_termC

Delete a taxonomy term.

list_termsC

List terms in a vocabulary with filters and pagination.

create_userC

Create a user account.

get_userC

Get a user by ID with optional relationship includes.

get_user_by_emailC

Get a user by email address.

update_userC

Update a user account.

delete_userC

Delete a user account.

list_usersC

List users with filters and pagination.

assign_roleC

Assign a role to a user.

remove_roleC

Remove a role from a user.

list_rolesB

List all available roles.

get_user_rolesC

Get roles assigned to a user.

block_userC

Block a user account.

unblock_userC

Unblock a user account.

db_queryA

Execute a single read-only SELECT query on the Drupal database.

One statement only, no comments, and no write or file-access clauses.

db_tablesB

List all database tables.

db_table_infoC

Get table schema information.

db_countC

Count rows in a table.

views_listC

List all views on a Drupal site.

views_getC

Get a single view configuration by ID.

views_createC

Create a new view.

views_updateD

Update an existing view.

views_deleteC

Delete a view.

views_executeA

Execute a view and return its rows.

Runs the view through the Views API rather than guessing at a GraphQL schema. The graphql module ships no view(view_id:...) root field, so the query this used to send could never resolve, and the fallback asked JSON:API for views/{id}/{display}, which is not a resource either. Neither path was reachable, so the tool failed wherever Views was installed and healthy.

args are the view's contextual filters, in order. filters are set on the view's exposed input, which is what a visitor filling in the view's own filter form sets. A display that does not exist is reported along with the displays the view does have: ViewExecutable::setDisplay would otherwise fail later, with a message naming neither the view nor the display the caller asked for.

views_exportB

Export a view as configuration YAML or JSON.

paragraphs_type_listC

List all paragraph types on a Drupal site.

paragraphs_type_getC

Get a single paragraph type configuration by ID.

paragraphs_type_createC

Create a new paragraph type.

paragraphs_type_updateC

Update an existing paragraph type.

paragraphs_type_deleteC

Delete a paragraph type.

paragraphs_item_listA

List paragraph items, optionally filtered by type.

A paragraph's type is its bundle, so filtering by type means addressing the paragraph--{type} collection. filter[paragraphs_type] does not exist -- it answered 400 "the field paragraphs_type does not exist" on every call, because there is no such field; the type lives in the resource type itself.

paragraphs_item_getC

Get a single paragraph item by ID.

paragraphs_item_createC

Create a new paragraph item of the specified type.

paragraphs_item_updateC

Update a paragraph item.

paragraphs_item_deleteC

Delete a paragraph item.

menu_listC

List all menus on a Drupal site.

menu_getC

Get a single menu configuration by ID.

menu_createC

Create a new menu.

menu_updateC

Update an existing menu.

menu_deleteC

Delete a menu.

menu_link_listC

List menu links, optionally filtered by menu.

menu_link_getC

Get a single menu link by ID.

menu_link_createC

Create a new menu link.

menu_link_updateC

Update a menu link.

menu_link_deleteC

Delete a menu link.

field_config_listC

List all field configurations on a Drupal site.

field_config_getB

Get a single field configuration by ID.

field_config_createC

Create a new field configuration.

field_config_updateC

Update a field configuration.

field_config_deleteC

Delete a field configuration.

field_storage_listC

List all field storage configurations on a Drupal site.

field_storage_getB

Get a single field storage configuration by ID.

field_storage_createC

Create a new field storage configuration.

field_storage_updateD

Update a field storage configuration.

field_storage_deleteC

Delete a field storage configuration.

revision_listC

List revisions for an entity.

Only the current revision is enumerable over JSON:API; the tool reports that honestly rather than inventing a collection URL.

revision_getC

Get a specific revision of an entity.

revision_revertA

Revert an entity to a specific revision.

Applies the revision's field values to the current entity. A PATCH that Drupal rejects is atomic, so a failure leaves the entity untouched.

revision_deleteC

Delete a specific revision of an entity.

revision_diffC

Diff two revisions of an entity.

redirect_listC

List all redirects on a Drupal site.

redirect_getB

Get a single redirect configuration by ID.

redirect_createC

Create a new redirect.

redirect_updateC

Update an existing redirect.

redirect_deleteC

Delete a redirect.

redirect_bulk_createC

Create multiple redirects in bulk.

redirect_bulk_deleteC

Delete multiple redirects in bulk.

cron_runC

Run cron.

cron_listA

List the jobs Drupal runs on cron, and when cron last ran.

In Drupal 8+ a "cron job" is a module implementing hook_cron; there is no job registry and no drupal_get_cron_jobs() - that Drupal 7 function is what this tool used to call, so it returned "Call to undefined function" on every site it has ever run against.

The implementations sit behind ModuleHandler::invokeAllWith(), whose callback is handed the listener without being forced to invoke it. Only $module is relied on: through Drupal 8-10 the callback receives ($function, $module, $arguments) and in Drupal 11 ($listener, $module), so the module is the second argument in every version, and never calling the first argument is what stops listing a job from running cron.

queue_listB

List all queues.

queue_runC

Run a specific queue.

queue_deleteA

Delete queue items: one by id, the oldest count, or the whole queue.

Drush's queue:delete takes exactly one argument - the queue name - so the item_id and count forms cannot go through it: they passed extra arguments that Drush refused with "Too many arguments", and all three branches failed, so this tool never once succeeded.

Even the plain case now runs in PHP rather than through Drush, because queue:delete only resolves queues that are registered as services and answers "Queue not found" for anything else - including a queue this very server just created with queue_create. Queue::deleteQueue() is what Drush calls internally, so the result is the same operation without Drush's registration requirement.

item_id deliberately repeats the queue name in its condition even though core's own DatabaseQueue::deleteItem() does not - that method deletes by item_id alone, so without the name a request for an item in one queue would happily delete a different queue's item that happened to share the id.

queue_infoC

Get queue information.

queue_createA

Create a queue and make it ready to accept items.

class_name is refused rather than silently dropped. Drupal resolves a queue's implementation in settings.php - queue_service_<name>, else queue_default, else the queue.database service - and that service must already exist in the container, so no API accepts a class name when a queue is created. Accepting it would let a caller believe they had a custom queue implementation when they had the default one.

code_audit_phpstanC

Run PHPStan static analysis on Drupal custom modules.

drupal_checkC

Run Drupal Check for deprecated code detection.

code_snifferC

Run PHP_CodeSniffer with Drupal coding standards.

deprecation_scanC

Scan for deprecated Drupal API usage.

security_auditC

Run security-focused static analysis.

composer_auditB

Run Composer security audit on dependencies.

code_quality_reportC

Run multiple code quality tools and generate combined report.

codebase_index_refreshA

Rebuild the local codebase module index.

Call after installing, enabling or creating modules so the other codebase tools see the current state. Returns counts of indexed modules by type and the module directories that were scanned.

codebase_searchB

Search the local codebase for modules providing a capability.

Ranks exact machine-name/name matches above description matches, which rank above code-body matches (hooks, services, routes, classes). Use scope 'custom' or 'contrib' to filter by module origin; 'all' includes core.

codebase_module_listA

List indexed local modules with metadata.

Each item carries machine name, human name, type (custom/contrib/ core), version, dependencies, path and description. With show_unused=True each item is flagged when nothing references it and it implements no hooks.

codebase_module_describeB

Describe one local module in full.

Returns the module's info.yml fields, dependencies, reverse dependencies, hooks, services, routes, classes and file count — everything the index knows about it.

codebase_unused_modulesA

List custom/contrib modules nothing references and that define no hooks.

A module counts as used when another module depends on it, when another module's services inject one of its services, or when it implements hooks itself. Candidates for removal.

codebase_redundancy_checkA

Check whether the local codebase already covers a capability.

Searches the index and reports the closest existing modules plus a recommendation: extend what exists rather than duplicating it.

codebase_hooks_findA

Find which local modules implement a hook, with file and line.

Accepts the hook with or without its 'hook_' prefix (both 'form_alter' and 'hook_form_alter' work). Implementations are reported per module with the file and line of the function.

codebase_paths_listA

Show the configured docroot and the module directories indexed.

Use this to verify which locations the codebase tools actually scan (modules, web/modules, sites/*/modules, core) before relying on search results.

codebase_files_listA

List every file in a local module as module-relative paths.

Useful to find the right path before calling codebase_file_read or codebase_function_read.

codebase_directory_treeB

Show a local module's directory structure as a nested tree.

Directories have children; files carry a size. The tree is depth and item capped to keep responses bounded.

codebase_file_readA

Read one file from a local module.

path is module-relative (e.g. 'mymod.module'). Content is truncated at 64 KB with a truncated flag. Absolute paths, '..' traversal and symlinks escaping the codebase are rejected.

codebase_function_readA

Extract a single PHP function (with its docblock) from a module.

Returns the file path, the line of the function and its code — enough to review one hook or method without reading whole files. Searches all PHP-ish files in the module, including class methods.

security_scanC

Run security-focused SAST using PHPStan with security extensions.

dependency_scanB

Scan dependencies for vulnerabilities using Composer audit and other tools.

config_security_checkB

Check Drupal configuration for security issues.

permission_auditC

Audit user permissions and roles.

sql_injection_scanC

Scan for SQL injection vulnerabilities in custom code.

xss_scanC

Scan for XSS vulnerabilities in custom code.

csp_auditC

Content Security Policy audit.

file_permissions_auditC

Audit file permissions for security issues.

code_security_scanA

Scan custom code for vulnerability patterns — no tools to install.

Matches PHP/JS/Drupal files against a curated registry of XSS, SQL injection, command injection, path traversal, hardcoded secrets, access-control, CSRF, and deprecated-API patterns, with Drupal-aware false-positive rules (EntityQuery conditions, stream wrappers, escapeshellarg, and similar safe APIs are recognized). The counterpart of security_scan, which needs PHPStan installed.

Target one module by machine name, or a directory relative to DRUPAL_ROOT; with neither, the site's own modules/ and themes/ directories are scanned (contrib and core excluded). categories narrows to registry keys ('xss', 'sql_injection', 'command_injection', 'path_traversal', 'hardcoded_secrets', 'access_control', 'csrf', 'deprecated_api'); severity narrows to one level. Findings carry file, line, snippet, and a fix recommendation; counts cover the full run even when max_findings truncates the list.

route_access_auditA

Classify every route's access control from *.routing.yml files.

The routing half of a pre-deployment review: each route is classified by what it requires — fully anonymous (access: TRUE), a permission, roles, entity access, a custom access callback, or nothing at all, which is the finding. Controllers are mapped to the file that declares the class when it can be found, so a risky route leads straight to code. Targets work like code_security_scan: one module by machine name, a DRUPAL_ROOT directory, or the site's own modules/ and themes/ by default.

status_reportA

Run the site's status report (what /admin/reports/status shows).

Read-only. Returns each requirement with its title, severity ("error", "warning", "info", or "ok"), description, and value. By default errors and warnings are returned; use include_ok for the whole report or severity_filter for one level.

A failure here is usually the site's own requirements checker breaking, not this tool: the drush error is returned verbatim.

database_updatesA

List pending database updates (read-only; runs nothing).

Answers "did the modules I just updated leave schema behind?". Use drush_command("updatedb") (or the drush_updb tool) to apply them, after a database backup.

available_updatesA

List packages with newer versions available, from composer.

Read-only (composer outdated); needs the project's composer.json and network access. Packages are grouped into core, contrib, and other. Dev dependencies are excluded unless include_dev is set -- filtered via composer.json's require-dev, because composer marks none of them itself.

With security_only, the outdated list is cross-referenced against composer audit: only packages that are both outdated and covered by a security advisory are returned, with the advisories attached. (The composer_audit tool lists advisories regardless of updates.)

health_checkA

Check that this server can actually reach a working Drupal site.

Runs four read-only probes: Drush and the site status, the database connection, the JSON:API index, and the modules the other tools assume (jsonapi required; dblog and basic_auth recommended). Each failure comes with the concrete fix. Run this first when other tools return opaque connection errors.

module_searchC

Search Drupal.org for modules by name or description.

module_getB

Get module details from Drupal.org by machine name.

module_versionsC

Get all available releases for a module.

module_dependenciesA

Get the packages a module release requires.

Read from Composer metadata on packages.drupal.org, which is where Drupal publishes dependency data today. Omit version for the newest release.

theme_searchC

Search Drupal.org for themes by name or description.

theme_getB

Get theme details from Drupal.org by machine name.

release_historyC

Get release history for a project.

project_usageC

Get download/usage statistics for a project.

module_compatibilityB

Check whether a project has releases for a given core version.

module_issues_searchA

Search a module's drupal.org issue queue for issues that match a problem.

Describes the problem (e.g. "Azure AD attribute mapping fails") and the most recently updated issues are scored on keyword overlap with their titles and bodies; the best matches come back first, each with a link. Set drupal_version (e.g. "10") to hide issues filed against other major versions; when unset it is detected from DRUPAL_ROOT if configured.

module_popularA

List the most-installed modules on Drupal.org, newest usage first.

Optionally filter by a drupal.org category such as "E-commerce", "Security", "SEO", or "Media" (case-insensitive, substrings work). Usage is summed across every release line, so a module's full install base shows up in one number. Categories are listed in the error if the name does not match one.

module_recommendationB

Recommend modules for a need: what the local codebase already ships, plus drupal.org options.

Combines the local codebase index (available when DRUPAL_ROOT is set) with drupal.org search, so the answer starts with modules you already have before suggesting downloads.

moderation_state_listC

List all moderation states.

moderation_state_getC

Get a single moderation state by ID.

moderation_state_createC

Create a new moderation state.

moderation_state_updateC

Update a moderation state.

moderation_state_deleteC

Delete a moderation state.

moderation_transition_listA

List a workflow's moderation transitions.

Transitions are configuration inside the workflow entity, not entities of their own, so there is no workflow_transition resource for JSON:API to list. They are read from the workflow's workflow-type plugin (WorkflowTypeInterface::getTransitions()), which is where Drupal keeps them.

Every workflow is read when workflow_id is left out. Naming a workflow that does not exist answers an error listing the ones this site has, rather than an empty list that reads as "no transitions".

moderation_transition_getA

Get a single moderation transition by ID.

Transitions belong to a workflow rather than being entities, so this searches every workflow's transitions for the named one. Pass include=states to attach the states of the workflow that owns it -- transitions have no JSON:API relationships to include.

moderation_transition_createA

Create a new moderation transition on a workflow.

Transitions are configuration inside the workflow entity, so they cannot be POSTed as a JSON:API resource. This adds one the way Drupal's own transition form does: through WorkflowTypeInterface::addTransition() and a save of the workflow, which writes the change back into the workflow's configuration.

Both the origin states and the target state must already exist in the workflow; an error names the ones that do not and lists the states the workflow does have. weight defaults to 0, which places the transition first -- pass a higher number to append it.

moderation_transition_deleteA

Delete a moderation transition from a workflow.

The counterpart of moderation_transition_create: a transition is configuration inside its workflow, so this removes it through WorkflowTypeInterface::deleteTransition() and saves the workflow, exactly as Drupal's own delete form does. The reply reports how many transitions the workflow has left, and warns when that was the last one -- a workflow with no transitions cannot move content at all.

moderation_transition_executeA

Execute a moderation transition on an entity.

Looks the transition up on its workflow and applies its target state to the entity, refusing when the entity's current state is not one the transition starts from. The old version fetched the transition through JSON:API, which has no such resource, so this never ran.

content_moderation_dashboardC

Get content pending moderation - dashboard view.

workflow_listC

List all workflows.

workflow_getC

Get a single workflow by ID.

module_createC

Create a new Drupal module with full scaffolding.

module_service_createC

Create a service definition with PHP class stub.

module_plugin_createC

Create a plugin (block, field, views, etc.) with proper scaffolding.

module_form_createC

Create a form class (ConfigForm, ConfirmForm, FormBase, etc.) with proper scaffolding.

module_controller_createC

Create a controller class with routing.

module_event_subscriber_createC

Create an event subscriber service with getSubscribedEvents method.

module_hook_implementC

Implement a hook in an existing module.

module_info_generateC

Generate .info.yml from existing module code (reverse engineering).

module_permission_createC

Create or update permissions.yml with custom permissions.

module_config_schema_createC

Create or update config schema YAML for module settings.

module_test_createC

Create a PHPUnit/Kernel test skeleton.

module_dependencies_analyzeC

Analyze module code and suggest missing dependencies.

theme_createC

Create a new Drupal theme with full scaffolding.

theme_library_createC

Create or update a theme library.

theme_region_createC

Add a region to theme.

theme_template_overrideC

Create a template override in theme.

theme_preprocess_functionC

Add a preprocess function to theme.

theme_breakpoint_createC

Add a breakpoint to theme.

theme_base_changeC

Change the base theme.

theme_settings_formD

Generate theme settings form.

theme_asset_optimizeD

Configure theme asset optimization.

theme_debug_enableC

Enable theme debugging (Twig debug, etc.).

theme_lint_twigC

Lint Twig templates in theme.

block_listC

List all blocks.

block_getC

Get a single block by ID.

block_createD

Create a new block.

block_updateD

Update a block.

block_deleteC

Delete a block.

block_placeC

Place a block in a region with weight.

layout_builder_listB

Report which entity view displays have Layout Builder enabled.

Layouts themselves are not readable over JSON:API (see the other layout_builder_* tools), but the display config that switches Layout Builder on for a bundle is, so this returns that instead of a 404.

layout_builder_getA

Read the Layout Builder layout for an entity type and bundle.

Returns whether Layout Builder is enabled and overridable for the bundle, plus every section with its layout plugin, region and components. This reads the real view display rather than the JSON:API resource that does not exist.

layout_builder_createB

Replace the Layout Builder layout for a bundle.

layout may be a list of section specs, {"sections": [...]}, or a single {"layout_id": ..., "components": [...]}. Layout Builder is switched on if it was off. lock marks each component as locked against per-entity editing; Layout Builder has no display-level lock, so this is a component lock.

layout_builder_updateA

Update the Layout Builder layout for a bundle.

With layout given it replaces every section, exactly like layout_builder_create. With layout omitted it only applies lock, or just reports the current state when both are omitted.

layout_builder_sections_listB

List the sections in a bundle's Layout Builder layout.

Each section reports its layout plugin, and the components in it report region, plugin id and weight.

layout_builder_section_addA

Append a section to a bundle's Layout Builder layout.

section takes layout_id (default layout_onecol) and components, which may be plugin ids or objects with plugin, region and configuration. Layout Builder is switched on if it was off. Returns the full section list afterwards.

block_plugin_listC

List available block plugins.

block_region_listC

List available regions for a theme.

layout_builder_override_removeA

Remove a Layout Builder override so an entity falls back to the default.

Pass entity_id (for a node, its nid) to revert that one entity. Omit it to list the entities of this bundle that currently carry an override, which is what you need before you can pick one.

Reverting clears the entity's layout_builder__layout field through OverridesSectionStorage, which is where Drupal keeps overrides - they are not config and cannot be read from entity_view_display.

search_api_server_listC

List all Search API servers.

search_api_server_getC

Get a single Search API server by ID.

search_api_server_createC

Create a new Search API server.

search_api_index_listC

List Search API indexes.

search_api_index_getC

Get a single Search API index by ID.

search_api_index_createC

Create a new Search API index.

search_api_index_updateD

Update a Search API index.

search_api_index_reindexC

Trigger reindexing of a Search API index.

search_api_index_clearC

Clear a Search API index.

search_api_server_enableC

Enable a Search API server.

search_api_server_disableC

Disable a Search API server.

search_api_facet_listB

List Search API facets.

index_id is no longer applied. A facet is attached to a facet source, not to the index, and the only field it carries is facet_source_id -- so filter[index] answered 400 "the field index does not exist" on every call, and there is no field to filter on instead. Each returned facet carries its facet_source_id, which is what a caller needs to match facets to an index.

search_api_facet_createC

Create a Search API facet.

language_listC

List all languages.

language_getC

Get a single language by langcode.

language_addC

Add a new language.

language_enableC

Enable a language.

language_disableC

Disable a language.

language_deleteC

Delete a language.

content_translation_enableC

Enable content translation for entity type/bundle.

translation_statusC

Get translation status for an entity.

translation_addD

Add translation for an entity.

translation_updateC

Update translation for an entity.

interface_translation_listA

List the interface translations Drupal holds.

Locale does not store translations as entities, so there is no interface_translation resource to page through: they live in Locale's own storage, joined from each source string to its translation in a language -- which is where drush locale:export reads them from too.

langcode narrows the list to one language; left out, every language is listed and each row says which one it is. filters accepts search (a substring of the source text) and context (the source context, matched exactly). Only translated strings are returned: an untranslated source is not a translation. count is the total that matched, before paging.

interface_translation_addA

Add an interface translation for one source string.

Written through Locale's own string storage -- createString() / createTranslation() plus save() -- which is what locale:import does with a .po file, one entry at a time. There is no locale:translate:* command to run instead.

If the source string is not one Drupal has already collected, it is created too and the reply says so: a translation nobody will ever look up is worth knowing about. The locale lookup cache is invalidated, so the new text is visible without a cache rebuild.

interface_translation_updateA

Change an existing interface translation.

Same storage as interface_translation_add, but this one refuses to invent anything: an unknown source string, or a source with no translation in langcode, is an error that says which of those it is and points at interface_translation_add. The string is marked customized so a later locale:import does not overwrite it.

interface_translation_deleteA

Remove an interface translation from one language.

Drops the row from locales_target for this source and language; the source string itself stays, because it is Drupal's own string and other languages still use it. There is no locale:translate:delete command, and re-importing a .po file without the entry is no longer the only way to do this.

config_translation_listB

List the config objects that support translation.

There is no config_translation resource in JSON:API, because Drupal does not store config translations as entities: a translation belongs to the config object that declares a translation mapping. Asking JSON:API for a resource that cannot exist returned a 404 that read exactly like a missing module, so the tool looked uninstalled rather than wrong.

Each mapping is returned with the entity type it translates. The mapping's own config-name list is empty until Drupal builds it inside the translation form, so it is not reported here -- the id and the entity type are what config_translation_add needs.

config_translation_addA

Translate a config entity.

config_name is {entity_type}/{entity_id}, for example node_type/article. config_translation_list shows which entity types this site can translate. translation is a flat map of property to translated value.

A config entity is not a translatable entity. There is no TranslatableInterface to call, no addTranslation(), and no config:translation:add Drush command -- which is what this tool tried, twice, both failing every time. Drupal keeps a config translation as a language config override: the same config object, overridden per language. So the entity type is resolved through the config translation mapper to the config object it is stored as, and that object's override for the target language is what gets written.

language_negotiation_getB

Get language negotiation configuration.

language_negotiation_setC

Set language negotiation method.

media_type_listC

List all media types.

media_type_getC

Get a single media type by ID.

media_type_createD

Create a new media type.

media_create_from_urlC

Create media from URL (oEmbed).

media_create_from_base64C

Create media from base64 encoded file data.

media_derivative_generateC

Generate a specific derivative for media.

media_bulk_importC

Bulk import media files from directory.

media_library_listD

List media library items.

pathauto_pattern_listA

List pathauto patterns.

A pattern's target entity type and bundle are encoded in its id, as {entity_type}--{bundle}, rather than held in fields of their own. filter[entity_type] and filter[bundle] therefore answered 400 "the field ... does not exist" on every call. Both are needed to filter server-side; with only one there is no field to match on, so every pattern is returned and the caller narrows from the ids.

pathauto_pattern_getC

Get a single pathauto pattern by ID.

pathauto_pattern_createD

Create a new pathauto pattern.

pathauto_pattern_updateD

Update a pathauto pattern.

pathauto_pattern_deleteC

Delete a pathauto pattern.

pathauto_generateC

Generate pathauto aliases.

pathauto_token_listC

List available pathauto tokens.

redirect_pattern_listC

List redirect patterns.

metatag_config_listC

List all metatag configurations.

metatag_config_getC

Get a single metatag configuration by ID.

metatag_config_createC

Create a new metatag configuration.

metatag_config_updateD

Update a metatag configuration.

metatag_defaults_getC

Get default metatag values for entity type/bundle.

metatag_defaults_setC

Set default metatag values for entity type/bundle.

metatag_token_listC

List available metatag tokens.

metatag_canonical_setC

Set canonical URL for an entity.

metatag_jsonld_generateC

Generate JSON-LD structured data for entity.

commerce_store_listC

List all commerce stores.

commerce_store_getC

Get a single commerce store by ID.

commerce_store_createC

Create a new commerce store.

commerce_store_updateC

Update a commerce store.

commerce_product_listC

List commerce products.

commerce_product_getB

Get a single commerce product by ID.

commerce_product_createC

Create a new commerce product.

commerce_product_updateC

Update a commerce product.

commerce_order_listC

List commerce orders.

commerce_order_getC

Get a single commerce order by ID.

commerce_order_createC

Create a new commerce order.

commerce_order_updateD

Update a commerce order.

commerce_payment_gateway_listC

List payment gateways.

commerce_payment_gateway_getC

Get a single payment gateway by ID.

commerce_promotion_listC

List commerce promotions.

commerce_promotion_createC

Create a new commerce promotion.

commerce_shipping_method_listC

List shipping methods.

commerce_shipping_method_createC

Create a new shipping method.

webform_listC

List all webforms.

webform_getC

Get a single webform by ID.

webform_createC

Create a new webform.

webform_updateD

Update a webform.

webform_deleteC

Delete a webform.

webform_submission_listC

List webform submissions.

webform_submission_getC

Get a single webform submission by ID.

webform_submission_deleteC

Delete a webform submission.

webform_element_listB

List elements in a webform.

webform_element_createC

Add an element to a webform.

webform_handler_listB

List the handlers attached to a webform.

Handlers are plugins configured on the webform, not entities, so there is no webform_handler resource for JSON:API to list. This reads them off the webform instead, which is where they live.

webform_handler_createA

Create a webform handler (email, remote post, etc.).

A handler is a plugin held inside the webform's own configuration -- there is no webform_handler entity and JSON:API cannot POST one. This builds the plugin through plugin.manager.webform.handler and attaches it with Webform::addWebformHandler(), which is the same sequence Webform's own add-handler form runs.

id is the handler's id within the webform (email_confirmation, not email); handler_type is the plugin (email, webhook, auto_save, ...). configuration supplies plugin settings, which are merged over the plugin's defaults -- the reply echoes the whole resulting configuration so you can see what the defaults filled in.

webform_handler_updateA

Update a webform handler.

Handlers have no entity id of their own, so this finds the webform that owns handler_id and writes back through Webform::updateWebformHandler(). Pass webform_id to skip the search; without it, a handler id used by more than one webform is an error naming them rather than a guess.

configuration keys are replaced as a whole and keys you leave out keep their current value, so you can change one setting without resending the rest.

webform_handler_deleteB

Delete a webform handler from its webform.

Removes it the way Webform's own delete form does -- through Webform::deleteWebformHandler(), which also runs the plugin's teardown. The webform's other handlers are left alone.

webform_token_listC

List available webform tokens.

webform_export_submissionsC

Export webform submissions.

jsonapi_schema_getC

Get JSON:API schema (OpenAPI/Swagger).

jsonapi_include_optimizeC

Get optimized include paths for entity type.

jsonapi_sparse_fieldsetsC

Get entity with sparse fieldsets (only requested fields).

graphql_schema_getC

Get GraphQL schema.

graphql_queryC

Execute a GraphQL query.

graphql_schema_extendC

Extend GraphQL schema with custom fields (requires schema customization module).

nextjs_helpers_generateC

Generate Next.js helper functions for Drupal entities.

gatsby_helpers_generateC

Generate Gatsby source plugin config and helpers.

jsonapi_resources_listC

List all available JSON:API resources.

jsonapi_resource_typesB

Get all resource types available in JSON:API.

test_run_phpunitC

Run PHPUnit tests.

test_run_kernelD

Run Kernel tests.

test_run_behatC

Run Behat tests.

test_run_nightwatchC

Run Nightwatch tests.

test_scaffold_phpunitC

Scaffold a PHPUnit test class.

test_scaffold_behatC

Scaffold a Behat feature file.

test_scaffold_nightwatchC

Scaffold a Nightwatch test.

test_coverage_reportC

Generate test coverage report.

test_list_suitesB

List available test suites.

accessibility_axe_scanC

Run axe-core accessibility scan on a URL.

accessibility_wcag_checkC

Check WCAG compliance for entity content.

accessibility_color_contrastB

Check color contrast ratio.

Pure arithmetic: it deliberately does not touch the site, so it works without Drush configured.

accessibility_aria_validateC

Validate ARIA attributes on entity.

accessibility_report_generateC

Generate comprehensive accessibility report.

performance_query_logC

Get slow query log.

performance_cache_statsB

Get cache performance statistics.

performance_redis_infoB

Get Redis server info.

performance_bigpipe_statusB

Check BigPipe status and configuration.

performance_bigpipe_enableC

Enable or disable BigPipe.

performance_memcached_statsC

Get Memcached statistics.

performance_page_load_analyzeC

Analyze page load performance.

contact_form_listC

List all contact forms.

contact_form_getC

Get a single contact form by ID.

contact_form_createC

Create a new contact form.

contact_form_updateD

Update a contact form.

contact_form_deleteC

Delete a contact form.

contact_message_listC

List contact form submissions.

contact_message_getC

Get a single contact message by ID.

contact_message_deleteC

Delete a contact message.

contact_spam_checkC

Check if a contact message is spam.

comment_listD

List comments.

comment_getC

Get a single comment by ID.

comment_createC

Create a new comment.

comment_updateC

Update a comment.

comment_deleteC

Delete a comment.

comment_thread_listC

List comment thread for an entity.

Returns the whole thread, replies included. It used to add filter[pid] = 0 to get top-level comments only, but pid is an entity reference to the parent comment, so JSON:API rejected it with "must end with one of the following specifiers" -- and had it accepted pid.id = 0 it would have matched nothing, since no comment has id 0. Each row carries its own pid, which is what a caller needs to build the tree.

comment_approveB

Approve a comment (set status to published).

comment_unapproveB

Unapprove a comment (set status to unpublished).

comment_field_settingsC

Get comment field settings for entity type/bundle.

comment_field_configureD

Configure comment field settings.

feeds_feed_listC

List all feeds.

feeds_feed_getC

Get a single feed by ID.

feeds_feed_createC

Create a new feed.

feeds_feed_updateD

Update a feed.

feeds_feed_deleteC

Delete a feed.

feeds_importC

Run a feed import.

feeds_import_statusC

Get feed import status.

feeds_log_listA

List feed import logs.

Superseded by feeds_import_status, which reports the outcome of the current import. Feeds 3.x removed the log entity, so there is nothing of this shape to list on any site.

feeds_tamper_listB

List tamper plugins for a feed.

feeds_parser_listA

List available feed parsers.

feeds_fetcher_listB

List available feed fetchers.

feeds_processor_listB

List available feed processors.

export_nodesA

Export a node inventory to a CSV or Excel file on disk.

Writes one row per node (id, type, title, status, dates, author, path) and returns only the file path and statistics, so a 5,000-node audit never has to travel through the conversation. The data comes from JSON:API, so titles and bodies with newlines or accents survive intact.

content_type limits the export to one bundle (for example "article"); unpublished nodes are left out unless asked for. With include_fields a final fields column carries the node's remaining field values as JSON, each string capped at 5000 characters. limit caps the rows written (0 = no cap, 100000 maximum). format is "csv" (UTF-8 with BOM, opens cleanly in Excel) or "xlsx". The file may be written only inside the Drupal root, the system temp directory, or your home directory; without output_path it lands in {Drupal root}/exports/ or /tmp/drupal-mcp-exports/ with a timestamped name.

export_usersA

Export the site's user accounts to a CSV or Excel file on disk.

One row per user: id, name, email, active/blocked status, role labels, registration/last-login dates. Blocked accounts are always included (their status column says so) - an audit needs them. The file lands in {Drupal root}/exports/ or /tmp/drupal-mcp-exports/ unless output_path says otherwise (confined to the Drupal root, the temp directory, or your home). Drupal's uid-0 anonymous pseudo-account carries no id attributes and is skipped rather than exported as a row of nulls (see skipped_without_id).

export_mediaB

Export the media library to a CSV or Excel file on disk.

One row per media item: id, bundle, name, status, dates, owner, and the managed file's filename and URI when there is one (found through relationships, so renamed file fields still work). media_type limits the export to a bundle such as "image". Empty sites write nothing and say so.

export_taxonomyA

Export taxonomy terms to a CSV or Excel file on disk.

One row per term: id, vocabulary, name, description, weight, status, and - with include_usage (the default) - how many entities reference the term, through which fields, and a safe_to_delete verdict ("yes" only when nothing references it, and withheld entirely whenever some field could not be counted). Usage comes from one COUNT query per field storage targeting taxonomy terms, so a 5,000-term vocabulary costs a handful of queries, not 5,000.

vocabulary limits the export to one vocabulary machine name (for example "tags"). When Drush is unavailable the export still succeeds and says the usage columns are empty.

theme_activeA

List the site's themes: default, admin, and every enabled one.

Reads system.theme and drush pm:list; returns the default and admin theme machine names plus each enabled theme's package, path, and version, with counts of the disabled ones.

theme_infoA

Describe one theme: metadata, base-theme chain, regions, libraries.

Combines drush pm:list (status, version, path) with a YAML parse of the theme's own .info.yml (description, regions in declaration order, libraries, dependencies) and follows the base theme chain upward as far as the site allows. Requires DRUPAL_ROOT: the info.yml lives on the local docroot.

theme_regionsA

Region layout of a theme with the blocks placed in each one.

Regions come from the theme's info.yml in declaration order; each carries its blocks (label, plugin, weight, enabled state) and a count, so empty regions and placements in regions the theme no longer defines are both visible at a glance. Needs DRUPAL_ROOT (info.yml) and the JSON:API client (block placements).

theme_blocksA

List placed blocks with optional theme, region, and text filters.

Reads every block.block.* placement from JSON:API: id, theme, region, label, plugin, weight, and enabled state. search matches label and plugin case-insensitively (the "do we have a block like Site branding?" question); theme_name and region narrow the list to one placement set. With no filters every placement on the site is returned, most specific sort first (theme, region, weight).

theme_templatesA

List a theme's Twig templates (*.html.twig) with sizes.

Walks the theme directory on the local docroot (symlinks skipped, nothing outside DRUPAL_ROOT reported). pattern is a case-insensitive substring matched against the template name — "node--", "views", "field" — to narrow the list. Returns docroot-relative paths and byte sizes, sorted.

theme_template_overridesB

Which core/module templates a theme overrides, and which it invented.

For every Twig file in the theme, the docroot is indexed once for files with the same name outside that theme; a match means the theme's copy wins at render time (an override), no match means a theme-original template. Returns both lists with paths, plus how many Twig files were scanned. Requires DRUPAL_ROOT.

template_suggestionsA

Twig template names Drupal will try for an entity, specific first.

The suggestion chain for node, block, taxonomy_term, user, field, or page rendering (bracketed parts are placeholders Drupal fills in, e.g. node--article--123.html.twig beats node--article.html.twig). Unknown entity types get the generic chain. When DRUPAL_ROOT is configured each suggestion is marked in_checked_theme: whether the default theme already ships that file, so you know which name creating one would actually take effect.

view_template_infoA

Template names for overriding a Views display, verified against the site.

Looks the view up in the JSON:API view collection by its machine id (drupal_internal__id), so the display list is real: with display_id the chain starts at views-view--NAME--DISPLAY and falls back to the whole view; without it every display gets an entry, then the views-view base template. An unknown view errors with the views the site has, an unknown display_id with the displays that view has, and suggestions are marked in_checked_theme when the default theme's templates can be read (DRUPAL_ROOT). Views config changed names between Drupal generations (view.* on older sites, views.view.* on Drupal 11.4+), so the collection — addressed by entity id — is the stable source.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

C2.3/5.0

Scored across 414 tools

Disambiguation2/5

With 414 tools, many overlap heavily: cron_run vs drush_cron, cache_rebuild vs cache_clear, security_audit vs security_scan vs code_security_scan, and ai_analyze_content_quality vs analyze_content_quality are just a few examples. The CRUD families for each Drupal entity are distinct, but the sheer number of near-duplicates makes selection error-prone.

Naming Consistency3/5

Most names are snake_case and readable, but the verb/noun ordering is inconsistent: create_node uses verb_noun, while commerce_store_list and webform_submission_list use noun_verb. Mixed prefixed families and occasional abbreviations keep this from being fully predictable.

Tool Count1/5

414 tools is an extreme mismatch for a Drupal MCP server. Even a comprehensive site-management surface should be far smaller; this count guarantees heavy redundancy and makes tool discovery impractical for an agent.

Completeness4/5

The surface covers an enormous range of Drupal domains: content, taxonomy, users, config, migrations, testing, accessibility, performance, commerce, webforms, search, and translation. Some lifecycle gaps exist (e.g. no delete for several commerce entities), but most major workflows have some supporting tool.

Maintenance

ActivityMaintained
ResponsivenessNo issues