Skip to main content
Flows are named execution pipelines that define how requests are processed through a series of lifecycle stages. Every MCP operation (calling a tool, reading a resource, getting a prompt) passes through a flow that controls pre-processing, execution, post-processing, and finalization.
Flows are part of the FrontMCP execution model. They provide hook points for cross-cutting concerns like logging, caching, validation, and error handling.

Why Flows?

Flows give you fine-grained control over request processing without modifying tool, resource, or prompt code directly. Flows are ideal for:
  • Request validation — check permissions, validate inputs before execution
  • Caching — intercept responses and serve from cache
  • Logging and auditing — trace every request through the system
  • Error handling — centralized error recovery and formatting
  • Performance monitoring — measure timing across stages

Flow Lifecycle

Every request passes through these stages in order:

Built-in Flows

FrontMCP provides built-in flows for all MCP protocol operations:

Creating Custom Flows

Custom flows are defined with the @Flow decorator, a typed FlowPlan, and stage handlers attached via FlowHooksOf(...).Stage(...). The plan is keyed by phase (pre, execute, post, finalize) and lists the stage names that run in that phase. Each named stage in the plan is implemented by a method on the flow class decorated with @Stage('<stage-name>').

Flow Metadata


Hooking into Flows

You don’t need to create a full custom flow to customize behavior. Use hooks to intercept specific stages of existing flows.

Hook Types

Applying Hooks

Hooks are method decorators returned from a flow-specific factory. Use the pre-built hook factories (e.g. ToolHook, ResourceHook) or build your own with FlowHooksOf(flowName).
For other flows, build hook decorators with FlowHooksOf(flowName):

Around Hooks

Around hooks wrap a stage completely, giving you control over whether the stage executes:
For a complete guide to hooks, see the Hooks decorator reference.

Flow Control

Within flow stages, you have access to control methods:

State Management

Flows expose this.rawInput (raw request payload) and this.input (validated against inputSchema). Use this.state to pass data between stages — never mutate rawInput directly.
Never mutate rawInput in flows — use state.set() for flow state. This ensures each stage works with clean, immutable inputs.

Generating Flows

Use the Nx generator to scaffold a new flow:
This generates a flow class with all lifecycle methods:

Best Practices

Do:
  • Use hooks for cross-cutting concerns instead of duplicating logic in tools
  • Keep flow stages focused — each stage should have a single responsibility
  • Use state.set() / state.get() for passing data between stages
  • Handle errors in the error() stage for centralized error management
  • Validate hook flows match their entry type (e.g., tool hooks use tools:call-tool)
Don’t:
  • Mutate rawInput directly — use flow state instead
  • Create custom flows for simple operations that built-in flows already handle
  • Skip the error() stage — unhandled errors surface as generic MCP errors
  • Add business logic to hooks — keep hooks lightweight, delegate to providers