feat: centrally mount and dispatch agent MCP services
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMCPRuntimeStdioOnDemand(t *testing.T) {
|
||||
if _, err := exec.LookPath("python3"); err != nil {
|
||||
t.Skip("python3 unavailable")
|
||||
}
|
||||
dir := t.TempDir()
|
||||
script := dir + "/mcp.py"
|
||||
code := `import json,sys
|
||||
for line in sys.stdin:
|
||||
r=json.loads(line)
|
||||
if r.get("method")=="initialize":
|
||||
print(json.dumps({"jsonrpc":"2.0","id":r["id"],"result":{"protocolVersion":"2024-11-05"}}),flush=True)
|
||||
elif r.get("method")=="tools/call":
|
||||
a=r.get("params",{}).get("arguments",{})
|
||||
print(json.dumps({"jsonrpc":"2.0","id":r["id"],"result":{"content":[{"type":"text","text":"hello "+a.get("name","")}]}}),flush=True)
|
||||
`
|
||||
if err := os.WriteFile(script, []byte(code), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := NewMCPRuntime()
|
||||
r.Sync([]MCPService{{ID: "test", Transport: "stdio", Command: "python3", Args: []string{script}}})
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
v, err := r.Call(ctx, "test", "hello", map[string]any{"name": "vpc"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, _ := json.Marshal(v)
|
||||
if string(b) == "" {
|
||||
t.Fatal("empty result")
|
||||
}
|
||||
if !contains(string(b), "hello vpc") {
|
||||
t.Fatalf("unexpected %s", b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCPRuntimeHTTP(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
b, _ := io.ReadAll(r.Body)
|
||||
var q mcpRPC
|
||||
_ = json.Unmarshal(b, &q)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"jsonrpc":"2.0","id":%s,"result":{"ok":true}}`, jsonID(q.ID))
|
||||
}))
|
||||
defer ts.Close()
|
||||
r := NewMCPRuntime()
|
||||
r.Sync([]MCPService{{ID: "http", Transport: "http", URL: ts.URL}})
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
v, err := r.Call(ctx, "http", "ping", map[string]any{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !contains(fmt.Sprint(v), "true") {
|
||||
t.Fatalf("unexpected %v", v)
|
||||
}
|
||||
}
|
||||
func jsonID(v any) string { b, _ := json.Marshal(v); return string(b) }
|
||||
func contains(s, x string) bool {
|
||||
for i := 0; i+len(x) <= len(s); i++ {
|
||||
if s[i:i+len(x)] == x {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user