@@ -18,6 +18,7 @@ import (
1818 "errors"
1919 "fmt"
2020 "reflect"
21+ "slices"
2122 "strings"
2223
2324 "github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
@@ -35,6 +36,9 @@ const (
3536 GlobalToolRegistryKey = "GlobalToolRegistry"
3637)
3738
39+ // SupportedMCPVersions contains all supported MCP protocol versions
40+ var SupportedMCPVersions = []string {"2024-11-05" , "2025-03-26" , "2025-06-18" }
41+
3842type HttpContext wrapper.HttpContext
3943
4044type Context struct {
@@ -49,11 +53,12 @@ var globalContext Context
4953
5054// ToolInfo stores information about a tool for the global registry.
5155type ToolInfo struct {
52- Name string
53- Description string
54- InputSchema map [string ]any
55- ServerName string // Original server name
56- Tool Tool // The actual tool instance for cloning
56+ Name string
57+ Description string
58+ InputSchema map [string ]any
59+ OutputSchema map [string ]any // New field for MCP Protocol Version 2025-06-18
60+ ServerName string // Original server name
61+ Tool Tool // The actual tool instance for cloning
5762}
5863
5964// GlobalToolRegistry holds all tools from all servers.
@@ -72,13 +77,18 @@ func (r *GlobalToolRegistry) RegisterTool(serverName string, toolName string, to
7277 if _ , ok := r .serverTools [serverName ]; ! ok {
7378 r .serverTools [serverName ] = make (map [string ]ToolInfo )
7479 }
75- r. serverTools [ serverName ][ toolName ] = ToolInfo {
80+ toolInfo : = ToolInfo {
7681 Name : toolName ,
7782 Description : tool .Description (),
7883 InputSchema : tool .InputSchema (),
7984 ServerName : serverName ,
8085 Tool : tool ,
8186 }
87+ // Check if tool implements OutputSchema (MCP Protocol Version 2025-06-18)
88+ if toolWithSchema , ok := tool .(ToolWithOutputSchema ); ok {
89+ toolInfo .OutputSchema = toolWithSchema .OutputSchema ()
90+ }
91+ r.serverTools [serverName ][toolName ] = toolInfo
8292 log .Debugf ("Registered tool %s/%s" , serverName , toolName )
8393}
8494
@@ -122,6 +132,14 @@ type Tool interface {
122132 InputSchema () map [string ]any
123133}
124134
135+ // ToolWithOutputSchema is an optional interface for tools that support output schema
136+ // (MCP Protocol Version 2025-06-18). Tools can optionally implement this interface
137+ // to provide output schema information.
138+ type ToolWithOutputSchema interface {
139+ Tool
140+ OutputSchema () map [string ]any
141+ }
142+
125143// ToolSetConfig defines the configuration for a toolset.
126144type ToolSetConfig struct {
127145 Name string `json:"name"`
@@ -276,7 +294,15 @@ func parseConfigCore(configJson gjson.Result, config *McpServerConfig, opts *Con
276294 version := params .Get ("protocolVersion" ).String ()
277295 if version == "" {
278296 utils .OnMCPResponseError (ctx , errors .New ("Unsupported protocol version" ), utils .ErrInvalidParams , fmt .Sprintf ("mcp:%s:initialize:error" , currentServerNameForHandlers ))
297+ return nil
279298 }
299+
300+ // Support for multiple protocol versions including 2025-06-18
301+ if ! slices .Contains (SupportedMCPVersions , version ) {
302+ utils .OnMCPResponseError (ctx , fmt .Errorf ("Unsupported protocol version: %s" , version ), utils .ErrInvalidParams , fmt .Sprintf ("mcp:%s:initialize:error" , currentServerNameForHandlers ))
303+ return nil
304+ }
305+
280306 utils .OnMCPResponseSuccess (ctx , map [string ]any {
281307 "protocolVersion" : version ,
282308 "capabilities" : map [string ]any {
@@ -318,11 +344,18 @@ func parseConfigCore(configJson gjson.Result, config *McpServerConfig, opts *Con
318344 continue
319345 }
320346 }
321- listedTools = append ( listedTools , map [string ]any {
347+ toolDef := map [string ]any {
322348 "name" : toolFullName ,
323349 "description" : tool .Description (),
324350 "inputSchema" : tool .InputSchema (),
325- })
351+ }
352+ // Add outputSchema if tool implements ToolWithOutputSchema (MCP Protocol Version 2025-06-18)
353+ if toolWithSchema , ok := tool .(ToolWithOutputSchema ); ok {
354+ if outputSchema := toolWithSchema .OutputSchema (); outputSchema != nil && len (outputSchema ) > 0 {
355+ toolDef ["outputSchema" ] = outputSchema
356+ }
357+ }
358+ listedTools = append (listedTools , toolDef )
326359 }
327360 utils .OnMCPResponseSuccess (ctx , map [string ]any {
328361 "tools" : listedTools ,
@@ -471,6 +504,22 @@ func onHttpRequestHeaders(ctx wrapper.HttpContext, config McpServerConfig) types
471504 ctx .SetRequestBodyBufferLimit (DefaultMaxBodyBytes )
472505 ctx .SetResponseBodyBufferLimit (DefaultMaxBodyBytes )
473506
507+ // Parse MCP-Protocol-Version header and store in context
508+ // This allows clients to specify the MCP protocol version via HTTP header
509+ // instead of only through the JSON-RPC initialize method
510+ protocolVersion , _ := proxywasm .GetHttpRequestHeader ("MCP-Protocol-Version" )
511+ if protocolVersion != "" {
512+ // Validate the protocol version against supported versions
513+ if slices .Contains (SupportedMCPVersions , protocolVersion ) {
514+ log .Debugf ("MCP Protocol Version set from header: %s" , protocolVersion )
515+ } else {
516+ log .Warnf ("Unsupported MCP Protocol Version in header: %s" , protocolVersion )
517+ }
518+
519+ // Remove the header from the request to prevent it from being forwarded
520+ proxywasm .RemoveHttpRequestHeader ("MCP-Protocol-Version" )
521+ }
522+
474523 if ctx .Method () == "GET" {
475524 proxywasm .SendHttpResponseWithDetail (405 , "not_support_sse_on_this_endpoint" , nil , nil , - 1 )
476525 return types .HeaderStopAllIterationAndWatermark
0 commit comments