Protocol and Sessions¶
mcp-guide uses FastMCP 4 as its protocol boundary. It supports the modern MCP
protocol revision 2026-07-28 and retained handshake-era clients negotiated by
FastMCP. There is no separate wire protocol named “MCP v2”.
The retained-client bridge has no scheduled end date. It remains available while it is required by supported clients; a future removal would be announced independently.
Response instructions¶
Guide fixes an interaction's protocol type when its Session is established. This keeps response handling consistent for the life of that interaction, including after a project switch. A Session cannot change protocol type later.
Retained clients continue to receive task-generated guidance in the existing
additional_agent_instructions field of the structured Guide result. MCP
2026-07-28 clients can negotiate the
io.uniquode/mcp-guide-instructions extension. Guide then sends one queued
instruction as a separate notifications/instructions/dispatch notification,
containing the instruction text and, when relevant, an opaque tracking identifier.
The requested tool, prompt, or resource response does not include that instruction
in its structured content or mcp-guide metadata.
A modern client that does not negotiate this extension continues to receive the
single queued instruction in response metadata at
_meta["mcp-guide"]["instructions"]; that field is omitted from its structured
Guide result. When no instruction is queued, Guide emits neither the mcp-guide
metadata namespace nor its instructions key.
Notifications are delivery, not acknowledgement or authority. The client decides whether and how to surface them, and existing Guide acknowledgement requirements remain in effect where an instruction is tracked. On a sessionless Streamable HTTP connection, Guide can send a notification only through the owning in-flight request stream. If no suitable stream is active or the send fails, Guide retains the instruction for that session's next request; it never redirects it to another session.
Document cache metadata¶
When a document resolves to a cache policy, get_content, category-content
retrieval, and non-command guide:// resources include it in response metadata as
_meta["mcp-guide"]["cache"], with ttl_ms and scope fields. This is Guide's
explicit document-cache contract; it does not restore the former undocumented
io.modelcontextprotocol/cache-* metadata keys. Commands, prompts, and other tools
currently do not emit cache metadata, though a future operation may explicitly opt
in with its own resolved policy.
For MIME-formatted multi-document content, each MIME part also carries a standard
Cache-Control header based on that file's own policy. This remains useful when the
overall response is no-cache because another contributing document is undeclared.
Client migration¶
Existing retained clients continue to use their FastMCP connection identity. They do
not need to replay an identifier returned by Guide for tools and prompts. Native
content resource reads require the explicit session_id query parameter on both
retained and modern clients.
Modern 2026-07-28 clients bind an interaction with:
set_project({"path": "/absolute/client/path/to/project"})
The successful result includes session_id. The client must provide that value as the
session_id argument on later project-bound tool calls. It is an opaque value: pass it
through unchanged and do not construct, alter, or log it.
Clients that read guide:// resource templates directly must provide the same value
as the URI query parameter, for example:
guide://_status?session_id=<session_id>
guide://guidelines?session_id=<session_id>
guide://docs/readme?session_id=<session_id>
For native content resources, omitting session_id returns Guide's no_project
result with project-binding guidance; it does not inherit a legacy connection's
project binding. The advertised {?session_id} notation describes the URI query
syntax, not permission to retrieve content without a bound session.
The read_resource tool accepts session_id as its normal tool argument. This is
needed because rendered Guide resources can depend on the interaction's selected
project, agent details, and feature configuration.
Project and configuration identity¶
set_project is an agent-facing operation, not a project-name selector. Its required
path is the absolute path on the agent's filesystem. Guide derives the displayed
project name and a path hash from that root, then binds the interaction once. A later
set_project call, including one with the same path, is rejected. Use
switch_project({"path": "..."}) to rebind the root in the retained interaction.
Initial binding never accepts a relative path, even after filesystem verification.
Permitted user/environment expansion must produce an absolute path. Absolute paths
containing .. are normalised before binding; server CWD is never used to make
relative initial input absolute.
switch_project accepts exactly one selection. switch_project({"name": "..."})
changes the active Guide configuration within the bound root. Alternatively,
switch_project({"path": "..."}) rebinds the project root in the retained
interaction and selects the configuration named by the normalised path basename.
Use an absolute client path unless stdio filesystem sharing has been verified.
After verification, the path may also use ~, ~user, $VAR or ${VAR}, or
be relative to the current bound root. Do not provide both name and path.
Client filesystem verification¶
The first stdio binding requires an absolute client root. Guide creates a
uniquely named .mcp-guide-fs-probe-<random-id> file there and queues a one-time
instruction asking the agent to read it and return its exact contents through
send_file_content. The agent must not create or modify the probe. If it cannot
read the file, it should report unreadable as instructed.
The response timeout is 60 seconds, starting when the instruction is attached to an outgoing response, not when queued. This notification does not confirm client receipt. A matching response enables shorthand process-wide until the server restarts. Failure, timeout or disposal of the owning Session leaves it disabled. Guide removes the probe and its instruction/subscriptions on completion; there is no automatic retry. Until verification succeeds, supply absolute paths.
Verified sharing permits server-side user, environment and symlink resolution.
Guide assumes the client and server use the same user/home; ~user and variables
use the server's accounts and environment. Matching access is sufficient; matching
every mount or environment variable is not independently verified. Relative root
switches use the current bound root, never the server working directory.
Stdio alone does not prove sharing: a Docker stdio deployment without the same project mount at the same absolute path cannot use shorthand. HTTP and HTTPS always disable shorthand and never send a probe, including localhost HTTP and container or remote servers. Their roots are normalised lexically without server symlink resolution. Resolve shorthand on the client and submit an absolute path.
Server-owned configuration paths and docroot retain ordinary server-side expansion.
The optional inherited-PWD bootstrap additionally requires already verified stdio
sharing, so it cannot replace the first explicit binding after server startup.
A different selection creates a fresh internal Session under the same public
session_id; it does not reconnect the client. Selecting the current name and
root is a no-op unless a previous Session is still expiring.
Configuration identity is strict: a stored configuration is usable only when both its
<project-name>-<hash> key and stored hash match the bound root. Hashless, malformed,
and mismatched entries are ignored by normal project selection and listing. Guide does
not automatically migrate them.
To copy an existing project configuration, bind the intended current project and run
clone_project({"from_project": "old-name"}). With an unhashed source name, clone
lookup uses the first strict configuration whose project name is old-name in
configuration order. To select a particular configuration, provide its exact
old-name-<hash> key. Only the current bound project's valid hashed configuration is
updated.
clone_project no longer accepts a target project. Its destination is always the
active configuration of the bound interaction.
Interaction state and expiry¶
GuideRuntime keeps mutable interaction state—including instruction queues, rendering caches, task state, and active configuration—isolated by session owner. Different clients and subagents receive separate Sessions even when they select the same root; they can share durable project configuration but not transient task state.
Sessions progress from unbound → bound → expiring, then are disposed of. Unbound Sessions are request-local until initial binding succeeds. A project switch publishes a fresh bound Session and lets the outgoing Session finish work already in progress, including configuration saves to its original project. Its original binding never changes. New requests, including delayed client replies, use the current Session; no additional client token is needed.
The outgoing Session receives no new scheduling or configuration notifications. Once its work finishes, Guide disposes of its tasks, listeners, queues and caches. Disposal runs independently of the successful switch response. Cleanup failures are logged separately and keep the outgoing Session registered as expiring. While that Session is expiring, another switch is rejected without changing the current project, including an otherwise unchanged selection. Try again after the outstanding work has completed; switches are not queued automatically.
Guide logs the negotiated protocol revision and available client name/version once at interaction establishment. An internal Session replacement does not produce another establishment log. These logs exclude session IDs and client paths. Modern request-local work without a public interaction ID does not emit an establishment log.
Inactive runtime Sessions expire after one hour, checked at request boundaries. After expiry, begin a new interaction and bind the project again. A server restart also clears transient interaction state; durable configuration remains in the shared configuration file. Idle disposal uses the same expiring lifecycle: it cannot create a second expiring Session for an ID, and failed disposal prevents rebinding that ID.
Operational downgrade and reconnect¶
This change does not rewrite the configuration-file format. If an operator needs to replace a running build with an earlier one, restart the server using that build and have clients reconnect; they must bind a project again because interaction state is transient. No configuration rollback or migration is required. An older build may still interpret entries that the strict current build ignores, so configuration should be reviewed rather than modified merely to support a temporary downgrade.
HTTP and HTTPS¶
HTTP and HTTPS use FastMCP's Streamable HTTP application at /mcp by default. A path
prefix is followed by /mcp, such as /api/mcp. Install the HTTP optional dependency
before serving these transports:
uv sync --extra http
Use HTTPS for network traffic that requires transport confidentiality or integrity. The HTTP endpoint negotiates the MCP protocol revision through FastMCP; do not add custom cookies, headers, or a separate Guide session token.
For installation commands and TLS configuration, see Installation.