返回 DeepSeek-Reasonix
mcp_dynamic_tools.go
根目录 / internal / agent / mcp_dynamic_tools.go
1 package agent
2
3 import (
4 "encoding/json"
5 "strings"
6
7 "reasonix/internal/plugin"
8 "reasonix/internal/tool"
9 )
10
11 func (r *MCPCapabilityRuntime) syncRegistryInventory(previous, next map[string]mcpRuntimeServer) {
12 for name := range previous {
13 if _, ok := next[name]; ok {
14 continue
15 }
16 r.setRegistryServerEnabled(name, false)
17 r.state.clearServer(name)
18 }
19 for name, server := range next {
20 r.setRegistryServerEnabled(name, server.enabled)
21 if !server.enabled {
22 r.state.clearServer(name)
23 }
24 }
25 }
26
27 func (r *MCPCapabilityRuntime) setRegistryServerEnabled(name string, enabled bool) {
28 if r == nil || r.registry == nil {
29 return
30 }
31 prefix := plugin.ToolPrefix(name)
32 if enabled {
33 r.registry.ResumePrefix(prefix)
34 return
35 }
36 r.registry.SuspendPrefix(prefix)
37 }
38
39 func (r *MCPCapabilityRuntime) applyToolListChange(spec plugin.Spec, tools []tool.Tool) {
40 if r == nil {
41 return
42 }
43 name := strings.TrimSpace(spec.Name)
44 r.dispatchMu.Lock()
45 r.mu.RLock()
46 configured, ok := r.servers[name]
47 r.mu.RUnlock()
48 if !ok || !configured.enabled || !plugin.MCPRuntimeSpecMatches(configured.spec, spec) {
49 r.dispatchMu.Unlock()
50 return
51 }
52 if r.registry != nil {
53 r.registry.RemovePrefix(plugin.ToolPrefix(name))
54 for _, candidate := range tools {
55 if candidate != nil && plugin.MCPToolMatchesSpec(candidate, configured.spec) {
56 r.registry.Add(candidate)
57 }
58 }
59 }
60 r.state.markConnected(name)
61 r.state.setLiveTools(name, snapshotMCPTools(tools))
62 r.dispatchMu.Unlock()
63 r.notifyToolListChanged(name, tools)
64 }
65
66 func snapshotMCPTools(tools []tool.Tool) []plugin.CachedTool {
67 snapshot := make([]plugin.CachedTool, 0, len(tools))
68 for _, candidate := range tools {
69 metadata, ok := candidate.(tool.MCPMetadata)
70 if !ok || metadata.MCPRawToolName() == "" {
71 continue
72 }
73 snapshot = append(snapshot, plugin.CachedTool{
74 Name: metadata.MCPRawToolName(),
75 Description: candidate.Description(),
76 Schema: candidate.Schema(),
77 ReadOnly: candidate.ReadOnly(),
78 Destructive: mcpDestructiveHint(candidate),
79 })
80 }
81 return snapshot
82 }
83
84 func (t *UseCapabilityTool) resolveUnconnectedMCPCall(id string, args json.RawMessage, base tool.ResolvedCall, spec plugin.Spec, server, raw, modelName string) tool.ResolvedCall {
85 destructive := false
86 if t.catalog != nil {
87 if entry, found := t.catalog().Lookup(id); found {
88 destructive = entry.Destructive
89 }
90 }
91 readOnly := false
92 var schema json.RawMessage
93 if cached, _, found := t.localMCPTool(server, raw); found {
94 destructive = destructive || cached.Destructive
95 readOnly = cached.ReadOnly
96 schema = cached.Schema
97 } else if cached, found := plugin.CachedToolSafetyForSpec(spec, raw); found {
98 destructive = destructive || cached.Destructive
99 readOnly = cached.ReadOnly
100 }
101 lazy := &onDemandMCPTool{proxy: t, spec: spec, server: server, raw: raw, modelName: modelName, destructive: destructive, readOnly: readOnly, schema: schema}
102 base.Target = lazy
103 base.TargetName = modelName
104 base.ReadOnly = lazy.ReadOnly()
105 if len(args) == 0 {
106 base.Args = json.RawMessage(`{}`)
107 } else {
108 base.Args = args
109 }
110 return base
111 }
112
112 lines GO