active_mcp 0.1.0 → 0.1.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: 9f18994ffb431e43b365012a42a156596c09d0b1fef51352c7280363df3baddc
4
- data.tar.gz: ab39f6b59b7a14510d1f3bc1c18b8f8e854de8ec6055d7592671b7fa1e586382
3
+ metadata.gz: f768454eb918802f12f22205183172abcddeee402f1747c0223810e0622945f5
4
+ data.tar.gz: 336a6e84d15e9899240ef15de5912063cfe7729848a3617cf584cf987603d4d4
5
5
  SHA512:
6
- metadata.gz: b9cf091830ad128b958570361b252a396d9778d6eeaec596bbc22e88dd53bd16770726320928600c8d5e6ec7adc1adf436ab574a6355ec21a276ee15e4b6ccc1
7
- data.tar.gz: e7f65722c824d17de80903e899efa552733e747b64ca5abfdc8c44dc73e37ae74d50d7481974dc543c3daed0315050a761115956233f78ccfc1fd55f7eb9a23c
6
+ metadata.gz: 5a9db4bc9729b90fdc34caf1aae7715c73bb9596162641d34e5ca0ca12f03cac1b1b8576def4198bdc59d1967a4184377a1ee9dbf050d73d82c69385b8a2df40
7
+ data.tar.gz: 7027f29f2402272a75cce1e96791e4218b006558787efdbe6aa0ddadb93bc0ff84aa82afc36523eda1b16ba5d264f6e5be8df47316adb9f1b69d3b60ab691ddf
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # Active Context
1
+ # Active MCP
2
2
 
3
3
  A Ruby on Rails engine that provides [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) capabilities to Rails applications. This gem allows you to easily create and expose MCP-compatible tools from your Rails application.
4
4
 
5
+ ![Active MCP](./docs/active_mcp.png)
6
+
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
@@ -54,6 +56,7 @@ end
54
56
  3. Start the MCP server:
55
57
 
56
58
  ```ruby
59
+ # server.rb
57
60
  server = ActiveMcp::Server.new(
58
61
  name: "ActiveMcp DEMO",
59
62
  uri: 'https://your-app.example.com/mcp'
@@ -61,6 +64,19 @@ server = ActiveMcp::Server.new(
61
64
  server.start
62
65
  ```
63
66
 
67
+ 4. Set up MCP Client
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "active-mcp-demo": {
73
+ "command": "/path/to/ruby",
74
+ "args": ["/path/to/server.rb"]
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
64
80
  ## Rails Generators
65
81
 
66
82
  MCP Rails provides generators to help you quickly create new MCP tools:
@@ -17,9 +17,11 @@ module ActiveMcp
17
17
  request = JSON.parse(message, symbolize_names: true)
18
18
  handle_request(request)
19
19
  rescue JSON::ParserError => e
20
- error_response(nil, ErrorCode::PARSE_ERROR, "Invalid JSON: #{e.message}")
20
+ log_error("JSON parse error", e)
21
+ error_response(nil, ErrorCode::PARSE_ERROR, "Invalid JSON format")
21
22
  rescue => e
22
- error_response(nil, ErrorCode::INTERNAL_ERROR, e.message)
23
+ log_error("Internal error during message processing", e)
24
+ error_response(nil, ErrorCode::INTERNAL_ERROR, "An internal error occurred")
23
25
  end
24
26
 
25
27
  json_result = JSON.generate(result).force_encoding("UTF-8") if result
@@ -123,7 +125,8 @@ module ActiveMcp
123
125
 
124
126
  success_response(request[:id], result)
125
127
  rescue => e
126
- error_response(request[:id], ErrorCode::INTERNAL_ERROR, e.message)
128
+ log_error("Error calling tool #{name}", e)
129
+ error_response(request[:id], ErrorCode::INTERNAL_ERROR, "An error occurred while calling the tool")
127
130
  end
128
131
  end
129
132
 
@@ -162,6 +165,18 @@ module ActiveMcp
162
165
  response[:error][:data] = data if data
163
166
  response
164
167
  end
168
+
169
+ def log_error(message, error)
170
+ error_details = "#{message}: #{error.message}\n"
171
+ error_details += error.backtrace.join("\n") if error.backtrace
172
+
173
+ if defined?(Rails)
174
+ Rails.logger.error(error_details)
175
+ else
176
+ # Fallback to standard error output if Rails is not available
177
+ $stderr.puts(error_details)
178
+ end
179
+ end
165
180
  end
166
181
  end
167
182
  end
@@ -35,7 +35,43 @@ module ActiveMcp
35
35
 
36
36
  def invoke_tool(name, arguments)
37
37
  require "net/http"
38
- uri = URI.parse(@uri.to_s)
38
+
39
+ # URIの検証
40
+ unless @uri.is_a?(URI) || @uri.is_a?(String)
41
+ log_error("Invalid URI type", StandardError.new("URI must be a String or URI object"))
42
+ return {
43
+ isError: true,
44
+ content: [{type: "text", text: "Invalid URI configuration"}]
45
+ }
46
+ end
47
+
48
+ begin
49
+ uri = URI.parse(@uri.to_s)
50
+
51
+ # 有効なスキームとホストの検証
52
+ unless uri.scheme =~ /\Ahttps?\z/ && !uri.host.nil?
53
+ log_error("Invalid URI", StandardError.new("URI must have a valid scheme and host"))
54
+ return {
55
+ isError: true,
56
+ content: [{type: "text", text: "Invalid URI configuration"}]
57
+ }
58
+ end
59
+
60
+ # 本番環境ではHTTPSを強制
61
+ if defined?(Rails) && Rails.env.production? && uri.scheme != "https"
62
+ return {
63
+ isError: true,
64
+ content: [{type: "text", text: "HTTPS is required in production environment"}]
65
+ }
66
+ end
67
+ rescue URI::InvalidURIError => e
68
+ log_error("Invalid URI format", e)
69
+ return {
70
+ isError: true,
71
+ content: [{type: "text", text: "Invalid URI format"}]
72
+ }
73
+ end
74
+
39
75
  request = Net::HTTP::Post.new(uri)
40
76
  request.body = JSON.generate({
41
77
  method: "tools/call",
@@ -67,9 +103,11 @@ module ActiveMcp
67
103
  }
68
104
  end
69
105
  rescue => e
106
+ # ログに詳細を記録
107
+ log_error("Error calling tool", e)
70
108
  {
71
109
  isError: true,
72
- content: [{type: "text", text: "Error calling tool: #{e.message}"}]
110
+ content: [{type: "text", text: "Error calling tool"}]
73
111
  }
74
112
  end
75
113
  end
@@ -78,7 +116,32 @@ module ActiveMcp
78
116
  return unless @uri
79
117
 
80
118
  require "net/http"
81
- uri = URI.parse(@uri.to_s)
119
+
120
+ # URIの検証
121
+ unless @uri.is_a?(URI) || @uri.is_a?(String)
122
+ log_error("Invalid URI type", StandardError.new("URI must be a String or URI object"))
123
+ return
124
+ end
125
+
126
+ begin
127
+ uri = URI.parse(@uri.to_s)
128
+
129
+ # 有効なスキームとホストの検証
130
+ unless uri.scheme =~ /\Ahttps?\z/ && !uri.host.nil?
131
+ log_error("Invalid URI", StandardError.new("URI must have a valid scheme and host"))
132
+ return
133
+ end
134
+
135
+ # 本番環境ではHTTPSを強制
136
+ if defined?(Rails) && Rails.env.production? && uri.scheme != "https"
137
+ log_error("HTTPS is required in production environment", StandardError.new("Non-HTTPS URI in production"))
138
+ return
139
+ end
140
+ rescue URI::InvalidURIError => e
141
+ log_error("Invalid URI format", e)
142
+ return
143
+ end
144
+
82
145
  request = Net::HTTP::Post.new(uri)
83
146
  request.body = JSON.generate({
84
147
  method: "tools/list",
@@ -94,7 +157,8 @@ module ActiveMcp
94
157
 
95
158
  result = JSON.parse(response.body, symbolize_names: true)
96
159
  @tools = result[:result]
97
- rescue
160
+ rescue => e
161
+ log_error("Error fetching tools", e)
98
162
  @tools = []
99
163
  end
100
164
  end
@@ -109,6 +173,18 @@ module ActiveMcp
109
173
  {content: [{type: "text", text: result.to_s}]}
110
174
  end
111
175
  end
176
+
177
+ def log_error(message, error)
178
+ error_details = "#{message}: #{error.message}\n"
179
+ error_details += error.backtrace.join("\n") if error.backtrace
180
+
181
+ if defined?(Rails)
182
+ Rails.logger.error(error_details)
183
+ else
184
+ # Fallback to standard error output if Rails is not available
185
+ $stderr.puts(error_details)
186
+ end
187
+ end
112
188
  end
113
189
  end
114
190
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMcp
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
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.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Your Name
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-02 00:00:00.000000000 Z
10
+ date: 2025-04-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails