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:
parent
35dfcf21c9
commit
faddd764aa
7 changed files with 417 additions and 9 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
BIN
examples/server/everything/mcp.png
Normal file
BIN
examples/server/everything/mcp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -111,6 +111,19 @@ func structuredTool(ctx context.Context, req *CallToolRequest, args *structuredI
|
|||
return nil, &structuredOutput{"Ack " + args.In}, nil
|
||||
}
|
||||
|
||||
func contentTool(ctx context.Context, req *CallToolRequest, args *structuredInput) (*CallToolResult, any, error) {
|
||||
return &CallToolResult{
|
||||
Content: []Content{
|
||||
&ResourceLink{
|
||||
Name: "Example Resource Link with Icons",
|
||||
MIMEType: "text/plain",
|
||||
URI: "https://example.com/resource/" + args.In,
|
||||
Icons: []Icon{iconObj},
|
||||
},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
type tomorrowInput struct {
|
||||
Now time.Time
|
||||
}
|
||||
|
|
@ -135,12 +148,26 @@ func incTool(_ context.Context, _ *CallToolRequest, args incInput) (*CallToolRes
|
|||
return nil, incOutput{args.X + 1}, nil
|
||||
}
|
||||
|
||||
var iconObj = Icon{
|
||||
Source: "foobar",
|
||||
MIMEType: "image/png",
|
||||
Sizes: []string{"48x48", "96x96"},
|
||||
Theme: "light",
|
||||
}
|
||||
|
||||
// runServerTest runs the server conformance test.
|
||||
// It must be executed in a synctest bubble.
|
||||
func runServerTest(t *testing.T, test *conformanceTest) {
|
||||
ctx := t.Context()
|
||||
// Construct the server based on features listed in the test.
|
||||
s := NewServer(&Implementation{Name: "testServer", Version: "v1.0.0"}, nil)
|
||||
impl := &Implementation{Name: "testServer", Version: "v1.0.0"}
|
||||
|
||||
if test.name == "spec-sep-973-additional-metadata.txtar" {
|
||||
impl.Icons = []Icon{iconObj}
|
||||
impl.WebsiteURL = "https://github.com/modelcontextprotocol/go-sdk"
|
||||
}
|
||||
|
||||
s := NewServer(impl, nil)
|
||||
for _, tn := range test.tools {
|
||||
switch tn {
|
||||
case "greet":
|
||||
|
|
@ -148,6 +175,12 @@ func runServerTest(t *testing.T, test *conformanceTest) {
|
|||
Name: "greet",
|
||||
Description: "say hi",
|
||||
}, sayHi)
|
||||
case "greetWithIcon":
|
||||
AddTool(s, &Tool{
|
||||
Name: "greetWithIcon",
|
||||
Description: "say hi",
|
||||
Icons: []Icon{iconObj},
|
||||
}, sayHi)
|
||||
case "structured":
|
||||
AddTool(s, &Tool{Name: "structured"}, structuredTool)
|
||||
case "tomorrow":
|
||||
|
|
@ -159,6 +192,12 @@ func runServerTest(t *testing.T, test *conformanceTest) {
|
|||
}
|
||||
inSchema.Properties["x"].Default = json.RawMessage(`6`)
|
||||
AddTool(s, &Tool{Name: "inc", InputSchema: inSchema}, incTool)
|
||||
case "contentTool":
|
||||
AddTool(s, &Tool{
|
||||
Name: "contentTool",
|
||||
Title: "contentTool",
|
||||
Description: "return resourceLink content with Icon",
|
||||
}, contentTool)
|
||||
default:
|
||||
t.Fatalf("unknown tool %q", tn)
|
||||
}
|
||||
|
|
@ -167,6 +206,13 @@ func runServerTest(t *testing.T, test *conformanceTest) {
|
|||
switch pn {
|
||||
case "code_review":
|
||||
s.AddPrompt(codeReviewPrompt, codReviewPromptHandler)
|
||||
case "code_reviewWithIcon":
|
||||
s.AddPrompt(&Prompt{
|
||||
Name: "code_review",
|
||||
Description: "do a code review",
|
||||
Arguments: []*PromptArgument{{Name: "Code", Required: true}},
|
||||
Icons: []Icon{iconObj},
|
||||
}, codReviewPromptHandler)
|
||||
default:
|
||||
t.Fatalf("unknown prompt %q", pn)
|
||||
}
|
||||
|
|
@ -177,6 +223,13 @@ func runServerTest(t *testing.T, test *conformanceTest) {
|
|||
s.AddResource(resource1, readHandler)
|
||||
case "info":
|
||||
s.AddResource(resource3, handleEmbeddedResource)
|
||||
case "infoWithIcon":
|
||||
s.AddResource(&Resource{
|
||||
Name: "info",
|
||||
MIMEType: "text/plain",
|
||||
URI: "embedded:info",
|
||||
Icons: []Icon{iconObj},
|
||||
}, handleEmbeddedResource)
|
||||
default:
|
||||
t.Fatalf("unknown resource %q", rn)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ type ResourceLink struct {
|
|||
Size *int64
|
||||
Meta Meta
|
||||
Annotations *Annotations
|
||||
// Icons for the resource link, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
func (c *ResourceLink) MarshalJSON() ([]byte, error) {
|
||||
|
|
@ -143,6 +145,7 @@ func (c *ResourceLink) MarshalJSON() ([]byte, error) {
|
|||
Size: c.Size,
|
||||
Meta: c.Meta,
|
||||
Annotations: c.Annotations,
|
||||
Icons: c.Icons,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +158,7 @@ func (c *ResourceLink) fromWire(wire *wireContent) {
|
|||
c.Size = wire.Size
|
||||
c.Meta = wire.Meta
|
||||
c.Annotations = wire.Annotations
|
||||
c.Icons = wire.Icons
|
||||
}
|
||||
|
||||
// EmbeddedResource contains embedded resources.
|
||||
|
|
@ -237,6 +241,7 @@ type wireContent struct {
|
|||
Size *int64 `json:"size,omitempty"`
|
||||
Meta Meta `json:"_meta,omitempty"`
|
||||
Annotations *Annotations `json:"annotations,omitempty"`
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
func contentsFromWire(wires []*wireContent, allow map[string]bool) ([]Content, error) {
|
||||
|
|
|
|||
|
|
@ -121,8 +121,9 @@ func TestContent(t *testing.T) {
|
|||
Description: "This resource demonstrates all fields",
|
||||
MIMEType: "text/plain",
|
||||
Meta: mcp.Meta{"custom": "metadata"},
|
||||
Icons: []mcp.Icon{{Source: "foobar", MIMEType: "image/png", Sizes: []string{"48x48"}, Theme: "light"}},
|
||||
},
|
||||
`{"type":"resource_link","mimeType":"text/plain","uri":"https://example.com/resource","name":"Example Resource","title":"A comprehensive example resource","description":"This resource demonstrates all fields","_meta":{"custom":"metadata"}}`,
|
||||
`{"type":"resource_link","mimeType":"text/plain","uri":"https://example.com/resource","name":"Example Resource","title":"A comprehensive example resource","description":"This resource demonstrates all fields","_meta":{"custom":"metadata"},"icons":[{"src":"foobar","mimeType":"image/png","sizes":["48x48"],"theme":"light"}]}`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -192,3 +193,53 @@ func TestEmbeddedResource(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestContentUnmarshal tests that unmarshaling JSON into various Content types
|
||||
// works correctly, including when the Content fields are initially nil.
|
||||
func TestContentUnmarshal(t *testing.T) {
|
||||
valInt64 := int64(24)
|
||||
tests := []struct {
|
||||
name string
|
||||
json string
|
||||
content mcp.Content
|
||||
expectContent mcp.Content
|
||||
}{
|
||||
{
|
||||
name: "ResourceLink",
|
||||
json: `{"type":"resource_link","mimeType":"text/plain","uri":"https://example.com/resource","name":"Example Resource","title":"A comprehensive example resource","description":"This resource demonstrates all fields","_meta":{"custom":"metadata"},"icons":[{"src":"foobar","mimeType":"image/png","sizes":["48x48"],"theme":"light"}], "size":24,"annotations":{"audience":["user","assistant"],"lastModified":"2025-01-12T15:00:58Z","priority":0.5}}`,
|
||||
content: &mcp.ResourceLink{},
|
||||
expectContent: &mcp.ResourceLink{
|
||||
URI: "https://example.com/resource",
|
||||
Name: "Example Resource",
|
||||
Title: "A comprehensive example resource",
|
||||
Description: "This resource demonstrates all fields",
|
||||
MIMEType: "text/plain",
|
||||
// Meta: mcp.Meta{"custom": "metadata"},
|
||||
Size: &valInt64,
|
||||
Annotations: &mcp.Annotations{Audience: []mcp.Role{"user", "assistant"}, LastModified: "2025-01-12T15:00:58Z", Priority: 0.5},
|
||||
Icons: []mcp.Icon{{Source: "foobar", MIMEType: "image/png", Sizes: []string{"48x48"}, Theme: "light"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Test that unmarshaling doesn't panic on nil Content fields
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("UnmarshalJSON panicked: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
err := json.Unmarshal([]byte(tt.json), tt.content)
|
||||
if err != nil {
|
||||
t.Errorf("UnmarshalJSON failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify that the Content field was properly populated
|
||||
if cmp.Diff(tt.expectContent, tt.content) != "" {
|
||||
t.Errorf("Content is not equal: %v", cmp.Diff(tt.expectContent, tt.content))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -658,6 +658,23 @@ type ProgressNotificationParams struct {
|
|||
|
||||
func (*ProgressNotificationParams) isParams() {}
|
||||
|
||||
// Icon provides visual identifiers for their resources, tools, prompts, and implementations
|
||||
// See [/specification/draft/basic/index#icons] for notes on icons
|
||||
//
|
||||
// TODO(iamsurajbobade): update specification url from draft.
|
||||
type Icon struct {
|
||||
// Source is A URI pointing to the icon resource (required). This can be:
|
||||
// - An HTTP/HTTPS URL pointing to an image file
|
||||
// - A data URI with base64-encoded image data
|
||||
Source string `json:"src"`
|
||||
// Optional MIME type if the server's type is missing or generic
|
||||
MIMEType string `json:"mimeType,omitempty"`
|
||||
// Optional size specification (e.g., ["48x48"], ["any"] for scalable formats like SVG, or ["48x48", "96x96"] for multiple sizes)
|
||||
Sizes []string `json:"sizes,omitempty"`
|
||||
// Optional Theme of the icon, e.g., "light" or "dark"
|
||||
Theme string `json:"theme,omitempty"`
|
||||
}
|
||||
|
||||
// A prompt or prompt template that the server offers.
|
||||
type Prompt struct {
|
||||
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
|
||||
|
|
@ -673,6 +690,8 @@ type Prompt struct {
|
|||
// Intended for UI and end-user contexts — optimized to be human-readable and
|
||||
// easily understood, even by those unfamiliar with domain-specific terminology.
|
||||
Title string `json:"title,omitempty"`
|
||||
// Icons for the prompt, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
// Describes an argument that a prompt can accept.
|
||||
|
|
@ -782,6 +801,8 @@ type Resource struct {
|
|||
Title string `json:"title,omitempty"`
|
||||
// The URI of this resource.
|
||||
URI string `json:"uri"`
|
||||
// Icons for the resource, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceListChangedParams struct {
|
||||
|
|
@ -822,6 +843,8 @@ type ResourceTemplate struct {
|
|||
// A URI template (according to RFC 6570) that can be used to construct resource
|
||||
// URIs.
|
||||
URITemplate string `json:"uriTemplate"`
|
||||
// Icons for the resource template, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
// The sender or recipient of messages and data in a conversation.
|
||||
|
|
@ -948,6 +971,8 @@ type Tool struct {
|
|||
// If not provided, Annotations.Title should be used for display if present,
|
||||
// otherwise Name.
|
||||
Title string `json:"title,omitempty"`
|
||||
// Icons for the tool, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
// Additional properties describing a Tool to clients.
|
||||
|
|
@ -1090,6 +1115,10 @@ type Implementation struct {
|
|||
// easily understood, even by those unfamiliar with domain-specific terminology.
|
||||
Title string `json:"title,omitempty"`
|
||||
Version string `json:"version"`
|
||||
// WebsiteURL for the server, if any.
|
||||
WebsiteURL string `json:"websiteUrl,omitempty"`
|
||||
// Icons for the Server, if any.
|
||||
Icons []Icon `json:"icons,omitempty"`
|
||||
}
|
||||
|
||||
// Present if the server supports argument autocompletion suggestions.
|
||||
|
|
|
|||
216
mcp/testdata/conformance/server/spec-sep-973-additional-metadata.txtar
vendored
Normal file
216
mcp/testdata/conformance/server/spec-sep-973-additional-metadata.txtar
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
Check behavior of server with Icons and websiteUrl metadata added as part of SEP-973 specification.
|
||||
|
||||
check modelcontextprotocol/go-sdk/issues/552 for more details.
|
||||
|
||||
Checks following:
|
||||
- Test setting websiteUrl, icons for mcp.Implementation
|
||||
- Test setting icons for mcp.Prompt
|
||||
- Test setting icons for mcp.Tool
|
||||
- Test setting icons for mcp.Resource
|
||||
- Test if tool call returning ResourceLink with icons works as expected
|
||||
|
||||
|
||||
-- tools --
|
||||
greetWithIcon
|
||||
contentTool
|
||||
|
||||
-- prompts --
|
||||
code_reviewWithIcon
|
||||
|
||||
-- resources --
|
||||
infoWithIcon
|
||||
|
||||
-- client --
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2025-06-18",
|
||||
"capabilities": {},
|
||||
"clientInfo": { "name": "ExampleClient", "version": "1.0.0" }
|
||||
}
|
||||
}
|
||||
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
|
||||
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
|
||||
{ "jsonrpc": "2.0", "id": 3, "method": "resources/list" }
|
||||
{ "jsonrpc": "2.0", "id": 4, "method": "prompts/list" }
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 5,
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "contentTool",
|
||||
"arguments": {
|
||||
"In": "resource1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- server --
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"capabilities": {
|
||||
"logging": {},
|
||||
"prompts": {
|
||||
"listChanged": true
|
||||
},
|
||||
"resources": {
|
||||
"listChanged": true
|
||||
},
|
||||
"tools": {
|
||||
"listChanged": true
|
||||
}
|
||||
},
|
||||
"protocolVersion": "2025-06-18",
|
||||
"serverInfo": {
|
||||
"name": "testServer",
|
||||
"version": "v1.0.0",
|
||||
"websiteUrl": "https://github.com/modelcontextprotocol/go-sdk",
|
||||
"icons": [
|
||||
{
|
||||
"src": "foobar",
|
||||
"mimeType": "image/png",
|
||||
"sizes": [
|
||||
"48x48",
|
||||
"96x96"
|
||||
],
|
||||
"theme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"result": {
|
||||
"tools": [
|
||||
{
|
||||
"description": "return resourceLink content with Icon",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"In"
|
||||
],
|
||||
"properties": {
|
||||
"In": {
|
||||
"type": "string",
|
||||
"description": "the input"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"name": "contentTool",
|
||||
"title": "contentTool"
|
||||
},
|
||||
{
|
||||
"description": "say hi",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"Name"
|
||||
],
|
||||
"properties": {
|
||||
"Name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"name": "greetWithIcon",
|
||||
"icons": [
|
||||
{
|
||||
"src": "foobar",
|
||||
"mimeType": "image/png",
|
||||
"sizes": [
|
||||
"48x48",
|
||||
"96x96"
|
||||
],
|
||||
"theme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"result": {
|
||||
"resources": [
|
||||
{
|
||||
"mimeType": "text/plain",
|
||||
"name": "info",
|
||||
"uri": "embedded:info",
|
||||
"icons": [
|
||||
{
|
||||
"src": "foobar",
|
||||
"mimeType": "image/png",
|
||||
"sizes": [
|
||||
"48x48",
|
||||
"96x96"
|
||||
],
|
||||
"theme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 4,
|
||||
"result": {
|
||||
"prompts": [
|
||||
{
|
||||
"arguments": [
|
||||
{
|
||||
"name": "Code",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"description": "do a code review",
|
||||
"name": "code_review",
|
||||
"icons": [
|
||||
{
|
||||
"src": "foobar",
|
||||
"mimeType": "image/png",
|
||||
"sizes": [
|
||||
"48x48",
|
||||
"96x96"
|
||||
],
|
||||
"theme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 5,
|
||||
"result": {
|
||||
"content": [
|
||||
{
|
||||
"type": "resource_link",
|
||||
"mimeType": "text/plain",
|
||||
"uri": "https://example.com/resource/resource1",
|
||||
"name": "Example Resource Link with Icons",
|
||||
"icons": [
|
||||
{
|
||||
"src": "foobar",
|
||||
"mimeType": "image/png",
|
||||
"sizes": [
|
||||
"48x48",
|
||||
"96x96"
|
||||
],
|
||||
"theme": "light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue