mcp-bridge/test/adapter/main.go

129 lines
3.3 KiB
Go

package main
import (
"context"
"encoding/json"
"log"
"os"
"os/signal"
"syscall"
"github.com/creachadair/jrpc2"
"github.com/creachadair/jrpc2/channel"
"github.com/creachadair/jrpc2/handler"
)
// EchoRequest is the request structure for the echo method
type EchoRequest struct {
Message string `json:"message"`
}
// EchoResponse is the response structure for the echo method
type EchoResponse struct {
Message string `json:"message"`
Status string `json:"status"`
}
// Echo is a simple method that echoes back the message
func Echo(ctx context.Context, req *EchoRequest) (*EchoResponse, error) {
log.Printf("Echo method called with message: %s", req.Message)
return &EchoResponse{
Message: req.Message,
Status: "success",
}, nil
}
// ErrorRequest is the request structure for the error method
type ErrorRequest struct {
Code int `json:"code"`
Message string `json:"message"`
}
// Error is a method that always returns an error
func Error(ctx context.Context, req *ErrorRequest) (interface{}, error) {
log.Printf("Error method called with code: %d, message: %s", req.Code, req.Message)
return nil, &jrpc2.Error{
Code: jrpc2.Code(req.Code),
Message: req.Message,
}
}
// Sum calculates the sum of an array of numbers
func Sum(ctx context.Context, numbers []float64) (float64, error) {
log.Printf("Sum method called with numbers: %v", numbers)
var sum float64
for _, num := range numbers {
sum += num
}
return sum, nil
}
// ToolsCallRequest handles a tools/call request
type ToolsCallRequest struct {
Name string `json:"name"`
Parameters json.RawMessage `json:"parameters"`
}
type ToolsCallResponse struct {
Result json.RawMessage `json:"result"`
}
// ToolsCall handles a tools/call request
func ToolsCall(ctx context.Context, req *ToolsCallRequest) (*ToolsCallResponse, error) {
log.Printf("tools/call method called with name: %s, parameters: %s", req.Name, string(req.Parameters))
// Echo back the parameters as the result
return &ToolsCallResponse{
Result: req.Parameters,
}, nil
}
func main() {
// Set up signal handling for graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
log.Printf("Received signal %v, shutting down...", sig)
cancel()
}()
// Create a JSON-RPC server that communicates over stdin/stdout
log.Println("Starting mock MCP adapter")
// Define the methods
methods := map[string]handler.Func{
"echo": handler.New(Echo),
"error": handler.New(Error),
"sum": handler.New(Sum),
"tools/call": handler.New(ToolsCall),
}
// Create a server with the defined methods
srv := jrpc2.NewServer(handler.Map(methods), &jrpc2.ServerOptions{
AllowPush: true,
Logger: jrpc2.StdLogger(log.New(os.Stderr, "[jrpc2] ", log.LstdFlags)),
})
// Create a channel for communication over stdin/stdout
ch := channel.Line(os.Stdin, os.Stdout)
// Start the server and wait for it to exit
log.Println("Server ready to handle requests")
if err := srv.Start(ch); err != nil {
log.Fatalf("Server failed to start: %v", err)
}
// Wait for the server to exit or for context cancellation
select {
case <-ctx.Done():
log.Println("Context canceled, shutting down server")
srv.Stop()
}
log.Println("Server exited gracefully")
}