diff --git a/examples/server/mcp-app/index.html b/examples/server/mcp-app/index.html new file mode 100644 index 00000000..c2aee695 --- /dev/null +++ b/examples/server/mcp-app/index.html @@ -0,0 +1,239 @@ + + + + + + + + + +

Example MCP App

+
Loading SDK...
+ + + + + +
+
Call Tool from View
+ + +
+ + + + + + diff --git a/examples/server/mcp-app/main.go b/examples/server/mcp-app/main.go new file mode 100644 index 00000000..67282c01 --- /dev/null +++ b/examples/server/mcp-app/main.go @@ -0,0 +1,106 @@ +package main + +import ( + "context" + _ "embed" + "log" + + "github.com/modelcontextprotocol/go-sdk/mcp" +) + +//go:embed index.html +var viewHTML string + +func main() { + server := mcp.NewServer(&mcp.Implementation{ + Name: "example-app-server", + Version: "v0.1.0", + }, nil) + + // Register a UI resource that serves the pre-built HTML page, + // which pre-bundles the JS MCP Apps SDK into the HTML page. + // SDK: https://github.com/modelcontextprotocol/ext-apps + server.AddResource(&mcp.Resource{ + URI: "ui://example/view", + Name: "example-view", + MIMEType: "text/html;profile=mcp-app", + Meta: mcp.Meta{ + "ui": map[string]any{ + "csp": map[string]any{}, + }, + }, + }, func(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { + return &mcp.ReadResourceResult{ + Contents: []*mcp.ResourceContents{{ + URI: "ui://example/view", + MIMEType: "text/html;profile=mcp-app", + Text: viewHTML, + Meta: mcp.Meta{ + "ui": map[string]any{ + "csp": map[string]any{}, + }, + }, + }}, + }, nil + }) + + // Tool: show-data — visible to both the model and the app UI. + type ShowDataInput struct { + Data string `json:"data" jsonschema:"data to display"` + } + type ShowDataOutput struct { + Data string `json:"data"` + } + + mcp.AddTool(server, &mcp.Tool{ + Name: "show-data", + Description: "Shows data in the UI view", + Meta: mcp.Meta{ + "ui": map[string]any{ + "resourceUri": "ui://example/view", + "visibility": []string{"model", "app"}, + }, + }, + }, func(ctx context.Context, req *mcp.CallToolRequest, input ShowDataInput) (*mcp.CallToolResult, ShowDataOutput, error) { + output := ShowDataOutput{Data: input.Data} + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: input.Data}, + }, + }, output, nil + }) + + // Tool: count-words — app-only tool the UI calls via callServerTool. + type CountInput struct { + Text string `json:"text" jsonschema:"text to count words in"` + } + type CountOutput struct { + WordCount int `json:"wordCount"` + } + + mcp.AddTool(server, &mcp.Tool{ + Name: "count-words", + Description: "Counts words in text", + Meta: mcp.Meta{ + "ui": map[string]any{ + "visibility": []string{"app"}, + }, + }, + }, func(ctx context.Context, req *mcp.CallToolRequest, input CountInput) (*mcp.CallToolResult, CountOutput, error) { + words := 0 + inWord := false + for _, r := range input.Text { + if r == ' ' || r == '\t' || r == '\n' { + inWord = false + } else if !inWord { + inWord = true + words++ + } + } + return nil, CountOutput{WordCount: words}, nil + }) + + if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { + log.Fatalf("Server error: %v", err) + } +}