Research guide · MCP · Go SDK · middleware · 14 September 2026
MCP Go SDK nil pointer on tools/list: fix missing params middleware panic
If a Go MCP server crashes inside receiving middleware on an otherwise ordinary tools/list, prompts/list, resources/list or notifications/initialized message, check how the middleware tests req.GetParams(). A fresh upstream report shows a Go typed-nil trap: a valid request can omit the JSON-RPC params member, while GetParams() still appears non-nil at the interface boundary and then panics when middleware calls GetMeta().
Published 14 September 2026 · upstream status checked 14 September 2026
tools/list
Common reported trigger
GetParams() != nil
Unsafe presence test in affected versions
typed nil
Go interface boundary causing the trap
PR #1269 open
Proposed upstream HasParams fix
The failure boundary
A non-nil interface can still contain a nil params pointer
JSON-RPC allows params to be omitted, and the MCP Go SDK accepts missing params for several methods. The upstream issue opened 13 September 2026 demonstrates a complete tools/list request with no params member.
In the reported path, the SDK leaves the typed params pointer at its zero value. Request.GetParams() boxes that nil pointer into an interface. In Go, an interface that contains a typed nil pointer is itself non-nil, so req.GetParams() != nil reports true. Calling the promoted GetMeta() method then dereferences the nil pointer and can crash the process.
That makes this a middleware/API-shape problem, not evidence that the client sent malformed JSON-RPC. Adding params: may make one reproduction disappear, but forcing every client to do that would paper over the server-side boundary rather than repair it.
Error map
Match the stack before changing protocol behavior
| Observed symptom | What to inspect next |
|---|---|
panic: runtime error: invalid memory address or nil pointer dereference | Check whether a generic receiving middleware dereferences req.GetParams() on a params-optional method. |
(*ListToolsParams).GetMeta | Strong match for the currently reported typed-nil path on tools/list. |
Panic only when logging, auth or tracing middleware is enabled | Inspect middleware that reads _meta, protocol version, client information or capabilities before the real handler runs. |
Request succeeds after adding params: {} | That is a useful reproduction clue, not a protocol requirement; valid callers may still omit params. |
Diagnosis
Seven checks before blaming the MCP client
- 1. Capture the top useful stack frame. Look for
GetMetaon a params type such as*ListToolsParams, not just the generic nil-pointer headline. - 2. Disable only the suspect middleware in a controlled test. If the request succeeds without logging/auth/tracing middleware, inspect that layer before changing tools or transport code.
- 3. Record the exact method. The fresh report specifically reproduces params-optional list methods and
notifications/initialized. Do not generalize a fix to every request shape without evidence. - 4. Inspect the raw JSON-RPC shape safely. Confirm whether
paramsis actually absent rather than empty. Never log credentials, authorization headers or private tool arguments to prove the point. - 5. Find every generic
GetParams()presence check. A check against plainnilis the dangerous pattern described upstream when the interface contains a typed nil pointer. - 6. Check the deployed Go SDK version and upstream status. The proposed
mcp.HasParamsAPI is in open PR #1269 as of this page update; do not compile production guidance against an unmerged symbol by assumption. - 7. Re-test both missing and present params. Your mitigation must preserve requests with legitimate params while allowing params-optional messages to pass without a middleware panic.
Version-scoped mitigation
Use a typed-nil-safe predicate until the released SDK owns the check
If your pinned SDK does not yet expose a safe presence check, keep the compatibility logic local and easy to delete. The open upstream PR proposes HasParams using reflection so middleware never has to call a method on the potentially nil params value first.
func hasParams(req mcp.Request) bool {
params := req.GetParams()
if params == nil { return false }
v := reflect.ValueOf(params)
return v.Kind() != reflect.Pointer || !v.IsNil()
}
if hasParams(req) {
meta := req.GetParams().GetMeta()
_ = meta
}
This mirrors the shape proposed upstream; it is not a substitute for tracking the released SDK. Pin the dependency, add a regression test with a params-less tools/list, and remove the local helper when a reviewed upstream fix lands in the version you deploy.
What not to do
Do not turn a middleware panic into a protocol incompatibility
Reject every request without params
The reported methods are allowed to omit params. Rejecting them converts a server-side middleware defect into avoidable client incompatibility.
Patch clients to always send params: {}
Useful as a reproduction control, not a durable fix. You do not control every legitimate MCP client that may omit the optional member.
Import an unmerged fork into production by default
The proposed HasParams patch is useful evidence, but release status matters. Prefer a small local guard plus a pinned dependency until upstream ships a reviewed fix.
Sources
Primary evidence
- MCP Go SDK issue #1261 — open 13 September 2026 report reproducing the typed-nil
GetParamspanic on params-optional messages. - MCP Go SDK pull request #1269 — open proposal adding
HasParams, docs and regression tests; not treated here as a released API. - JSON-RPC 2.0 specification — the request
paramsmember is optional.
Continue the implementation path
Migrate safely to MCP 2026-07-28
Keep version-envelope and request-lifecycle migration work separate from this Go middleware failure.
Diagnose Streamable HTTP response failures
If the middleware path is healthy but the connection ends mid-response, move to SSE and server timeout diagnosis.
Verify an MCP server before connecting
Separate endpoint, transport, authentication and tool-surface evidence before trusting a discovered server.
Inspect zFinia machine APIs
Machine-readable services for agents and operators working across the machine economy.