MCP readonly state can desynchronize from generated instructions due to runtime mutation in Start()
Problem
The MCP server currently allows the readonly state to be configured in two different places:
- During construction using
WithReadonly(...)
- Later during runtime in
Start(ctx, writeEnabled bool)
During New(), the server generates instructions/tool descriptions using the initial readonly value:
s.instructions = buildInstructions(s.readonly)
However, Start() later mutates the readonly state again:
s.readonly.Store(!writeEnabled)
This can cause the generated instructions and the effective runtime enforcement state to drift apart.
Why this matters
The MCP instructions act as part of the AI agent contract. If the instructions are generated assuming readonly mode, but the runtime state later becomes writeable, the agent receives stale or incorrect capability information.
This creates a lifecycle consistency issue where:
- instructions may describe readonly behavior,
- while the server may actually allow mutating operations.
Suggested direction
A cleaner approach may be to make readonly immutable after construction and remove runtime readonly mutation from Start() entirely.
That would:
- establish a single source of truth,
- prevent instruction/enforcement desynchronization,
- simplify lifecycle reasoning,
- and make invalid states structurally impossible.
High-level idea:
// current
Start(ctx context.Context, writeEnabled bool)
// proposed
Start(ctx context.Context)
with readonly configuration handled only during server construction.
Additional notes
- This appears related to MCP lifecycle consistency rather than a UI-only issue.
- The change should not require additional runtime complexity or synchronization.
- Invariant-focused regression tests around readonly behavior and exposed tool capabilities would help prevent future desynchronization issues.
I’d be happy to work on a fix and accompanying tests if this direction makes sense.
MCP readonly state can desynchronize from generated instructions due to runtime mutation in
Start()Problem
The MCP server currently allows the readonly state to be configured in two different places:
WithReadonly(...)Start(ctx, writeEnabled bool)During
New(), the server generates instructions/tool descriptions using the initial readonly value:However,
Start()later mutates the readonly state again:This can cause the generated instructions and the effective runtime enforcement state to drift apart.
Why this matters
The MCP instructions act as part of the AI agent contract. If the instructions are generated assuming readonly mode, but the runtime state later becomes writeable, the agent receives stale or incorrect capability information.
This creates a lifecycle consistency issue where:
Suggested direction
A cleaner approach may be to make readonly immutable after construction and remove runtime readonly mutation from
Start()entirely.That would:
High-level idea:
with readonly configuration handled only during server construction.
Additional notes
I’d be happy to work on a fix and accompanying tests if this direction makes sense.