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
Define custom flows with the@Flow decorator:
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
Use the@Hooks decorator on tools, resources, or prompts:
Around Hooks
Around hooks wrap a stage completely, giving you control over whether the stage executes:Flow Control
Within flow stages, you have access to control methods:State Management
Flows use a state object to pass data between stages. Never mutaterawInput directly — use state.set() instead:
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: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)
- Mutate
rawInputdirectly — 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