legion-mcp 0.1.0
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 +7 -0
- data/.github/workflows/ci.yml +16 -0
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.rubocop.yml +40 -0
- data/CHANGELOG.md +20 -0
- data/CLAUDE.md +101 -0
- data/Gemfile +10 -0
- data/LICENSE +167 -0
- data/README.md +182 -0
- data/Rakefile +5 -0
- data/legion-mcp.gemspec +35 -0
- data/lib/legion/mcp/auth.rb +50 -0
- data/lib/legion/mcp/context_compiler.rb +173 -0
- data/lib/legion/mcp/context_guard.rb +105 -0
- data/lib/legion/mcp/embedding_index.rb +113 -0
- data/lib/legion/mcp/observer.rb +171 -0
- data/lib/legion/mcp/pattern_store.rb +303 -0
- data/lib/legion/mcp/resources/extension_info.rb +67 -0
- data/lib/legion/mcp/resources/runner_catalog.rb +63 -0
- data/lib/legion/mcp/server.rb +178 -0
- data/lib/legion/mcp/tier_router.rb +122 -0
- data/lib/legion/mcp/tool_governance.rb +77 -0
- data/lib/legion/mcp/tools/create_chain.rb +50 -0
- data/lib/legion/mcp/tools/create_relationship.rb +51 -0
- data/lib/legion/mcp/tools/create_schedule.rb +64 -0
- data/lib/legion/mcp/tools/delete_chain.rb +52 -0
- data/lib/legion/mcp/tools/delete_relationship.rb +52 -0
- data/lib/legion/mcp/tools/delete_schedule.rb +52 -0
- data/lib/legion/mcp/tools/delete_task.rb +49 -0
- data/lib/legion/mcp/tools/describe_runner.rb +92 -0
- data/lib/legion/mcp/tools/disable_extension.rb +50 -0
- data/lib/legion/mcp/tools/discover_tools.rb +53 -0
- data/lib/legion/mcp/tools/do_action.rb +85 -0
- data/lib/legion/mcp/tools/enable_extension.rb +50 -0
- data/lib/legion/mcp/tools/get_config.rb +63 -0
- data/lib/legion/mcp/tools/get_extension.rb +56 -0
- data/lib/legion/mcp/tools/get_status.rb +50 -0
- data/lib/legion/mcp/tools/get_task.rb +48 -0
- data/lib/legion/mcp/tools/get_task_logs.rb +56 -0
- data/lib/legion/mcp/tools/list_chains.rb +48 -0
- data/lib/legion/mcp/tools/list_extensions.rb +46 -0
- data/lib/legion/mcp/tools/list_relationships.rb +45 -0
- data/lib/legion/mcp/tools/list_schedules.rb +51 -0
- data/lib/legion/mcp/tools/list_tasks.rb +50 -0
- data/lib/legion/mcp/tools/list_workers.rb +54 -0
- data/lib/legion/mcp/tools/rbac_assignments.rb +45 -0
- data/lib/legion/mcp/tools/rbac_check.rb +46 -0
- data/lib/legion/mcp/tools/rbac_grants.rb +41 -0
- data/lib/legion/mcp/tools/routing_stats.rb +51 -0
- data/lib/legion/mcp/tools/run_task.rb +68 -0
- data/lib/legion/mcp/tools/show_worker.rb +48 -0
- data/lib/legion/mcp/tools/team_summary.rb +55 -0
- data/lib/legion/mcp/tools/update_chain.rb +54 -0
- data/lib/legion/mcp/tools/update_relationship.rb +55 -0
- data/lib/legion/mcp/tools/update_schedule.rb +65 -0
- data/lib/legion/mcp/tools/worker_costs.rb +55 -0
- data/lib/legion/mcp/tools/worker_lifecycle.rb +54 -0
- data/lib/legion/mcp/usage_filter.rb +86 -0
- data/lib/legion/mcp/version.rb +7 -0
- data/lib/legion/mcp.rb +30 -0
- metadata +195 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class UpdateSchedule < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.update_schedule'
|
|
8
|
+
description 'Update an existing schedule.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
id: { type: 'integer', description: 'Schedule ID' },
|
|
13
|
+
cron: { type: 'string', description: 'New cron expression' },
|
|
14
|
+
interval: { type: 'integer', description: 'New interval in seconds' },
|
|
15
|
+
active: { type: 'boolean', description: 'Active status' },
|
|
16
|
+
function_id: { type: 'integer', description: 'New function ID' },
|
|
17
|
+
payload: { type: 'object', description: 'New payload', additionalProperties: true }
|
|
18
|
+
},
|
|
19
|
+
required: ['id']
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def call(id:, **attrs)
|
|
24
|
+
return error_response('legion-data is not connected') unless data_connected?
|
|
25
|
+
return error_response('lex-scheduler is not loaded') unless scheduler_loaded?
|
|
26
|
+
|
|
27
|
+
record = Legion::Extensions::Scheduler::Data::Model::Schedule[id.to_i]
|
|
28
|
+
return error_response("Schedule #{id} not found") unless record
|
|
29
|
+
|
|
30
|
+
updates = {}
|
|
31
|
+
updates[:cron] = attrs[:cron] if attrs.key?(:cron)
|
|
32
|
+
updates[:interval] = attrs[:interval].to_i if attrs.key?(:interval)
|
|
33
|
+
updates[:active] = attrs[:active] if attrs.key?(:active)
|
|
34
|
+
updates[:function_id] = attrs[:function_id].to_i if attrs.key?(:function_id)
|
|
35
|
+
updates[:payload] = Legion::JSON.dump(attrs[:payload]) if attrs.key?(:payload)
|
|
36
|
+
|
|
37
|
+
record.update(updates) unless updates.empty?
|
|
38
|
+
record.refresh
|
|
39
|
+
text_response(record.values)
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
error_response("Failed to update schedule: #{e.message}")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def data_connected?
|
|
47
|
+
Legion::Settings[:data][:connected]
|
|
48
|
+
rescue StandardError
|
|
49
|
+
false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def scheduler_loaded? = defined?(Legion::Extensions::Scheduler)
|
|
53
|
+
|
|
54
|
+
def text_response(data)
|
|
55
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump(data) }])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def error_response(msg)
|
|
59
|
+
::MCP::Tool::Response.new([{ type: 'text', text: Legion::JSON.dump({ error: msg }) }], error: true)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class WorkerCosts < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.worker_costs'
|
|
8
|
+
description 'Retrieve cost data for a digital worker. Returns a stub response until lex-metering is available.'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
worker_id: { type: 'string', description: 'UUID of the digital worker' },
|
|
13
|
+
period: { type: 'string', description: 'Reporting period: daily, weekly, monthly (default: weekly)' }
|
|
14
|
+
},
|
|
15
|
+
required: ['worker_id']
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def call(worker_id:, period: 'weekly')
|
|
20
|
+
return error_response('legion-data is not connected') unless data_connected?
|
|
21
|
+
|
|
22
|
+
worker = Legion::DigitalWorker.find(worker_id: worker_id)
|
|
23
|
+
return error_response("Worker not found: #{worker_id}") unless worker
|
|
24
|
+
|
|
25
|
+
text_response({
|
|
26
|
+
worker_id: worker_id,
|
|
27
|
+
period: period,
|
|
28
|
+
available: false,
|
|
29
|
+
message: 'Cost metering is not yet available. Install lex-metering to enable worker cost tracking.',
|
|
30
|
+
worker_name: worker.values[:name]
|
|
31
|
+
})
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
error_response("Failed to fetch worker costs: #{e.message}")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def data_connected?
|
|
39
|
+
Legion::Settings[:data][:connected]
|
|
40
|
+
rescue StandardError
|
|
41
|
+
false
|
|
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,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module Tools
|
|
6
|
+
class WorkerLifecycle < ::MCP::Tool
|
|
7
|
+
tool_name 'legion.worker_lifecycle'
|
|
8
|
+
description 'Transition a digital worker to a new lifecycle state (bootstrap, active, paused, retired, terminated).'
|
|
9
|
+
|
|
10
|
+
input_schema(
|
|
11
|
+
properties: {
|
|
12
|
+
worker_id: { type: 'string', description: 'UUID of the digital worker' },
|
|
13
|
+
to_state: { type: 'string', description: 'Target lifecycle state' },
|
|
14
|
+
by: { type: 'string', description: 'MSID or identifier of the person performing the transition' },
|
|
15
|
+
reason: { type: 'string', description: 'Optional reason for the transition' }
|
|
16
|
+
},
|
|
17
|
+
required: %w[worker_id to_state by]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def call(worker_id:, to_state:, by:, reason: nil)
|
|
22
|
+
return error_response('legion-data is not connected') unless data_connected?
|
|
23
|
+
|
|
24
|
+
worker = Legion::DigitalWorker.find(worker_id: worker_id)
|
|
25
|
+
return error_response("Worker not found: #{worker_id}") unless worker
|
|
26
|
+
|
|
27
|
+
updated = Legion::DigitalWorker::Lifecycle.transition!(worker, to_state: to_state, by: by, reason: reason)
|
|
28
|
+
text_response(updated.values)
|
|
29
|
+
rescue Legion::DigitalWorker::Lifecycle::InvalidTransition => e
|
|
30
|
+
error_response("Invalid transition: #{e.message}")
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
error_response("Lifecycle transition failed: #{e.message}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def data_connected?
|
|
38
|
+
Legion::Settings[:data][:connected]
|
|
39
|
+
rescue StandardError
|
|
40
|
+
false
|
|
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
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module MCP
|
|
5
|
+
module UsageFilter
|
|
6
|
+
ESSENTIAL_TOOLS = %w[
|
|
7
|
+
legion.do legion.tools legion.run_task legion.get_status legion.describe_runner
|
|
8
|
+
].freeze
|
|
9
|
+
|
|
10
|
+
FREQUENCY_WEIGHT = 0.5
|
|
11
|
+
RECENCY_WEIGHT = 0.3
|
|
12
|
+
KEYWORD_WEIGHT = 0.2
|
|
13
|
+
BASELINE_SCORE = 0.1
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def score_tools(tool_names, keywords: [])
|
|
18
|
+
all_stats = Observer.all_tool_stats
|
|
19
|
+
call_counts = tool_names.map { |n| all_stats.dig(n, :call_count) || 0 }
|
|
20
|
+
max_calls = call_counts.max || 0
|
|
21
|
+
|
|
22
|
+
tool_names.each_with_object({}) do |name, hash|
|
|
23
|
+
stats = all_stats[name]
|
|
24
|
+
|
|
25
|
+
freq_score = if max_calls.positive? && stats
|
|
26
|
+
(stats[:call_count].to_f / max_calls) * FREQUENCY_WEIGHT
|
|
27
|
+
else
|
|
28
|
+
0.0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
rec_score = if stats&.dig(:last_used)
|
|
32
|
+
recency_decay(stats[:last_used]) * RECENCY_WEIGHT
|
|
33
|
+
else
|
|
34
|
+
0.0
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
kw_score = keyword_match(name, keywords) * KEYWORD_WEIGHT
|
|
38
|
+
|
|
39
|
+
total = freq_score + rec_score + kw_score
|
|
40
|
+
total = BASELINE_SCORE if total.zero?
|
|
41
|
+
|
|
42
|
+
hash[name] = total.round(6)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ranked_tools(tool_names, limit: nil, keywords: [])
|
|
47
|
+
scores = score_tools(tool_names, keywords: keywords)
|
|
48
|
+
ranked = tool_names.sort_by { |n| -scores.fetch(n, BASELINE_SCORE) }
|
|
49
|
+
limit ? ranked.first(limit) : ranked
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def prune_dead_tools(tool_names, prune_after_seconds: 86_400 * 30)
|
|
53
|
+
stats = Observer.stats
|
|
54
|
+
window = stats[:since]
|
|
55
|
+
elapsed = window ? (Time.now - window) : 0
|
|
56
|
+
|
|
57
|
+
return tool_names if elapsed < prune_after_seconds
|
|
58
|
+
|
|
59
|
+
all_stats = Observer.all_tool_stats
|
|
60
|
+
tool_names.reject do |name|
|
|
61
|
+
next false if ESSENTIAL_TOOLS.include?(name)
|
|
62
|
+
|
|
63
|
+
calls = all_stats.dig(name, :call_count) || 0
|
|
64
|
+
calls.zero?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def recency_decay(last_used)
|
|
69
|
+
return 0.0 unless last_used
|
|
70
|
+
|
|
71
|
+
age_seconds = Time.now - last_used
|
|
72
|
+
return 1.0 if age_seconds <= 0
|
|
73
|
+
|
|
74
|
+
decay = 1.0 - (age_seconds / 86_400.0)
|
|
75
|
+
decay.clamp(0.0, 1.0)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def keyword_match(tool_name, keywords)
|
|
79
|
+
return 0.0 if keywords.nil? || keywords.empty?
|
|
80
|
+
|
|
81
|
+
hits = keywords.count { |kw| tool_name.include?(kw.to_s) }
|
|
82
|
+
hits.to_f / keywords.size
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/legion/mcp.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mcp'
|
|
4
|
+
require 'legion/json'
|
|
5
|
+
require_relative 'mcp/version'
|
|
6
|
+
|
|
7
|
+
require_relative 'mcp/auth'
|
|
8
|
+
require_relative 'mcp/tool_governance'
|
|
9
|
+
require_relative 'mcp/server'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module MCP
|
|
13
|
+
class << self
|
|
14
|
+
def server
|
|
15
|
+
@server ||= Server.build
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def server_for(token:)
|
|
19
|
+
auth_result = Auth.authenticate(token)
|
|
20
|
+
return { error: auth_result[:error] } unless auth_result[:authenticated]
|
|
21
|
+
|
|
22
|
+
Server.build(identity: auth_result[:identity])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def reset!
|
|
26
|
+
@server = nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: legion-mcp
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Esity
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: concurrent-ruby
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.2'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.2'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: mcp
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.8'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.8'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: legion-data
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.4'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.4'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: legion-json
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.2'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.2'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: legion-logging
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.3'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0.3'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: legion-settings
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0.3'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0.3'
|
|
96
|
+
description: Model Context Protocol server with semantic tool matching, observation
|
|
97
|
+
pipeline, and tiered inference for LegionIO
|
|
98
|
+
email:
|
|
99
|
+
- matthewdiverson@gmail.com
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files:
|
|
103
|
+
- CHANGELOG.md
|
|
104
|
+
- LICENSE
|
|
105
|
+
- README.md
|
|
106
|
+
files:
|
|
107
|
+
- ".github/workflows/ci.yml"
|
|
108
|
+
- ".gitignore"
|
|
109
|
+
- ".rspec"
|
|
110
|
+
- ".rubocop.yml"
|
|
111
|
+
- CHANGELOG.md
|
|
112
|
+
- CLAUDE.md
|
|
113
|
+
- Gemfile
|
|
114
|
+
- LICENSE
|
|
115
|
+
- README.md
|
|
116
|
+
- Rakefile
|
|
117
|
+
- legion-mcp.gemspec
|
|
118
|
+
- lib/legion/mcp.rb
|
|
119
|
+
- lib/legion/mcp/auth.rb
|
|
120
|
+
- lib/legion/mcp/context_compiler.rb
|
|
121
|
+
- lib/legion/mcp/context_guard.rb
|
|
122
|
+
- lib/legion/mcp/embedding_index.rb
|
|
123
|
+
- lib/legion/mcp/observer.rb
|
|
124
|
+
- lib/legion/mcp/pattern_store.rb
|
|
125
|
+
- lib/legion/mcp/resources/extension_info.rb
|
|
126
|
+
- lib/legion/mcp/resources/runner_catalog.rb
|
|
127
|
+
- lib/legion/mcp/server.rb
|
|
128
|
+
- lib/legion/mcp/tier_router.rb
|
|
129
|
+
- lib/legion/mcp/tool_governance.rb
|
|
130
|
+
- lib/legion/mcp/tools/create_chain.rb
|
|
131
|
+
- lib/legion/mcp/tools/create_relationship.rb
|
|
132
|
+
- lib/legion/mcp/tools/create_schedule.rb
|
|
133
|
+
- lib/legion/mcp/tools/delete_chain.rb
|
|
134
|
+
- lib/legion/mcp/tools/delete_relationship.rb
|
|
135
|
+
- lib/legion/mcp/tools/delete_schedule.rb
|
|
136
|
+
- lib/legion/mcp/tools/delete_task.rb
|
|
137
|
+
- lib/legion/mcp/tools/describe_runner.rb
|
|
138
|
+
- lib/legion/mcp/tools/disable_extension.rb
|
|
139
|
+
- lib/legion/mcp/tools/discover_tools.rb
|
|
140
|
+
- lib/legion/mcp/tools/do_action.rb
|
|
141
|
+
- lib/legion/mcp/tools/enable_extension.rb
|
|
142
|
+
- lib/legion/mcp/tools/get_config.rb
|
|
143
|
+
- lib/legion/mcp/tools/get_extension.rb
|
|
144
|
+
- lib/legion/mcp/tools/get_status.rb
|
|
145
|
+
- lib/legion/mcp/tools/get_task.rb
|
|
146
|
+
- lib/legion/mcp/tools/get_task_logs.rb
|
|
147
|
+
- lib/legion/mcp/tools/list_chains.rb
|
|
148
|
+
- lib/legion/mcp/tools/list_extensions.rb
|
|
149
|
+
- lib/legion/mcp/tools/list_relationships.rb
|
|
150
|
+
- lib/legion/mcp/tools/list_schedules.rb
|
|
151
|
+
- lib/legion/mcp/tools/list_tasks.rb
|
|
152
|
+
- lib/legion/mcp/tools/list_workers.rb
|
|
153
|
+
- lib/legion/mcp/tools/rbac_assignments.rb
|
|
154
|
+
- lib/legion/mcp/tools/rbac_check.rb
|
|
155
|
+
- lib/legion/mcp/tools/rbac_grants.rb
|
|
156
|
+
- lib/legion/mcp/tools/routing_stats.rb
|
|
157
|
+
- lib/legion/mcp/tools/run_task.rb
|
|
158
|
+
- lib/legion/mcp/tools/show_worker.rb
|
|
159
|
+
- lib/legion/mcp/tools/team_summary.rb
|
|
160
|
+
- lib/legion/mcp/tools/update_chain.rb
|
|
161
|
+
- lib/legion/mcp/tools/update_relationship.rb
|
|
162
|
+
- lib/legion/mcp/tools/update_schedule.rb
|
|
163
|
+
- lib/legion/mcp/tools/worker_costs.rb
|
|
164
|
+
- lib/legion/mcp/tools/worker_lifecycle.rb
|
|
165
|
+
- lib/legion/mcp/usage_filter.rb
|
|
166
|
+
- lib/legion/mcp/version.rb
|
|
167
|
+
homepage: https://github.com/LegionIO/legion-mcp
|
|
168
|
+
licenses:
|
|
169
|
+
- Apache-2.0
|
|
170
|
+
metadata:
|
|
171
|
+
bug_tracker_uri: https://github.com/LegionIO/legion-mcp/issues
|
|
172
|
+
changelog_uri: https://github.com/LegionIO/legion-mcp/blob/main/CHANGELOG.md
|
|
173
|
+
documentation_uri: https://github.com/LegionIO/legion-mcp
|
|
174
|
+
homepage_uri: https://github.com/LegionIO/LegionIO
|
|
175
|
+
source_code_uri: https://github.com/LegionIO/legion-mcp
|
|
176
|
+
wiki_uri: https://github.com/LegionIO/legion-mcp/wiki
|
|
177
|
+
rubygems_mfa_required: 'true'
|
|
178
|
+
rdoc_options: []
|
|
179
|
+
require_paths:
|
|
180
|
+
- lib
|
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '3.4'
|
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
|
+
requirements:
|
|
188
|
+
- - ">="
|
|
189
|
+
- !ruby/object:Gem::Version
|
|
190
|
+
version: '0'
|
|
191
|
+
requirements: []
|
|
192
|
+
rubygems_version: 3.6.9
|
|
193
|
+
specification_version: 4
|
|
194
|
+
summary: MCP server for the LegionIO framework
|
|
195
|
+
test_files: []
|