active_mcp 0.3.0 → 0.3.1

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: 051dd51506aaadb0c6bf460f1f001049b5d70dc950a060a663d2256050224de7
4
- data.tar.gz: e70d63d1618f882dd9d459de896a5ba086e29cbef9acbdf897f800a76266850e
3
+ metadata.gz: 791510bf59750086b139e1688d8cfd7367c635a359f2dfe2678756e612a20816
4
+ data.tar.gz: 320cb00fa8a75622a667260477c479fd1c9df653e54af85238dc77384923b0a9
5
5
  SHA512:
6
- metadata.gz: 7b5c6aaa00d5f9138d2186f2ea4c988f621f5f231674f4c01eeda64418187e0502999b1385c9417824bd99b888a9252f2833c5f5f42026e8943ce07d8a8952a4
7
- data.tar.gz: 31d7ea0b9f9cd7b6385a30ced3a9caf14d2105f366d614c1ae8fc5c227f617c547f1f86c63084e4816265cb838ed8e089a4997e9cd1d3e757f8304cd197717a7
6
+ metadata.gz: d65ba7458c1718d59d8b718eb8422192a1b520e72f877427feb4bdcb9057f9350718ebc8e4687eb7cc05f447962d728949cef94ed2c90937d82deb5ea3fc0727
7
+ data.tar.gz: 54ed82f6c351d9e91e4e4108ed27767564c84d7d0bfc65a101598c0cdc5b879c70aa1b926d2e5c60a8181372a88ad6e9049a7232242726607ae65f58b9585816
data/README.md CHANGED
@@ -72,7 +72,7 @@ end
72
72
 
73
73
  #### with streamable HTTP
74
74
 
75
- Set MCP destination as `https:your-app.example.com/mcp`
75
+ Set MCP destination to `https:your-app.example.com/mcp`
76
76
 
77
77
  #### with independent MCP Server
78
78
 
@@ -9,58 +9,32 @@ module ActiveMcp
9
9
  def index
10
10
  case params[:method]
11
11
  when Method::INITIALIZE
12
- render_initialize
12
+ result = Response::Initialize.call(id: params[:id])
13
13
  when Method::INITIALIZED
14
- render json: {
15
- jsonrpc: "2.0",
16
- method: "notifications/initialized"
17
- }
14
+ result = Response::Initialized.call
18
15
  when Method::CANCELLED
19
- render json: {
20
- jsonrpc: "2.0",
21
- method: "notifications/cancelled"
22
- }
16
+ result = Response::Cancelled.call
23
17
  when Method::TOOLS_LIST
18
+ tools = Response::Tools.to_hash(auth_info: @auth_info)
24
19
  if params[:jsonrpc]
25
- render_tools_list_as_jsonrpc
20
+ result = Response::ToolsList::Jsonrpc.call(id: params[:id], tools:)
26
21
  else
27
- render_tools_list
22
+ result = Response::ToolsList::Json.call(tools:)
28
23
  end
29
24
  when Method::TOOLS_CALL
30
25
  if params[:jsonrpc]
31
- call_tool_as_jsonrpc
26
+ result = Response::ToolsCall::Jsonrpc.call(id: params[:id], params:, auth_info: @auth_info)
32
27
  else
33
- render json: call_tool(params)
28
+ result = Response::ToolsCall::Json.call(params:, auth_info: @auth_info)
34
29
  end
35
30
  else
36
- render json: {error: "Method not found: #{params[:method]}"}, status: 404
31
+ result = Response::NoMethod.call
37
32
  end
38
- end
39
-
40
- private
41
33
 
42
- def render_tools_list_as_jsonrpc
43
- render json: {
44
- jsonrpc: "2.0",
45
- id: params[:id],
46
- result: {tools:}
47
- }
34
+ render json: result[:body], status: result[:status]
48
35
  end
49
36
 
50
- def call_tool_as_jsonrpc
51
- render json: {
52
- jsonrpc: "2.0",
53
- id: params[:id],
54
- result: {
55
- content: [
56
- {
57
- type: "text",
58
- text: call_tool(params[:params])[:result]
59
- }
60
- ]
61
- }
62
- }
63
- end
37
+ private
64
38
 
65
39
  def process_authentication
66
40
  auth_header = request.headers["Authorization"]
@@ -78,90 +52,5 @@ module ActiveMcp
78
52
  }
79
53
  end
80
54
  end
81
-
82
- def render_initialize
83
- render json: {
84
- jsonrpc: "2.0",
85
- id: params[:id],
86
- result: {
87
- protocolVersion: "2024-11-05",
88
- capabilities: {
89
- logging: {},
90
- capabilities: {
91
- resources: {
92
- subscribe: false,
93
- listChanged: false
94
- },
95
- tools: {
96
- listChanged: false
97
- }
98
- },
99
- },
100
- serverInfo: {
101
- name: ActiveMcp::Configuration.config.server_name,
102
- version: ActiveMcp::Configuration.config.server_version
103
- }
104
- }
105
- }
106
- end
107
-
108
- def render_tools_list
109
- render json: {result: tools}
110
- end
111
-
112
- def tools
113
- Tool.registered_tools.select do |tool_class|
114
- tool_class.authorized?(@auth_info)
115
- end.map do |tool_class|
116
- {
117
- name: tool_class.tool_name,
118
- description: tool_class.desc,
119
- inputSchema: tool_class.schema
120
- }
121
- end
122
- end
123
-
124
- def call_tool(params)
125
- tool_name = params[:name]
126
-
127
- unless tool_name
128
- return {error: "Invalid params: missing tool name"}
129
- end
130
-
131
- tool_class = Tool.registered_tools.find do |tc|
132
- tc.tool_name == tool_name
133
- end
134
-
135
- unless tool_class
136
- return {error: "Tool not found: #{tool_name}"}
137
- end
138
-
139
- unless tool_class.authorized?(@auth_info)
140
- return {error: "Unauthorized: Access to tool '#{tool_name}' denied"}
141
- end
142
-
143
- if params[:arguments].is_a?(Hash)
144
- arguments = params[:arguments].symbolize_keys
145
- else
146
- arguments = params[:arguments].permit!.to_hash.symbolize_keys.transform_values { _1.match(/^\d+$/) ? _1.to_i : _1 }
147
- end
148
-
149
- tool = tool_class.new
150
- validation_result = tool.validate_arguments(arguments)
151
-
152
- if validation_result.is_a?(Hash) && validation_result[:error]
153
- return {result: validation_result[:error]}
154
- end
155
-
156
- begin
157
- arguments[:auth_info] = @auth_info if @auth_info.present?
158
-
159
- result = tool.call(**arguments.symbolize_keys)
160
-
161
- return {result: result}
162
- rescue => e
163
- return {error: "Error: #{e.message}"}
164
- end
165
- end
166
55
  end
167
56
  end
@@ -0,0 +1,12 @@
1
+ module ActiveMcp
2
+ module Response
3
+ class Cancelled
4
+ def self.call
5
+ {
6
+ jsonrpc: JSON_RPC_VERSION,
7
+ method: Method::CANCELLED
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ module ActiveMcp
2
+ module Response
3
+ class Initialize
4
+ def self.to_hash(id:, name:, version:)
5
+ {
6
+ body: {
7
+ jsonrpc: JSON_RPC_VERSION,
8
+ id:,
9
+ result: {
10
+ protocolVersion: PROTOCOL_VERSION,
11
+ capabilities: {
12
+ logging: {},
13
+ capabilities: {
14
+ resources: {
15
+ subscribe: false,
16
+ listChanged: false
17
+ },
18
+ tools: {
19
+ listChanged: false
20
+ }
21
+ },
22
+ },
23
+ serverInfo: {
24
+ name: ActiveMcp.config.server_name,
25
+ version: ActiveMcp.config.server_version
26
+ }
27
+ }
28
+ },
29
+ status: 200
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveMcp
2
+ module Response
3
+ class Initialized
4
+ def self.to_hash
5
+ {
6
+ body: {
7
+ jsonrpc: JSON_RPC_VERSION,
8
+ method: Method::INITIALIZED
9
+ },
10
+ status: 200
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module ActiveMcp
2
+ module Response
3
+ class NoMethod
4
+ def self.call
5
+ {
6
+ body: { error: "Method not found" },
7
+ status: 404
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveMcp
2
+ module Response
3
+ class Tools
4
+ def self.to_hash(auth_info:)
5
+ Tool.registered_tools.select do |tool_class|
6
+ tool_class.authorized?(auth_info)
7
+ end.map do |tool_class|
8
+ {
9
+ name: tool_class.tool_name,
10
+ description: tool_class.desc,
11
+ inputSchema: tool_class.schema
12
+ }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,66 @@
1
+ module ActiveMcp
2
+ module Response
3
+ module ToolsCall
4
+ class Json
5
+ def self.call(params:, auth_info:)
6
+ tool_name = params[:name]
7
+
8
+ unless tool_name
9
+ return {
10
+ body: {error: "Invalid params: missing tool name"},
11
+ status: 400
12
+ }
13
+ end
14
+
15
+ tool_class = Tool.registered_tools.find do |tc|
16
+ tc.tool_name == tool_name
17
+ end
18
+
19
+ unless tool_class
20
+ return {
21
+ body: {error: "Tool not found: #{tool_name}"},
22
+ status: 404
23
+ }
24
+ end
25
+
26
+ unless tool_class.authorized?(auth_info)
27
+ return {
28
+ body: {error: "Unauthorized: Access to tool '#{tool_name}' denied"},
29
+ status: 401
30
+ }
31
+ end
32
+
33
+ arguments = params[:arguments].permit!.to_hash.symbolize_keys.transform_values { _1.match(/^\d+$/) ? _1.to_i : _1 }
34
+
35
+ p arguments
36
+
37
+ tool = tool_class.new
38
+ validation_result = tool.validate_arguments(arguments)
39
+
40
+ if validation_result.is_a?(Hash) && validation_result[:error]
41
+ return {
42
+ body: {result: validation_result[:error]},
43
+ status: 400
44
+ }
45
+ end
46
+
47
+ begin
48
+ arguments[:auth_info] = auth_info if auth_info.present?
49
+
50
+ result = tool.call(**arguments.symbolize_keys)
51
+
52
+ return {
53
+ body: {result: result},
54
+ status: 200,
55
+ }
56
+ rescue => e
57
+ return {
58
+ body: {error: "Error: #{e.message}"},
59
+ status: 500
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveMcp
2
+ module Response
3
+ module ToolsCall
4
+ class Jsonrpc
5
+ def self.call(id:, params:, auth_info:)
6
+ result = Json.call(params: params[:params], auth_info:)
7
+ {
8
+ body: {
9
+ jsonrpc: JSON_RPC_VERSION,
10
+ id:,
11
+ result: {
12
+ content: [
13
+ {
14
+ type: "text",
15
+ text: result[:body][:result]
16
+ }
17
+ ]
18
+ },
19
+ },
20
+ status: result[:status]
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveMcp
2
+ module Response
3
+ module ToolsList
4
+ class Json
5
+ def self.call(tools:)
6
+ {
7
+ body: { result: tools},
8
+ status: 200
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module ActiveMcp
2
+ module Response
3
+ module ToolsList
4
+ class Jsonrpc
5
+ def self.call(id:, tools:)
6
+ {
7
+ body: {
8
+ jsonrpc: JSON_RPC_VERSION,
9
+ id:,
10
+ result: {tools:}
11
+ },
12
+ status: 200
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveMcp
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/active_mcp.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "active_mcp/version"
4
- require_relative "active_mcp/config"
4
+ require_relative "active_mcp/configuration"
5
5
  require_relative "active_mcp/tool"
6
6
  require_relative "active_mcp/server"
7
7
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Your Name
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-05 00:00:00.000000000 Z
10
+ date: 2025-04-06 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -54,9 +54,18 @@ files:
54
54
  - README.md
55
55
  - Rakefile
56
56
  - app/controllers/active_mcp/base_controller.rb
57
+ - app/models/active_mcp/response/cancelled.rb
58
+ - app/models/active_mcp/response/initialize.rb
59
+ - app/models/active_mcp/response/initialized.rb
60
+ - app/models/active_mcp/response/no_method.rb
61
+ - app/models/active_mcp/response/tools.rb
62
+ - app/models/active_mcp/response/tools_call/json.rb
63
+ - app/models/active_mcp/response/tools_call/jsonrpc.rb
64
+ - app/models/active_mcp/response/tools_list/json.rb
65
+ - app/models/active_mcp/response/tools_list/jsonrpc.rb
57
66
  - config/routes.rb
58
67
  - lib/active_mcp.rb
59
- - lib/active_mcp/config.rb
68
+ - lib/active_mcp/configuration.rb
60
69
  - lib/active_mcp/engine.rb
61
70
  - lib/active_mcp/server.rb
62
71
  - lib/active_mcp/server/error_codes.rb
File without changes