Skip to main content

Expose Celery tasks as async MCP tools with automatic lifecycle management

Project description

mcp-celery

Expose Celery tasks as asynchronous MCP tools — with automatic lifecycle management and no boilerplate.

Surfacing a long-running Celery task to an MCP client normally means hand-writing start / status / result / cancel tools for every task. mcp-celery generates that surface for you: register a task once and the right MCP tools appear, from a single synchronous call to full polling, depending on the strategy you pick.

Status: Alpha. The four stable strategies use only ratified MCP primitives and work on any MCP client today.

Installation

pip install mcp-celery

Requires Python ≥ 3.10, mcp >= 1.0, and Celery with a broker and result backend (e.g. Redis).

Quick start

from celery import Celery
from mcp_celery import AsyncToolServer

celery_app = Celery(
    "myapp",
    broker="redis://localhost:6379/0",
    backend="redis://localhost:6379/1",
)

@celery_app.task
def generate_report(user_id: str) -> dict:
    ...  # slow work
    return {"user_id": user_id, "revenue": 42000}

server = AsyncToolServer("my-server", celery_app=celery_app)
server.register_async_tool(generate_report, description="Generate a report")

if __name__ == "__main__":
    server.run()

That single registration generates the MCP tools. The default AdaptiveExposureStrategy returns the result inline when the task is fast, and hands back a token plus generate_report_status / _result / _cancel tools when it runs long.

To define and register a task in one step, use the decorator:

@server.async_tool(cancel=True, result_ttl=300)
def train_model(dataset: str) -> dict:
    ...

Choosing a strategy

The exposure strategy decides how a task is surfaced over MCP. Pick by task duration and client constraints; see docs/strategy-stability.md for full guidance.

Strategy Tools/task Best for Stability
AdaptiveExposureStrategy (default) 1 + polling fallback Mixed or unknown durations — inline if fast, polling if slow; streams progress while blocking stable
BlockingExposureStrategy 1 Short tasks — one synchronous call, result inline stable
SingleToolExposureStrategy 1 (action-driven) Full lifecycle in one tool — minimal tool budget stable
PollingExposureStrategy 4 (_start / _status / _result / _cancel) Long tasks, or explicit lifecycle control stable
OperationResourceStrategy 1 + MCP task/resource API MCP-native async tasks (SEP-1391) experimental
from mcp_celery.exposure import BlockingExposureStrategy

server = AsyncToolServer(
    "my-server",
    celery_app=celery_app,
    strategy=BlockingExposureStrategy(max_wait=15.0),
)

Every stable strategy relies only on MCP tools, so it works on any client. OperationResourceStrategy depends on the un-ratified SEP-1391 Task primitive and emits an ExperimentalFeatureWarning on use.

Architecture

AsyncToolServer sits on two swappable layers:

  • Backend (AbstractBackend) — how a task runs. CeleryBackend is the only implementation today.
  • Exposure strategy (AbstractExposureStrategy) — how the task is surfaced over MCP (the table above).

Task state is normalised to a single TaskStatus enum (PENDING, RUNNING, COMPLETED, FAILED, CANCELLED, RETRYING). The token a client carries across calls is the Celery task id. Transport (stdio, SSE, streamable-HTTP) is delegated to FastMCP via server.run().

Attach to a FastMCP server you already configured with AsyncToolServer.from_fastmcp(existing_mcp, celery_app=...).

Examples

Runnable end-to-end examples live in examples/, each driven by a single script that handles Redis, the virtualenv, and the Celery worker:

bash examples/run.sh adaptive       # AdaptiveExposureStrategy (default)
bash examples/run.sh blocking       # BlockingExposureStrategy
bash examples/run.sh single_tool    # SingleToolExposureStrategy
bash examples/run.sh with_package   # PollingExposureStrategy
bash examples/run.sh approach3      # OperationResourceStrategy (experimental)
bash examples/run.sh baseline       # hand-written MCP tools, for comparison

Requires python3, bash, and Docker (only to auto-start Redis).

Limitations

  • Token validity. Celery cannot tell an unknown or expired task id from a pending one — both report PENDING. A polling strategy given a bad or TTL-expired token keeps reporting PENDING rather than erroring.
  • Cancellation is best-effort. cancel issues revoke(terminate=True) and reports the current state, which is often still RUNNING immediately after, since revocation is asynchronous.
  • OperationResourceStrategy is experimental. It depends on the un-ratified MCP SEP-1391 Task primitive; most clients do not understand the returned task:// URI.

Development

pip install -e ".[dev]"
pytest                 # unit tests use an in-memory backend — no Redis or worker needed
ruff check src tests

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_celery-0.2.0.tar.gz (41.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_celery-0.2.0-py3-none-any.whl (33.9 kB view details)

Uploaded Python 3

File details

Details for the file mcp_celery-0.2.0.tar.gz.

File metadata

  • Download URL: mcp_celery-0.2.0.tar.gz
  • Upload date:
  • Size: 41.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for mcp_celery-0.2.0.tar.gz
Algorithm Hash digest
SHA256 52e530e60640b7ab8cf4b9c7a7ebfaaf13d5c93a23869aa700d4973bc4d2f5f1
MD5 4626722ca5503a4507ecfdf42bbaffd5
BLAKE2b-256 b7bb53709a8a44af1921fd44842f70d7860f7a3399453d8c43e787eb31c5e119

See more details on using hashes here.

File details

Details for the file mcp_celery-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_celery-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 33.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for mcp_celery-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 64f5afe3842259ea84355635d16afe1d565c54ea8e53ac4b429885e738eb3114
MD5 a69906115d664ff177a3a5fa4484f65d
BLAKE2b-256 5f6d2c98df7deaacdfbfaf44e869994ecd42978d89f1eb59950797b97199173a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page