Summary
Why: There is a small but critical amount of additional context that would
benefit every MCP server we front, not just any one server (e.g. BigQuery).
Today we have no way to inject it. We want to append a configured custom
instruction string on top of each server's default instructions, so the
server's own guidance still comes through and our context is added on top.
Append, not override — the default server instructions (if any) must be preserved.
What: Add support for appending custom instructions to the instructions field
ToolHive serves to MCP clients on the remote proxy (streamable HTTP), for both
the legacy (2025-11-25 and earlier) and modern (2026-07-28 stateless) protocol
revisions.
Background: where instructions lives per era
Today nothing in ToolHive touches instructions — the field is proxied through
untouched (.Instructions appears nowhere in pkg//cmd/). The field survives the
stateless spec migration but changes delivery vehicle:
| Era |
Message carrying instructions |
| Legacy (≤ 2025-11-25) |
initialize → InitializeResult.instructions |
| Modern (2026-07-28) |
server/discover → DiscoverResult.instructions |
Same field name, same semantics (optional natural-language LLM guidance). The append
operation is conceptually identical in both eras; only the intercepted message differs.
Scope
Remote proxy (streamable HTTP):
- Legacy: intercept the
initialize JSON result and append to .instructions.
Natural seam is the ResponseProcessor interface via ModifyResponse
(pkg/transport/proxy/transparent/response_processor.go); the streamable path
currently uses a NoOpResponseProcessor that must be replaced with a real one.
- Modern: intercept the
server/discover result and append to .instructions.
- Append is literal here — single upstream server, so there is a real "default"
to append to.
Acceptance criteria
Dependencies / sequencing
This builds on the protocol-currency work:
Legacy side (initialize) has no hard blocker and could start at any time — the
instructions field and the ResponseProcessor/ModifyResponse seam already exist on
main, and the field is identical across mcp-go and go-sdk, so it survives the migration.
There's nonetheless benefit to waiting until #5754 lands and #5755's design is set:
The modern side only makes sense once server/discover and stateless traffic are handled
(#5754/#5755) and should be folded into those designs rather than built standalone.
Note: the config surface (how the custom string is specified and wired to the processor)
is currently unspecified and must be defined before implementation, whenever it starts.
Summary
Why: There is a small but critical amount of additional context that would
benefit every MCP server we front, not just any one server (e.g. BigQuery).
Today we have no way to inject it. We want to append a configured custom
instruction string on top of each server's default
instructions, so theserver's own guidance still comes through and our context is added on top.
Append, not override — the default server instructions (if any) must be preserved.
What: Add support for appending custom instructions to the
instructionsfieldToolHive serves to MCP clients on the remote proxy (streamable HTTP), for both
the legacy (
2025-11-25and earlier) and modern (2026-07-28stateless) protocolrevisions.
Background: where
instructionslives per eraToday nothing in ToolHive touches
instructions— the field is proxied throughuntouched (
.Instructionsappears nowhere inpkg//cmd/). The field survives thestateless spec migration but changes delivery vehicle:
instructionsinitialize→InitializeResult.instructionsserver/discover→DiscoverResult.instructionsSame field name, same semantics (optional natural-language LLM guidance). The append
operation is conceptually identical in both eras; only the intercepted message differs.
Scope
Remote proxy (streamable HTTP):
initializeJSON result and append to.instructions.Natural seam is the
ResponseProcessorinterface viaModifyResponse(
pkg/transport/proxy/transparent/response_processor.go); the streamable pathcurrently uses a
NoOpResponseProcessorthat must be replaced with a real one.server/discoverresult and append to.instructions.to append to.
Acceptance criteria
instructionsserved by the remoteproxy (streamable HTTP) for a legacy backend, preserving the backend's default.
server/discover.Dependencies / sequencing
This builds on the protocol-currency work:
be co-designed here
Legacy side (
initialize) has no hard blocker and could start at any time — theinstructionsfield and theResponseProcessor/ModifyResponseseam already exist onmain, and the field is identical across mcp-go and go-sdk, so it survives the migration.There's nonetheless benefit to waiting until #5754 lands and #5755's design is set:
feature that only covers one era for months until the modern half catches up.
Design stateless MCP (2026-07-28) support in the transport proxies #5755 restructures the exact proxy code the legacy path lives near (initialize-sniffing,
session logic), so building against it prematurely risks churn.
The modern side only makes sense once
server/discoverand stateless traffic are handled(#5754/#5755) and should be folded into those designs rather than built standalone.
Note: the config surface (how the custom string is specified and wired to the processor)
is currently unspecified and must be defined before implementation, whenever it starts.