On this page7 sections
Stateful Strategies
For complex models with many fields organized into sections, mcp-rune ships a stateful strategy that walks the agent through one section at a time, validating as it goes. Use this when a single-shot validation would overwhelm the LLM — typically 20+ fields, multiple required dependencies, or workflows where the user needs to see partial progress before committing.
This guide covers the configuration knobs, the validation flow, and the StatefulFormStrategy API. For the structure stateful strategies consume (sections + fieldGroups), see the Sections & Field Groups guide. For the comparison with stateless and hybrid, see the Prompt Creation guide.
The walk is per-section, not per-field:
validateSection is the only validation the LLM calls during the walk — section-scoped, so an error in timing doesn’t reopen basics. getProgress is a status query the LLM can call at any point to know what’s done and what’s left.
Mode configuration
Stateful prompts support two interaction modes:
| Mode | Behavior | Use Case |
|---|---|---|
guided | Walk through each section interactively | Human interaction via MCP client |
quick | Minimize questions, infer values from context | Agentic workflows, automation |
Enabling mode selection
1. Add mode to static arguments
static arguments = [
{ name: 'mode', description: '"guided" (step-by-step) or "quick" (minimal interaction)', required: false },
// ... other prompt-specific arguments
]static arguments = [
{ name: 'mode', description: '"guided" (step-by-step) or "quick" (minimal interaction)', required: false },
// ... other prompt-specific arguments
]2. Mode selection is automatic via the builder
The .guidance() step (included in .standard()) automatically includes mode-selection instructions.
Structural overview
The Flow diagram (generated by .flowDiagram()) serves as the single structural overview. In guided mode, the LLM references this diagram rather than repeating section information.
Stateful prompt structure
import { BasePrompt, derivePromptSchema, PromptContentBuilder } from '@mcp-rune/mcp-rune/prompts'
import { Activity } from '../models/index.js'
export class ActivityPrompt extends BasePrompt {
// 1. Declare strategy
static formStrategy = 'stateful'
// 2. Define sections (user-facing workflow)
static sections = {
basics: {
title: 'Basic Information',
description: 'Title and description',
required: true,
groups: ['basics']
}
}
// 3. Define field groups (validation structure)
static fieldGroups = {
basics: {
fields: ['title', 'description'],
required: true
}
}
// 4. Schema derivation
static {
const schema = derivePromptSchema(Activity, {
fieldGroups: this.fieldGroups
})
this.fieldGroups = schema.fieldGroups
this.fieldDefinitions = schema.fieldDefinitions
}
// 5. MCP metadata
static title = 'Create Activity'
static modelName = 'activity'
// 6. Arguments with mode support
static arguments = [
{ name: 'mode', description: '"guided" or "quick"', required: false },
{ name: 'title', description: 'Activity title', required: false }
]
// 7. Generate description using the strategy intro fragment
static description = `${ActivityPrompt.getStrategyIntro()} activities.`
// 8. Prompt content using PromptContentBuilder
get promptContent() {
return PromptContentBuilder.for(ActivityPrompt, 'activity')
.add(`# Activity Creation Guide\n\n...`)
.standard()
.toolUsage()
.attributeReference()
.build()
}
}import { BasePrompt, derivePromptSchema, PromptContentBuilder } from '@mcp-rune/mcp-rune/prompts'
import { Activity } from '../models/index.js'
export class ActivityPrompt extends BasePrompt {
// 1. Declare strategy
static formStrategy = 'stateful'
// 2. Define sections (user-facing workflow)
static sections = {
basics: {
title: 'Basic Information',
description: 'Title and description',
required: true,
groups: ['basics']
}
}
// 3. Define field groups (validation structure)
static fieldGroups = {
basics: {
fields: ['title', 'description'],
required: true
}
}
// 4. Schema derivation
static {
const schema = derivePromptSchema(Activity, {
fieldGroups: this.fieldGroups
})
this.fieldGroups = schema.fieldGroups
this.fieldDefinitions = schema.fieldDefinitions
}
// 5. MCP metadata
static title = 'Create Activity'
static modelName = 'activity'
// 6. Arguments with mode support
static arguments = [
{ name: 'mode', description: '"guided" or "quick"', required: false },
{ name: 'title', description: 'Activity title', required: false }
]
// 7. Generate description using the strategy intro fragment
static description = `${ActivityPrompt.getStrategyIntro()} activities.`
// 8. Prompt content using PromptContentBuilder
get promptContent() {
return PromptContentBuilder.for(ActivityPrompt, 'activity')
.add(`# Activity Creation Guide\n\n...`)
.standard()
.toolUsage()
.attributeReference()
.build()
}
}BasePrompt helpers
The rendering helpers that used to live on BasePrompt are now generator functions reached through PromptContentBuilder steps. What survives on BasePrompt is a small set of configuration-read statics:
| Static | Purpose |
|---|---|
getStrategyIntro() | Strategy-appropriate intro fragment for static description |
getSectionForGroup(groupName) | Reverse lookup: section for a fieldGroup |
getDefaults() | Default values across all field definitions |
toFormSchema() | Transport-safe schema serialization for prompts/getFormSchema |
Everything rendered — flow diagram, guidance, section docs, tool usage, attribute reference — comes from builder steps:
| Builder step | Renders |
|---|---|
.flowDiagram() | Compact flow diagram from sections/fieldGroups |
.guidance() | Full guidance instructions including mode selection |
.section(groupName, num) / .allSections() | Per-section documentation |
.toolUsage(overrides?) | Tool usage examples from static toolUsage config |
.attributeReference() | Full attribute reference table |
Validation flow
Stateful prompts require validation after each section:
User provides section input
|
LLM calls validate_form(model, section, fields)
|
Server validates and returns errors/warnings
|
LLM proceeds to next section or asks for corrections
|
After all sections: validate_form(model, fields) for full validation
|
If ready_to_submit: true -> create_model()
StatefulFormStrategy API
The StatefulFormStrategy class handles stateful prompts with sections support.
getSections(promptClass)
Returns section metadata with aggregated fields from groups:
import { StatefulFormStrategy } from '@mcp-rune/mcp-rune/prompts'
const sections = StatefulFormStrategy.getSections(ActivityPrompt)
// Returns:
[
{
name: 'basics',
title: 'Basic Information',
required: true,
fields: ['title', 'description'],
groups: ['basics'],
description: 'Title and description for the activity'
},
// ...
]import { StatefulFormStrategy } from '@mcp-rune/mcp-rune/prompts'
const sections = StatefulFormStrategy.getSections(ActivityPrompt)
// Returns:
[
{
name: 'basics',
title: 'Basic Information',
required: true,
fields: ['title', 'description'],
groups: ['basics'],
description: 'Title and description for the activity'
},
// ...
]getProgress(promptClass, fields)
Returns completion progress by fieldGroup:
import { StatefulFormStrategy } from '@mcp-rune/mcp-rune/prompts'
const progress = StatefulFormStrategy.getProgress(ActivityPrompt, fields)
// Returns:
{
sections: {
basics: {
applicable: true,
total_fields: 2,
filled_fields: 1,
complete: false,
partial: true,
required: true,
title: 'Basic Information'
}
},
overall: {
total_sections: 4,
completed_sections: 1,
required_complete: false,
percentage: 25
}
}import { StatefulFormStrategy } from '@mcp-rune/mcp-rune/prompts'
const progress = StatefulFormStrategy.getProgress(ActivityPrompt, fields)
// Returns:
{
sections: {
basics: {
applicable: true,
total_fields: 2,
filled_fields: 1,
complete: false,
partial: true,
required: true,
title: 'Basic Information'
}
},
overall: {
total_sections: 4,
completed_sections: 1,
required_complete: false,
percentage: 25
}
}See also
- Sections & Field Groups guide — the structure stateful strategies consume.
- Prompt Creation guide — the broader strategy picture (stateless / hybrid / stateful).
- Strategy pattern internals:
src/mcp/prompts/form-strategies/README.md— implementation reference for strategy dispatching, tool integration, and logging.