Skip to main content

Decorators

MCPApp exposes a small set of decorators that register tools, workflows, and workflow tasks. The decorators are engine-aware: when you switch from the default asyncio executor to Temporal, the same annotations automatically apply the appropriate Temporal SDK wrappers.

Tool decorators

Tools expose code as MCP functions that agents and LLMs can call. Both decorators accept the same keyword arguments:

@app.tool — synchronous tools

  • The decorator validates the signature up-front; missing type hints or unsupported default values raise an error during import.
  • @app.tool automatically creates a hidden workflow so the tool is reachable via both callTool and the workflow endpoints (run, get_status) exposed by FastMCP.
  • The function executes inside the app event loop; heavy work should offload itself (for example, using asyncio.to_thread).

@app.async_tool — asynchronous tools

  • The coroutine is awaited directly, so you can call other async APIs without wrappers.
  • When Temporal is active, the decorated function is wrapped with workflow.activity metadata automatically.

Workflow decorator suite

Workflows orchestrate complex sequences, combining tasks, tools, and signals. Every workflow subclass must inherit from mcp_agent.executor.workflow.Workflow.

@app.workflow

  • Registers the class with the app and applies engine-specific decorators (workflow.defn for Temporal, no-op for asyncio).
  • An optional workflow_id parameter lets you export the workflow under a different name when registering.
  • The decorator stores a reference to the MCPApp, letting workflow instances access self.context.app.

@app.workflow_run

Wraps the run coroutine so that initialization, tracing, and Temporal-specific instrumentation are handled automatically. You rarely need to call it manually—applying @app.workflow and naming the method run is enough—but explicit usage lets you decorate additional entry points.

@app.workflow_task

Registers a coroutine as a reusable activity. Key options: The decorator enforces that the target is async; synchronous functions should wrap their blocking work with asyncio.to_thread. Tasks defined outside a workflow are also supported—they are registered globally and can be reused across multiple workflows.

@app.workflow_signal

Signals let external actors (humans, webhooks, other workflows) nudge a running workflow. The decorator accepts an optional name argument and works in both asyncio and Temporal modes.
The generated wrapper automatically strips the workflow instance (self) for Temporal’s signal handler signature.
All workflow decorators defer to the active executor. When you switch to Temporal, tasks become activities, run becomes a workflow entry point, and signals map to @workflow.signal—no additional changes required.

Putting it together

This pattern gives you:
  • A reusable list_servers tool that exposes runtime metadata without boilerplate.
  • A workflow that can run locally (asyncio) or durably (Temporal) with the same code.
  • Optional signals/tasks to pause, resume, or branch as needed.
For CLI-driven workflows and deployment details, continue with the CLI reference. For configuration options that pair with these decorators, review the Configuration reference.