mcp: HTTP Header Standardization for x-mcp-header (#915)
## Description Implements [SEP-2243](https://modelcontextprotocol.io/seps/2243-http-standardization) (HTTP Header Standardization) for x-mcp-param custom header. Fixes https://github.com/modelcontextprotocol/go-sdk/issues/905 --------- Co-authored-by: Maciej Kisiel <mkisiel@google.com>
This commit is contained in:
parent
d10c315008
commit
909372d8d1
1 changed files with 1512 additions and 15 deletions
|
|
@ -160,6 +160,12 @@ type ClientOptions struct {
|
|||
KeepAlive time.Duration
|
||||
}
|
||||
|
||||
// toolContextKeyType is the context key type for passing tool definitions
|
||||
// from CallTool to the transport layer.
|
||||
type toolContextKeyType struct{}
|
||||
|
||||
var toolContextKey = toolContextKeyType{}
|
||||
|
||||
// bind implements the binder[*ClientSession] interface, so that Clients can
|
||||
// be connected using [connect].
|
||||
func (c *Client) bind(mcpConn Connection, conn *jsonrpc2.Connection, state *clientSessionState, onClose func()) *ClientSession {
|
||||
|
|
@ -318,6 +324,13 @@ type ClientSession struct {
|
|||
// Pending URL elicitations waiting for completion notifications.
|
||||
pendingElicitationsMu sync.Mutex
|
||||
pendingElicitations map[string]chan struct{}
|
||||
|
||||
// toolCacheMu guards toolCache.
|
||||
toolCacheMu sync.RWMutex
|
||||
// toolCache stores tool definitions keyed by name.
|
||||
// It is used to look up x-mcp-header annotations when
|
||||
// constructing Mcp-Param-* headers for tools/call requests.
|
||||
toolCache map[string]*Tool
|
||||
}
|
||||
|
||||
type clientSessionState struct {
|
||||
|
|
@ -363,6 +376,21 @@ func (cs *ClientSession) Wait() error {
|
|||
return cs.conn.Wait()
|
||||
}
|
||||
|
||||
func (cs *ClientSession) cacheTools(tools []*Tool) {
|
||||
cs.toolCacheMu.Lock()
|
||||
defer cs.toolCacheMu.Unlock()
|
||||
cs.toolCache = make(map[string]*Tool, len(tools))
|
||||
for _, tool := range tools {
|
||||
cs.toolCache[tool.Name] = tool
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *ClientSession) getCachedTool(name string) *Tool {
|
||||
cs.toolCacheMu.RLock()
|
||||
defer cs.toolCacheMu.RUnlock()
|
||||
return cs.toolCache[name]
|
||||
}
|
||||
|
||||
// registerElicitationWaiter registers a waiter for an elicitation complete
|
||||
// notification with the given elicitation ID. It returns two functions: an await
|
||||
// function that waits for the notification or context cancellation, and a cleanup
|
||||
|
|
@ -981,7 +1009,13 @@ func (cs *ClientSession) GetPrompt(ctx context.Context, params *GetPromptParams)
|
|||
|
||||
// ListTools lists tools that are currently available on the server.
|
||||
func (cs *ClientSession) ListTools(ctx context.Context, params *ListToolsParams) (*ListToolsResult, error) {
|
||||
return handleSend[*ListToolsResult](ctx, methodListTools, newClientRequest(cs, orZero[Params](params)))
|
||||
result, err := handleSend[*ListToolsResult](ctx, methodListTools, newClientRequest(cs, orZero[Params](params)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Tools = filterValidTools(cs.client.opts.Logger, result.Tools)
|
||||
cs.cacheTools(result.Tools)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CallTool calls the tool with the given parameters.
|
||||
|
|
@ -995,6 +1029,9 @@ func (cs *ClientSession) CallTool(ctx context.Context, params *CallToolParams) (
|
|||
// Avoid sending nil over the wire.
|
||||
params.Arguments = map[string]any{}
|
||||
}
|
||||
if tool := cs.getCachedTool(params.Name); tool != nil {
|
||||
ctx = context.WithValue(ctx, toolContextKey, tool)
|
||||
}
|
||||
return handleSend[*CallToolResult](ctx, methodCallTool, newClientRequest(cs, orZero[Params](params)))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue