Skip to main content
Glama

Server Details

Drupal core API changes, contrib usage, upgrade readiness, patch verdicts, code search, SQL.

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Uptime
99.7% over 41 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A4.5/5.0

Scored across 16 tools

Disambiguation3/5

Tools are mostly distinct, but some overlap: check_patches and reroll_patch are clearly sequential, but scan_composer also handles patches, and what_changed/list_change_records/get_change_record have some overlap. Most have clear purposes, but a few could be confused (e.g., list_symbol_users vs lookup_core_symbol).

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: check_, describe_, get_, list_, lookup_, project_, query_, reroll_, scan_, search_, subsystem_, what_. Clear and predictable.

Tool Count4/5

16 tools is at the high end of reasonable, but each serves a distinct purpose in a complex domain (Drupal code analysis). Slightly heavy, but justified given the scope: patch checking, dataset queries, symbol lookups, change records, project profiles, and upgrade reports.

Completeness5/5

The tool set covers the full lifecycle of Drupal code analysis: scanning composer files, applying patches, checking core changes, querying datasets, and generating upgrade reports. No obvious gaps; even exported parquet files are mentioned for further analysis.

Available Tools

16 tools
check_patchesCheck composer patches against a releaseA
Read-onlyIdempotent
Inspect

Does each composer patch still apply to the release the site installed, and is its fix already in that release?

  • Send composer_json and composer_lock after composer update. Add patch_files for every patch, a local one read from disk and a URL one fetched by you. Every extra.patches entry is checked at its installed version in one call.

  • Do not download releases. Do not run patch --dry-run.

  • Send a package's patches together, in the order composer.json lists them.

  • items: up to 50 of {project, version, patch, title}, in place of the composer files. project: the drupal.org machine name (webform) or composer name (drupal/webform); drupal or core for Drupal core. version: the installed composer version (1.13.0, 2.0.0-beta4, 11.4.5). patch: the diff text, or its URL on www.drupal.org/files/issues or a git.drupalcode.org merge request or commit, ending .patch or .diff.

  • Per item. tag: the release tag matched, or unknown_version. applies_at: the -p level at which git apply passes, null when none. fuzzy: true when it applied only with reduced context and whitespace ignored; review it. hunks_failed: [{file, line, reason}]. reverse_applies: true when the patched lines are already in the tag. mr: the merge request state when the patch is an MR URL. merged_in_version. suggested. failure_mode: set when a patch applies and a file it touches no longer parses; keep the patch and fix the file. syntax_errors: the files behind it, one per file, path then the parser's message.

  • suggested: the verdict. merged: the fix is in the release; drop the patch. applies: keep the patch. conflicts: call reroll_patch with that item. unknown: see error.

  • next_step: the follow-up calls and the row count the report must have. counts: the verdict tally; check the report's table against it. An item that could not be judged comes back unknown with the reason in error. Report it as unclear. Never leave the row out.

  • hunks_shipped, files_shipped: the parts of a patch already in the release verbatim. On a conflicts row, check whether the rest is still needed before re-rolling. moved_to: on a failed hunk, the release path of the renamed file.

  • core_references: what the added code references in core, checked at target_core. flagged: removed or moved classes, and calls whose argument count does not fit the target signature, each with file, line, change_record and replacement. parent::__construct is checked against the constructor of the core parent class. deprecated: a short side list. checked: how many references the catalog knows. Scope: added lines and direct references only (extends, implements, trait use, new, static calls, parent::__construct). A patch that does not apply has a note instead.

  • Verdicts come from git apply --check against the tag. An applies patch can still be wrong at runtime.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemsNoUp to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: the diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. source: optional, the path or URL the patch was declared with. merge_patch: optional, the .diff form of a merge request, used for the merge of a re-roll while patch decides the verdict. provenance: optional, where a copied patch's bytes came from, {mr, commit, url, base, head, fetched, rerolled}. Send it when source is a local path. title: optional, echoed back. base: optional, the release the site had before the upgrade. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock.
patch_filesNoThe text of every patch the site declares, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too.
target_coreNoCore the added code is checked against: a minor (11.4 or 11.4.x) or a release (11.4.5). A minor with no core release in the data is refused, and so is a major alone. latest checks no references. Defaults to the lock's drupal/core, else the version of a drupal item.
patches_fileNoThe text of the patches file, for a site on cweagans/composer-patches 2.x that keeps its patches out of composer.json. The path is in its own extra.composer-patches.patches-file, patches.json by default.
patches_lockNoThe text of patches.lock.json, which 2.x of the patch manager writes and applies from. Send it to judge what the site actually applies: it answers alone, over extra.patches and the patches file.
composer_jsonNoThe contents of composer.json. Send the text; this server cannot read your filesystem. Its extra.patches becomes the item list, one item per patch.
composer_lockNoThe contents of composer.lock. It gives the installed version of each patched package.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly/idempotent/non-destructive/openWorld=false, and the description adds genuinely new behavioral facts: verdicts come from 'git apply --check against the tag', the service performs no downloading so URL patches must be fetched by the caller, and the caveat that 'An applies patch can still be wrong at runtime'. It stops short of describing performance bounds or how the tag is resolved beyond the failure_mode/unknown notes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very dense and long, but the opening question front-loads the purpose and each subsequent line is scoped to either an input parameter or an output field. Some output-field lines (e.g. hunks_shipped/moved_to) are tightly packed and could be split for readability, but little is redundant filler given there is no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full return-value burden and does so: it documents tag, applies_at, fuzzy, hunks_failed, reverse_applies, mr, merged_in_version, suggested verdicts, failure_mode, syntax_errors, core_references/flagged/deprecated/checked, next_step and counts. The unknown-row handling ('Report it as unclear. Never leave the row out.') closes the failure loop for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so 3 is the floor; the description goes beyond it by stating that a package's patches must be sent together and in composer.json order, and by enumerating the accepted patch sources (.drupal.org/files/issues, git.drupalcode.org MR/commit, .patch or .diff suffixes) and the accepted project/version formats. The order constraint in particular is not enforced by the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The lead sentence states a precise test with two outcomes ('does each composer patch still apply to the release... and is its fix already in that release'), which is a specific verb+resource rather than a restatement of the name. It also implicitly separates this tool from reroll_patch by naming that sibling as the escalation path for conflicts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('Send composer_json and composer_lock after composer update. Add patch_files for every patch'), explicit when-not ('Do not download releases. Do not run patch --dry-run'), and an explicit alternative routing rule ('conflicts: call reroll_patch with that item'). Ordering guidance per package is also given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

describe_datasetDescribe the datasetA
Read-onlyIdempotent
Inspect

Learn the dataset before writing SQL for query_dataset. Call it with no arguments first. Returns text. Prefer a typed tool when one answers the question.

  • No arguments: one line per view, the join map, the four invariants, the causes of empty results, and the recipe index. The invariants: dev-branch isolation, no SUM(usage), *_seq compares, adoption polarity. Empty results come from fqn forms, placeholders and machine name forms.

  • view=, or views=[…] for several in one call. Returns the columns with types and descriptions, an example filter that returns rows, and the joins into the view.

  • recipe=: a ready-to-run statement for a common question. Fill in the placeholders and run it with query_dataset. Recipes cover who uses a symbol, deprecated symbols per project, and a change record's adoption. Others cover symbols deprecated between minors, one project's deprecated uses, and change records between minors.

ParametersJSON Schema
NameRequiredDescriptionDefault
viewNoOne view name. Returns its columns with types and descriptions, an example filter, and the joins into it. Leave empty for the overview.
viewsNoUp to 8 views at once, documented one after the other in one call.
recipeNoOne recipe id from the overview's index. Returns a ready-to-run query_dataset statement with its placeholders explained.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnly, idempotent, non-destructive behavior, and the description adds rich behavioral context: output varies by argument mode, no-args returns invariants and empty-result causes, view mode returns columns/filters/joins, and recipe mode returns ready-to-run statements. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured with a leading usage directive and clear bullet-style modes. Every sentence carries useful information, and the most important instruction ('call it with no arguments first') is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only metadata tool with no output schema, the description covers all three invocation modes, return contents, and connection to query_dataset. It also gives enough detail about invariants and empty-result causes to set agent expectations. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds extra meaning by explaining the no-arg overview, how view vs. views relate, what each variant returns, and how recipes connect to query_dataset. This goes beyond the schema descriptions without needing to compensate for missing schema docs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states this tool learns/describes the dataset before SQL work, and distinguishes it from query_dataset and other typed siblings. It specifies exactly what the tool does: returns an overview, view metadata, or recipes depending on arguments.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says to call it before writing SQL for query_dataset, to call with no arguments first, and to prefer a typed tool when one answers the question. This provides clear when-to-use and when-not-to-use guidance relative to siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_change_recordOne change recordA
Read-onlyIdempotent
Inspect

Return one core change record in full: title, flavour, target version, machine-checkable tracks, linked issues, linked core symbols, and contrib adoption counts. To find records, use list_change_records or the change_record_nids from what_changed. For one symbol's detail, use lookup_core_symbol.

  • flavour: coming-break (an API going away), coming-new-API (an API added), landed-but-still-relevant (shipped), policy-only (no code target, no adoption).

  • Adoption counts contrib development branches only. legacy: still calls the going-away side. migrated: moved to the new side.

  • Returns counts across every affected project plus a ranked head, outstanding first. For one project, use project_upgrade_report; do not raise top_projects.

  • symbols: the core API the record is about. role: from (going away) or to (replacement). Use the fqn with lookup_core_symbol. Empty means the catalog links no symbol; that is common.

ParametersJSON Schema
NameRequiredDescriptionDefault
nidYesThe change record's drupal.org node id, for example 3581981.
top_projectsNoHow many impacted projects to return in the ranked head. Defaults to 10, capped at 40.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even though readOnlyHint/idempotentHint already signal safe reads, the description adds valuable behavioral context: the flavour taxonomy, the fact that adoption counts only cover contrib development branches, the legacy/migrated meanings, the ranked-head ordering with outstanding first, and the meaning of an empty symbols list. None of this is present in annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a front-loaded summary sentence, routing guidance, then concise bullets for flavour, adoption, output shape, and symbols. It is longer than minimal but every bullet earns its place. Minor deduction for the ambiguous 'do not raise top_projects' phrasing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries extra responsibility for explaining return semantics, and it mostly succeeds: it lists returned content, explains flavour values, adoption scope, and symbol roles. It does not describe exact JSON shape or possible error conditions, but an agent has enough to invoke the tool correctly. The ambiguity around top_projects keeps this from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaning beyond the schema by explaining that top_projects controls the ranked head and that the head is ordered outstanding first, and it connects nid to change_record_nids from what_changed. The phrase 'do not raise top_projects' is slightly cryptic, but overall the description enhances the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — 'Return one core change record in full' — and enumerates the contained fields. It also differentiates itself from siblings by pointing to list_change_records for finding records and lookup_core_symbol for a single symbol's detail.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing: use list_change_records or what_changed to find records, use lookup_core_symbol for symbol-level detail, and use project_upgrade_report for a single project's upgrade report. This gives an agent clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_change_recordsChange records in a version rangeA
Read-onlyIdempotent
Inspect

List the core change records (the human write-ups) that target a range of core versions, tagged by flavour and ranked, with counts. For the symbol-level diff, use what_changed. For one record in full, use get_change_record.

  • Bounds are inclusive. Forms: 11.2, 11.2.x, 11.2.0, 11, 11.x. A bare major covers every minor of it.

  • Flavours: coming-break (an API going away), coming-new-API (an API added), landed-but-still-relevant (already shipped). policy-only records target no version and never appear here.

  • project: one machine name. Each record then has the count of that project's development branches still on the legacy side.

  • Returns the count of every record in range plus a ranked head. Each entry has its nid for get_change_record.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesUpper core version bound, inclusive. Same forms as from.
fromYesLower core version bound, inclusive: 11.2, 11.2.x, 11.2.0, 11, or 11.x. A bare major (11) covers every minor of it.
limitNoRecords in the head, 1 to 40 (default 15). Above the cap the call is refused.
projectNoOptional contrib project machine name. Narrows the list to records a development branch of that project still matches.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already assert readOnly, idempotent, non-destructive behavior, and the description adds significant behavioral detail beyond that: inclusive bounds, supported version forms, flavour taxonomy, exclusion of policy-only records, and the return contract (count of all records plus a ranked head with nids). This is exactly the kind of context annotations alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a one-sentence summary followed by compact bullet points. Each bullet earns its place: bounds, flavours, project behavior, and return shape. There is no repetition, filler, or vague language.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the essential return contract: count of every record, a ranked head, and each entry's nid for use with get_change_record. Combined with parameter semantics and explicit sibling routing, an agent has everything needed to invoke and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning by explaining version-form semantics, inclusive bounds, flavour values, and what the project parameter actually counts. The limit parameter is left to the schema, which already documents its default and cap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names the exact operation and resource: 'List the core change records ... that target a range of core versions, tagged by flavour and ranked, with counts.' It also explicitly differentiates from what_changed (symbol-level diff) and get_change_record (single record in full), so an agent can disambiguate it from the sibling list without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly routes to alternatives: 'For the symbol-level diff, use what_changed. For one record in full, use get_change_record.' It also clarifies which records never appear here (policy-only) and explains the narrowing effect of the project parameter, giving clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_class_relationsContrib classes extending a core classA
Read-onlyIdempotent
Inspect

List the contrib classes that extend, implement or use a core class, interface or trait, one row per edge with file and line, paged. Example: "who subclasses FormBase". Call-site counts: list_symbol_users. The symbol's status: lookup_core_symbol.

  • target: with or without the leading backslash. An unknown target is refused with a pointer at lookup_core_symbol; a fragment there lists candidates. rel_kind: one of extends, implements, uses_trait. project: one machine name.

  • Development branches only. edge_count: every edge. project_count: projects. count: edges after the per_project cap. project_edges on each row: the project's full count. per_project=50 with project= lists one project in full.

  • Rows are ordered by project installs, project, source_fqn. Each row: project, branch, installs, source_fqn, rel_kind, file, line, project_edges. limit ≤ 100. next_offset is absent on the last page.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoRows per page, 1 to 100 (default 50).
offsetNoSkip this many rows in the same ranked order. Pass the previous page's next_offset.
targetYesThe core class, interface or trait, with or without the leading backslash: Drupal\Core\Form\FormBase.
projectNoRestrict to one project machine name.
rel_kindNoextends, implements, or uses_trait; any when absent.
per_projectNoEdges shown per project on a page, 1 to 50 (default 3). Each row has project_edges, the project's full count.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool read-only and idempotent, but the description adds important runtime behavior: development branches only, unknown targets are refused with a pointer to lookup_core_symbol, per-project capping semantics, ordering, and next_offset absence on the last page. There is no contradiction with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the primary purpose and an example, then moves into dense but purposeful reference details. Every sentence adds information needed to call the tool correctly; there is no filler or repetition of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully specifies the row fields, ordering, pagination behavior, and error handling. The inclusion of sibling-tool routing and parameter edge cases makes the tool self-sufficient for an agent deciding whether and how to invoke it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the input schema covers all parameters, the description adds meaning beyond it: the target may include or omit the leading backslash, rel_kind values are clarified, per_project controls the capping while project_edges gives the full count, and limit/offset/next_offset behavior is explained. This is substantial navigational guidance for constructing queries.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states exactly what the tool does: lists contrib classes that extend, implement, or use a core class/interface/trait, with one row per edge including file and line, paged. The concrete example "who subclasses FormBase" and the naming of related sibling tools remove ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly routes the agent to alternatives: call-site counts should use list_symbol_users, and symbol-status or candidate lookup should use lookup_core_symbol. It also explains the unknown-target refusal path, making the choice between tools clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_projectsList projects by filtersA
Read-onlyIdempotent
Inspect

List drupal.org projects after filters, largest install base first, paged. Examples: "top modules without an 11.4 branch", "themes over 10k installs without security coverage". One project: project_profile. Its pending records: project_upgrade_report.

  • Filters combine: type, min_installs, security (covered, not-covered, revoked), core_minor (+ missing), era (d8plus, pre_d8), member_of (+ max_depth). All apply to count and rows.

  • core_minor reads the composer constraint of the newest release on each development branch. A minor counts when any patch of it satisfies the constraint. An unreleased tip change is not seen. missing=true keeps projects with no branch declaring it: the upgrade gap list.

  • member_of keeps one root's members, direct and transitive; max_depth (needs member_of) drops members past that many requires away. A filtered list adds membership: root_release, complete, unread_count and unread (up to 20, package + cause).

  • Row: machine_name, title, type, installs, security, status, dev_branches (branch, installs, core_minors, era), latest_release, cms_depth, member_of_count. cms_depth is the row's membership depth under the cms root; member_of_count is how many roots include it. A project in no root has neither; a project that is not a cms member has member_of_count alone. count: projects. next_offset is absent on the last page.

ParametersJSON Schema
NameRequiredDescriptionDefault
eraNoFilter: d8plus (Drupal 8+ code) or pre_d8, on any development branch.
typeNoFilter: project_module, project_theme, project_distribution, project_general, project_theme_engine, project_translation.
limitNoProjects per page, 1 to 100 (default 50).
offsetNoSkip this many projects in the same ranked order. Pass the previous page's next_offset.
missingNoInvert core_minor: keep projects whose development branches do not declare it.
securityNoFilter: security advisory coverage: covered, not-covered, revoked.
max_depthNoWith member_of: drop members further than this many requires away, 1 or more.
member_ofNoFilter: keep only members of this root project's composer requires walk, for example cms.
core_minorNoFilter: a core minor in 11.4.x form. Keeps projects where the newest release on some development branch declares support for it. With missing=true, keeps projects with no such branch.
min_installsNoFilter: reported install base at or above this.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the readOnly/idempotent annotations: it explains filter combination, count behavior, core_minor matching semantics, unreleased-tip exclusion, transitive member_of walks, max_depth coupling, and row-level computed fields like cms_depth and member_of_count.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured, front-loaded with the core operation and followed by scoped bullet explanations. For a 10-parameter tool with nuanced membership and core-minor semantics, every sentence earns its place and no filler is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description appropriately documents return row fields, count field, and next_offset behavior. It also covers edge cases such as projects not in any root and the absence of next_offset on the last page, making the tool fully callable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds substantial meaning: core_minor's composer-constraint logic, missing as an inversion that produces the 'upgrade gap list', member_of's transitive behavior, max_depth's dependency on member_of, and the fact that all filters apply to both count and rows.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('List drupal.org projects') with clear scope, ordering ('largest install base first'), and paging behavior. It also distinguishes itself from single-project siblings by noting 'One project: project_profile. Its pending records: project_upgrade_report.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Examples of intended queries ('top modules without an 11.4 branch', 'themes over 10k installs without security coverage') make usage context clear. It points to project_profile and project_upgrade_report for one-project and pending-record cases, but does not exhaustively cover when not to use this tool versus all siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_symbol_usersProjects using core symbolsA
Read-onlyIdempotent
Inspect

List every contrib project using one core symbol, or any symbol in a class of symbols, one row per project, paged, with the matched symbols. lookup_core_symbol answers one symbol with a head of 30.

  • Pass fqn, or filters: kind, status (deprecated, scheduled_removal, removed), subsystem, removal_in (13.0), deprecated_in (11.4). Example: "top modules still calling a method going away in 13.0" is kind=method, status=scheduled_removal, removal_in=13.0. Filters take public symbols only.

  • Development branches only, from the evidence rollup as of evidence_built_at. count: projects. symbol_count: matched symbols. symbols_matched: those symbols, up to matched, most used first, each with stamps, projects_using and change_record_nids.

  • Rows are ordered by installs, occurrences, name. Each row: project, title, installs, branch, branches, symbol_count, occurrences, symbols. symbols: heaviest first, each with fqn, kind, removal_in, occurrences, files and change_record_nids for get_change_record. next_offset is absent on the last page.

ParametersJSON Schema
NameRequiredDescriptionDefault
fqnNoOne core symbol, as lookup_core_symbol takes it. Pass this or a filter.
kindNoFilter: one symbol kind (function, method, class, library, hook, service …).
limitNoProjects per page, 1 to 100 (default 50).
offsetNoSkip this many projects. Pass the previous next_offset.
statusNoFilter: deprecated | scheduled_removal (still present) | removed (gone).
matchedNoMatched symbols listed on the envelope, 1 to 50 (default 20).
symbolsNoSymbols per project row, 1 to 30 (default 10), heaviest first.
subsystemNoFilter: a core subsystem (Entity API, Views), case-insensitive. subsystem_coupling with no arguments lists them.
removal_inNoFilter: removal stamp in this core minor (13.0). With status=scheduled_removal: still present, going away then.
deprecated_inNoFilter: symbols deprecated in this core minor (11.4).

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark read-only/idempotent, and the description adds substantial behavior: paging, public-symbol-only filtering, development-branch scope, evidence rollup timestamp, ordering, and per-row fields. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is long but every sentence carries operational detail; bullet layout makes it scannable. Front-loaded with main purpose before filters/output details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a complex read tool with no output schema, so the description carries the burden of defining return values; it covers count, symbol_count, symbols_matched, row ordering, row fields, symbol fields, and last-page pagination marker. Complete enough for an agent to invoke and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema coverage at 100%, the baseline is 3; the description adds value by explaining fqn-or-filter alternatives, filter combinations via the 13.0 example, and public-symbol restriction. It does not restate every schema description but reinforces the most consequential interactions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List'), resource ('contrib projects'), and scope ('using one core symbol, or any symbol in a class of symbols'), with explicit output shape. Differentiates itself from lookup_core_symbol by noting that sibling answers one symbol with a head of 30.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly says to pass either fqn or filters, gives a concrete example query, and references sibling tools (lookup_core_symbol, subsystem_coupling) for adjacent behaviors. It could be more explicit about when list_projects is the better choice, but guidance is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lookup_core_symbolOne core symbol: status and usersA
Read-onlyIdempotent
Inspect

Answer "is this core symbol safe to use, and who still uses it" for one symbol. A name that resolves to nothing returns the catalog entries containing it instead. Every user in pages: list_symbol_users. Changed between versions: what_changed. Code text: search_code.

  • fqn forms: a namespaced name with or without the leading backslash, a bare function or constant name, a prefixed pseudo-symbol, or a fragment. Pseudo-symbols: fn:check_markup, core:hook:preprocess_page, core:library:claro/drupal.shortcut. Fragments: fromRoute, EntityInterface.

  • Resolved (found true): symbol, with status flags. removed: gone. scheduled_removal: still present, @deprecated gives the removal version. deprecated, internal. placeholder: a catalog row no scanner located. audience: contrib, test_support, test or theme. usage: contrib development branches only, from the evidence rollup as of evidence_built_at. It has projects and branches counts, plus top_projects (≤ 30) by install base. change_records: records that touched the symbol, each with nid for get_change_record.

  • Not resolved (found false): count: catalog entries containing the fragment, case-insensitive, public symbols only; kind narrows. candidates: a head of up to candidates entries, each with fqn, kind, subsystem, stamps, projects_using, change_record_nids. Entries starting with the fragment come first, then by projects_using. Call again with one fqn.

ParametersJSON Schema
NameRequiredDescriptionDefault
fqnYesCore symbol name, or part of one. A namespaced name with or without the leading backslash (Drupal\Core\Entity\EntityInterface, Drupal\Core\Recipe\RecipeRunner::installModule). A bare function or constant name (check_markup, DRUPAL_DISABLED). A prefixed pseudo-symbol as what_changed reports it (fn:check_markup, core:hook:preprocess_page, core:library:claro/drupal.shortcut). A fragment of 3+ characters (fromRoute), which returns candidates when no symbol has that exact name.
kindNoRestrict candidates to one symbol kind (class, method, function, hook, library, service …).
candidatesNoWhen the name resolves to no symbol: how many catalog entries containing it to return, 1 to 50 (default 10).
top_projectsNoHow many using projects to return in the ranked head. Defaults to 10, capped at 30.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so safety is covered. The description adds substantial behavioral detail beyond those annotations: the meaning of status flags like removed, scheduled_removal, deprecated, placeholder; the audience and usage scope; the evidence rollup timestamp; and the exact fallback behavior for unresolved fragments, including ordering and calling again with one fqn.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense and well structured: a one-sentence purpose, sibling routing, then terse bullet-like sections for fqn forms, resolved output, and unresolved output. Every sentence carries distinct information; nothing is redundant with the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with four parameters, no output schema, and two very different response modes (resolved vs. fragment fallback), the description covers both modes, the field types returned, the sorting and caps, the fqn input forms, and the relevant sibling tools. An agent has enough to invoke the tool correctly and interpret the main output without guessing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all four parameters well. The description adds meaningful extra semantics: case-insensitive matching for fragments, public-symbols-only scope, candidates ordering ('entries starting with the fragment come first, then by projects_using'), and the top_projects cap context. This exceeds the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource: 'Answer is this core symbol safe to use, and who still uses it for one symbol.' It also distinguishes its fragment-lookup behavior from exact symbol lookup and names sibling tools that cover related but different needs, so an agent can tell it apart from list_symbol_users, what_changed, and search_code.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly routes to alternatives: 'Every user in pages: list_symbol_users. Changed between versions: what_changed. Code text: search_code.' It also explains when the tool switches from exact lookup to candidate listing ('A name that resolves to nothing returns the catalog entries containing it instead'), giving clear selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

project_profileProject profileA
Read-onlyIdempotent
Inspect

Answer "what is this contrib project, how big is it, which core versions does it support, what moves with it" for one drupal.org project. Pending change records: project_upgrade_report. Core symbols it calls: list_symbol_users.

  • project: title, type, status, security, installs. installs_by_version: install base per contrib version.

  • dev_branches: each scanned development branch, with installs, core_constraint, core_minors, latest commit date and era. core_constraint: the composer constraint of the newest release on that line, as drupal.org publishes it. The unreleased tip is excluded. core_minors: the minors it admits; a minor counts when any patch satisfies. latest_core_minor: the newest admitted.

  • releases: newest first, up to releases, each with core_compatibility and security. release_count, supported_branches. missing_sections: what the bundle could not fill.

  • related (summary): requires and required_by counts with the top 3, co_installed top 3 or a note, delta_12m per release line ("*" is the total).

  • member_of: how many roots pull this project in (count), and up to 10 {root, depth}, shallowest and alphabetical first.

  • include=["related"]: related becomes the full report. requires: every dependency, via info_yml or composer, core modules left out. required_by: paged by installs, with count and next_offset; page with dependents and dependents_offset. co_installed: rho, rank, method residual_spearman, or a note.

  • include=["trend"]: trend has months (oldest first), series per release_line aligned with months (null: no count, "*": total), and lines. Each line: installs_now, share, delta_3m, delta_12m, delta_36m, peak, first_seen, last_seen. Counts are drupal.org month-end installs.

  • Unknown project: error. An included section refuses when the bundle predates its view.

ParametersJSON Schema
NameRequiredDescriptionDefault
monthsNoWith include trend: months of history, 1 to 120 (default 36), ending at the latest month in the data.
includeNoOptional sections: trend (monthly install series per release line) and related (full requires / required_by / co_installed lists, replacing the related summary).
projectYesdrupal.org project machine name, e.g. webform. The composer name drupal/webform is accepted.
releasesNoReleases to list, newest first, 1 to 30 (default 10). release_count says how many exist.
dependentsNoWith include related: dependents per page in required_by, 1 to 100 (default 20).
dependents_offsetNoWith include related: dependents to skip. Pass required_by.next_offset from the previous call.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnly/idempotent annotations, documenting error behavior for unknown projects, the refusal of included sections when the bundle predates the view, data sources, exclusions like the unreleased tip, and count semantics. This gives an agent a precise model of side effects and limitations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but organized into tight bullets that each carry specific output facts; no filler. Some definitions, such as core_constraint, are repeated between bullets, and the cross-reference line at the top adds only marginal value, so it is not perfect.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining return shape, and it does so thoroughly: every return section, parameter effect, paging mechanism, and error/refusal case is covered. An agent has enough to invoke correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All six parameters are already described in the schema (100% coverage), so the baseline is 3. The description adds value by explaining how include modifies the related section, how dependents_offset paginates via next_offset, and how releases/months interact with output, so it earns a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a quoted purpose statement naming the exact questions the tool answers for one drupal.org project, then enumerates returned sections. It is a specific verb+resource and distinguishes itself from siblings by explicitly naming project_upgrade_report and list_symbol_users as related but separate concerns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use when a one-project profile is needed, but it never states when to choose this over siblings or when not to use it. The cross-references to project_upgrade_report and list_symbol_users hint at boundaries without giving explicit selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

project_upgrade_reportProject upgrade readinessA
Read-onlyIdempotent
Inspect

Answer "is this contrib project ready for a target core version, and what work is left". For one record's detail, use get_change_record. For a symbol's users, use list_symbol_users.

  • A record applies when it targets the target version or earlier, and a development branch of the project matched one of its tracks.

  • Verdict per record: outstanding (a branch still calls the going-away side), in_progress (some branches moved), adopted (all moved).

  • Returns counts by verdict, then a ranked head of outstanding records with file and line evidence from the project's own code.

  • Each entry has the count of other projects outstanding on the same record, and its nid for get_change_record.

  • removed_symbols: core symbols removed by the target, or scheduled for removal at or before it, that the project's development branches still reference. Each has occurrences, files, and the replacement when the catalog lists one. They need no change record: a class moved to another module, a service dropped. removed_symbol_count: the whole set. The head is newest removal first, then by occurrences. Test and test-support symbols are left out.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoOutstanding records to return with evidence, 1 to 15 (default 8). Above the cap the call is refused.
projectYesContrib project machine name as it appears on drupal.org, for example webform. The composer name drupal/webform is accepted. Packages from other vendors are not in the dataset.
target_versionYesTarget core version: 11.2, 11.2.x, 11.2.0, 11, or 11.x. A bare major (11) covers every minor of it.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, and non-destructive behavior. The description adds substantial behavioral detail beyond that: per-record verdicts, ranking order, cap refusal for limit, exclusion of test/test-support symbols, and which fields each returned entry contains. This is exactly the kind of non-obvious behavior an agent needs to predict results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but dense and well-structured, with purpose front-loaded and details organized by record verdicts and removed symbols. The length is justified by the absence of an output schema and the complexity of the report, though a few phrases could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining return values, and it does so thoroughly: verdicts, counts, ranked evidence, per-entry fields, removed_symbols structure, and exclusion rules. An agent has enough information to call the tool and interpret its result without guessing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents limit, project, and target_version formats and constraints. The description mostly restates those constraints and adds output semantics rather than new parameter meaning, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a concrete question the tool answers: whether a contrib project is ready for a target core version and what work remains. It also names sibling tools for narrower tasks, immediately distinguishing this aggregate readiness report from get_change_record and list_symbol_users.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly routes readers to get_change_record for one record's detail and to list_symbol_users for a symbol's users, which helps agents choose between tools. It does not enumerate broader exclusion conditions or compare against other readiness-related siblings like check_patches or project_profile, so it stops short of full when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_datasetRun SQL over the datasetA
Read-onlyIdempotent
Inspect

Run read-only DuckDB SELECTs over the dataset behind the other tools, for a question none of them asks. Call describe_dataset first; it lists the 31 views, their columns, joins and recipes. Prefer a typed tool when one fits.

  • statements=[…]: up to 5 statements in one call, one result or error each.

  • Result: columns, and rows as arrays, up to max_rows (≤ 500, default 100) and 16 KB. When truncated is true: aggregate, filter, or use LIMIT and OFFSET. One SELECT (or SHOW, DESCRIBE, FROM-first), no semicolon, 15 s limit, nothing outside the bundle.

  • Dev-branch isolation: JOIN contrib_branch and filter kind = 'dev_branch' AND project <> 'drupal' before counting projects. change_record_adoption, symbol_usage and core_symbol_evidence hold release tags too. core_symbol_evidence is the full rollup; symbol_usage is its string-scan subset.

  • Adoption polarity: legacy is still on the old API (not adopted); migrated is adopted. Versions are text: compare _seq integers (major1000+minor). Never SUM(usage) across branch rows.

  • Errors list the views, the columns of the views you used, or the join map. An empty result over an fqn without a leading backslash gets a hint.

  • The same views are downloadable as parquet under https://api.tresbien.tech/data/docs. Its cookbook targets api.duckdb plus prelude views this mirror does not have, so take recipes from describe_dataset.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlNoOne DuckDB SELECT over the views describe_dataset lists. SHOW TABLES, DESCRIBE <view> and FROM-first syntax also work. No semicolon, one statement. Use statements for several at once.
max_rowsNoRows to return per statement, 1 to 500 (default 100). The result byte budget may cut a wide result sooner. truncated says so either way.
statementsNoUp to 5 statements in one call. Results come back in order under results, each with its own rows or error. The byte budget is shared. Use this instead of sql for more than one statement.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool read-only, idempotent, and non-destructive. The description adds substantial behavior beyond that: one-statement constraint, no semicolon, 15-second limit, 16 KB shared byte budget, truncation handling, dev-branch isolation rules, adoption polarity, and error behavior. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every block earns its place: purpose is front-loaded, followed by invocation rules, result semantics, data-model pitfalls, and error behavior. The bulleted structure makes dense operational guidance easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a flexible SQL tool with no output schema, the description covers return shape, truncation, limits, error hints, required preliminary steps, domain-specific correctness rules, and external documentation caveats. An agent has enough context to invoke it correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaning by explaining statement limits, result truncation, byte budget, SQL syntax constraints, and when to use statements instead of sql. This goes beyond the schema's field-level descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: run read-only DuckDB SELECTs over the dataset behind the other tools. It also distinguishes itself from siblings by targeting questions none of the other tools ask and by saying to prefer a typed tool when one fits.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly directs the agent to call describe_dataset first, tells it to prefer a typed sibling when one fits, and defines the generic SQL-query use case. This gives both positive guidance and an exclusion criterion for alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reroll_patchRe-roll one patch against a releaseA
Read-onlyIdempotent
Inspect

Re-roll one composer patch that check_patches reported conflicts or fuzzy: a new diff that applies to the installed release. Call check_patches first for the whole list. Call this once per patch that came back conflicts or fuzzy.

  • Input: project, version, patch, title, base. patch is the diff text; this service downloads nothing, so fetch a URL patch yourself and send what came back. base is the release the site had before the upgrade. One patch per call. A hand-made patch without index lines is merged from base when it applies there, else from the newest tag it applies to. reroll.base is the tag used.

  • drop_tests: leave it out and the re-roll drops every file the release package omits. false keeps every hunk, for a site installed from source. reroll.dropped_paths lists what went.

  • reroll.verified true: the service already ran the check. reroll.verified_by: the command, the -p level and the tag. Write reroll.patch to the patch file and move on. Do not run git apply --check or patch --dry-run. Do not diff against a copy of the release. composer install is the test.

  • After a conflicts result, send the same project, version and patch again with resolutions, one per region of reroll.conflicts[].hunks. A resolution is {file, region, choice: release|patch}, {file, region, text}, or {file, region, delete: true}. The service re-merges with your decisions and apply-checks the diff. What comes back is the finished patch file: write it and run composer install. Do not read the release files, edit the patch by hand, or dry-run it.

  • reroll.status clean: every file merged, or GNU patch applied every hunk, and the diff apply-checked against the release, reroll.verified true. Write reroll.patch as the new patch file; no re-test needed. An empty reroll.patch with reroll.note means the release already has the change; suggested is merged.

  • reroll.status conflicts: reroll.patch holds the hunks that merged cleanly, apply-checked when reroll.verified is true. Each file in reroll.conflicts has hunks with the three sides of every region. release: what the release has. base: what the patch was written against. patch: what the patch wants. release_line and release_context: the release file's numbered lines around the region. Write the missing hunks from those and append them to reroll.patch. No download, file read or dry-run is needed.

  • reroll.syntax_errors: files that do not parse after the merge, with the parser's line. reroll.verified is false then, though the diff applies. Fix the text of the resolutions on those files and call again.

  • reroll.status unavailable: no release takes the patch, or it was made from a commit in no release; reroll.error says which. Re-roll by hand from hunks_failed.

  • reroll.patch paths are relative to the repository root. Contrib patches apply at -p1. Core patches start with core/ and apply at -p2 from web/core. patch_truncated: the diff was cut to the result budget; POST /v1/patch/check on api.tresbien.tech with reroll: true returns it whole.

  • A patch already in the release (merged), or one git apply accepts unchanged, returns its verdict with reroll null. A patch that applies only because a lenient sweep took it (fuzzy) is re-rolled, since a strict patch manager refuses it. Its re-roll keeps the lines GNU patch writes with fuzz, the code a lenient patch manager installs, and reroll.base stays empty.

  • core_references: as on check_patches, read from the re-rolled diff when the merge was clean. Removed or moved core classes, and calls whose argument count no longer fits the target signature, at target_core.

ParametersJSON Schema
NameRequiredDescriptionDefault
baseNoOptional. The release the site had before the upgrade. Its commit sha from composer.lock (source.reference), or its composer version: 6.1.0 when version is 6.2.0. A patch without index lines is merged from it when it applies there, before the newest tags are tried.
patchYesUnified diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. With the index lines git diff writes, it is merged onto the release. Without them (hand-made), it is merged from base when it applies there, else from the newest tag it applies to. reroll.base is the tag used.
titleNoOptional, echoed back.
projectYesdrupal.org machine name (webform) or composer name (drupal/webform); drupal or core for Drupal core.
versionYesThe composer version installed, e.g. 1.13.0 or 11.4.5.
drop_testsNoOptional. Leave it out and the re-roll drops every file the release package omits, read from the release's own archive. false keeps every hunk, for a site installed from source.
resolutionsNoDecisions for the conflicted regions of a previous call on the same project, version and patch, one entry per region. region: the index in that file's conflicts[].hunks. {file, region, choice}: choice is release or patch. {file, region, text}: your own text for the region. {file, region, delete: true}: empty the region. The service re-runs the merge with them and apply-checks the result. Regions you leave out keep the release side and come back in reroll.resolutions_missing.
target_coreNoCore the added code is checked against: a minor (11.4 or 11.4.x) or a release (11.4.5). A minor with no core release in the data is refused, and so is a major alone. latest checks no references. Defaults to version for a core patch.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds significant behavioral detail: it downloads nothing (so the user must fetch the patch), it merges patches from base or tags, it explains the meaning of reroll.status and reroll.verified, and it instructs the user on what not to do (e.g., 'Do not run git apply --check or patch --dry-run'). No contradiction with annotations; the description enhances transparency beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very long and dense, but it is well-structured with bullet points and clear sections (Input, status handling, etc.). Every sentence carries necessary operational detail—there is no fluff. However, it could be more concise by summarizing key points or moving some details to an output schema; as-is, it is verbose but justified by the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, multiple statuses, nested resolutions) and the absence of an output schema, the description covers every aspect: input requirements, how to interpret results, what to do for each status (clean, conflicts, syntax_errors, unavailable), and even edge cases like fuzzy patches and already-merged patches. It is complete enough that an agent can call the tool correctly without external documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% (every parameter has a description). The tool description adds substantial meaning beyond the schema: for 'patch' it explains the difference between index lines and hand-made patches, for 'base' it details the merge fallback order, for 'drop_tests' it clarifies the effect on the re-roll, and for 'resolutions' it provides a detailed structure and behavior. This goes well beyond the schema's one-line descriptions, making parameters far more actionable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Re-roll one composer patch that check_patches reported conflicts or fuzzy: a new diff that applies to the installed release.' It specifies the verb (re-roll), the resource (composer patch), and the condition (conflicts or fuzzy), distinguishing it from the sibling check_patches.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is explicit: 'Call check_patches first for the whole list. Call this once per patch that came back conflicts or fuzzy.' It also describes when to send resolutions, what to do after each status (clean, conflicts, etc.), and even warns against manual steps like running git apply --check or editing the patch by hand. Clear when-to-use and when-not-to-use guidance is present.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scan_composerScan a site's composer files for a core upgradeA
Read-onlyIdempotent
Inspect

Which of a site's drupal/* packages need a new release for a target core, and which have none? Send composer.lock and composer.json once; do not query one package at a time. The answer is the release scan for every package, plus extra.patches as check_patches items. Constraints are read by composer's own semver library.

  • composer_lock: the whole file, or its path to get the upload command. A real lock does not fit a call. With the path, the files go from disk to the api by curl and only the plan comes back. composer_json: adds constraints and extra.patches. patches_file and patches_lock: the two documents a site on cweagans/composer-patches 2.x keeps its patches in, since such a site declares none under extra.patches. Sent as text with a lock path, the command lists every patch to send. target_core: 11.4, 11.4.5, or latest for the newest core the site's constraint allows. Without patches, target_from holds the package whose constraint decided latest. When the site requires no core package, latest is the installed core and target_from says so. Empty scans against the installed core (target_is_installed): what can be updated without a core upgrade.

  • installed_unknown: the release data does not have the installed version; the row offers no older release. installed_from_tag: the project's git tag answered instead. Neither is a finding about the site.

  • A sub-module has no releases of its own; drupal.org packages it as a metapackage built from its project's release. Its row says submodule_of and has that project's answer. The lock's type, require and extra.drupal.datestamp fields pair a metapackage with its project.

  • rows, problems first. no_release: no published release supports the target; latest_any and dev_branch say what exists. update: a compatible release the site does not have; latest, latest_core. unknown: not a drupal.org project in the bundle; note says where its releases are. current: installed_supports and nothing newer needed; such a row has package, installed and installed_supports only. counts covers every package even when rows are cut.

  • candidates, on every row that is not current: the newest three releases, each with version, core constraint, date and supports_target. project_profile adds installs and branches to the same three.

  • patches: one item per declared patch with the installed version filled in. Pass them to check_patches after composer update; local paths need the file text. A patch on a package outside drupal/ gets no item and no row; outside_drupal lists it.

  • patches:true answers with plan instead: every patch judged against the release its package would install for target_core. plan.counts: the verdict tally. plan.package_counts: the scan tallies. plan.no_release: the packages that block the target. plan.patches: one row per patch needing a decision (conflicts, unknown, merged, and an applies that only a lenient apply took). plan.applying: the number that apply with nothing to decide. The scan rows are not in a plan; call again without patches for them.

  • A patch whose package has no release for the target is judged against the branch when the lock installs a dev version. Otherwise it is unknown, with the reason in note. plan.warnings: a package is in no_release because of something the site controls. Each warning gives the requirement to change: its own constraint, or its minimum stability. A row's project for reroll_patch is its package without the drupal/ prefix.

  • A plan never has a re-rolled diff. plan.next_step points at reroll_patch, one call per patch, when any patch needs a re-roll.

  • bundle_date: when the release data was published. A release after it is invisible here. Confirm a no_release with composer show or drupal.org before acting.

ParametersJSON Schema
NameRequiredDescriptionDefault
patchesNoJudge the site's patches in the same call: each one against the release its package would install for target_core. Returns a verdict per patch instead of items to check yourself.
patch_filesNoThe text of every patch the site declares, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Only needed with patches:true. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too.
target_coreNoCore to move to: a minor (11.4), a release (11.4.5), or latest for the newest core the site's own constraint allows. Leave empty to scan against the core the site already runs: which packages have a newer release for it.
patches_fileNoThe text of the patches file, for a site on cweagans/composer-patches 2.x that keeps its patches out of composer.json. The path is in its own extra.composer-patches.patches-file, patches.json by default. A site on 2.x declares nothing under extra.patches, so without this its patches are invisible.
patches_lockNoThe text of patches.lock.json, which 2.x of the patch manager writes and applies from. Send it to judge what the site actually applies: it answers alone, over extra.patches and the patches file.
composer_jsonNoThe contents of composer.json (require, require-dev, extra.patches). Send the text; this server cannot read your filesystem. Optional; without it there are no constraints and no patches.
composer_lockYesThe text of composer.lock. A real lock is too big to paste: send its path (composer.lock) instead. The answer is then the curl command that uploads the files from the site root.
installed_coreNoWhat each installed release requires of core, keyed by composer name. Read it from the site's own vendor directory: composer show -f json <pkg>, or the drupal/core entry of its composer.json. Send it and the installed release is judged by what it declares.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (readOnly/idempotent/non-destructive/closed-world), and the description adds substantial behavior beyond them: data freshness (bundle_date makes later releases invisible), the distinction that installed_unknown/installed_from_tag are not findings about the site, and that a plan omits scan rows and never contains a re-rolled diff.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is a ~600-word wall of dash-prefixed fragments whose bullet semantics are ambiguous, with some cryptic lines ('the files go from disk to the api by curl'). Length is defensible given no output schema, but structure and readability suffer.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full return burden and does so: it documents rows/counts/candidates, the patches items, and the plan shape (counts, package_counts, no_release, patches, applying, warnings, next_step). An agent has what it needs to interpret results correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema descriptions are already rich, so the baseline is 3. The description still adds real meaning the schema doesn't: patches:true switches the return shape to a plan, patches_lock answers alone over extra.patches and the patches file, and an empty target_core scans against the installed core.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a precise verb+resource+scope: which drupal/* packages need a new release for a target core. It also implicitly differentiates from siblings by naming check_patches and reroll_patch as downstream steps, so an agent knows where this tool sits in the workflow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('send composer.lock and composer.json once'), an explicit exclusion ('do not query one package at a time'), and explicit routing to alternatives ('pass them to check_patches after composer update', 'plan.next_step points at reroll_patch'). It even states when to re-call the tool without patches.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_codeSearch contrib and core codeA
Read-onlyIdempotent
Inspect

Search the source of every indexed contrib project, plus core, for a code pattern: which files, or with by_repo which projects. Who-uses-a-core-symbol counts: list_symbol_users or lookup_core_symbol.

  • query is a regex. Set literal for exact text with ( [ ] . $ : or a space, and put r: f: lang: case: sym: b: terms in filters. repos: project machine name list. The index runs RE2, which has no lookaround or backreferences.

  • .module, .install, .theme, .engine, .profile and .inc count as PHP: lang:php includes them and sym: resolves inside them. No language filter is applied for you.

  • Returns total_matches and total_files plus a head of files (repo, path, matching lines), limit ≤ 50. by_repo: (repo, file_count) rows from a pull of up to 1000 files; total_files is the ceiling; truncated when cut. A parse error returns the index's own message.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoFiles to return, default 20, cap 50. Ignored with by_repo.
queryYesCode to find, a regex unless literal is true. Filters may be inline when literal is false, else in filters. Example: hook_form_alter f:\.module$
reposNoRestrict to these projects, by machine name, in one query.
by_repoNoReturn repos as (repo, file_count) instead of files. Pulls up to 1000 files; total_files is the ceiling.
filtersNoZoekt filters appended as written: r:<repo regex> f:<path regex> lang:<language> b:<branch> sym:<symbol> case:yes.
literalNotrue: query is matched as exact text. Use it for text with ( [ ] $ . such as #[Hook(. With literal, filters go in filters.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only and idempotent behavior, and the description adds substantial behavioral detail: RE2 regex limitations, .module/.install/.inc counted as PHP, no automatic language filter, result shape with total_matches/total_files, by_repo semantics, limit cap, and parse-error propagation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place. It opens with the core purpose, then covers regex syntax, language handling, and return behavior in a structured way. No filler or redundant restatement of the tool name is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description properly explains return values: total_matches, total_files, head of files, and by_repo rows. It also covers edge behavior like truncation, the 50-result cap, the 1000-file pull, and parse-error messages, making it sufficiently complete for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description goes beyond the schema by explaining RE2's lack of lookaround/backreferences, which file extensions count as PHP for lang:/sym:, how literal mode interacts with filters, and the by_repo pull/truncation behavior. This adds real meaning to query, literal, filters, and by_repo.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Search the source of every indexed contrib project, plus core, for a code pattern.' It also distinguishes the tool from siblings by explicitly saying symbol-use counts belong to list_symbol_users or lookup_core_symbol.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing: use list_symbol_users or lookup_core_symbol for 'Who-uses-a-core-symbol counts.' It also provides practical guidance on query construction, filters, literal mode, and the absence of an applied language filter, helping the agent decide how to invoke the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

subsystem_couplingSubsystem co-failure graphA
Read-onlyIdempotent
Inspect

Answer "what else tends to fail when a merge request touches this core subsystem" from CI history over about 9,000 core merge requests. With issue_nid: "which subsystems does this issue touch, and what co-fails with them". No arguments: the list of subsystems, the same one core_symbol.subsystem and list_symbol_users subsystem= use.

  • subsystem: a name (Views, case-insensitive) or a bucket (module:views, core_lib:Entity). An unknown one is refused, with the nearest matches.

  • Edge: touched_bucket → failing_bucket (+ subsystem), lift, co_fail_count, touched_count, failed_count, total_mrs. lift = P(fail | touched) − P(fail | any MR). Self edges are left out.

  • Floors min_lift (0.05) and min_co_fail (3) drop noise. count: edges above them. edges: up to limit (≤ 50), by lift. When nothing clears the floors, the strongest edges are listed with a note.

  • issue_nid: touched_subsystems first. A note explains an issue with no MR file data.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoEdges to return, 1 to 50 (default 20). count says how many pass the floors.
min_liftNoKeep edges with lift at or above this (default 0.05).
issue_nidNoA drupal.org core issue nid: reports the subsystems its merge request touches, then the coupling edges from each.
subsystemNoA core subsystem (Views, Entity API) or a path bucket (module:views, core_lib:Entity). Leave both subsystem and issue_nid empty to get the list of subsystems.
min_co_failNoKeep edges seen in at least this many merge requests (default 3).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only annotations, the description reveals important behavior: unknown subsystems are refused with nearest matches, self-edges are omitted, lift is defined, floors filter noise, and edge cases like no clearing edges or no MR file data produce notes. This gives the agent strong expectations of output and failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured with clear bullets. Every line adds operational detail, from accepted inputs to output fields and edge-case notes. Despite its length, there is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a complex 5-parameter tool and no output schema, the description still explains all modes, parameter forms, output edge fields, defaults, filtering behavior, and special-case notes. Nothing critical is left to guesswork.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds substantial meaning: subsystem names can be case-insensitive names or buckets like module:views, edge fields are enumerated with a precise lift formula, and the interaction of min_lift/min_co_fail with count and edges is explained. This goes well beyond the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific analytical question ('what else tends to fail when a merge request touches this core subsystem') and names the data source (CI history over about 9,000 core merge requests). It also distinguishes the two main calling modes (subsystem vs issue_nid), so the tool's purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage modes: pass subsystem, pass issue_nid, or pass nothing to list subsystems. It also explains how an unknown subsystem is handled. It does not explicitly contrast this tool with sibling alternatives, but the specialized context makes the intended use clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

what_changedCore API diff between versionsA
Read-onlyIdempotent
Inspect

Answer "what changed in the core API between two core versions": symbols added, deprecated and removed, as ranked groups with counts. One symbol: lookup_core_symbol. Human write-ups: list_change_records. Every row of one bucket: flat=true with bucket, paged. Every row of the whole diff: the result's bulk block, with attach and sql for the published catalog. Write those rows to a file, so they stay out of the context window.

  • Bounds are inclusive. Forms: 11.2, 11.2.x, 11.2.0, 11, 11.x. The same version twice is one minor. Upgrading 11.2 → 11.4 means from=11.3. Buckets are independent.

  • Grouped (default): a head entry is a symbol group; grouped_by is change_record, name_prefix or singleton. head: groups, up to 5. count: symbols. group_count: groups. members: up to 3 per group, highest usage first. Group fields appear only when every member agrees. Rank: max_projects_using desc, then member_count magnitude, tier, count, key; ranked_by states it. When head_covers_all_callers is false, narrow with kind or min_projects_using, or page with offset.

  • Flat (flat=true, bucket=added, deprecated, removed): rows by projects_using then fqn. Each row: fqn, kind, subsystem, stamp, projects_using, removal_in, removal_kind, replacement when the catalog lists one, change_record_nids. count: public symbols in the bucket after filters. limit ≤ 100. next_offset is absent on the last page.

  • Filters apply to every count. internal_excluded and test_theme_excluded are counted apart and left out. unplaceable_symbols have no minor in their stamp.

  • Usage: contrib development branches only, from the evidence rollup as of usage_evidence_built_at. 0 means no caller observed.

  • change_record_nids: for get_change_record. removal_kind observed: gone. removal_kind scheduled: promised and still present; say "scheduled for removal in 13.0".

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesUpper bound, inclusive, same forms.
flatNotrue: one bucket as flat symbol rows, paged, instead of three buckets of ranked groups. Needs bucket.
fromYesLower core version bound, inclusive: 11.2, 11.2.x, 11.2.0, 11, 11.x. Upgrading from 11.2 means from=11.3.
headNoGroups per bucket, 1 to 5 (default 5). Ignored when flat is true.
kindNoRestrict to one symbol kind (method, class, function, hook, service, library …). Applies to counts too.
limitNoWith flat: rows per page, 1 to 100 (default 50). A page of very long fqns may come back shorter. next_offset always says where the next page starts.
bucketNoWith flat: which side of the diff to list, added, deprecated, or removed. One bucket per call.
offsetNoSkip this many groups per bucket (grouped) or rows (flat), in ranked order. Flat: pass the previous page's next_offset.
min_projects_usingNoDrop symbols fewer than this many contrib projects call on a development branch. Applies to counts too.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark readOnly, idempotent, and non-destructive, and the description adds substantial behavioral detail: inclusive bounds, bucket independence, pagination edge cases, unplaceable symbols, removal_kind semantics, and how filters affect counts. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but highly structured, with each bullet covering a distinct behavioral aspect of a complex 9-parameter tool. It is front-loaded with the core purpose and then organizes mode-specific details, filters, and usage constraints without significant redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema and 9 parameters, the description is exceptionally complete: it explains both output modes, row shapes, grouping rules, ranking, filtering, pagination, limits, data source, and special cases. An agent has nearly everything needed to call it correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds meaning well beyond the parameter descriptions: version form semantics, 'from=11.3' upgrade interpretation, flat-mode bucket requirements, limit page-size behavior, offset pagination, and when next_offset is absent. This materially improves correct parameter usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first line states exactly what the tool does: answer what changed in the core API between two versions, listing added, deprecated, and removed symbols. It also explicitly distinguishes itself from related siblings: lookup_core_symbol for a single symbol and list_change_records for human write-ups.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: contrib development branches only, from the evidence rollup. It also names alternatives with one-symbol lookup and human write-up routes, and explains when to choose flat vs grouped mode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool update
    • Changedreroll_patch1 field changed
      • changedInput schema / properties / drop_tests / description
        Previous value: -"Optional. true leaves the patch's test files out of the re-roll, false keeps them. Without it, core 12 and later leave them out and every other patch keeps them."New value: +"Optional. Leave it out and the re-roll drops every file the release package omits, read from the release's own archive. false keeps every hunk, for a site installed from source."
  2. 1 tool update
    • Changedproject_upgrade_report1 field changed
      • changedInput schema / properties / project / description
        Previous value: -"Contrib project machine name as it appears on drupal.org, for example webform. The composer name drupal/webform is accepted. Packages from other vendors (acquia/cohesion) are not in the dataset."New value: +"Contrib project machine name as it appears on drupal.org, for example webform. The composer name drupal/webform is accepted. Packages from other vendors are not in the dataset."
  3. 1 tool update
    • Changedlist_projects2 fields changed
      • addedInput schema / properties / max_depth
        Added value: +{
        +  "description": "With member_of: drop members further than this many requires away, 1 or more.",
        +  "type": [
        +    "null",
        +    "integer"
        +  ]
        +}
      • addedInput schema / properties / member_of
        Added value: +{
        +  "description": "Filter: keep only members of this root project's composer requires walk, for example cms.",
        +  "type": "string"
        +}
  4. 3 tool updates
    • Changedcheck_patches1 field changed
      • changedInput schema / properties / target_core / description
        Previous value: -"The core version the added code is checked against, 11.4.5. Defaults to the lock's drupal/core, else the version of a drupal item."New value: +"Core the added code is checked against: a minor (11.4 or 11.4.x) or a release (11.4.5). A minor with no core release in the data is refused, and so is a major alone. latest checks no references. Defaults to the lock's drupal/core, else the version of a drupal item."
    • Changedreroll_patch1 field changed
      • changedInput schema / properties / target_core / description
        Previous value: -"The core version the added code is checked against (11.4.5). Defaults to version for a core patch."New value: +"Core the added code is checked against: a minor (11.4 or 11.4.x) or a release (11.4.5). A minor with no core release in the data is refused, and so is a major alone. latest checks no references. Defaults to version for a core patch."
    • Changedscan_composer1 field changed
      • changedInput schema / properties / target_core / description
        Previous value: -"Core version to move to, e.g. 11.4 or 11.4.5. Leave empty to scan against the core the site already runs: which packages have a newer release for it."New value: +"Core to move to: a minor (11.4), a release (11.4.5), or latest for the newest core the site's own constraint allows. Leave empty to scan against the core the site already runs: which packages have a newer release for it."
  5. 1 tool update
    • Changedreroll_patch1 field changed
      • addedInput schema / properties / drop_tests
        Added value: +{
        +  "description": "Optional. true leaves the patch's test files out of the re-roll, false keeps them. Without it, core 12 and later leave them out and every other patch keeps them.",
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
  6. 2 tool updates
    • Changedcheck_patches1 field changed
      • changedInput schema / properties / patch_files / description
        Previous value: -"The text of every patch listed in extra.patches, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."New value: +"The text of every patch the site declares, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."
    • Changedscan_composer1 field changed
      • changedInput schema / properties / patch_files / description
        Previous value: -"The text of every patch listed in extra.patches, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Only needed with patches:true. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."New value: +"The text of every patch the site declares, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Only needed with patches:true. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."
  7. 2 tool updates
    • Changedcheck_patches4 fields changed
      • changedInput schema / properties / items / description
        Previous value: -"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: the diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. source: optional, the path or URL the patch was declared with. merge_patch: optional, the .diff form of a merge request, used for the merge of a re-roll while patch decides the verdict. title: optional, echoed back. base: optional, the release the site had before the upgrade. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."New value: +"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: the diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. source: optional, the path or URL the patch was declared with. merge_patch: optional, the .diff form of a merge request, used for the merge of a re-roll while patch decides the verdict. provenance: optional, where a copied patch's bytes came from, {mr, commit, url, base, head, fetched, rerolled}. Send it when source is a local path. title: optional, echoed back. base: optional, the release the site had before the upgrade. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."
      • addedInput schema / properties / items / items / properties / provenance
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "base": {
        +      "type": "string"
        +    },
        +    "commit": {
        +      "type": "string"
        +    },
        +    "fetched": {
        +      "type": "string"
        +    },
        +    "head": {
        +      "type": "string"
        +    },
        +    "mr": {
        +      "type": "string"
        +    },
        +    "rerolled": {
        +      "type": "string"
        +    },
        +    "url": {
        +      "type": "string"
        +    }
        +  },
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedInput schema / properties / patches_file
        Added value: +{
        +  "description": "The text of the patches file, for a site on cweagans/composer-patches 2.x that keeps its patches out of composer.json. The path is in its own extra.composer-patches.patches-file, patches.json by default.",
        +  "type": "string"
        +}
      • addedInput schema / properties / patches_lock
        Added value: +{
        +  "description": "The text of patches.lock.json, which 2.x of the patch manager writes and applies from. Send it to judge what the site actually applies: it answers alone, over extra.patches and the patches file.",
        +  "type": "string"
        +}
    • Changedscan_composer2 fields changed
      • addedInput schema / properties / patches_file
        Added value: +{
        +  "description": "The text of the patches file, for a site on cweagans/composer-patches 2.x that keeps its patches out of composer.json. The path is in its own extra.composer-patches.patches-file, patches.json by default. A site on 2.x declares nothing under extra.patches, so without this its patches are invisible.",
        +  "type": "string"
        +}
      • addedInput schema / properties / patches_lock
        Added value: +{
        +  "description": "The text of patches.lock.json, which 2.x of the patch manager writes and applies from. Send it to judge what the site actually applies: it answers alone, over extra.patches and the patches file.",
        +  "type": "string"
        +}
  8. 1 tool update
    • Changedcheck_patches1 field changed
      • addedInput schema / properties / items / items / properties / upstream
        Added value: +{
        +  "type": "string"
        +}
  9. 3 tool updates
    • Changedcheck_patches2 fields changed
      • changedInput schema / properties / composer_json / description
        Previous value: -"The text of composer.json, not a path. Its extra.patches becomes the item list, one item per patch."New value: +"The contents of composer.json. Send the text; this server cannot read your filesystem. Its extra.patches becomes the item list, one item per patch."
      • changedInput schema / properties / composer_lock / description
        Previous value: -"The text of composer.lock, not a path. It gives the installed version of each patched package."New value: +"The contents of composer.lock. It gives the installed version of each patched package."
    • Changedscan_composer2 fields changed
      • changedInput schema / properties / composer_json / description
        Previous value: -"The text of composer.json, not a path (require, require-dev, extra.patches). Optional; without it there are no constraints and no patches."New value: +"The contents of composer.json (require, require-dev, extra.patches). Send the text; this server cannot read your filesystem. Optional; without it there are no constraints and no patches."
      • changedInput schema / properties / composer_lock / description
        Previous value: -"The text of composer.lock, not a path."New value: +"The text of composer.lock. A real lock is too big to paste: send its path (composer.lock) instead. The answer is then the curl command that uploads the files from the site root."
    • Changedsearch_code1 field changed
      • changedInput schema / properties / literal / description
        Previous value: -"true: query is exact text, not a regex. Use it for text with ( [ ] $ . such as #[Hook(. With literal, filters go in filters."New value: +"true: query is matched as exact text. Use it for text with ( [ ] $ . such as #[Hook(. With literal, filters go in filters."
  10. 3 tool updates
    • Changedcheck_patches4 fields changed
      • changedInput schema / properties / items / description
        Previous value: -"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: diff text, or a drupal.org or git.drupalcode.org URL. title: optional, echoed back. base: optional, the package's release installed before the upgrade, not version. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."New value: +"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: the diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. source: optional, the path or URL the patch was declared with. merge_patch: optional, the .diff form of a merge request, used for the merge of a re-roll while patch decides the verdict. title: optional, echoed back. base: optional, the release the site had before the upgrade. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."
      • addedInput schema / properties / items / items / properties / merge_patch
        Added value: +{
        +  "type": "string"
        +}
      • addedInput schema / properties / items / items / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • changedInput schema / properties / patch_files / description
        Previous value: -"The text of each local patch file listed in extra.patches, keyed by the path as written (patches/x.patch) or its base name. URL patches need nothing."New value: +"The text of every patch listed in extra.patches, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."
    • Changedreroll_patch2 fields changed
      • changedInput schema / properties / base / description
        Previous value: -"Optional. The package's release installed before the upgrade, not version. Its commit sha from composer.lock (source.reference), or its composer version: 6.1.0 when version is 6.2.0. A patch without index lines is merged from it when it applies there, before the newest tags are tried."New value: +"Optional. The release the site had before the upgrade. Its commit sha from composer.lock (source.reference), or its composer version: 6.1.0 when version is 6.2.0. A patch without index lines is merged from it when it applies there, before the newest tags are tried."
      • changedInput schema / properties / patch / description
        Previous value: -"Unified diff text, or a drupal.org or git.drupalcode.org patch URL. With the index lines git diff writes, it is merged onto the release. Without them (hand-made), it is merged from base when it applies there, else from the newest tag it applies to. reroll.base is the tag used."New value: +"Unified diff text. This service downloads nothing, so fetch a URL patch yourself and send what came back. With the index lines git diff writes, it is merged onto the release. Without them (hand-made), it is merged from base when it applies there, else from the newest tag it applies to. reroll.base is the tag used."
    • Changedscan_composer1 field changed
      • changedInput schema / properties / patch_files / description
        Previous value: -"The text of each local patch file listed in extra.patches, keyed by the path as written (patches/x.patch) or its base name. Only needed with patches:true. URL patches need nothing."New value: +"The text of every patch listed in extra.patches, keyed by the source as written: a path (patches/x.patch) or its base name, or the URL. Only needed with patches:true. Fetch a URL patch yourself and send its text under that URL. For a merge request .patch URL, send its .diff form under a second key too."
  11. 2 tool updates
    • Changedcheck_patches1 field changed
      • changedInput schema / properties / items / description
        Previous value: -"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: diff text, or a drupal.org or git.drupalcode.org URL. title: optional, echoed back. base: optional, the release the site runs, a commit sha or a version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."New value: +"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: diff text, or a drupal.org or git.drupalcode.org URL. title: optional, echoed back. base: optional, the package's release installed before the upgrade, not version. A commit sha or a composer version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."
    • Changedreroll_patch1 field changed
      • changedInput schema / properties / base / description
        Previous value: -"Optional. The release the site runs: a commit sha, or a composer version. A patch without index lines is merged from it when it applies there, before the newest tags are tried."New value: +"Optional. The package's release installed before the upgrade, not version. Its commit sha from composer.lock (source.reference), or its composer version: 6.1.0 when version is 6.2.0. A patch without index lines is merged from it when it applies there, before the newest tags are tried."
  12. 2 tool updates
    • Changedcheck_patches1 field changed
      • changedInput schema / properties / items / description
        Previous value: -"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: diff text, or a drupal.org or git.drupalcode.org URL. title: optional, echoed back. Leave empty to build the items from composer_json and composer_lock."New value: +"Up to 50 patches to check. Each item has project, version, patch and title. project: webform or drupal/webform; drupal or core for Drupal core. version: the installed composer version, 1.13.0 or 11.4.5. patch: diff text, or a drupal.org or git.drupalcode.org URL. title: optional, echoed back. base: optional, the release the site runs, a commit sha or a version, tried first as the merge base of a re-roll. Leave empty to build the items from composer_json and composer_lock."
    • Changedreroll_patch2 fields changed
      • addedInput schema / properties / base
        Added value: +{
        +  "description": "Optional. The release the site runs: a commit sha, or a composer version. A patch without index lines is merged from it when it applies there, before the newest tags are tried.",
        +  "type": "string"
        +}
      • changedInput schema / properties / patch / description
        Previous value: -"Unified diff text, or a drupal.org or git.drupalcode.org patch URL. With the index lines git diff writes, it is merged onto the release. Without them (hand-made), it is merged from the newest tag it applies to, given as reroll.base."New value: +"Unified diff text, or a drupal.org or git.drupalcode.org patch URL. With the index lines git diff writes, it is merged onto the release. Without them (hand-made), it is merged from base when it applies there, else from the newest tag it applies to. reroll.base is the tag used."
  13. 1 tool update
    • Changedcheck_patches1 field changed
      • addedInput schema / properties / items / items / properties / base
        Added value: +{
        +  "type": "string"
        +}
  14. 2 tool updates
    • Changedcheck_patches1 field changed
      • changedInput schema / properties / composer_lock / description
        Previous value: -"The text of composer.lock, not a path, or the slim {\"packages\":[{\"name\",\"version\"}]} form. It gives the installed version of each patched package."New value: +"The text of composer.lock, not a path. It gives the installed version of each patched package."
    • Changedscan_composer1 field changed
      • changedInput schema / properties / composer_lock / description
        Previous value: -"The text of composer.lock, not a path, or the slim form {\"packages\":[{\"name\":…,\"version\":…}]} with only drupal/* packages."New value: +"The text of composer.lock, not a path."

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    PHP static analysis MCP server with 11 tools for querying 60+ code quality metrics, detecting problems (God Class, dependency cycles, SOLID violations), analyzing dependencies, identifying refactoring priorities, and mapping test coverage — all from live analysis data.
    11
    1 npm
    92
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources