Implement SEP-973 (#570)

mcp/protocol: Implement SEP-973

- Define Icon structure, which includes source, mimeType and sizes.
- sizes is any array of strings. refer
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1531
- Support setting websiteUrl, icons for mcp.Implementation
- Support setting icons for mcp.Prompt
- Support setting icons for mcp.Tool
- Support setting icons for mcp.Resource

Fixes #552
This commit is contained in:
Suraj Bobade 2025-11-13 03:22:44 +05:30 • committed by GitHub
commit faddd764aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 417 additions and 9 deletions

View file

@ -7,6 +7,7 @@ package main
import (
"context"
"encoding/base64"
"flag"
"fmt"
"log"
@ -50,19 +51,28 @@ func main() {
CompletionHandler: complete, // support completions by setting this handler
}
server := mcp.NewServer(&mcp.Implementation{Name: "everything"}, opts)
// Optionally add an icon to the server implementation.
icons, err := iconToBase64DataURL("./mcp.png")
if err != nil {
log.Fatalf("failed to read icon: %v", err)
}
server := mcp.NewServer(&mcp.Implementation{Name: "everything", WebsiteURL: "https://example.com", Icons: icons}, opts)
// Add tools that exercise different features of the protocol.
mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, contentTool)
mcp.AddTool(server, &mcp.Tool{Name: "greet (structured)"}, structuredTool) // returns structured output
mcp.AddTool(server, &mcp.Tool{Name: "ping"}, pingingTool) // performs a ping
mcp.AddTool(server, &mcp.Tool{Name: "log"}, loggingTool) // performs a log
mcp.AddTool(server, &mcp.Tool{Name: "sample"}, samplingTool) // performs sampling
mcp.AddTool(server, &mcp.Tool{Name: "elicit"}, elicitingTool) // performs elicitation
mcp.AddTool(server, &mcp.Tool{Name: "roots"}, rootsTool) // lists roots
mcp.AddTool(server, &mcp.Tool{Name: "greet (structured)"}, structuredTool) // returns structured output
mcp.AddTool(server, &mcp.Tool{Name: "greet (with Icons)", Icons: icons}, structuredTool) // tool with icons
mcp.AddTool(server, &mcp.Tool{Name: "greet (content with ResourceLink)"}, resourceLinkContentTool(icons)) // tool that returns content with a resource link
mcp.AddTool(server, &mcp.Tool{Name: "ping"}, pingingTool) // performs a ping
mcp.AddTool(server, &mcp.Tool{Name: "log"}, loggingTool) // performs a log
mcp.AddTool(server, &mcp.Tool{Name: "sample"}, samplingTool) // performs sampling
mcp.AddTool(server, &mcp.Tool{Name: "elicit"}, elicitingTool) // performs elicitation
mcp.AddTool(server, &mcp.Tool{Name: "roots"}, rootsTool) // lists roots
// Add a basic prompt.
server.AddPrompt(&mcp.Prompt{Name: "greet"}, prompt)
server.AddPrompt(&mcp.Prompt{Name: "greet (with Icons)", Icons: icons}, prompt) // greet prompt with icons
// Add an embedded resource.
server.AddResource(&mcp.Resource{
@ -70,6 +80,20 @@ func main() {
MIMEType: "text/plain",
URI: "embedded:info",
}, embeddedResource)
server.AddResource(&mcp.Resource{ // text resource with icons
Name: "info (with Icons)",
MIMEType: "text/plain",
URI: "embedded:info",
Icons: icons,
}, embeddedResource)
// Add a resource template.
server.AddResourceTemplate(&mcp.ResourceTemplate{
Name: "Resource template (with Icon)",
MIMEType: "text/plain",
URITemplate: "http://example.com/~{resource_name}/",
Icons: icons,
}, embeddedResource)
// Serve over stdio, or streamable HTTP if -http is set.
if *httpAddr != "" {
@ -140,6 +164,23 @@ func contentTool(ctx context.Context, req *mcp.CallToolRequest, args args) (*mcp
}, nil, nil
}
// resourceLinkContentTool returns a ResourceLink content with icons.
func resourceLinkContentTool(icons []mcp.Icon) func(ctx context.Context, req *mcp.CallToolRequest, args args) (*mcp.CallToolResult, any, error) {
return func(ctx context.Context, req *mcp.CallToolRequest, args args) (*mcp.CallToolResult, any, error) {
return &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.ResourceLink{
Name: "greeting",
Title: "A friendly greeting",
MIMEType: "text/plain",
URI: "data:text/plain,Hi%20" + url.PathEscape(args.Name),
Icons: icons,
},
},
}, nil, nil
}
}
type result struct {
Message string `json:"message" jsonschema:"the message to convey"`
}
@ -222,3 +263,16 @@ func complete(ctx context.Context, req *mcp.CompleteRequest) (*mcp.CompleteResul
},
}, nil
}
func iconToBase64DataURL(path string) ([]mcp.Icon, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
return []mcp.Icon{{
Source: "data:image/png;base64," + base64.StdEncoding.EncodeToString(data),
MIMEType: "image/png",
Sizes: []string{"48x48"},
Theme: "light", // or "dark" or empty
}}, nil
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB