stack-service-base 0.0.65 → 0.0.66
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/lib/stack-service-base/examples/mcp_config.ru +7 -7
- data/lib/stack-service-base/{mcp_helper.rb → mcp/mcp_helper.rb} +1 -1
- data/lib/stack-service-base/{mcp_processor.rb → mcp/mcp_processor.rb} +1 -1
- data/lib/stack-service-base/{mcp_tool_registry.rb → mcp/mcp_tool_registry.rb} +3 -3
- data/lib/stack-service-base/mcp/rack_test_mcp_protocol.rb +52 -0
- data/lib/stack-service-base/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5364bb7f74a8a5882409f1756051e6157203cf89b148cf3ee69ca60456d5285
|
|
4
|
+
data.tar.gz: 532831a451ce25cc18a3310b35f0eec5f2d6aa2b69cf2bfa49ec267c22d462e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7ee6fb74e36aba27c59632ffaa64dcc208f1af6e03c00a295b238c2e6340abe7a73fdf220863e034574df71204326b13555ec5726ac0fe38c7e8243b3902ed3
|
|
7
|
+
data.tar.gz: '08deb1846f8eb0f47983ae3d9a1cb7ea7408d9f254d5f8e922ab6c5f319082ba700fba8cb2ae1d42045571a3903f889638f1610c4f38fedec5ac0f483d7fc98c'
|
|
@@ -11,13 +11,13 @@ SERVICES = {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
require 'stack-service-base/mcp_helper'
|
|
14
|
+
require 'stack-service-base/mcp/mcp_helper'
|
|
15
15
|
helpers McpHelper
|
|
16
16
|
|
|
17
17
|
Tool :search do
|
|
18
18
|
description 'Search for a term in the database'
|
|
19
19
|
input query: { type: "string", description: "Term to search for", required: true }
|
|
20
|
-
|
|
20
|
+
call do |inputs|
|
|
21
21
|
query = inputs[:query]
|
|
22
22
|
{ results: [{id:"doc-1",title:"...",url:"..."}] }
|
|
23
23
|
end
|
|
@@ -26,7 +26,7 @@ end
|
|
|
26
26
|
Tool :fetch do
|
|
27
27
|
description 'Fetch a resource from the database'
|
|
28
28
|
input resource_id: { type: "string", description: "Resource ID to fetch", required: true }
|
|
29
|
-
|
|
29
|
+
call do |inputs|
|
|
30
30
|
id = inputs[:id]
|
|
31
31
|
{ id: "doc-1", title: "...", text: "full text...", url: "https://example.com/doc", metadata: { source: "vector_store" } }
|
|
32
32
|
end
|
|
@@ -35,10 +35,10 @@ end
|
|
|
35
35
|
Tool :service_status do
|
|
36
36
|
description 'Check current status of a service'
|
|
37
37
|
input service_name: { type: "string", description: "Service name to inspect", required: true }
|
|
38
|
-
|
|
38
|
+
call do |inputs|
|
|
39
39
|
service_name = inputs[:service_name]
|
|
40
40
|
service = SERVICES[service_name]
|
|
41
|
-
rpc_error!(
|
|
41
|
+
rpc_error!(-32000, "Unknown service #{service_name}") unless service
|
|
42
42
|
{
|
|
43
43
|
service_name: service_name,
|
|
44
44
|
status: service[:status],
|
|
@@ -52,10 +52,10 @@ Tool :restart_service do
|
|
|
52
52
|
description 'Restart a service'
|
|
53
53
|
input service_name: { type: "string", description: "Service name to restart", required: true },
|
|
54
54
|
force: { type: "boolean", default: false, description: "Force restart if graceful fails" }
|
|
55
|
-
|
|
55
|
+
call do |inputs|
|
|
56
56
|
service_name = inputs[:service_name]
|
|
57
57
|
service = SERVICES[service_name]
|
|
58
|
-
rpc_error!(
|
|
58
|
+
rpc_error!(-32000, "Unknown service #{service_name}") unless service
|
|
59
59
|
|
|
60
60
|
service[:status] = "running"
|
|
61
61
|
service[:last_restart] = Time.now
|
|
@@ -115,7 +115,7 @@ class McpProcessor
|
|
|
115
115
|
name = params["name"]
|
|
116
116
|
arguments = params["arguments"] || {}
|
|
117
117
|
tool = ToolRegistry.fetch(name) || rpc_error!(-32601, "Unknown tool #{name}")
|
|
118
|
-
response = tool.
|
|
118
|
+
response = tool.call_tool(arguments)
|
|
119
119
|
{
|
|
120
120
|
content: [
|
|
121
121
|
{ "type": "text", "text": response.is_a?(String) ? response : response.to_json }
|
|
@@ -30,10 +30,10 @@ module ToolRegistry
|
|
|
30
30
|
properties[field] = cfg.transform_keys(&:to_s)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
{ type:
|
|
33
|
+
{ type: 'object', properties: properties, required: required }
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def call(&block) = @executor = block
|
|
37
37
|
|
|
38
38
|
def to_h
|
|
39
39
|
{
|
|
@@ -43,7 +43,7 @@ module ToolRegistry
|
|
|
43
43
|
}
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def
|
|
46
|
+
def call_tool(arguments)
|
|
47
47
|
raise JsonRpcError.new(code: 500, message: "Tool #{name} missing executor") unless @executor
|
|
48
48
|
|
|
49
49
|
ExecutionContext.new.instance_exec(symbolize_keys(arguments || {}), &@executor)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Rack
|
|
4
|
+
module Test
|
|
5
|
+
module McpProtocol
|
|
6
|
+
def rpc_request(payload)
|
|
7
|
+
post '/mcp', JSON.dump(payload), { 'CONTENT_TYPE' => 'application/json' }
|
|
8
|
+
expect(last_response.status).to eq(200)
|
|
9
|
+
parsed_response_body
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parsed_response_body
|
|
13
|
+
body = +''
|
|
14
|
+
last_response.each { |chunk| body << chunk.to_s }
|
|
15
|
+
data_lines = body.lines.select { |line| line.start_with?('data:') }
|
|
16
|
+
payload_line = data_lines.reverse.find { |l| l !~ /ping/i } || data_lines.last
|
|
17
|
+
payload = (payload_line || body).sub(/\Adata:\s*/, '').sub(/\n\z/, '')
|
|
18
|
+
JSON.parse(payload, symbolize_names: true)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def mcp_list_tools
|
|
22
|
+
req_id = next_id
|
|
23
|
+
response = rpc_request(id: req_id, method: 'tools/list', params: {})
|
|
24
|
+
expect(response[:id]).to eq(req_id)
|
|
25
|
+
response.dig(:result, :tools)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def mcp_call_tool(name:, arguments:)
|
|
29
|
+
response = mcp_call_tool_raw(name: name, arguments: arguments)
|
|
30
|
+
tool_results = response.dig(:result, :content)
|
|
31
|
+
expect(tool_results[0][:type]).to eq('text')
|
|
32
|
+
JSON.parse(tool_results[0][:text], symbolize_names: true)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def mcp_call_tool_raw(name:, arguments:)
|
|
36
|
+
rpc_request(
|
|
37
|
+
id: next_id,
|
|
38
|
+
method: 'tools/call',
|
|
39
|
+
params: { 'name' => name, 'arguments' => arguments }
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def next_id
|
|
46
|
+
@next_id ||= -1
|
|
47
|
+
@next_id += 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stack-service-base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.66
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artyom B
|
|
@@ -401,9 +401,10 @@ files:
|
|
|
401
401
|
- lib/stack-service-base/examples/mcp_config.ru
|
|
402
402
|
- lib/stack-service-base/fiber_pool.rb
|
|
403
403
|
- lib/stack-service-base/logging.rb
|
|
404
|
-
- lib/stack-service-base/mcp_helper.rb
|
|
405
|
-
- lib/stack-service-base/mcp_processor.rb
|
|
406
|
-
- lib/stack-service-base/mcp_tool_registry.rb
|
|
404
|
+
- lib/stack-service-base/mcp/mcp_helper.rb
|
|
405
|
+
- lib/stack-service-base/mcp/mcp_processor.rb
|
|
406
|
+
- lib/stack-service-base/mcp/mcp_tool_registry.rb
|
|
407
|
+
- lib/stack-service-base/mcp/rack_test_mcp_protocol.rb
|
|
407
408
|
- lib/stack-service-base/nats_patch_1.rb
|
|
408
409
|
- lib/stack-service-base/nats_service.rb
|
|
409
410
|
- lib/stack-service-base/open_telemetry.rb
|