129 lines
3.3 KiB
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")
|
|
}
|