Skip to content

Rough edges: API decisions to reconsider for v2

This file collects a list of API oversights or rough edges that we've uncovered post v1.0.0, along with their current workarounds. These issues can't be addressed without breaking backward compatibility, but we'll revisit them for v2.

  • EventStore.Open is unnecessary. This was an artifact of an earlier version of the SDK where event persistence and delivery were combined.

Workaround: Open may be implemented as a no-op.

  • Event need not have been exported: it's an implementation detail of the SSE and streamable transports. Also the 'Name' field is a misnomer: it should be 'event'.

  • Enforcing valid tool names: with SEP-986 landing after the SDK was at v1, we missed an opportunity to panic on invalid tool names. Instead, we have to simply produce an error log. In v2, we should panic.

  • Inconsistent naming.

  • ResourceUpdatedNotificationsParams should probably have just been ResourceUpdatedParams, as we don't include the word 'notification' in other notification param types.
  • Similarly, ProgressNotificationParams should probably have been ProgressParams.

  • AudioContent.MarshalJSON should have had a pointer receiver, to be consistent with other content types.

  • ClientCapabilities.Roots should have been a distinguished struct pointer (see #607).

Workaround: use ClientCapabilities.RootsV2, which aligns with the semantics of other capability fields.

  • Default capabilities should have been empty. Instead, servers default to advertising logging, and clients default to advertising roots with listChanged: true. This is confusing because a nil Capabilities field does not mean "no capabilities".

Workaround: to advertise no capabilities, set ServerOptions.Capabilities or ClientOptions.Capabilities to an empty &ServerCapabilities{} or &ClientCapabilities{} respectively.

  • CreateMessageResult.Content is singular Content, but the 2025-11-25 spec allows content to be a single block or an array (for parallel tool calls). We added CreateMessageResultWithTools (with Content []Content) as a workaround, matching the TypeScript SDK's approach. In v2, CreateMessageResult should use []Content directly. Similarly, SamplingMessage.Content should become []Content to support sending multiple tool_result blocks in a single user message.

  • We didn't actually need CallToolParams and CallToolParamsRaw, since even when we're unmarshalling into a custom Go type (for the mcp.AddTool convenience wrapper) we need to first unmarshal into a map[string]any in order to do server-side validation of required fields. CallToolParams could have just had a map[string]any.