Skip to content

Commit 2fb3775

Browse files
committed
feat: consolidate SEP-2575 metadata injection into ClientSession methods
1 parent ad296c3 commit 2fb3775

2 files changed

Lines changed: 59 additions & 54 deletions

File tree

mcp/client.go

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,27 @@ func (cs *ClientSession) usesNewProtocol() bool {
430430
return res != nil && res.ProtocolVersion >= protocolVersion20260630
431431
}
432432

433+
// injectRequestMeta populates the SEP-2575 per-request `_meta` triple
434+
// (protocolVersion, clientInfo, clientCapabilities) on the given outgoing
435+
// request params. Keys already present in params.Meta are not overwritten.
436+
func (cs *ClientSession) injectRequestMeta(params Params) {
437+
res := cs.state.InitializeResult
438+
m := params.GetMeta()
439+
if m == nil {
440+
m = map[string]any{}
441+
}
442+
if _, ok := m[MetaKeyProtocolVersion]; !ok {
443+
m[MetaKeyProtocolVersion] = res.ProtocolVersion
444+
}
445+
if _, ok := m[MetaKeyClientInfo]; !ok {
446+
m[MetaKeyClientInfo] = cs.client.impl
447+
}
448+
if _, ok := m[MetaKeyClientCapabilities]; !ok {
449+
m[MetaKeyClientCapabilities] = cs.client.capabilities(res.ProtocolVersion)
450+
}
451+
params.SetMeta(m)
452+
}
453+
433454
func (cs *ClientSession) ID() string {
434455
if c, ok := cs.mcpConn.(hasSessionID); ok {
435456
return c.SessionID()
@@ -1090,24 +1111,33 @@ func (cs *ClientSession) Ping(ctx context.Context, params *PingParams) error {
10901111

10911112
// ListPrompts lists prompts that are currently available on the server.
10921113
func (cs *ClientSession) ListPrompts(ctx context.Context, params *ListPromptsParams) (*ListPromptsResult, error) {
1093-
if params == nil && cs.usesNewProtocol() {
1094-
params = &ListPromptsParams{}
1114+
if cs.usesNewProtocol() {
1115+
if params == nil {
1116+
params = &ListPromptsParams{}
1117+
}
1118+
cs.injectRequestMeta(params)
10951119
}
10961120
return handleSend[*ListPromptsResult](ctx, methodListPrompts, newClientRequest(cs, orZero[Params](params)))
10971121
}
10981122

10991123
// GetPrompt gets a prompt from the server.
11001124
func (cs *ClientSession) GetPrompt(ctx context.Context, params *GetPromptParams) (*GetPromptResult, error) {
1101-
if params == nil && cs.usesNewProtocol() {
1102-
params = &GetPromptParams{}
1125+
if cs.usesNewProtocol() {
1126+
if params == nil {
1127+
params = &GetPromptParams{}
1128+
}
1129+
cs.injectRequestMeta(params)
11031130
}
11041131
return handleSend[*GetPromptResult](ctx, methodGetPrompt, newClientRequest(cs, orZero[Params](params)))
11051132
}
11061133

11071134
// ListTools lists tools that are currently available on the server.
11081135
func (cs *ClientSession) ListTools(ctx context.Context, params *ListToolsParams) (*ListToolsResult, error) {
1109-
if params == nil && cs.usesNewProtocol() {
1110-
params = &ListToolsParams{}
1136+
if cs.usesNewProtocol() {
1137+
if params == nil {
1138+
params = &ListToolsParams{}
1139+
}
1140+
cs.injectRequestMeta(params)
11111141
}
11121142
result, err := handleSend[*ListToolsResult](ctx, methodListTools, newClientRequest(cs, orZero[Params](params)))
11131143
if err != nil {
@@ -1132,6 +1162,9 @@ func (cs *ClientSession) CallTool(ctx context.Context, params *CallToolParams) (
11321162
if tool := cs.getCachedTool(params.Name); tool != nil {
11331163
ctx = context.WithValue(ctx, toolContextKey, tool)
11341164
}
1165+
if cs.usesNewProtocol() {
1166+
cs.injectRequestMeta(params)
1167+
}
11351168
return handleSend[*CallToolResult](ctx, methodCallTool, newClientRequest(cs, orZero[Params](params)))
11361169
}
11371170

@@ -1142,31 +1175,43 @@ func (cs *ClientSession) SetLoggingLevel(ctx context.Context, params *SetLogging
11421175

11431176
// ListResources lists the resources that are currently available on the server.
11441177
func (cs *ClientSession) ListResources(ctx context.Context, params *ListResourcesParams) (*ListResourcesResult, error) {
1145-
if params == nil && cs.usesNewProtocol() {
1146-
params = &ListResourcesParams{}
1178+
if cs.usesNewProtocol() {
1179+
if params == nil {
1180+
params = &ListResourcesParams{}
1181+
}
1182+
cs.injectRequestMeta(params)
11471183
}
11481184
return handleSend[*ListResourcesResult](ctx, methodListResources, newClientRequest(cs, orZero[Params](params)))
11491185
}
11501186

11511187
// ListResourceTemplates lists the resource templates that are currently available on the server.
11521188
func (cs *ClientSession) ListResourceTemplates(ctx context.Context, params *ListResourceTemplatesParams) (*ListResourceTemplatesResult, error) {
1153-
if params == nil && cs.usesNewProtocol() {
1154-
params = &ListResourceTemplatesParams{}
1189+
if cs.usesNewProtocol() {
1190+
if params == nil {
1191+
params = &ListResourceTemplatesParams{}
1192+
}
1193+
cs.injectRequestMeta(params)
11551194
}
11561195
return handleSend[*ListResourceTemplatesResult](ctx, methodListResourceTemplates, newClientRequest(cs, orZero[Params](params)))
11571196
}
11581197

11591198
// ReadResource asks the server to read a resource and return its contents.
11601199
func (cs *ClientSession) ReadResource(ctx context.Context, params *ReadResourceParams) (*ReadResourceResult, error) {
1161-
if params == nil && cs.usesNewProtocol() {
1162-
params = &ReadResourceParams{}
1200+
if cs.usesNewProtocol() {
1201+
if params == nil {
1202+
params = &ReadResourceParams{}
1203+
}
1204+
cs.injectRequestMeta(params)
11631205
}
11641206
return handleSend[*ReadResourceResult](ctx, methodReadResource, newClientRequest(cs, orZero[Params](params)))
11651207
}
11661208

11671209
func (cs *ClientSession) Complete(ctx context.Context, params *CompleteParams) (*CompleteResult, error) {
1168-
if params == nil && cs.usesNewProtocol() {
1169-
params = &CompleteParams{}
1210+
if cs.usesNewProtocol() {
1211+
if params == nil {
1212+
params = &CompleteParams{}
1213+
}
1214+
cs.injectRequestMeta(params)
11701215
}
11711216
return handleSend[*CompleteResult](ctx, methodComplete, newClientRequest(cs, orZero[Params](params)))
11721217
}
@@ -1253,9 +1298,6 @@ func (c *Client) callElicitationCompleteHandler(ctx context.Context, req *Elicit
12531298
// This can be used if the client is performing a long-running task that was
12541299
// initiated by the server.
12551300
func (cs *ClientSession) NotifyProgress(ctx context.Context, params *ProgressNotificationParams) error {
1256-
if params == nil && cs.usesNewProtocol() {
1257-
params = &ProgressNotificationParams{}
1258-
}
12591301
return handleNotify(ctx, notificationProgress, newClientRequest(cs, orZero[Params](params)))
12601302
}
12611303

mcp/shared.go

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,6 @@ func defaultSendingMethodHandler(ctx context.Context, method string, req Request
105105
// capabilities, so any panic here is a bug.
106106
params = initParams.toV2()
107107
}
108-
// Populate the SEP-2575 per-request _meta triple on the outgoing request.
109-
// This is a no-op for old protocol versions and for requests where the
110-
// caller did not provide params.
111-
injectRequestMeta(req)
112108

113109
// Notifications don't have results.
114110
if strings.HasPrefix(method, "notifications/") {
@@ -210,39 +206,6 @@ func checkRequest(req *jsonrpc.Request, infos map[string]methodInfo) (methodInfo
210206
return info, nil
211207
}
212208

213-
// injectRequestMeta populates the SEP-2575 per-request `_meta` triple
214-
// (protocolVersion, clientInfo, clientCapabilities) on the outgoing request
215-
// when the negotiated protocol version is >= 2026-06-30. Keys already
216-
// present in params.Meta are not overwritten.
217-
func injectRequestMeta(req Request) {
218-
cs, ok := req.GetSession().(*ClientSession)
219-
if !ok {
220-
return
221-
}
222-
res := cs.state.InitializeResult
223-
if res == nil || res.ProtocolVersion < protocolVersion20260630 {
224-
return
225-
}
226-
params := req.GetParams()
227-
if params == nil || params.isNil() {
228-
return
229-
}
230-
m := params.GetMeta()
231-
if m == nil {
232-
m = map[string]any{}
233-
}
234-
if _, ok := m[MetaKeyProtocolVersion]; !ok {
235-
m[MetaKeyProtocolVersion] = res.ProtocolVersion
236-
}
237-
if _, ok := m[MetaKeyClientInfo]; !ok {
238-
m[MetaKeyClientInfo] = cs.client.impl
239-
}
240-
if _, ok := m[MetaKeyClientCapabilities]; !ok {
241-
m[MetaKeyClientCapabilities] = cs.client.capabilities(res.ProtocolVersion)
242-
}
243-
params.SetMeta(m)
244-
}
245-
246209
// methodInfo is information about sending and receiving a method.
247210
type methodInfo struct {
248211
// flags is a collection of flags controlling how the JSONRPC method is

0 commit comments

Comments
 (0)