Skip to main content
Glama

rq-mcp

CI License: MIT

An MCP (Model Context Protocol) server for RQ (Redis Queue), letting AI agents inspect, debug, and operate RQ queues, jobs, and workers.

Status

Phase 1 (read-only), Phase 2 (write: enqueue/requeue/cancel), and Phase 3 (admin: delete/purge/worker shutdown) are all complete — see the "Modes" section below and "Available tools" for the full surface.

Related MCP server: Redis MCP Server

Requirements

  • Python 3.14+

  • uv

  • A running Redis instance (a docker-compose.yml is provided for local dev)

  • Docker — only needed if you use the provided docker-compose.yml instead of your own Redis

Installation

uv sync

Configuration

All configuration is via environment variables.

Variable

Default

Purpose

REDIS_URL

redis://localhost:6379/0

Redis connection string

RQ_MCP_MODE

readonly

readonly, write, or admin — see "Modes" below

RQ_MCP_WORKER_TTL_S

420

health_check's WORKER_STALE_HEARTBEAT threshold (matches RQ's own default worker TTL)

RQ_MCP_OLDEST_JOB_THRESHOLD_S

300

health_check's OLDEST_JOB_TOO_OLD threshold

RQ_MCP_HIGH_FAILURE_THRESHOLD

50

health_check's HIGH_FAILURE_COUNT threshold

RQ_MCP_TASK_WHITELIST

unset

Path to a TOML file listing functions enqueue_task may enqueue (write mode) — see examples/task_whitelist.toml. Unset/missing/unparseable all mean "nothing is enqueueable" (fails closed).

export REDIS_URL="redis://localhost:6379/0"

Modes

RQ_MCP_MODE gates which tools get registered: readonly (default) exposes only inspection tools (12); write adds enqueue/requeue/cancel tools (6 more, 18 total); admin adds delete/purge/worker-shutdown tools (6 more, 24 total). Modes are cumulative — admin gets write and readonly tools too.

admin mode grants genuinely destructive capabilities — permanently deleting jobs, wiping entire status registries, emptying queues, shutting down or globally suspending workers. Don't set RQ_MCP_MODE=admin against a Redis instance you don't want an AI agent able to disrupt.

WARNING

suspend_workers is global, not scoped to a queue or a single worker: it stops every RQ worker sharing that Redis connection from picking up new jobs, regardless of which queue(s) they listen to. This is RQ's own suspend mechanism (rq.suspension), not something rq-mcp narrows down. resume_workers undoes it (also globally); an optional ttl on suspend_workers can auto-expire the suspension.

Quickstart: trying it out locally

This spins up Redis, puts demo data on a couple of queues, and lets you call the MCP tools interactively through the MCP Inspector — no AI client required.

# 1. Start Redis
docker compose up -d

# 2. Seed demo data across every job/queue/worker state
uv run python scripts/seed_demo_data.py

# 3. Launch the server with the MCP Inspector (opens a browser UI)
uv run mcp dev src/rq_mcp/server.py

scripts/seed_demo_data.py (see "Local dev / example data" below) seeds queued, scheduled, deferred, finished, and failed jobs (two different exception types, so summarize_failures has something to group), plus a fake stale worker entry so health_check reports a finding out of the box. For a lighter touch — just a couple of queued jobs — use examples/seed_queues.py instead.

In the Inspector UI, connect and use "List Tools" to see the tools for your current RQ_MCP_MODE (see "Available tools" below), and "List Prompts" for the 5 guided workflows. mcp dev requires the cli extra, which is already included as a dev dependency.

list_jobs/summarize_failures/list_scheduled_jobs are how you discover job IDs to pass to get_job/get_job_result — none of the seed scripts print them directly.

Optionally, run a real worker in another terminal so jobs keep getting processed live, and so you have a live worker to inspect with list_workers/get_worker (this is on top of seed_demo_data.py's built-in one-shot processing — a live worker keeps running afterward):

uv run python examples/worker.py

See examples/ and scripts/ for the job definitions and seed scripts.

When you're done:

docker compose down -v

Running the server

Outside of the Inspector, the server communicates over stdio, so it's normally launched by an MCP client (e.g. Claude Desktop, Claude Code) rather than run standalone. To start it directly:

uv run rq-mcp
# or
uv run python -m rq_mcp

Available tools

Read-only (readonly mode and above)

All 12 of these are read-only (readOnlyHint: true).

System

  • get_rq_info — Redis connection status, Redis/RQ versions, discovered queue names, and worker count.

  • redis_info — selected Redis INFO fields (used_memory, maxmemory, maxmemory_policy, evicted_keys, connected_clients, per-database key counts), by section (defaults to memory/clients/stats/keyspace).

Queues

  • list_queues — per queue: job counts by status (queued, started, finished, failed, deferred, scheduled, canceled) and worker count.

  • get_queue — the same per-queue detail plus the oldest queued job's age in seconds and default_timeout.

Jobs

  • get_job — full details for a single job by ID (status, origin queue, function name, redacted/truncated args/kwargs/meta, timeout, ttl, dependency IDs, worker name, lifecycle timestamps), or null if the job doesn't exist.

  • get_job_result — a job's result or exception info, truncated to max_bytes (default 2000), or null if the job doesn't exist.

  • list_jobs — jobs in a queue filtered by status, paginated (offset/limit, max 100 per page), with a total count.

  • summarize_failures — a queue's failed jobs grouped by function name + exception type: count, an example job ID, first/last failure time.

  • list_scheduled_jobs — a queue's scheduled jobs: ID, function name, scheduled time, paginated.

Workers

  • list_workers — every registered worker (optionally filtered by queue): name, state, queues, current job ID, heartbeat + age, job counters.

  • get_worker — full details for a single worker by name (state, hostname, IP, PID, queues, current job ID, timestamps, job counters, total working time), or null if it isn't currently registered.

Health

  • health_check — runs six diagnostics across queues/workers/Redis and returns {"ok": bool, "findings": [...]}. Finding codes: QUEUE_NO_WORKERS, WORKER_STALE_HEARTBEAT, ORPHANED_STARTED_JOB, OLDEST_JOB_TOO_OLD, REDIS_EVICTION_RISK, HIGH_FAILURE_COUNT.

Write (write mode and above)

Mutate job state, but nothing here deletes data or touches workers.

  • list_task_functions — the enqueue whitelist loaded from RQ_MCP_TASK_WHITELIST (name, description, args per entry).

  • enqueue_task — enqueue a whitelisted function by dotted name (func_name must be in list_task_functions's output — nothing else can be enqueued), immediately or scheduled via at/in_seconds.

  • requeue_job — requeue a single failed job.

  • requeue_failed — bulk-requeue a queue's failed jobs, optionally filtered by function name/exception type; dry_run=True by default.

  • cancel_job — cancel a queued/scheduled/deferred job.

  • stop_running_job — send a stop signal to a currently-executing job.

Admin (admin mode only)

Destructive. delete_job/clear_registry/empty_queue/ shutdown_worker/suspend_workers all require confirm=True to actually act (or dry_run=True to preview the affected count first, which needs no confirmation). resume_workers needs neither.

  • delete_job — permanently delete a single job.

  • clear_registry — permanently delete every job in one queue's status registry (started/finished/failed/deferred/scheduled/canceled).

  • empty_queue — permanently delete every queued job in a queue.

  • shutdown_worker — send a shutdown command to one named worker.

  • suspend_workers — global: stop every worker on this Redis from picking up new jobs (see the warning above).

  • resume_workers — undo suspend_workers (also global); no confirmation needed.

Available prompts

Five guided read-only diagnostic workflows, each naming which tools above to call, in order, and what to conclude from the results:

  • diagnose_queue(queue_name)

  • triage_failed_jobs(queue_name, limit)

  • why_is_job_stuck(job_id)

  • capacity_check()

  • post_deploy_check()

Running tests

uv run pytest

Two layers of tests, neither requiring a running Redis instance:

  • tests/test_rq_service.py, tests/test_config.py, tests/test_helpers.py, tests/test_audit.py, tests/test_prompts.py — mock the Redis connection (unittest.mock); fast, cover most branches directly.

  • tests/test_integration.py — runs real RQService methods against a real redis/rq API surface backed by an in-memory fakeredis instance (using RQ's non-forking SimpleWorker so job execution stays visible to the test process). Covers scenarios that are awkward to fully exercise with mocks: an orphaned started-job registry entry (real composite-key format), mixed-exception grouping, and pagination boundaries.

Linting and formatting

uv run ruff check .
uv run ruff format --check .

Architecture

Simple layered src layout, no unnecessary abstractions. See ARCHITECTURE.md for the full layer breakdown, request lifecycle, and shared helpers (pagination, redaction, truncation).

Local dev / example data

  • docker-compose.yml — a local Redis 7 instance for development, not used in production or in tests.

  • examples/ — minimal scripts (tasks.py, seed_queues.py, worker.py) for a quick two-queue smoke test. Not part of the installable package.

  • scripts/seed_demo_data.py (+ seed_tasks.py) — a richer seed covering every job status, two distinct exception types, and a hand-crafted stale worker entry, so every Phase 1 tool (including health_check's findings and summarize_failures's grouping) has something real to show. Not part of the installable package.

RQ gotchas worth knowing

A few things discovered while building this that aren't obvious from RQ's own docs:

  • Queue's default_timeout isn't persisted to Redis. It's a Python-side constructor default (180s) that only exists in the process that created the Queue object — get_queue's default_timeout field reflects this server's default, not necessarily what any given producer used (each job's own .timeout, exposed via get_job, is the real source of truth per job).

  • worker.queue_names() is a method, not a property in rq==2.12.0 — easy to get wrong since many other worker fields are plain attributes.

  • worker.get_current_job_id() does a live Redis round trip every call; it isn't populated by Worker.all()'s bulk refresh().

  • RQ doesn't expose a structured exception class, only the raw traceback text (Result.exc_string) — summarize_failures parses the traceback's last line by convention (ExceptionType: message).

  • StartedJobRegistry.add() raises NotImplementedError in this RQ version (an unimplemented base-class stub); entries are written directly via ZADD with a "{job_id}:{execution_id}" composite key internally by the worker. Relevant if you ever need to hand-craft a started-registry entry (as scripts/seed_demo_data.py's tests do).

  • fakeredis doesn't implement the INFO command — get_info() and redis_info() degrade gracefully against it (their existing RedisError handling), but don't expect real memory/stats data from integration tests.

  • A non-forking SimpleWorker burst-processing several jobs in one long-lived process intermittently failed to re-resolve later jobs' function imports in this environment (Python 3.14 / rq 2.12.0) when the task module was only importable via a bare sys.path[0]-relative script directory (not a proper package). Not fully root-caused; worked around by using the regular forking Worker wherever multiple real jobs need to run outside of fakeredis-backed tests (see scripts/seed_demo_data.py).

Available Tools

12 tools
get_jobA
Read-onlyIdempotent

Return full details for a single RQ job by ID, or null if it does not exist.

Includes status, origin queue, function name, redacted/truncated args/kwargs/meta, timeout, ttl, dependency IDs, worker name, and lifecycle timestamps. Does not include the job's result or exception info -- use get_job_result for that.

Inputs: job_id (required). Returns: result

get_job_resultA
Read-onlyIdempotent

Return a job's result/exc_info, or null if the job does not exist.

Truncated to max_bytes, with a truncated flag when that happened.

Inputs: job_id (required), max_bytes. Returns: result

get_queueA
Read-onlyIdempotent

Return detailed status for a single queue by name.

Includes the same per-status counts as list_queues, the age in seconds of the oldest still-queued job (null if empty), and default_timeout in seconds (reflects this server's own default, since RQ does not persist a per-queue default_timeout to Redis). An unknown queue name is not an error -- RQ queues are lazy/virtual, so it returns the same shape with all counts at 0.

Inputs: name (required). Returns: object

get_rq_infoA
Read-onlyIdempotent

Return basic information about the Redis/RQ environment.

Includes Redis connection status, Redis/RQ versions, discovered queue names, and the number of active workers.

Inputs: no named parameters. Returns: object

get_workerA
Read-onlyIdempotent

Return full details for a single worker by name, or null if not currently registered.

Includes state, hostname, IP address, PID, queue names, current job ID (if any), birth/last-heartbeat timestamps (plus heartbeat age in seconds), job counters, and total working time in seconds.

Inputs: name (required). Returns: result

health_checkA
Read-onlyIdempotent

Run read-only diagnostics across queues, workers, and Redis itself.

Returns {"ok": bool, "findings": [...]}; findings is empty and ok is true when nothing is wrong. Each finding has a severity, a stable code (QUEUE_NO_WORKERS, WORKER_STALE_HEARTBEAT, ORPHANED_STARTED_JOB, OLDEST_JOB_TOO_OLD, REDIS_EVICTION_RISK, HIGH_FAILURE_COUNT), a human-readable message, and structured details.

Inputs: no named parameters. Returns: object

list_jobsA
Read-onlyIdempotent

List jobs in a queue filtered by status.

status must be one of: queued, started, finished, failed, deferred, scheduled, canceled. Returns up to limit (max 100) job summaries (id, function name, description, status, enqueued_at, started_at, ended_at) starting at offset, plus the total number of jobs at that status in the queue.

Inputs: status (required), queue_name (required), limit, offset. Returns: object

list_queuesA
Read-onlyIdempotent

List all discovered RQ queues.

Returns, per queue: job counts by status (queued, started, finished, failed, deferred, scheduled, canceled) and the number of workers currently listening to it.

Inputs: no named parameters. Returns: result

list_scheduled_jobsA
Read-onlyIdempotent

List scheduled jobs in a queue: id, function name, and scheduled time.

Returns up to limit (max 100) entries starting at offset, plus the total number of scheduled jobs in the queue.

Inputs: queue_name (required), limit, offset. Returns: object

list_workersA
Read-onlyIdempotent

List currently registered RQ workers, optionally filtered by queue.

Returns, per worker: name, state (idle/busy/started/suspended), the queue names it listens to, the ID of the job it's currently processing (if any), last heartbeat and its age in seconds, and its successful/failed job counters. If queue is given, only workers listening to that queue are returned.

Inputs: queue. Returns: result

redis_infoA
Read-onlyIdempotent

Return selected Redis INFO fields.

Defaults to memory, clients, stats, and keyspace sections: used_memory, maxmemory, maxmemory_policy, evicted_keys, connected_clients, and per-database key counts. Unrecognized section names are ignored and listed in ignored_sections rather than raising an error.

Inputs: sections. Returns: object

summarize_failuresA
Read-onlyIdempotent

Group a queue's failed jobs by function name + exception type.

Scans up to limit failed jobs (default 200) and returns one entry per (function, exception type) group: count, an example job ID, and first/last failure timestamps.

Inputs: queue_name (required), limit. Returns: object

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 12 tools

    Disambiguation5/5

    Each tool targets a distinct RQ resource or view: environment info, Redis internals, queues, jobs, results, workers, failures, and health. The only close pair is list_jobs with status=scheduled and list_scheduled_jobs, but their return shapes and descriptions make the intended use clear.

    Naming Consistency4/5

    The naming is mostly predictable with get_ for single entities and list_ for collections, all in snake_case. summarize_failures and health_check deviate slightly from the get_/list_ pattern but remain readable and consistent in style.

    Tool Count5/5

    Twelve tools is well-scoped for an RQ monitoring and inspection server. Each tool covers a meaningful part of the domain without unnecessary redundancy or bloat.

    Completeness5/5

    The tool surface covers the major RQ monitoring areas: environment, Redis health, queues, jobs by status, individual job details and results, scheduled jobs, workers, failure aggregation, and health diagnostics. For a read-only monitoring server, there are no obvious dead ends or missing core operations.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      Enables AI assistants to manage BullMQ Redis-based job queues through natural language, supporting operations like job monitoring, queue control, and multi-instance Redis connections. Users can add, retry, promote, and clean jobs while accessing detailed job logs and queue statistics directly within the assistant.
      20
      493 npm
      7
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Enables AI agents to manage and search data in Redis using natural language. Supports hashes, lists, sets, sorted sets, streams, JSON, and vector search.
      44
      MIT
    • A
      license
      B
      quality
      C
      maintenance
      Enables AI agents to manage RabbitMQ message brokers through admin APIs, supporting multiple brokers, OAuth authentication, and mutative tools.
      39
      272 PyPI
      43
      Apache 2.0
    • A
      license
      Not graded
      quality
      D
      maintenance
      Lets an LLM like Claude inspect and control an automation job queue — list jobs, check status, trigger new runs, retry failures, and pull queue-wide stats through natural language.
      MIT