npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

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

About

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

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

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

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

Open Software & Tools

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

© 2026 – Pkg Stats / Ryan Hefner

@lockweb/drupal-ticket-mcp

v0.1.4

Published

Standalone MCP server for Drupal ticket processing, task execution, verification, and AAR generation.

Readme

drupal-ticket-mcp

Standalone MCP server for ticket intake, task breakdown, task-by-task execution, verification, and AAR generation.

What this is for

Use this server when you want to:

  • turn a ticket into an actionable task list
  • work tasks one at a time
  • fetch task subsets by status, including todo, completed, skipped, and needs_input
  • add a new task when a review turns up extra work
  • run PHPCS and Drush-based verification against changed code
  • generate a single final report from the workflow state

Install

npm install -g @lockweb/drupal-ticket-mcp

Or run it without a global install:

npx @lockweb/drupal-ticket-mcp

MCP client config example

Use this as a starting point for a client config that launches the server over stdio:

{
  "mcpServers": {
    "drupal-ticket-mcp": {
      "command": "npx",
      "args": ["-y", "@lockweb/drupal-ticket-mcp"],
      "env": {
        "MCP_PHPCS_COMMAND": "phpcs",
        "MCP_DRUSH_COMMAND": "drush"
      }
    }
  }
}

You can also copy the packaged example file at mcp.client.example.json.

Client config vs project config

There are two different configuration layers:

  • Client config: register the MCP server once in Windsurf, Claude Code, Codex, or Gemini.
  • Project config: optionally provide a repo-local JSON file when a project needs custom report paths, file names, PHPCS, Drush, or site mappings.

You do not need a project config file for every repo.

If a repo does need custom settings, place a file like mcp.config.json in that repo and point configure at it:

{
  "configPath": "./mcp.config.json"
}

That project config can override:

  • reportRoot
  • reportFileTemplate
  • phpcsCommand
  • drushCommand
  • defaultSite
  • sites
  • templatePath
  • workflowPolicy

If no project config is provided, the server uses defaults and any values supplied directly to configure.

The server returns the active workflowPolicy in process_ticket, workflow.run, and the task/report tools so the model has the instruction text available while it works.

process_ticket is review-only. It should present the checklist, ask for confirmation or clarification in plain text, and not mark tasks as needs_input there. needs_input and skipped are handled during workflow.run.

Server instructions

The server exposes a prompt named workflow_policy that returns the current workflow policy text.

Use it when you want the server to hand the client/model a ready-made instruction block for:

  • when to retry
  • when to block
  • when to ask for missing input

The default policy can be overridden through workflowPolicy in the server config.

Client differences

The server launch command is the same everywhere:

npx -y @lockweb/drupal-ticket-mcp

What changes by client is where you paste the config.

  • Codex: use Codex's MCP config flow and add the same stdio command there.
  • Claude Code: use claude mcp add-json or the project/user MCP config.
  • Gemini Code Assist / Gemini CLI: add the server in ~/.gemini/settings.json.
  • Windsurf: add the server in ~/.codeium/windsurf/mcp_config.json.

Claude Code

claude mcp add-json drupal-ticket-mcp '{
  "type": "stdio",
  "command": "npx",
  "args": ["-y", "@lockweb/drupal-ticket-mcp"],
  "env": {
    "MCP_PHPCS_COMMAND": "phpcs",
    "MCP_DRUSH_COMMAND": "drush"
  }
}'

Gemini Code Assist / Gemini CLI

Add this to ~/.gemini/settings.json:

{
  "mcpServers": {
    "drupal-ticket-mcp": {
      "command": "npx",
      "args": ["-y", "@lockweb/drupal-ticket-mcp"],
      "env": {
        "MCP_PHPCS_COMMAND": "phpcs",
        "MCP_DRUSH_COMMAND": "drush"
      }
    }
  }
}

Windsurf

Add this to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "drupal-ticket-mcp": {
      "command": "npx",
      "args": ["-y", "@lockweb/drupal-ticket-mcp"],
      "env": {
        "MCP_PHPCS_COMMAND": "phpcs",
        "MCP_DRUSH_COMMAND": "drush"
      }
    }
  }
}

Run locally

npm install
npm run mcp

Tools

  • configure
  • health.check
  • process_ticket
  • workflow.run
  • workflow.status
  • report.aar

Advanced tools

  • task.list
  • task.show
  • task.add
  • task.set_status
  • task.do
  • task.resume
  • task.run
  • task.verify

Typical flow

  1. Load a ticket with process_ticket.
  2. Review the generated checklist and adjust the ticket or project config if needed.
  3. Run the workflow with workflow.run.
  4. Use workflow.status if you want a compact progress summary.
  5. Generate the final report with report.aar.

workflow.run returns one of three outcomes:

  • success: all tasks completed
  • failed: verification failed on a task
  • needs_input: one or more tasks need input before they can complete

workflow.run and task.do both skip tasks that were already completed or skipped in a previous pass. If a task is already done, the server moves on to the next runnable task instead of failing. Do not build a custom loop out of task.list plus repeated task.do calls. Use workflow.run for the full workflow and task.do for one task.

The needs_input gate is any of these fields on the workflow.run call:

  • needsInput: true
  • inputReason
  • inputQuestion
  • neededInput

Example needs-input call:

{
  "needsInput": true,
  "inputReason": "Need product confirmation before choosing the final copy.",
  "inputQuestion": "Should this use the shorter headline or the full headline?",
  "neededInput": "Pick one of the two copy variants."
}

Advanced workflow controls

Use task.list when you want a filtered view of the workflow state.

Examples:

{
  "workflowPath": "./path/to/workspace",
  "status": "skipped"
}
{
  "workflowPath": "./path/to/workspace",
  "statuses": ["todo", "completed", "needs_input"]
}

task.list returns the matching tasks plus their ids, so the agent can pick one task at a time.

Use task.do when you want the server to work exactly one task and then stop.

Example one-task call:

{
  "workflowPath": "./path/to/workspace",
  "taskId": "T3"
}

Use task.resume when the user has answered a needs_input question and you want to continue the task from that response.

MCP tool example:

{
  "workflowPath": "./path/to/workspace",
  "taskId": "T3",
  "userResponse": "Use the shorter headline."
}

Use task.add when a review finds a new issue that should be tracked as part of the workflow.

Example add-task call:

{
  "workflowPath": "./path/to/workspace",
  "title": "Add missing validation for the new form field",
  "detail": "The review found a missing server-side validation branch.",
  "status": "pending"
}

Use task.set_status when a task needs to move back to work, get skipped, or be marked complete again.

Example status-change call:

{
  "workflowPath": "./path/to/workspace",
  "taskId": "T3",
  "status": "pending",
  "reason": "The completed change needs another pass after review."
}

If you change a completed task back to pending, the workflow loop will treat it as runnable again on the next pass.

Use task.show when you want to inspect one task without changing workflow state.

Example show call:

{
  "workflowPath": "./path/to/workspace",
  "taskId": "T3"
}

Use task.run and task.verify only if you want lower-level step-by-step control instead of workflow.run.

Default workflow policy

If you do not override it, the server uses this policy:

Workflow policy:
- Use process_ticket to build the checklist and report before execution.
- Treat process_ticket as the review stage only: present the checklist, ask for confirmation or clarification in plain text, and do not mark tasks as needs_input there.
- Run workflow.run to execute the workflow loop.
- Do not build your own loop out of task.list and repeated task.do calls.
- Use task.list only to inspect tasks or fetch ids for a single task.
- Use task.show when you want to inspect one task without changing state.
- Use task.do when you want exactly one task worked.
- Use task.resume when the user has answered a needs_input question and you want to continue that task.
- Use workflow.status when you only need a compact progress summary.
- Use needs_input only inside workflow.run when a task needs missing context, has multiple plausible fixes, or would be unsafe to guess.
- If verification fails with a concrete error, make one clear retry before asking for input.
- Do not guess when the next step is ambiguous or unsafe.

Configuration

You can configure the server with a JSON file passed to configure, or by sending config fields directly to configure.

Example config-file call:

{
  "configPath": "./mcp.config.json"
}

Supported config keys:

  • reportRoot
  • reportFileTemplate
  • phpcsCommand
  • drushCommand
  • defaultSite
  • sites
  • templatePath
  • workflowPolicy

Example config:

{
  "reportRoot": "/tmp/drupal-ticket-mcp-reports",
  "reportFileTemplate": "{{ticket.key}}.aar.md",
  "phpcsCommand": ["phpcs"],
  "drushCommand": ["drush"],
  "defaultSite": "site1",
  "workflowPolicy": "Workflow policy:\\n- Try once on clear errors.\\n- Ask for input on ambiguity.",
  "sites": {
    "site1": {
      "alias": "@site1",
      "root": "/path/to/site1",
      "uri": "https://site1.example.test"
    },
    "site2": {
      "alias": "@site2",
      "root": "/path/to/site2",
      "uri": "https://site2.example.test"
    }
  },
  "templatePath": "/path/to/template.aar.md"
}

Site selection

For multi-site workflows, use selectors such as @site1 and @site2 in process_ticket or task.verify.

Example:

{
  "sites": ["@site1", "@site2"]
}

Report output

  • If reportRoot is set, reports are written there.
  • Otherwise the report is written in the workflow root for the ticket.
  • The default filename is {{ticket.key}}.aar.md.

Template lookup

report.aar looks for a template in this order:

  1. template.aar.md in the workspace
  2. template.aar in the workspace
  3. template.md in the workspace
  4. the bundled fallback template in templates/default.aar.md

Notes

  • UNLICENSED is intentional for now.
  • phpcsCommand and drushCommand can also be supplied through MCP_PHPCS_COMMAND and MCP_DRUSH_COMMAND when needed.