rq-mcp
Provides tools for inspecting and managing RQ (Redis Queue) jobs, queues, and workers on a Redis instance, including enqueueing, requeueing, canceling jobs, running health checks, and performing admin operations like deleting jobs or suspending workers.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rq-mcp show me the failed jobs and summarize the exceptions"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
rq-mcp
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+
A running Redis instance (a
docker-compose.ymlis provided for local dev)Docker — only needed if you use the provided
docker-compose.ymlinstead of your own Redis
Installation
uv syncConfiguration
All configuration is via environment variables.
Variable | Default | Purpose |
|
| Redis connection string |
|
|
|
|
|
|
|
|
|
|
|
|
| unset | Path to a TOML file listing functions |
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.
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.pyscripts/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.pySee examples/ and scripts/ for the job
definitions and seed scripts.
When you're done:
docker compose down -vRunning 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_mcpAvailable 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 RedisINFOfields (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 anddefault_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), ornullif the job doesn't exist.get_job_result— a job's result or exception info, truncated tomax_bytes(default 2000), ornullif 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), ornullif 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 fromRQ_MCP_TASK_WHITELIST(name, description, args per entry).enqueue_task— enqueue a whitelisted function by dotted name (func_namemust be inlist_task_functions's output — nothing else can be enqueued), immediately or scheduled viaat/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=Trueby 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— undosuspend_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 pytestTwo 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 realRQServicemethods against a realredis/rqAPI surface backed by an in-memoryfakeredisinstance (using RQ's non-forkingSimpleWorkerso 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 (includinghealth_check's findings andsummarize_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'sdefault_timeoutisn't persisted to Redis. It's a Python-side constructor default (180s) that only exists in the process that created theQueueobject —get_queue'sdefault_timeoutfield reflects this server's default, not necessarily what any given producer used (each job's own.timeout, exposed viaget_job, is the real source of truth per job).worker.queue_names()is a method, not a property inrq==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 byWorker.all()'s bulkrefresh().RQ doesn't expose a structured exception class, only the raw traceback text (
Result.exc_string) —summarize_failuresparses the traceback's last line by convention (ExceptionType: message).StartedJobRegistry.add()raisesNotImplementedErrorin this RQ version (an unimplemented base-class stub); entries are written directly viaZADDwith a"{job_id}:{execution_id}"composite key internally by the worker. Relevant if you ever need to hand-craft a started-registry entry (asscripts/seed_demo_data.py's tests do).fakeredisdoesn't implement theINFOcommand —get_info()andredis_info()degrade gracefully against it (their existingRedisErrorhandling), but don't expect real memory/stats data from integration tests.A non-forking
SimpleWorkerburst-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 baresys.path[0]-relative script directory (not a proper package). Not fully root-caused; worked around by using the regular forkingWorkerwherever multiple real jobs need to run outside offakeredis-backed tests (seescripts/seed_demo_data.py).
Available Tools
12 toolsget_jobARead-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_resultARead-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_queueARead-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_infoARead-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_workerARead-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_checkARead-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_jobsARead-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_queuesARead-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_jobsARead-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_workersARead-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_infoARead-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_failuresARead-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
Scored across 12 tools
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.
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.
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.
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
Related MCP Connectors
Durable background job execution, async task scheduling, and state persistence for AI agents.
Reliable async execution for agent tool calls: schema gating, retries, idempotency, audit trail.
Debug background jobs — runs, traces, spans, schedules, queues and deployments.
Connect, monitor, and control AI agents — tasks, approvals, schedules, and governance.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables 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.20493 npm7MIT
- AlicenseAqualityDmaintenanceEnables AI agents to manage and search data in Redis using natural language. Supports hashes, lists, sets, sorted sets, streams, JSON, and vector search.44MIT
- AlicenseBqualityCmaintenanceEnables AI agents to manage RabbitMQ message brokers through admin APIs, supporting multiple brokers, OAuth authentication, and mutative tools.39272 PyPI43Apache 2.0
- AlicenseNot gradedqualityDmaintenanceLets 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