examples: add an everything example, and simplify hello
Our 'hello' example should be as simple as possible. On the other hand, we should have an 'everything' example that exercises (almost) everything we offer. Using the everything example, I did some final testing using the inspector. This turned up a couple rough edges related to JSON null that I addressed by preferring empty slices. For #33
This commit is contained in:
parent
c631641296
commit
9754a2aa86
1 changed files with 240 additions and 71 deletions
|
|
@ -2,89 +2,45 @@
|
|||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The hello server contains a single tool that says hi to the user.
|
||||
//
|
||||
// It runs over the stdio transport.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
var httpAddr = flag.String("http", "", "if set, use streamable HTTP at this address, instead of stdin/stdout")
|
||||
|
||||
type HiArgs struct {
|
||||
Name string `json:"name" jsonschema:"the name to say hi to"`
|
||||
}
|
||||
|
||||
func SayHi(ctx context.Context, req *mcp.CallToolRequest, args HiArgs) (*mcp.CallToolResult, any, error) {
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Hi " + args.Name},
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func PromptHi(ctx context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
|
||||
return &mcp.GetPromptResult{
|
||||
Description: "Code review prompt",
|
||||
Messages: []*mcp.PromptMessage{
|
||||
{Role: "user", Content: &mcp.TextContent{Text: "Say hi to " + req.Params.Arguments["name"]}},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Create a server with a single tool that says "Hi".
|
||||
server := mcp.NewServer(&mcp.Implementation{Name: "greeter"}, nil)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi)
|
||||
server.AddPrompt(&mcp.Prompt{Name: "greet"}, PromptHi)
|
||||
server.AddResource(&mcp.Resource{
|
||||
Name: "info",
|
||||
MIMEType: "text/plain",
|
||||
URI: "embedded:info",
|
||||
}, handleEmbeddedResource)
|
||||
|
||||
if *httpAddr != "" {
|
||||
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {
|
||||
return server
|
||||
}, nil)
|
||||
log.Printf("MCP handler listening at %s", *httpAddr)
|
||||
http.ListenAndServe(*httpAddr, handler)
|
||||
} else {
|
||||
t := &mcp.LoggingTransport{Transport: &mcp.StdioTransport{}, Writer: os.Stderr}
|
||||
if err := server.Run(context.Background(), t); err != nil {
|
||||
log.Printf("Server failed: %v", err)
|
||||
}
|
||||
// Using the generic AddTool automatically populates the the input and output
|
||||
// schema of the tool.
|
||||
//
|
||||
// The schema considers 'json' and 'jsonschema' struct tags to get argument
|
||||
// names and descriptions.
|
||||
type args struct {
|
||||
Name string `json:"name" jsonschema:"the person to greet"`
|
||||
}
|
||||
mcp.AddTool(server, &mcp.Tool{
|
||||
Name: "greet",
|
||||
Description: "say hi",
|
||||
}, func(ctx context.Context, req *mcp.CallToolRequest, args args) (*mcp.CallToolResult, any, error) {
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
&mcp.TextContent{Text: "Hi " + args.Name},
|
||||
},
|
||||
}, nil, nil
|
||||
})
|
||||
|
||||
// server.Run runs the server on the given transport.
|
||||
//
|
||||
// In this case, the server communicates over stdin/stdout.
|
||||
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
|
||||
log.Printf("Server failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var embeddedResources = map[string]string{
|
||||
"info": "This is the hello example server.",
|
||||
}
|
||||
|
||||
func handleEmbeddedResource(_ context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
|
||||
u, err := url.Parse(req.Params.URI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Scheme != "embedded" {
|
||||
return nil, fmt.Errorf("wrong scheme: %q", u.Scheme)
|
||||
}
|
||||
key := u.Opaque
|
||||
text, ok := embeddedResources[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no embedded resource named %q", key)
|
||||
}
|
||||
return &mcp.ReadResourceResult{
|
||||
Contents: []*mcp.ResourceContents{
|
||||
{URI: req.Params.URI, MIMEType: "text/plain", Text: text},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue