mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
fix(studio): keep uvx version pins out of MCP server names
This commit is contained in:
1 parent
77990ed9eb
commit
da0221a66f
3 files changed
+99
No files matched your search
@@ -177,6 +177,9 @@ func NameFromArgv(command string, args []string) string {
|
||||
}
|
||||
}
|
||||
base := filepath.Base(candidate)
|
||||
if runner == "uvx" {
|
||||
base, _, _ = strings.Cut(base, "==")
|
||||
}
|
||||
if at := strings.Index(base, "@"); at > 0 {
|
||||
base = base[:at]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package mcpsetup
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUVXVersionPinDoesNotChangeDerivedServerName(t *testing.T) {
|
||||
for _, spec := range []string{"demo-server", "[email protected]", "demo-server==1.2.0", "demo-server==2.0.0", "demo-server==1.2.0.post1", "demo-server==1.2.0+local"} {
|
||||
t.Run(spec, func(t *testing.T) {
|
||||
args := []string{"--python", "3.12", spec, "--stdio"}
|
||||
draft, err := Parse("uvx --python 3.12 " + spec + " --stdio")
|
||||
if err != nil || len(draft.Entries) != 1 {
|
||||
t.Fatalf("Parse = %+v, %v", draft, err)
|
||||
}
|
||||
e := draft.Entries[0]
|
||||
if e.Name != "demo-server" || e.Command != "uvx" || !reflect.DeepEqual(e.Args, args) {
|
||||
t.Errorf("pasted version pin = %+v, want package name and unchanged argv", e)
|
||||
}
|
||||
cli, err := ParseArgs(append([]string{"--", "uvx"}, args...))
|
||||
if err != nil || !reflect.DeepEqual(cli, e) {
|
||||
t.Errorf("CLI entry = %+v, %v; want %+v", cli, err, e)
|
||||
}
|
||||
if got := NameFromArgv("uvx", args); got != "demo-server" {
|
||||
t.Errorf("NameFromArgv = %q, want demo-server", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
if got := NameFromArgv("custom", []string{"demo-server==1.2.0"}); got != "custom" {
|
||||
t.Errorf("custom command name = %q", got)
|
||||
}
|
||||
if e, err := ParseArgs([]string{"chosen", "uvx", "demo-server==1.2.0"}); err != nil || e.Name != "chosen" {
|
||||
t.Errorf("explicit server name = %+v, %v", e, err)
|
||||
}
|
||||
if got := NameFromArgv("uvx", nil); got != "mcp-server" {
|
||||
t.Errorf("uvx without an operand = %q", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package serve
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"reasonix/internal/contract/config"
|
||||
"reasonix/internal/ext/mcpregistry"
|
||||
"reasonix/internal/session/control"
|
||||
)
|
||||
|
||||
func TestMCPParseKeepsRegistryPyPIPackageIdentity(t *testing.T) {
|
||||
registry := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/v0.1/servers" || r.URL.Query().Get("version") != "latest" {
|
||||
t.Errorf("registry request = %s", r.URL)
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"servers":[{"server":{"name":"io.example/demo-server","version":"1.2.0","packages":[{"registryType":"pypi","identifier":"demo-server","version":"1.2.0","transport":{"type":"stdio"}}]}}]}`))
|
||||
}))
|
||||
t.Cleanup(registry.Close)
|
||||
client := mcpregistry.New("")
|
||||
client.BaseURL = registry.URL
|
||||
entry, _, err := client.Resolve(t.Context(), "io.example/demo-server")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
configured, err := entry.PluginEntry("")
|
||||
if err != nil || configured.Command != "uvx" || !reflect.DeepEqual(configured.Args, []string{"demo-server==1.2.0"}) {
|
||||
t.Fatalf("registry configuration = %+v, %v", configured, err)
|
||||
}
|
||||
input := configured.Command + " " + strings.Join(configured.Args, " ")
|
||||
ctrl := control.New(control.Options{})
|
||||
t.Cleanup(ctrl.Close)
|
||||
srv := httptest.NewServer(operatorHandler(New(ctrl, NewBroadcaster(), config.ServeConfig{})))
|
||||
t.Cleanup(srv.Close)
|
||||
resp := postJSON(t, srv.URL+"/mcp/parse", map[string]string{"input": input})
|
||||
defer resp.Body.Close()
|
||||
var got struct {
|
||||
Servers []draftServer `json:"servers"`
|
||||
Risks []draftRisk `json:"risks"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&got); err != nil || resp.StatusCode != http.StatusOK || len(got.Servers) != 1 {
|
||||
t.Fatalf("preview: status=%d body=%+v err=%v", resp.StatusCode, got, err)
|
||||
}
|
||||
e := got.Servers[0]
|
||||
if e.Name != configured.Name || e.Transport != "stdio" || e.Command != configured.Command || !reflect.DeepEqual(e.Args, configured.Args) {
|
||||
t.Errorf("preview = %+v, want registry identity %q and exact pinned command", e, configured.Name)
|
||||
}
|
||||
if len(got.Risks) != 1 || got.Risks[0].Server != configured.Name || got.Risks[0].Kind != "shell" || got.Risks[0].Detail != input {
|
||||
t.Errorf("preview disclosure = %+v", got.Risks)
|
||||
}
|
||||
if names := ctrl.ConfiguredMCPNames(); len(names) != 0 {
|
||||
t.Errorf("preview installed servers: %v", names)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user