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.| Aspect | Flow | Tool | Plugin |
|---|---|---|---|
| Purpose | Request lifecycle management | Execute actions | Cross-cutting extensions |
| Scope | Per-request pipeline | Single action | Across all requests |
| Customization | Stage-level hooks | Execute method | Registration hooks |
| Use case | Logging, caching, auth checks | Business logic | Feature extensions |
- 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:| Stage | Purpose | Example |
|---|---|---|
| pre | Validation, auth checks, input transformation | Check API key, parse headers |
| execute | Run the core operation (tool, resource, prompt) | Call execute() on the tool |
| post | Transform output, apply caching, logging | Cache response, format output |
| finalize | Send response, cleanup | Emit response to client, release resources |
| error | Handle failures from any stage | Log error, return formatted error response |
Built-in Flows
FrontMCP provides built-in flows for all MCP protocol operations:| Flow Name | Trigger | Description |
|---|---|---|
tools:call-tool | tools/call request | Execute a tool with validated arguments |
tools:list-tools | tools/list request | List all available tools |
resources:read-resource | resources/read request | Read a resource by URI |
resources:list-resources | resources/list request | List all available resources |
resources:subscribe | resources/subscribe request | Subscribe to resource changes |
prompts:get-prompt | prompts/get request | Generate a prompt with arguments |
prompts:list-prompts | prompts/list request | List all available prompts |
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
| Hook Type | When It Runs | Use Case |
|---|---|---|
| Will | Before a stage executes | Validate, transform input |
| Did | After a stage completes | Log, cache, transform output |
| Around | Wraps the entire stage | Timing, retry logic, circuit breakers |
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:| Method | Description |
|---|---|
this.respond(value) | End the flow and send a response to the client |
this.fail(message) | Abort the flow with an error |
this.state.get(key) | Read from flow state |
this.state.set(key, value) | Write to flow state |
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