legion-mcp 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -10
- data/CLAUDE.md +19 -7
- data/lib/legion/mcp/catalog_dispatcher.rb +5 -23
- data/lib/legion/mcp/server.rb +7 -108
- data/lib/legion/mcp/tool_adapter.rb +8 -1
- data/lib/legion/mcp/version.rb +1 -1
- metadata +1 -2
- data/lib/legion/mcp/catalog_bridge.rb +0 -66
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f74d80bf3fc37b0b0130f77f38d7b1611c3efa6ab193085022d3aa1462e3ad4
|
|
4
|
+
data.tar.gz: a9ca6d64d2f3c089a787258e4ac88855d9f5d149c22eef1863bfa429157b70ed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd0bf2a74ac997e5ce7db2bee56a6e9d821f6244ba211c41be054700bfeb7037c557079b6616403a4f188193133d2b2087f496a0ea7be43eec96694e6feed9b9
|
|
7
|
+
data.tar.gz: af2d74fa1eeb888753a815af65e9a4527fc00d44dfdf4941abc9955f1da539606f3284413518b0b618bcd50c71894ef5f37750154cbf3f35ae224390a89b4204
|
data/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
# legion-mcp Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
4
|
-
|
|
5
|
-
### Added
|
|
6
|
-
- `Legion::MCP::ToolAdapter` - wraps Tools::Base into MCP::Tool
|
|
7
|
-
- `rebuild_tool_registry` method for dynamic tool registration
|
|
3
|
+
## [0.7.4] - 2026-04-06
|
|
8
4
|
|
|
9
5
|
### Changed
|
|
10
|
-
-
|
|
11
|
-
- `
|
|
12
|
-
- `EmbeddingIndex` uses `Tools::EmbeddingCache` for persistent caching
|
|
13
|
-
- `FunctionDiscovery` delegates to `Tools::Discovery` with double-fire guard
|
|
6
|
+
- `STATIC_TOOLS` renamed to `MCP_SPECIFIC_TOOLS` (6 MCP-only tools)
|
|
7
|
+
- `Catalog::Registry` calls replaced with `Tools::Registry` in catalog_dispatcher
|
|
14
8
|
|
|
15
9
|
### Removed
|
|
16
|
-
-
|
|
10
|
+
- `CatalogBridge` module (replaced by `Tools::Registry`)
|
|
11
|
+
- `dynamic_tool_list`, `dispatch_catalog_tool`, `register_catalog_listener` from server.rb
|
|
12
|
+
- Stale spec files for catalog integration
|
|
17
13
|
|
|
18
14
|
## [0.7.2] - 2026-04-03
|
|
19
15
|
|
data/CLAUDE.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
Standalone gem providing the Model Context Protocol (MCP) server for LegionIO. Extracted from LegionIO to enable independent versioning and reuse. Includes semantic tool matching, observation pipeline, context compilation, tiered inference (Tier 0/1/2), and tool governance.
|
|
8
8
|
|
|
9
9
|
**GitHub**: https://github.com/LegionIO/legion-mcp
|
|
10
|
-
**Version**: 0.
|
|
10
|
+
**Version**: 0.7.4
|
|
11
11
|
**License**: Apache-2.0
|
|
12
12
|
**Ruby**: >= 3.4
|
|
13
13
|
|
|
@@ -15,20 +15,30 @@ Standalone gem providing the Model Context Protocol (MCP) server for LegionIO. E
|
|
|
15
15
|
|
|
16
16
|
```
|
|
17
17
|
Legion::MCP
|
|
18
|
-
├── Server # MCP::Server builder,
|
|
18
|
+
├── Server # MCP::Server builder, governance-aware build; tool list sourced from Legion::Tools::Registry via DeferredRegistry
|
|
19
19
|
├── Auth # JWT + API key authentication
|
|
20
20
|
├── ToolGovernance # Risk-tier tool filtering + invocation audit
|
|
21
21
|
├── ContextCompiler # Keyword + semantic tool matching, blended scoring (60% semantic + 40% keyword)
|
|
22
|
-
├── EmbeddingIndex #
|
|
22
|
+
├── EmbeddingIndex # Semantic tool matching; delegates embedding persistence to Tools::EmbeddingCache (L0-L4)
|
|
23
23
|
├── Observer # Instrumentation pipeline: counters, ring buffer, pattern promotion
|
|
24
24
|
├── UsageFilter # Frequency/recency/keyword scoring for dynamic tool filtering
|
|
25
25
|
├── PatternStore # 4-layer degrading storage (L0 memory, L1 cache, L2 local SQLite)
|
|
26
26
|
├── TierRouter # Confidence-gated tier selection (Tier 0/1/2)
|
|
27
27
|
├── ContextGuard # Staleness, rapid-fire, anomaly detection guards
|
|
28
|
-
├──
|
|
28
|
+
├── ToolAdapter # Adapts Legion::Tools::Base subclasses to MCP SDK format (McpToolAdapter kept as alias)
|
|
29
|
+
├── DeferredRegistry # Reads deferred tools from Legion::Tools::Registry at request time
|
|
30
|
+
├── Tools/ # MCP_SPECIFIC_TOOLS only (6 registered); remaining tool files exist but are not registered in Server.tool_registry — extension tools discovered via Legion::Tools::Discovery
|
|
29
31
|
└── Resources/ # RunnerCatalog, ExtensionInfo
|
|
30
32
|
```
|
|
31
33
|
|
|
34
|
+
### Tool Registry Migration Notes
|
|
35
|
+
|
|
36
|
+
- **Before**: legion-mcp owned 57+ individual `Tools/*.rb` files registered in `TOOL_CLASSES`.
|
|
37
|
+
- **After**: Tools discovered dynamically via `Legion::Tools::Discovery` from extension `runner_modules` at boot. `Legion::Tools::Registry` classifies each as `:always` or `:deferred`. `DeferredRegistry` resolves the deferred set at request time.
|
|
38
|
+
- `MCP_SPECIFIC_TOOLS` (6 tools) covers MCP-only concerns not owned by any extension.
|
|
39
|
+
- `CatalogBridge` removed — bridged old `Extensions::Capability` / `Catalog::Registry` which no longer exist.
|
|
40
|
+
- `EmbeddingIndex` uses `Legion::Tools::EmbeddingCache` (5-tier L0–L4) instead of its own in-memory store.
|
|
41
|
+
|
|
32
42
|
## Dependencies
|
|
33
43
|
|
|
34
44
|
| Gem | Required | Purpose |
|
|
@@ -65,17 +75,19 @@ All optional dependencies use `defined?()` guards:
|
|
|
65
75
|
|------|---------|
|
|
66
76
|
| `lib/legion/mcp.rb` | Entry point: `Legion::MCP.server` singleton factory |
|
|
67
77
|
| `lib/legion/mcp/version.rb` | `Legion::MCP::VERSION` constant |
|
|
68
|
-
| `lib/legion/mcp/server.rb` | MCP::Server builder,
|
|
78
|
+
| `lib/legion/mcp/server.rb` | MCP::Server builder, governance-aware build; reads tools from Tools::Registry |
|
|
69
79
|
| `lib/legion/mcp/auth.rb` | JWT + API key authentication |
|
|
70
80
|
| `lib/legion/mcp/tool_governance.rb` | Risk-tier tool filtering + invocation audit |
|
|
71
81
|
| `lib/legion/mcp/context_compiler.rb` | Keyword + semantic tool matching (60/40 blend) |
|
|
72
|
-
| `lib/legion/mcp/embedding_index.rb` |
|
|
82
|
+
| `lib/legion/mcp/embedding_index.rb` | Semantic tool matching; delegates persistence to Legion::Tools::EmbeddingCache |
|
|
73
83
|
| `lib/legion/mcp/observer.rb` | Instrumentation: counters, ring buffer, pattern promotion |
|
|
74
84
|
| `lib/legion/mcp/usage_filter.rb` | Frequency/recency/keyword scoring for dynamic tool filtering |
|
|
75
85
|
| `lib/legion/mcp/pattern_store.rb` | 4-layer degrading storage (L0/L1/L2) with thread-safe access |
|
|
76
86
|
| `lib/legion/mcp/tier_router.rb` | Confidence-gated tier selection, tool chain execution |
|
|
77
87
|
| `lib/legion/mcp/context_guard.rb` | Staleness, rapid-fire, anomaly detection |
|
|
78
|
-
| `lib/legion/mcp/
|
|
88
|
+
| `lib/legion/mcp/tool_adapter.rb` | MCP::ToolAdapter — wraps Legion::Tools::Base for MCP SDK (McpToolAdapter kept as alias) |
|
|
89
|
+
| `lib/legion/mcp/deferred_registry.rb` | DeferredRegistry — reads deferred tools from Legion::Tools::Registry at request time |
|
|
90
|
+
| `lib/legion/mcp/tools/` | All tool implementations; only MCP_SPECIFIC_TOOLS (6 tools) registered in Server.tool_registry — extension tools sourced via Legion::Tools::Discovery |
|
|
79
91
|
| `lib/legion/mcp/tools/do_action.rb` | Natural language intent routing with Tier 0 fast path |
|
|
80
92
|
| `lib/legion/mcp/tools/discover_tools.rb` | Dynamic tool discovery with context |
|
|
81
93
|
| `lib/legion/mcp/tools/run_task.rb` | Execute runner function via dot notation |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'logging_support'
|
|
4
|
+
require_relative 'tool_adapter'
|
|
4
5
|
|
|
5
6
|
module Legion
|
|
6
7
|
module MCP
|
|
@@ -113,35 +114,16 @@ module Legion
|
|
|
113
114
|
end
|
|
114
115
|
|
|
115
116
|
def generate_tools_from_catalog
|
|
116
|
-
return [] unless defined?(Legion::
|
|
117
|
-
return [] unless Legion::
|
|
117
|
+
return [] unless defined?(Legion::Tools::Registry)
|
|
118
|
+
return [] unless Legion::Tools::Registry.respond_to?(:all_tools)
|
|
118
119
|
|
|
119
|
-
Legion::
|
|
120
|
-
|
|
121
|
-
build_tool_class(
|
|
122
|
-
runner_class: resolve_runner_class(cap),
|
|
123
|
-
function: cap.function,
|
|
124
|
-
tool_name: sanitize_tool_name(raw_name),
|
|
125
|
-
description: cap.respond_to?(:description) ? cap.description : "Auto-generated: #{cap.function}",
|
|
126
|
-
input_schema: cap.respond_to?(:input_schema) ? cap.input_schema : { properties: {} },
|
|
127
|
-
category: cap.respond_to?(:category) ? cap.category : nil,
|
|
128
|
-
tier: cap.respond_to?(:tier) ? cap.tier : nil
|
|
129
|
-
)
|
|
120
|
+
Legion::Tools::Registry.all_tools.filter_map do |tool_class|
|
|
121
|
+
ToolAdapter.from_legion_tool(tool_class) if defined?(ToolAdapter) && ToolAdapter.respond_to?(:from_legion_tool)
|
|
130
122
|
rescue StandardError => e
|
|
131
123
|
handle_exception(e, level: :debug, operation: 'legion.mcp.catalog_dispatcher.generate_tools_from_catalog')
|
|
132
|
-
log.debug("CatalogDispatcher: skipping #{cap}: #{e.message}")
|
|
133
124
|
nil
|
|
134
125
|
end
|
|
135
126
|
end
|
|
136
|
-
|
|
137
|
-
def resolve_runner_class(cap)
|
|
138
|
-
segments = cap.extension.delete_prefix('lex-').split('-')
|
|
139
|
-
(%w[Legion Extensions] + segments.map(&:capitalize) + ['Runners', cap.runner]).join('::')
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def sanitize_tool_name(name)
|
|
143
|
-
name.gsub(/[^A-Za-z0-9_.-]/, '')
|
|
144
|
-
end
|
|
145
127
|
end
|
|
146
128
|
end
|
|
147
129
|
end
|
data/lib/legion/mcp/server.rb
CHANGED
|
@@ -17,82 +17,24 @@ require_relative 'tool_quality'
|
|
|
17
17
|
require_relative 'deferred_registry'
|
|
18
18
|
require_relative 'catalog_dispatcher'
|
|
19
19
|
require_relative 'dynamic_injector'
|
|
20
|
-
require_relative 'catalog_bridge'
|
|
21
20
|
require_relative 'resources/runner_catalog'
|
|
22
21
|
require_relative 'resources/extension_info'
|
|
23
22
|
|
|
24
23
|
module Legion
|
|
25
24
|
module MCP
|
|
26
|
-
module Server
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Tools::DescribeRunner,
|
|
31
|
-
Tools::ListTasks,
|
|
32
|
-
Tools::GetTask,
|
|
33
|
-
Tools::DeleteTask,
|
|
34
|
-
Tools::GetTaskLogs,
|
|
35
|
-
Tools::ListChains,
|
|
36
|
-
Tools::CreateChain,
|
|
37
|
-
Tools::UpdateChain,
|
|
38
|
-
Tools::DeleteChain,
|
|
39
|
-
Tools::ListRelationships,
|
|
40
|
-
Tools::CreateRelationship,
|
|
41
|
-
Tools::UpdateRelationship,
|
|
42
|
-
Tools::DeleteRelationship,
|
|
43
|
-
Tools::ListExtensions,
|
|
44
|
-
Tools::GetExtension,
|
|
45
|
-
Tools::EnableExtension,
|
|
46
|
-
Tools::DisableExtension,
|
|
47
|
-
Tools::ListSchedules,
|
|
48
|
-
Tools::CreateSchedule,
|
|
49
|
-
Tools::UpdateSchedule,
|
|
50
|
-
Tools::DeleteSchedule,
|
|
51
|
-
Tools::GetStatus,
|
|
52
|
-
Tools::GetConfig,
|
|
53
|
-
Tools::ListWorkers,
|
|
54
|
-
Tools::ShowWorker,
|
|
55
|
-
Tools::WorkerLifecycle,
|
|
56
|
-
Tools::WorkerCosts,
|
|
57
|
-
Tools::TeamSummary,
|
|
58
|
-
Tools::RoutingStats,
|
|
59
|
-
Tools::RbacCheck,
|
|
60
|
-
Tools::RbacAssignments,
|
|
61
|
-
Tools::RbacGrants,
|
|
62
|
-
Tools::PromptList,
|
|
63
|
-
Tools::PromptShow,
|
|
64
|
-
Tools::PromptRun,
|
|
65
|
-
Tools::DatasetList,
|
|
66
|
-
Tools::DatasetShow,
|
|
67
|
-
Tools::ExperimentResults,
|
|
68
|
-
Tools::EvalList,
|
|
69
|
-
Tools::EvalRun,
|
|
70
|
-
Tools::EvalResults,
|
|
71
|
-
Tools::DoAction,
|
|
25
|
+
module Server
|
|
26
|
+
# MCP-specific tools not owned by any extension.
|
|
27
|
+
# All extension-owned tools are discovered via Legion::Tools::Registry.
|
|
28
|
+
MCP_SPECIFIC_TOOLS = [
|
|
72
29
|
Tools::PlanAction,
|
|
73
30
|
Tools::DiscoverTools,
|
|
74
|
-
Tools::AskPeer,
|
|
75
|
-
Tools::ListPeers,
|
|
76
|
-
Tools::NotifyPeer,
|
|
77
|
-
Tools::BroadcastPeers,
|
|
78
|
-
Tools::MeshStatus,
|
|
79
|
-
Tools::MindGrowthStatus,
|
|
80
|
-
Tools::MindGrowthPropose,
|
|
81
|
-
Tools::MindGrowthApprove,
|
|
82
|
-
Tools::MindGrowthBuildQueue,
|
|
83
|
-
Tools::MindGrowthCognitiveProfile,
|
|
84
|
-
Tools::MindGrowthHealth,
|
|
85
|
-
Tools::QueryKnowledge,
|
|
86
|
-
Tools::KnowledgeHealth,
|
|
87
|
-
Tools::KnowledgeContext,
|
|
88
|
-
Tools::Absorb,
|
|
89
31
|
Tools::StructuralIndexTool,
|
|
90
32
|
Tools::ToolAudit,
|
|
91
33
|
Tools::StateDiff,
|
|
92
34
|
Tools::SearchSessions
|
|
93
35
|
].freeze
|
|
94
36
|
|
|
95
|
-
@tool_registry = Concurrent::Array.new(
|
|
37
|
+
@tool_registry = Concurrent::Array.new(MCP_SPECIFIC_TOOLS)
|
|
96
38
|
@tool_registry_lock = Mutex.new
|
|
97
39
|
|
|
98
40
|
class << self # rubocop:disable Metrics/ClassLength
|
|
@@ -100,7 +42,7 @@ module Legion
|
|
|
100
42
|
|
|
101
43
|
def rebuild_tool_registry
|
|
102
44
|
@tool_registry_lock.synchronize do
|
|
103
|
-
@tool_registry = Concurrent::Array.new(
|
|
45
|
+
@tool_registry = Concurrent::Array.new(MCP_SPECIFIC_TOOLS)
|
|
104
46
|
|
|
105
47
|
if defined?(Legion::Tools::Registry) && Legion::Tools::Registry.respond_to?(:all_tools)
|
|
106
48
|
Legion::Tools::Registry.all_tools.each do |legion_tool_class|
|
|
@@ -148,8 +90,8 @@ module Legion
|
|
|
148
90
|
end
|
|
149
91
|
|
|
150
92
|
def build(identity: nil) # rubocop:disable Metrics/MethodLength
|
|
93
|
+
run_function_discovery
|
|
151
94
|
rebuild_tool_registry
|
|
152
|
-
register_catalog_listener
|
|
153
95
|
|
|
154
96
|
LoggingSupport.info(
|
|
155
97
|
'server.build.start',
|
|
@@ -182,7 +124,6 @@ module Legion
|
|
|
182
124
|
|
|
183
125
|
PatternStore.hydrate_from_l2 if defined?(PatternStore)
|
|
184
126
|
ColdStart.load_community_patterns if defined?(ColdStart)
|
|
185
|
-
run_function_discovery
|
|
186
127
|
populate_embedding_index
|
|
187
128
|
|
|
188
129
|
Resources::RunnerCatalog.register(server)
|
|
@@ -263,48 +204,6 @@ module Legion
|
|
|
263
204
|
end
|
|
264
205
|
end
|
|
265
206
|
|
|
266
|
-
def dynamic_tool_list
|
|
267
|
-
static = tool_registry.map do |klass|
|
|
268
|
-
{ name: klass.tool_name, description: klass.description,
|
|
269
|
-
input_schema: klass.input_schema, source: :builtin, klass: klass }
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
dynamic = if defined?(Legion::Extensions::Catalog::Registry)
|
|
273
|
-
Legion::Extensions::Catalog::Registry.for_mcp.map(&:to_mcp_tool)
|
|
274
|
-
else
|
|
275
|
-
[]
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
static + dynamic
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
def dispatch_catalog_tool(tool_name, arguments)
|
|
282
|
-
return nil unless defined?(Legion::Extensions::Catalog::Registry)
|
|
283
|
-
|
|
284
|
-
cap = Legion::Extensions::Catalog::Registry.find_by_mcp_name(tool_name)
|
|
285
|
-
return nil unless cap
|
|
286
|
-
|
|
287
|
-
segments = cap.extension.delete_prefix('lex-').split('-')
|
|
288
|
-
runner_path = (%w[Legion Extensions] + segments.map(&:capitalize) + ['Runners', cap.runner]).join('::')
|
|
289
|
-
runner = Kernel.const_get(runner_path)
|
|
290
|
-
fn = cap.function.to_sym
|
|
291
|
-
result = runner.send(fn, **(arguments || {}).transform_keys(&:to_sym))
|
|
292
|
-
{ status: :success, result: result, source: :catalog }
|
|
293
|
-
rescue NameError => e
|
|
294
|
-
handle_exception(e, level: :warn, operation: 'legion.mcp.server.dispatch_catalog_tool')
|
|
295
|
-
nil
|
|
296
|
-
rescue StandardError => e
|
|
297
|
-
handle_exception(e, level: :error, operation: 'legion.mcp.server.dispatch_catalog_tool')
|
|
298
|
-
{ status: :error, error: e.message, source: :catalog }
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def register_catalog_listener
|
|
302
|
-
return unless defined?(Legion::Extensions::Catalog::Registry)
|
|
303
|
-
return unless Legion::Extensions::Catalog::Registry.respond_to?(:on_change)
|
|
304
|
-
|
|
305
|
-
Legion::Extensions::Catalog::Registry.on_change { Legion::MCP.reset! }
|
|
306
|
-
end
|
|
307
|
-
|
|
308
207
|
private
|
|
309
208
|
|
|
310
209
|
def run_function_discovery
|
|
@@ -4,9 +4,16 @@ module Legion
|
|
|
4
4
|
module MCP
|
|
5
5
|
class ToolAdapter < ::MCP::Tool
|
|
6
6
|
class << self
|
|
7
|
+
MCP_NAME_PATTERN = /[^a-zA-Z0-9_-]/
|
|
8
|
+
|
|
9
|
+
def sanitize_tool_name(name)
|
|
10
|
+
name.to_s.gsub(MCP_NAME_PATTERN, '_').slice(0, 64)
|
|
11
|
+
end
|
|
12
|
+
|
|
7
13
|
def from_legion_tool(tool_class)
|
|
14
|
+
safe_name = sanitize_tool_name(tool_class.tool_name)
|
|
8
15
|
Class.new(::MCP::Tool) do
|
|
9
|
-
tool_name
|
|
16
|
+
tool_name safe_name
|
|
10
17
|
description tool_class.description
|
|
11
18
|
input_schema(tool_class.input_schema || { properties: {} })
|
|
12
19
|
|
data/lib/legion/mcp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-mcp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -122,7 +122,6 @@ files:
|
|
|
122
122
|
- lib/legion/mcp.rb
|
|
123
123
|
- lib/legion/mcp/actors/self_generate_cycle.rb
|
|
124
124
|
- lib/legion/mcp/auth.rb
|
|
125
|
-
- lib/legion/mcp/catalog_bridge.rb
|
|
126
125
|
- lib/legion/mcp/catalog_dispatcher.rb
|
|
127
126
|
- lib/legion/mcp/client.rb
|
|
128
127
|
- lib/legion/mcp/client/connection.rb
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Legion
|
|
4
|
-
module MCP
|
|
5
|
-
module CatalogBridge
|
|
6
|
-
include Legion::Logging::Helper
|
|
7
|
-
|
|
8
|
-
def hydrate_override_confidence
|
|
9
|
-
return unless defined?(Legion::LLM::OverrideConfidence)
|
|
10
|
-
return unless Legion::LLM::OverrideConfidence.respond_to?(:hydrate_from_l2)
|
|
11
|
-
|
|
12
|
-
Legion::LLM::OverrideConfidence.hydrate_from_l2
|
|
13
|
-
Legion::LLM::OverrideConfidence.hydrate_from_apollo if Legion::LLM::OverrideConfidence.respond_to?(:hydrate_from_apollo)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def register_catalog_listener
|
|
17
|
-
return unless defined?(Legion::Extensions::Catalog::Registry)
|
|
18
|
-
return unless Legion::Extensions::Catalog::Registry.respond_to?(:on_change)
|
|
19
|
-
|
|
20
|
-
Legion::Extensions::Catalog::Registry.on_change { Legion::MCP.reset! }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def dispatch_catalog_tool(tool_name, arguments)
|
|
24
|
-
log.info('Starting legion.mcp.catalog_bridge.dispatch_catalog_tool')
|
|
25
|
-
return nil unless defined?(Legion::Extensions::Catalog::Registry)
|
|
26
|
-
|
|
27
|
-
cap = Legion::Extensions::Catalog::Registry.find_by_mcp_name(tool_name)
|
|
28
|
-
return nil unless cap
|
|
29
|
-
|
|
30
|
-
segments = cap.extension.delete_prefix('lex-').split('-')
|
|
31
|
-
runner_path = (%w[Legion Extensions] + segments.map(&:capitalize) + ['Runners', cap.runner]).join('::')
|
|
32
|
-
runner = Kernel.const_get(runner_path)
|
|
33
|
-
fn = cap.function.to_sym
|
|
34
|
-
result = runner.send(fn, **(arguments || {}).transform_keys(&:to_sym))
|
|
35
|
-
{ status: :success, result: result, source: :catalog }
|
|
36
|
-
rescue NameError => e
|
|
37
|
-
handle_exception(e, level: :warn, operation: 'legion.mcp.catalog_bridge.dispatch_catalog_tool')
|
|
38
|
-
log.warn("Catalog dispatch failed: #{e.message}")
|
|
39
|
-
nil
|
|
40
|
-
rescue StandardError => e
|
|
41
|
-
handle_exception(e, level: :error, operation: 'legion.mcp.catalog_bridge.dispatch_catalog_tool')
|
|
42
|
-
{ status: :error, error: e.message, source: :catalog }
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def register_catalog_tools
|
|
46
|
-
log.info('Starting legion.mcp.catalog_bridge.register_catalog_tools')
|
|
47
|
-
CatalogDispatcher.generate_tools_from_catalog.each { |tc| Server.register_tool(tc) }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def dynamic_tool_list
|
|
51
|
-
static = Server.tool_registry.map do |klass|
|
|
52
|
-
{ name: klass.tool_name, description: klass.description,
|
|
53
|
-
input_schema: klass.input_schema, source: :builtin, klass: klass }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
dynamic = if defined?(Legion::Extensions::Catalog::Registry)
|
|
57
|
-
Legion::Extensions::Catalog::Registry.for_mcp.map(&:to_mcp_tool)
|
|
58
|
-
else
|
|
59
|
-
[]
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
static + dynamic
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|