stack-service-base 0.0.64 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f73b91212d7125c660258defabaa0f09540b66458f31222340109ee1b4e31354
4
- data.tar.gz: 296d9f39dd8fac208801c5195141c2a29d134163ae20cc230f3baecc24380c2c
3
+ metadata.gz: e5364bb7f74a8a5882409f1756051e6157203cf89b148cf3ee69ca60456d5285
4
+ data.tar.gz: 532831a451ce25cc18a3310b35f0eec5f2d6aa2b69cf2bfa49ec267c22d462e1
5
5
  SHA512:
6
- metadata.gz: e5f0a35ad58b849f923bd0a9df6a794b1ab52964f51732c60649d3308e29cab3df691c9090e857b0d7d2037ece0cf6068faf1473eb276881fb1db3fbdec0d566
7
- data.tar.gz: ea99bd368e07a109da81577522ca6a8071662b67b7cc198a4c78159a74c68ee81a68a11a0c601a46560706ecdc061679a6a512328b64372c8df21119aa334212
6
+ metadata.gz: d7ee6fb74e36aba27c59632ffaa64dcc208f1af6e03c00a295b238c2e6340abe7a73fdf220863e034574df71204326b13555ec5726ac0fe38c7e8243b3902ed3
7
+ data.tar.gz: '08deb1846f8eb0f47983ae3d9a1cb7ea7408d9f254d5f8e922ab6c5f319082ba700fba8cb2ae1d42045571a3903f889638f1610c4f38fedec5ac0f483d7fc98c'
@@ -11,25 +11,39 @@ SERVICES = {
11
11
  }
12
12
  }
13
13
 
14
- require 'stack-service-base/mcp_processor'
15
- require 'stack-service-base/mcp_tool_registry'
14
+ require 'stack-service-base/mcp/mcp_helper'
15
+ helpers McpHelper
16
16
 
17
- MCP_PROCESSOR = McpProcessor.new
17
+ Tool :search do
18
+ description 'Search for a term in the database'
19
+ input query: { type: "string", description: "Term to search for", required: true }
20
+ call do |inputs|
21
+ query = inputs[:query]
22
+ { results: [{id:"doc-1",title:"...",url:"..."}] }
23
+ end
24
+ end
25
+
26
+ Tool :fetch do
27
+ description 'Fetch a resource from the database'
28
+ input resource_id: { type: "string", description: "Resource ID to fetch", required: true }
29
+ call do |inputs|
30
+ id = inputs[:id]
31
+ { id: "doc-1", title: "...", text: "full text...", url: "https://example.com/doc", metadata: { source: "vector_store" } }
32
+ end
33
+ end
18
34
 
19
35
  Tool :service_status do
20
36
  description 'Check current status of a service'
21
37
  input service_name: { type: "string", description: "Service name to inspect", required: true }
22
- execute do |inputs|
38
+ call do |inputs|
23
39
  service_name = inputs[:service_name]
24
40
  service = SERVICES[service_name]
25
- rpc_error!(404, "Unknown service #{service_name}") unless service
41
+ rpc_error!(-32000, "Unknown service #{service_name}") unless service
26
42
  {
27
- toolResult: {
28
- service_name: service_name,
29
- status: service[:status],
30
- uptime_sec: service[:uptime],
31
- last_restart: service[:last_restart].utc.iso8601,
32
- }
43
+ service_name: service_name,
44
+ status: service[:status],
45
+ uptime_sec: service[:uptime],
46
+ last_restart: service[:last_restart].utc.iso8601,
33
47
  }
34
48
  end
35
49
  end
@@ -38,36 +52,21 @@ Tool :restart_service do
38
52
  description 'Restart a service'
39
53
  input service_name: { type: "string", description: "Service name to restart", required: true },
40
54
  force: { type: "boolean", default: false, description: "Force restart if graceful fails" }
41
- execute do |inputs|
55
+ call do |inputs|
42
56
  service_name = inputs[:service_name]
43
57
  service = SERVICES[service_name]
44
- rpc_error!(404, "Unknown service #{service_name}") unless service
58
+ rpc_error!(-32000, "Unknown service #{service_name}") unless service
45
59
 
46
60
  service[:status] = "running"
47
61
  service[:last_restart] = Time.now
48
62
  service[:uptime] = 0
49
-
50
63
  {
51
- toolResult: {
52
- service_name: service_name,
53
- status: service[:status],
54
- restarted_at: service[:last_restart].utc.iso8601,
55
- force: inputs.fetch(:force, false)
56
- }
64
+ service_name: service_name,
65
+ status: service[:status],
66
+ restarted_at: service[:last_restart].utc.iso8601,
67
+ force: inputs.fetch(:force, false)
57
68
  }
58
69
  end
59
70
  end
60
71
 
61
- before { content_type :json }
62
- error McpProcessor::ParseError do |err|
63
- status err.status
64
- err.body
65
- end
66
-
67
- get '/', &MCP_PROCESSOR.method(:root_endpoint)
68
- post '/' do
69
- request.body.rewind
70
- MCP_PROCESSOR.rpc_endpoint(request.body.read)
71
- end
72
-
73
72
  run Sinatra::Application
@@ -12,7 +12,7 @@ module McpHelper
12
12
  err.body
13
13
  end
14
14
 
15
- get '/mcp' do
15
+ get '/mcp' do
16
16
  content_type :json
17
17
  MCP_PROCESSOR.root_endpoint
18
18
  end
@@ -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.call(arguments)
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: "object", properties: properties, required: required }
33
+ { type: 'object', properties: properties, required: required }
34
34
  end
35
35
 
36
- def execute(&block) = @executor = block
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 call(arguments)
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
+
@@ -1,3 +1,3 @@
1
1
  module StackServiceBase
2
- VERSION = '0.0.64'
2
+ VERSION = '0.0.66'
3
3
  end
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.64
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