Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ func main() {
Arguments: map[string]interface{}{
"increment": 1,
},
Meta: &struct {
ProgressToken mcp.ProgressToken `json:"progressToken,omitempty"`
}{
Meta: &mcp.Meta{
ProgressToken: 123,
},
},
Expand Down
2 changes: 2 additions & 0 deletions mcp_messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,12 @@ const (
const (
ProtocolVersion_2024_11_05 = "2024-11-05"
ProtocolVersion_2025_03_26 = "2025-03-26"
ProtocolVersion_2025_06_18 = "2025-06-18"
)

// List of supported protocol versions, ordered by priority
var SupportedProtocolVersions = []string{
ProtocolVersion_2025_06_18, // Latest: Added _meta AdditionalFields support
ProtocolVersion_2025_03_26,
ProtocolVersion_2024_11_05,
}
Expand Down
4 changes: 1 addition & 3 deletions mcp_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ type CallToolRequest struct {
type CallToolParams struct {
Name string `json:"name"`
Arguments map[string]interface{} `json:"arguments,omitempty"`
Meta *struct {
ProgressToken ProgressToken `json:"progressToken,omitempty"`
} `json:"_meta,omitempty"`
Meta *Meta `json:"_meta,omitempty"`
}

// RequestMeta represents request metadata
Expand Down
97 changes: 81 additions & 16 deletions mcp_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,89 @@ const (

// MCP protcol Layer

// Meta represents metadata attached to a request's parameters.
// This can include fields formally defined by the protocol (like ProgressToken)
// or other arbitrary data for custom use cases.
// Based on mcp-go implementation for MCP 2025-06-18 protocol support.
type Meta struct {
// ProgressToken is used to request out-of-band progress notifications.
// If specified, the caller is requesting progress notifications for this
// request (as represented by notifications/progress). The value is an
// opaque token that will be attached to any subsequent notifications.
// The receiver is not obligated to provide these notifications.
ProgressToken ProgressToken `json:"-"`

// AdditionalFields are any fields present in the Meta that are not
// otherwise defined in the protocol. This allows for custom metadata
// to be passed between clients and servers.
AdditionalFields map[string]interface{} `json:"-"`
}

// MarshalJSON implements custom JSON marshaling for Meta.
// It flattens ProgressToken and AdditionalFields into a single JSON object.
func (m *Meta) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}

raw := make(map[string]interface{})

// Add progressToken if present
if m.ProgressToken != nil {
raw["progressToken"] = m.ProgressToken
}

// Add all additional fields
for k, v := range m.AdditionalFields {
raw[k] = v
}

return json.Marshal(raw)
}

// UnmarshalJSON implements custom JSON unmarshaling for Meta.
// It extracts progressToken and puts all other fields into AdditionalFields.
func (m *Meta) UnmarshalJSON(data []byte) error {
raw := make(map[string]interface{})
if err := json.Unmarshal(data, &raw); err != nil {
return err
}

// Extract progressToken
if pt, ok := raw["progressToken"]; ok {
m.ProgressToken = pt
delete(raw, "progressToken")
}

// Store remaining fields as additional fields
m.AdditionalFields = raw

return nil
}

// Get retrieves a value from AdditionalFields by key.
// Returns nil if the key doesn't exist or AdditionalFields is nil.
func (m *Meta) Get(key string) interface{} {
if m == nil || m.AdditionalFields == nil {
return nil
}
return m.AdditionalFields[key]
}

// Set sets a value in AdditionalFields.
// Initializes AdditionalFields if it's nil.
func (m *Meta) Set(key string, value interface{}) {
if m.AdditionalFields == nil {
m.AdditionalFields = make(map[string]interface{})
}
m.AdditionalFields[key] = value
}

// Request is the base request struct for all MCP requests.
type Request struct {
Method string `json:"method"`
Params struct {
Meta *struct {
ProgressToken ProgressToken `json:"progressToken,omitempty"`
} `json:"_meta,omitempty"`
Meta *Meta `json:"_meta,omitempty"`
} `json:"params,omitempty"`
}

Expand All @@ -47,10 +123,6 @@ type NotificationParams struct {
AdditionalFields map[string]interface{} `json:"-"` // Additional fields that are not part of the MCP protocol.
}

// Meta represents the _meta field in MCP objects.
// Using map[string]interface{} for flexibility as in mcp-go.
type Meta map[string]interface{}

// MarshalJSON implements custom JSON marshaling for NotificationParams.
// It flattens the AdditionalFields into the main JSON object.
func (p NotificationParams) MarshalJSON() ([]byte, error) {
Expand Down Expand Up @@ -91,7 +163,7 @@ func (p *NotificationParams) UnmarshalJSON(data []byte) error {
if sData == "null" || sData == "{}" {
// If params is null or an empty object, initialize and return
p.AdditionalFields = make(map[string]interface{})
p.Meta = make(Meta) // Initialize Meta as well
p.Meta = make(map[string]interface{}) // Initialize Meta as well
return nil
}

Expand All @@ -103,18 +175,13 @@ func (p *NotificationParams) UnmarshalJSON(data []byte) error {
if p.AdditionalFields == nil {
p.AdditionalFields = make(map[string]interface{})
}
// Ensure Meta is initialized if it's going to be populated or checked
// p.Meta might be nil initially.
// if p.Meta == nil { // Not strictly needed here as we assign directly or check m["_meta"]
// p.Meta = make(Meta)
// }

for k, v := range m {
if k == "_meta" {
if metaMap, ok := v.(map[string]interface{}); ok {
// Initialize p.Meta only if it's nil and metaMap is not nil and not empty
if p.Meta == nil && metaMap != nil && len(metaMap) > 0 {
p.Meta = make(Meta)
p.Meta = make(map[string]interface{})
}
// Populate p.Meta. This handles case where p.Meta was nil or already existed.
if p.Meta != nil { // ensure p.Meta is not nil before assigning to it
Expand All @@ -123,8 +190,6 @@ func (p *NotificationParams) UnmarshalJSON(data []byte) error {
}
}
}
// else: you might want to handle cases where _meta is not a map[string]interface{}
// or log a warning, depending on strictness.
} else {
p.AdditionalFields[k] = v
}
Expand Down
Loading