Add four new example servers demonstrating different SEP-2053 variant patterns: - model-optimized (same tools, different descriptions per LLM family) - trading (API versioning with deprecation lifecycle) - research (context budget management) - Refactor the existing variants-http example into a GitHub-style server with custom ranking. Signed-off-by: Kurt Degiorgio <kdegiorgio@bloomberg.net>
116 lines
5.1 KiB
Go
116 lines
5.1 KiB
Go
// Example: Model-Optimized Weather Service — the same tools with different
|
|
// descriptions and schemas optimized for different LLM families. This
|
|
// demonstrates the SEP-2053 primary use case where tool descriptions are
|
|
// tailored per model family for optimal tool-calling performance.
|
|
//
|
|
// Capability demonstrated: Same tools, different descriptions per variant.
|
|
//
|
|
// Variants:
|
|
// - claude-optimized: Detailed, structured descriptions with explicit guidance
|
|
// - gpt-optimized: Concise function-style descriptions with JSON Schema emphasis
|
|
// - compact: Minimal descriptions for context-constrained environments
|
|
//
|
|
// Run:
|
|
//
|
|
// go run ./examples/server/model-optimized
|
|
//
|
|
// Then connect any MCP client to http://localhost:8080.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
|
|
"github.com/modelcontextprotocol/experimental-ext-variants/go/sdk/variants"
|
|
)
|
|
|
|
func main() {
|
|
// Claude-optimized variant: verbose, structured descriptions with
|
|
// explicit guidance on when and how to use each tool.
|
|
claudeServer := mcp.NewServer(&mcp.Implementation{Name: "weather-service", Version: "v1.0.0"}, nil)
|
|
mcp.AddTool(claudeServer, &mcp.Tool{
|
|
Name: "get_weather",
|
|
Description: "Get the current weather conditions for a specific location. " +
|
|
"Use this tool when the user asks about current weather, temperature, or conditions. " +
|
|
"Accepts city names (e.g., 'San Francisco, CA'), country names, or lat/long coordinates. " +
|
|
"Returns temperature, humidity, wind speed, and a human-readable condition description. " +
|
|
"Prefer this over get_forecast when the user only needs current conditions.",
|
|
}, getWeather)
|
|
mcp.AddTool(claudeServer, &mcp.Tool{
|
|
Name: "get_forecast",
|
|
Description: "Get a multi-day weather forecast for a specific location. " +
|
|
"Use this tool when the user asks about future weather, upcoming conditions, or wants to plan ahead. " +
|
|
"Returns daily high/low temperatures and conditions for 1-7 days. " +
|
|
"Defaults to 3 days if not specified. Use get_weather instead if only current conditions are needed.",
|
|
}, getForecast)
|
|
|
|
// GPT-optimized variant: concise function-style descriptions with
|
|
// JSON Schema emphasis for OpenAI-family models.
|
|
gptServer := mcp.NewServer(&mcp.Implementation{Name: "weather-service", Version: "v1.0.0"}, nil)
|
|
mcp.AddTool(gptServer, &mcp.Tool{
|
|
Name: "get_weather",
|
|
Description: "Returns current weather data (temperature, humidity, wind, conditions) for a given location.",
|
|
}, getWeather)
|
|
mcp.AddTool(gptServer, &mcp.Tool{
|
|
Name: "get_forecast",
|
|
Description: "Returns multi-day forecast (high/low temps, conditions) for a location. Days: 1-7, default 3.",
|
|
}, getForecast)
|
|
|
|
// Compact variant: minimal descriptions for context-constrained
|
|
// environments where token budget is limited.
|
|
compactServer := mcp.NewServer(&mcp.Implementation{Name: "weather-service", Version: "v1.0.0"}, nil)
|
|
mcp.AddTool(compactServer, &mcp.Tool{
|
|
Name: "get_weather",
|
|
Description: "Current weather for a location.",
|
|
}, getWeather)
|
|
mcp.AddTool(compactServer, &mcp.Tool{
|
|
Name: "get_forecast",
|
|
Description: "Multi-day forecast for a location.",
|
|
}, getForecast)
|
|
|
|
vs := variants.NewServer(&mcp.Implementation{Name: "weather-service", Version: "v1.0.0"}).
|
|
WithVariant(variants.ServerVariant{
|
|
ID: "claude-optimized",
|
|
Description: "Detailed, structured tool descriptions with explicit usage guidance. Optimized for Anthropic Claude models that benefit from rich context and clear instructions.",
|
|
Hints: map[string]string{"modelFamily": "anthropic", "contextSize": "verbose"},
|
|
Status: variants.Stable,
|
|
}, claudeServer, 0).
|
|
WithVariant(variants.ServerVariant{
|
|
ID: "gpt-optimized",
|
|
Description: "Concise function-style descriptions with JSON Schema emphasis. Optimized for OpenAI GPT models that work well with terse, specification-like tool definitions.",
|
|
Hints: map[string]string{"modelFamily": "openai", "contextSize": "standard"},
|
|
Status: variants.Stable,
|
|
}, gptServer, 1).
|
|
WithVariant(variants.ServerVariant{
|
|
ID: "compact",
|
|
Description: "Minimal tool descriptions for context-constrained environments. Use when token budget is severely limited or tools are self-explanatory from their schemas.",
|
|
Hints: map[string]string{"modelFamily": "any", "contextSize": "compact"},
|
|
Status: variants.Stable,
|
|
}, compactServer, 2).
|
|
// Custom ranking: match by modelFamily hint, fall back to priority.
|
|
WithRanking(func(_ context.Context, hints variants.VariantHints, vs []variants.ServerVariant) []variants.ServerVariant {
|
|
requested, _ := variants.HintValue[string](hints, "modelFamily")
|
|
slices.SortStableFunc(vs, func(a, b variants.ServerVariant) int {
|
|
aMatch := strings.EqualFold(a.Hints["modelFamily"], requested)
|
|
bMatch := strings.EqualFold(b.Hints["modelFamily"], requested)
|
|
if aMatch != bMatch {
|
|
if aMatch {
|
|
return -1
|
|
}
|
|
return 1
|
|
}
|
|
return a.Priority() - b.Priority()
|
|
})
|
|
return vs
|
|
})
|
|
|
|
handler := variants.NewStreamableHTTPHandler(vs, nil)
|
|
|
|
log.Println("Listening on :8080")
|
|
log.Fatal(http.ListenAndServe(":8080", handler))
|
|
}
|