first commit
This commit is contained in:
279
examples/mcps/error-test-server/main.go
Normal file
279
examples/mcps/error-test-server/main.go
Normal file
@@ -0,0 +1,279 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Seed random number generator
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
// Create MCP server
|
||||
s := server.NewMCPServer(
|
||||
"error-test-server",
|
||||
"1.0.0",
|
||||
server.WithToolCapabilities(true),
|
||||
)
|
||||
|
||||
// Register all tools
|
||||
registerTimeoutAfterTool(s)
|
||||
registerReturnMalformedJSONTool(s)
|
||||
registerReturnErrorTool(s)
|
||||
registerIntermittentFailTool(s)
|
||||
registerMemoryIntensiveTool(s)
|
||||
|
||||
// Start STDIO server
|
||||
if err := server.ServeStdio(s); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Server error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TOOL 1: timeout_after
|
||||
// ============================================================================
|
||||
|
||||
func registerTimeoutAfterTool(s *server.MCPServer) {
|
||||
tool := mcp.NewTool("timeout_after",
|
||||
mcp.WithDescription("Simulates a timeout by delaying for specified seconds"),
|
||||
mcp.WithNumber("seconds",
|
||||
mcp.Required(),
|
||||
mcp.Description("Number of seconds to wait before responding"),
|
||||
),
|
||||
)
|
||||
|
||||
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var args struct {
|
||||
Seconds float64 `json:"seconds"`
|
||||
}
|
||||
|
||||
// Get arguments using the proper method
|
||||
argsInterface := request.GetArguments()
|
||||
|
||||
// Marshal and unmarshal to convert to our struct
|
||||
argsBytes, err := json.Marshal(argsInterface)
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to marshal arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(argsBytes, &args); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Invalid arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
duration := time.Duration(args.Seconds * float64(time.Second))
|
||||
|
||||
// Use context-aware sleep
|
||||
select {
|
||||
case <-time.After(duration):
|
||||
response := map[string]interface{}{
|
||||
"delayed_seconds": args.Seconds,
|
||||
"message": fmt.Sprintf("Delayed for %.2f seconds", args.Seconds),
|
||||
}
|
||||
jsonResult, _ := json.Marshal(response)
|
||||
return mcp.NewToolResultText(string(jsonResult)), nil
|
||||
case <-ctx.Done():
|
||||
return mcp.NewToolResultError("Operation cancelled or timed out"), nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TOOL 2: return_malformed_json
|
||||
// ============================================================================
|
||||
|
||||
func registerReturnMalformedJSONTool(s *server.MCPServer) {
|
||||
tool := mcp.NewTool("return_malformed_json",
|
||||
mcp.WithDescription("Returns intentionally malformed JSON to test error handling"),
|
||||
)
|
||||
|
||||
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
// Return deliberately broken JSON
|
||||
// Note: This will be wrapped in the MCP protocol, so the MCP layer should handle it
|
||||
// But the content itself is invalid JSON
|
||||
malformedJSON := `{"key": "value", "broken": }`
|
||||
return mcp.NewToolResultText(malformedJSON), nil
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TOOL 3: return_error
|
||||
// ============================================================================
|
||||
|
||||
func registerReturnErrorTool(s *server.MCPServer) {
|
||||
tool := mcp.NewTool("return_error",
|
||||
mcp.WithDescription("Returns an error with specified type"),
|
||||
mcp.WithString("error_type",
|
||||
mcp.Required(),
|
||||
mcp.Description("Type of error to return"),
|
||||
mcp.Enum("validation", "runtime", "network", "timeout", "permission"),
|
||||
),
|
||||
)
|
||||
|
||||
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var args struct {
|
||||
ErrorType string `json:"error_type"`
|
||||
}
|
||||
|
||||
// Get arguments using the proper method
|
||||
argsInterface := request.GetArguments()
|
||||
|
||||
// Marshal and unmarshal to convert to our struct
|
||||
argsBytes, err := json.Marshal(argsInterface)
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to marshal arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(argsBytes, &args); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Invalid arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
var errorMessage string
|
||||
switch args.ErrorType {
|
||||
case "validation":
|
||||
errorMessage = "Validation Error: Invalid input parameters provided"
|
||||
case "runtime":
|
||||
errorMessage = "Runtime Error: Unexpected condition occurred during execution"
|
||||
case "network":
|
||||
errorMessage = "Network Error: Failed to connect to remote service"
|
||||
case "timeout":
|
||||
errorMessage = "Timeout Error: Operation exceeded maximum allowed time"
|
||||
case "permission":
|
||||
errorMessage = "Permission Error: Insufficient privileges to perform operation"
|
||||
default:
|
||||
errorMessage = fmt.Sprintf("Unknown error type: %s", args.ErrorType)
|
||||
}
|
||||
|
||||
return mcp.NewToolResultError(errorMessage), nil
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TOOL 4: intermittent_fail
|
||||
// ============================================================================
|
||||
|
||||
func registerIntermittentFailTool(s *server.MCPServer) {
|
||||
tool := mcp.NewTool("intermittent_fail",
|
||||
mcp.WithDescription("Fails randomly based on specified fail rate percentage (0-100)"),
|
||||
mcp.WithNumber("fail_rate",
|
||||
mcp.Required(),
|
||||
mcp.Description("Percentage chance of failure (0-100)"),
|
||||
),
|
||||
)
|
||||
|
||||
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var args struct {
|
||||
FailRate float64 `json:"fail_rate"`
|
||||
}
|
||||
|
||||
// Get arguments using the proper method
|
||||
argsInterface := request.GetArguments()
|
||||
|
||||
// Marshal and unmarshal to convert to our struct
|
||||
argsBytes, err := json.Marshal(argsInterface)
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to marshal arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(argsBytes, &args); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Invalid arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
// Validate fail rate
|
||||
if args.FailRate < 0 || args.FailRate > 100 {
|
||||
return mcp.NewToolResultError("Fail rate must be between 0 and 100"), nil
|
||||
}
|
||||
|
||||
// Generate random number between 0-100
|
||||
randomValue := rand.Float64() * 100
|
||||
|
||||
if randomValue < args.FailRate {
|
||||
// Fail
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Intermittent failure (fail_rate: %.1f%%, random: %.2f)", args.FailRate, randomValue)), nil
|
||||
}
|
||||
|
||||
// Success
|
||||
response := map[string]interface{}{
|
||||
"success": true,
|
||||
"fail_rate": args.FailRate,
|
||||
"random": randomValue,
|
||||
"message": "Operation succeeded",
|
||||
}
|
||||
|
||||
jsonResult, _ := json.Marshal(response)
|
||||
return mcp.NewToolResultText(string(jsonResult)), nil
|
||||
})
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TOOL 5: memory_intensive
|
||||
// ============================================================================
|
||||
|
||||
func registerMemoryIntensiveTool(s *server.MCPServer) {
|
||||
tool := mcp.NewTool("memory_intensive",
|
||||
mcp.WithDescription("Allocates specified amount of memory to test resource limits"),
|
||||
mcp.WithNumber("size_mb",
|
||||
mcp.Required(),
|
||||
mcp.Description("Amount of memory to allocate in megabytes"),
|
||||
),
|
||||
)
|
||||
|
||||
s.AddTool(tool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var args struct {
|
||||
SizeMB int `json:"size_mb"`
|
||||
}
|
||||
|
||||
// Get arguments using the proper method
|
||||
argsInterface := request.GetArguments()
|
||||
|
||||
// Marshal and unmarshal to convert to our struct
|
||||
argsBytes, err := json.Marshal(argsInterface)
|
||||
if err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Failed to marshal arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(argsBytes, &args); err != nil {
|
||||
return mcp.NewToolResultError(fmt.Sprintf("Invalid arguments: %v", err)), nil
|
||||
}
|
||||
|
||||
// Limit to reasonable size to prevent crashes
|
||||
if args.SizeMB > 100 {
|
||||
return mcp.NewToolResultError("Size limited to 100MB for safety"), nil
|
||||
}
|
||||
|
||||
// Allocate memory (use int64 to prevent overflow)
|
||||
sizeBytes := int64(args.SizeMB) * 1024 * 1024
|
||||
data := make([]byte, sizeBytes)
|
||||
|
||||
// Fill with pattern to ensure allocation
|
||||
for i := range data {
|
||||
data[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
// Calculate checksum to verify allocation
|
||||
var checksum uint64
|
||||
for _, b := range data {
|
||||
checksum += uint64(b)
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"allocated_mb": args.SizeMB,
|
||||
"allocated_bytes": sizeBytes,
|
||||
"checksum": checksum,
|
||||
"message": fmt.Sprintf("Successfully allocated %dMB", args.SizeMB),
|
||||
}
|
||||
|
||||
// Clear memory before returning
|
||||
data = nil
|
||||
|
||||
jsonResult, _ := json.Marshal(response)
|
||||
return mcp.NewToolResultText(string(jsonResult)), nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user