@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-mcpOr run it without a global install:
npx @lockweb/drupal-ticket-mcpMCP 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:
reportRootreportFileTemplatephpcsCommanddrushCommanddefaultSitesitestemplatePathworkflowPolicy
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-mcpWhat changes by client is where you paste the config.
- Codex: use Codex's MCP config flow and add the same
stdiocommand there. - Claude Code: use
claude mcp add-jsonor 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 mcpTools
configurehealth.checkprocess_ticketworkflow.runworkflow.statusreport.aar
Advanced tools
task.listtask.showtask.addtask.set_statustask.dotask.resumetask.runtask.verify
Typical flow
- Load a ticket with
process_ticket. - Review the generated checklist and adjust the ticket or project config if needed.
- Run the workflow with
workflow.run. - Use
workflow.statusif you want a compact progress summary. - Generate the final report with
report.aar.
workflow.run returns one of three outcomes:
success: all tasks completedfailed: verification failed on a taskneeds_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: trueinputReasoninputQuestionneededInput
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:
reportRootreportFileTemplatephpcsCommanddrushCommanddefaultSitesitestemplatePathworkflowPolicy
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
reportRootis 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:
template.aar.mdin the workspacetemplate.aarin the workspacetemplate.mdin the workspace- the bundled fallback template in
templates/default.aar.md
Notes
UNLICENSEDis intentional for now.phpcsCommandanddrushCommandcan also be supplied throughMCP_PHPCS_COMMANDandMCP_DRUSH_COMMANDwhen needed.
