legion-mcp 0.4.1 → 0.4.2
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 +12 -0
- data/CODEOWNERS +39 -0
- data/lib/legion/mcp/server.rb +11 -1
- data/lib/legion/mcp/tools/ask_peer.rb +56 -0
- data/lib/legion/mcp/tools/broadcast_peers.rb +55 -0
- data/lib/legion/mcp/tools/list_peers.rb +47 -0
- data/lib/legion/mcp/tools/mesh_status.rb +43 -0
- data/lib/legion/mcp/tools/notify_peer.rb +54 -0
- data/lib/legion/mcp/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 423fca2b66220aa4bfd5dce33490a6fb92826da7e999a21be9afed00610fd435
|
|
4
|
+
data.tar.gz: 7e9a664b742ee174140f2463c008bd99475736afe074c056cf298d9742a7ec5d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d610777e7f105a5b72e4a58fb0a06cd129361639837638b49888de9b6feeb3697a5147184d5d415ba95315d2bafcf3011b9a6c5d7515b8ceec3155a8173477a9
|
|
7
|
+
data.tar.gz: 6c74faf7a062f61e8b9e10d79b6236dc9b361d6b5ff657bfe651bfa731f6a633a8c8acaf0a68f907b49cd333c4328d77e919d45a114c8e8b7a40323bbfeb9dac
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# legion-mcp Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.2] - 2026-03-22
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `legion.ask_peer` — synchronous RPC query to a specific mesh peer via `lex-mesh` `request_task`
|
|
7
|
+
- `legion.list_peers` — list all registered mesh agents, with optional capability filter via `find_agents`
|
|
8
|
+
- `legion.notify_peer` — fire-and-forget unicast notification to a specific mesh agent via `send_message`
|
|
9
|
+
- `legion.broadcast_peers` — broadcast to all agents or multicast to a capability group via `send_message`
|
|
10
|
+
- `legion.mesh_status` — retrieve current mesh network state via `mesh_status`
|
|
11
|
+
- All 5 tools registered in `TOOL_CLASSES`; total tool count raised from 45 to 50
|
|
12
|
+
- Specs for all 5 new tools (25 examples)
|
|
13
|
+
- Updated `server_spec.rb` tool count assertion from 45 to 50
|
|
14
|
+
|
|
3
15
|
## [0.4.1] - 2026-03-19
|
|
4
16
|
|
|
5
17
|
### Added
|
data/CODEOWNERS
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Default owner — all files
|
|
2
|
+
* @Esity
|
|
3
|
+
|
|
4
|
+
# Core library code
|
|
5
|
+
# lib/ @Esity @future-ai-team
|
|
6
|
+
|
|
7
|
+
# MCP tools (35 tool subclasses)
|
|
8
|
+
# lib/legion/mcp/tools/ @Esity @future-ai-team
|
|
9
|
+
|
|
10
|
+
# MCP resources
|
|
11
|
+
# lib/legion/mcp/resources/ @Esity @future-ai-team
|
|
12
|
+
|
|
13
|
+
# Tiered Behavioral Intelligence (TBI) — pattern store, tier router, context guard
|
|
14
|
+
# lib/legion/mcp/pattern_store.rb @Esity @future-ai-team
|
|
15
|
+
# lib/legion/mcp/tier_router.rb @Esity @future-ai-team
|
|
16
|
+
# lib/legion/mcp/context_guard.rb @Esity @future-ai-team
|
|
17
|
+
|
|
18
|
+
# Semantic matching and embeddings
|
|
19
|
+
# lib/legion/mcp/context_compiler.rb @Esity @future-ai-team
|
|
20
|
+
# lib/legion/mcp/embedding_index.rb @Esity @future-ai-team
|
|
21
|
+
|
|
22
|
+
# Observer pipeline and usage filter
|
|
23
|
+
# lib/legion/mcp/observer.rb @Esity @future-ai-team
|
|
24
|
+
# lib/legion/mcp/usage_filter.rb @Esity @future-ai-team
|
|
25
|
+
|
|
26
|
+
# Tool governance
|
|
27
|
+
# lib/legion/mcp/tool_governance.rb @Esity @future-security-team
|
|
28
|
+
|
|
29
|
+
# Authentication
|
|
30
|
+
# lib/legion/mcp/auth.rb @Esity @future-security-team
|
|
31
|
+
|
|
32
|
+
# Specs
|
|
33
|
+
# spec/ @Esity @future-contributors
|
|
34
|
+
|
|
35
|
+
# Documentation
|
|
36
|
+
# *.md @Esity @future-docs-team
|
|
37
|
+
|
|
38
|
+
# CI/CD
|
|
39
|
+
# .github/ @Esity
|
data/lib/legion/mcp/server.rb
CHANGED
|
@@ -50,6 +50,11 @@ require_relative 'cold_start'
|
|
|
50
50
|
require_relative 'tools/do_action'
|
|
51
51
|
require_relative 'tools/plan_action'
|
|
52
52
|
require_relative 'tools/discover_tools'
|
|
53
|
+
require_relative 'tools/ask_peer'
|
|
54
|
+
require_relative 'tools/list_peers'
|
|
55
|
+
require_relative 'tools/notify_peer'
|
|
56
|
+
require_relative 'tools/broadcast_peers'
|
|
57
|
+
require_relative 'tools/mesh_status'
|
|
53
58
|
require_relative 'resources/runner_catalog'
|
|
54
59
|
require_relative 'resources/extension_info'
|
|
55
60
|
|
|
@@ -101,7 +106,12 @@ module Legion
|
|
|
101
106
|
Tools::EvalResults,
|
|
102
107
|
Tools::DoAction,
|
|
103
108
|
Tools::PlanAction,
|
|
104
|
-
Tools::DiscoverTools
|
|
109
|
+
Tools::DiscoverTools,
|
|
110
|
+
Tools::AskPeer,
|
|
111
|
+
Tools::ListPeers,
|
|
112
|
+
Tools::NotifyPeer,
|
|
113
|
+
Tools::BroadcastPeers,
|
|
114
|
+
Tools::MeshStatus
|
|
105
115
|
].freeze
|
|
106
116
|
|
|
107
117
|
class << self
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class AskPeer < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.ask_peer'
|
|
8
|
+
description 'Send a synchronous query to a specific mesh peer and return the result.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
to: { type: 'string', description: 'Agent ID or capability name to route to' },
|
|
13
|
+
query: { type: 'string', description: 'The question or request to send to the peer' },
|
|
14
|
+
timeout: { type: 'integer', description: 'Seconds to wait for response (default 30)' }
|
|
15
|
+
},
|
|
16
|
+
required: %w[to query]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def call(to:, query:, timeout: 30)
|
|
21
|
+
return error_response('lex-mesh is not available') unless mesh_available?
|
|
22
|
+
|
|
23
|
+
result = mesh_client.request_task(
|
|
24
|
+
from: 'legion.mcp',
|
|
25
|
+
to: to,
|
|
26
|
+
task: 'query',
|
|
27
|
+
payload: { query: query },
|
|
28
|
+
timeout: timeout
|
|
29
|
+
)
|
|
30
|
+
text_response(result)
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
error_response("Failed to query peer: #{e.message}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def mesh_available?
|
|
38
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def mesh_client
|
|
42
|
+
@mesh_client ||= Legion::Extensions::Mesh::Client.new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def text_response(data)
|
|
46
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def error_response(msg)
|
|
50
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class BroadcastPeers < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.broadcast_peers'
|
|
8
|
+
description 'Broadcast a message to all mesh agents, or multicast to agents with a specific capability.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
message: { type: 'string', description: 'Message content to broadcast' },
|
|
13
|
+
capability: { type: 'string', description: 'If provided, multicast only to agents with this capability' }
|
|
14
|
+
},
|
|
15
|
+
required: %w[message]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def call(message:, capability: nil)
|
|
20
|
+
return error_response('lex-mesh is not available') unless mesh_available?
|
|
21
|
+
|
|
22
|
+
pattern = capability ? :multicast : :broadcast
|
|
23
|
+
result = mesh_client.send_message(
|
|
24
|
+
from: 'legion.mcp',
|
|
25
|
+
to: capability || :all,
|
|
26
|
+
pattern: pattern,
|
|
27
|
+
payload: { message: message }
|
|
28
|
+
)
|
|
29
|
+
text_response(result)
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
error_response("Failed to broadcast: #{e.message}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def mesh_available?
|
|
37
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def mesh_client
|
|
41
|
+
@mesh_client ||= Legion::Extensions::Mesh::Client.new
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def text_response(data)
|
|
45
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def error_response(msg)
|
|
49
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class ListPeers < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.list_peers'
|
|
8
|
+
description 'List all registered mesh agents, optionally filtered by capability.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
capability: { type: 'string', description: 'Filter agents by capability' }
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def call(capability: nil)
|
|
18
|
+
return error_response('lex-mesh is not available') unless mesh_available?
|
|
19
|
+
|
|
20
|
+
result = mesh_client.find_agents(capability: capability)
|
|
21
|
+
text_response(result)
|
|
22
|
+
rescue StandardError => e
|
|
23
|
+
error_response("Failed to list peers: #{e.message}")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def mesh_available?
|
|
29
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mesh_client
|
|
33
|
+
@mesh_client ||= Legion::Extensions::Mesh::Client.new
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def text_response(data)
|
|
37
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def error_response(msg)
|
|
41
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class MeshStatus < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.mesh_status'
|
|
8
|
+
description 'Get current mesh network status including registered agents and topology.'
|
|
9
|
+
|
|
10
|
+
input_schema(properties: {})
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def call
|
|
14
|
+
return error_response('lex-mesh is not available') unless mesh_available?
|
|
15
|
+
|
|
16
|
+
result = mesh_client.mesh_status
|
|
17
|
+
text_response(result)
|
|
18
|
+
rescue StandardError => e
|
|
19
|
+
error_response("Failed to get mesh status: #{e.message}")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def mesh_available?
|
|
25
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def mesh_client
|
|
29
|
+
@mesh_client ||= Legion::Extensions::Mesh::Client.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def text_response(data)
|
|
33
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def error_response(msg)
|
|
37
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class NotifyPeer < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.notify_peer'
|
|
8
|
+
description 'Send a fire-and-forget async notification to a specific mesh agent.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
to: { type: 'string', description: 'Target agent ID' },
|
|
13
|
+
message: { type: 'string', description: 'Notification content to send' }
|
|
14
|
+
},
|
|
15
|
+
required: %w[to message]
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def call(to:, message:)
|
|
20
|
+
return error_response('lex-mesh is not available') unless mesh_available?
|
|
21
|
+
|
|
22
|
+
result = mesh_client.send_message(
|
|
23
|
+
from: 'legion.mcp',
|
|
24
|
+
to: to,
|
|
25
|
+
pattern: :unicast,
|
|
26
|
+
payload: { message: message }
|
|
27
|
+
)
|
|
28
|
+
text_response(result)
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
error_response("Failed to notify peer: #{e.message}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def mesh_available?
|
|
36
|
+
defined?(Legion::Extensions::Mesh::Client)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def mesh_client
|
|
40
|
+
@mesh_client ||= Legion::Extensions::Mesh::Client.new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def text_response(data)
|
|
44
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def error_response(msg)
|
|
48
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
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.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -110,6 +110,7 @@ files:
|
|
|
110
110
|
- ".rubocop.yml"
|
|
111
111
|
- CHANGELOG.md
|
|
112
112
|
- CLAUDE.md
|
|
113
|
+
- CODEOWNERS
|
|
113
114
|
- Gemfile
|
|
114
115
|
- LICENSE
|
|
115
116
|
- README.md
|
|
@@ -134,6 +135,8 @@ files:
|
|
|
134
135
|
- lib/legion/mcp/server.rb
|
|
135
136
|
- lib/legion/mcp/tier_router.rb
|
|
136
137
|
- lib/legion/mcp/tool_governance.rb
|
|
138
|
+
- lib/legion/mcp/tools/ask_peer.rb
|
|
139
|
+
- lib/legion/mcp/tools/broadcast_peers.rb
|
|
137
140
|
- lib/legion/mcp/tools/create_chain.rb
|
|
138
141
|
- lib/legion/mcp/tools/create_relationship.rb
|
|
139
142
|
- lib/legion/mcp/tools/create_schedule.rb
|
|
@@ -159,10 +162,13 @@ files:
|
|
|
159
162
|
- lib/legion/mcp/tools/get_task_logs.rb
|
|
160
163
|
- lib/legion/mcp/tools/list_chains.rb
|
|
161
164
|
- lib/legion/mcp/tools/list_extensions.rb
|
|
165
|
+
- lib/legion/mcp/tools/list_peers.rb
|
|
162
166
|
- lib/legion/mcp/tools/list_relationships.rb
|
|
163
167
|
- lib/legion/mcp/tools/list_schedules.rb
|
|
164
168
|
- lib/legion/mcp/tools/list_tasks.rb
|
|
165
169
|
- lib/legion/mcp/tools/list_workers.rb
|
|
170
|
+
- lib/legion/mcp/tools/mesh_status.rb
|
|
171
|
+
- lib/legion/mcp/tools/notify_peer.rb
|
|
166
172
|
- lib/legion/mcp/tools/plan_action.rb
|
|
167
173
|
- lib/legion/mcp/tools/prompt_list.rb
|
|
168
174
|
- lib/legion/mcp/tools/prompt_run.rb
|