active_mcp 0.3.1 → 0.3.3
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/README.md +18 -18
- data/app/controllers/active_mcp/base_controller.rb +33 -16
- data/app/models/active_mcp/response/initialize.rb +18 -21
- data/app/models/active_mcp/response/initialized.rb +3 -6
- data/app/models/active_mcp/response/no_method.rb +1 -2
- data/app/models/active_mcp/response/tools.rb +1 -1
- data/app/models/active_mcp/response/tools_call/json.rb +1 -56
- data/app/models/active_mcp/response/tools_call/jsonrpc.rb +4 -14
- data/app/models/active_mcp/response/tools_list/json.rb +1 -2
- data/app/models/active_mcp/response/tools_list/jsonrpc.rb +3 -6
- data/app/models/active_mcp/tool_executor.rb +104 -0
- data/lib/active_mcp/server/tool_manager.rb +1 -28
- data/lib/active_mcp/tool.rb +5 -1
- data/lib/active_mcp/version.rb +1 -1
- data/lib/generators/active_mcp/tool/templates/tool.rb.erb +3 -3
- metadata +4 -4
- data/lib/generators/active_mcp/install/templates/mcp_server.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1552f0de026c1ac0790e5fa34924b9263c0ce93ed7b331d174267e2b7dc2f7da
|
4
|
+
data.tar.gz: 7450308c7d05d625aa5f51e81695afa84039a0994ff055db068794ea8c9274fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 392a25227f1dc6d0d073821dec6f6e0b17fa3fcdf1c2bb55793b4d71eab2422c173abb21a70820134d119e785f0991fe2e68cfa85aee987ef5f542cd966b5b49
|
7
|
+
data.tar.gz: fb1af057ea0a2f4a0dcdb664c2228013a8f058f13850be2de19be1516e26febbb9df06d51c9d74ec6262d2aa1a14f283067390ee579b5a93c96c1a736b2b15fa
|
data/README.md
CHANGED
@@ -59,8 +59,8 @@ end
|
|
59
59
|
class CreateNoteTool < ActiveMcp::Tool
|
60
60
|
description "Create Note!!"
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
argument :title, :string
|
63
|
+
argument :content, :string
|
64
64
|
|
65
65
|
def call(title:, content:)
|
66
66
|
Note.create(title:, content:)
|
@@ -129,8 +129,8 @@ This creates a new tool file at `app/tools/search_users_tool.rb` with the follow
|
|
129
129
|
class SearchUsersTool < ActiveMcp::Tool
|
130
130
|
description 'Search users'
|
131
131
|
|
132
|
-
|
133
|
-
|
132
|
+
argument :param1, :string, required: true, description: 'First parameter description'
|
133
|
+
argument :param2, :string, required: false, description: 'Second parameter description'
|
134
134
|
# Add more parameters as needed
|
135
135
|
|
136
136
|
def call(param1:, param2: nil, auth_info: nil, **args)
|
@@ -147,10 +147,10 @@ You can then customize the generated tool to fit your needs.
|
|
147
147
|
## Input Schema
|
148
148
|
|
149
149
|
```ruby
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
argument :name, :string, required: true, description: 'User name'
|
151
|
+
argument :age, :integer, required: false, description: 'User age'
|
152
|
+
argument :addresses, :array, required: false, description: 'User addresses'
|
153
|
+
argument :preferences, :object, required: false, description: 'User preferences'
|
154
154
|
```
|
155
155
|
|
156
156
|
Supported types include:
|
@@ -179,16 +179,16 @@ ActiveMcp supports both authentication (verifying who a user is) and authorizati
|
|
179
179
|
|
180
180
|
### Authorization for Tools
|
181
181
|
|
182
|
-
You can control which tools are visible and accessible to different users by overriding the `
|
182
|
+
You can control which tools are visible and accessible to different users by overriding the `visible?` class method:
|
183
183
|
|
184
184
|
```ruby
|
185
185
|
class AdminOnlyTool < ActiveMcp::Tool
|
186
186
|
description "This tool is only accessible by admins"
|
187
187
|
|
188
|
-
|
188
|
+
argument :command, :string, required: true, description: "Admin command to execute"
|
189
189
|
|
190
190
|
# Define authorization logic - only admin tokens can access this tool
|
191
|
-
def self.
|
191
|
+
def self.visible?(auth_info)
|
192
192
|
return false unless auth_info
|
193
193
|
return false unless auth_info[:type] == :bearer
|
194
194
|
|
@@ -274,7 +274,7 @@ Authentication information is automatically passed to your tools through the `au
|
|
274
274
|
class SecuredDataTool < ActiveMcp::Tool
|
275
275
|
description 'Access secured data'
|
276
276
|
|
277
|
-
|
277
|
+
argument :resource_id, :string, required: true, description: 'ID of the resource to access'
|
278
278
|
|
279
279
|
def call(resource_id:, auth_info: nil, **args)
|
280
280
|
# Check if auth info exists
|
@@ -345,9 +345,9 @@ For example, instead of creating a generic search tool, create specific search t
|
|
345
345
|
class SearchUsersTool < ActiveMcp::Tool
|
346
346
|
description 'Search users by criteria'
|
347
347
|
|
348
|
-
|
349
|
-
|
350
|
-
|
348
|
+
argument :email, :string, required: false, description: 'Email to search for'
|
349
|
+
argument :name, :string, required: false, description: 'Name to search for'
|
350
|
+
argument :limit, :integer, required: false, description: 'Maximum number of records to return'
|
351
351
|
|
352
352
|
def call(email: nil, name: nil, limit: 10)
|
353
353
|
criteria = {}
|
@@ -367,9 +367,9 @@ end
|
|
367
367
|
class SearchPostsTool < ActiveMcp::Tool
|
368
368
|
description 'Search posts by criteria'
|
369
369
|
|
370
|
-
|
371
|
-
|
372
|
-
|
370
|
+
argument :title, :string, required: false, description: 'Title to search for'
|
371
|
+
argument :author_id, :integer, required: false, description: 'Author ID to filter by'
|
372
|
+
argument :limit, :integer, required: false, description: 'Maximum number of records to return'
|
373
373
|
|
374
374
|
def call(title: nil, author_id: nil, limit: 10)
|
375
375
|
criteria = {}
|
@@ -4,9 +4,34 @@ module ActiveMcp
|
|
4
4
|
class BaseController < ActionController::Base
|
5
5
|
protect_from_forgery with: :null_session
|
6
6
|
skip_before_action :verify_authenticity_token
|
7
|
-
before_action :
|
7
|
+
before_action :authenticate, only: [:index]
|
8
8
|
|
9
9
|
def index
|
10
|
+
if params[:jsonrpc]
|
11
|
+
process_request_from_mcp_client
|
12
|
+
else
|
13
|
+
process_request_from_mcp_server
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def process_request_from_mcp_server
|
20
|
+
case params[:method]
|
21
|
+
when Method::TOOLS_LIST
|
22
|
+
result = Response::ToolsList::Json.call(
|
23
|
+
tools: Response::Tools.to_hash(auth_info: @auth_info)
|
24
|
+
)
|
25
|
+
when Method::TOOLS_CALL
|
26
|
+
result = Response::ToolsCall::Json.call(params:, auth_info: @auth_info)
|
27
|
+
else
|
28
|
+
result = Response::NoMethod.call
|
29
|
+
end
|
30
|
+
|
31
|
+
render json: result, status: 200
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_request_from_mcp_client
|
10
35
|
case params[:method]
|
11
36
|
when Method::INITIALIZE
|
12
37
|
result = Response::Initialize.call(id: params[:id])
|
@@ -15,28 +40,20 @@ module ActiveMcp
|
|
15
40
|
when Method::CANCELLED
|
16
41
|
result = Response::Cancelled.call
|
17
42
|
when Method::TOOLS_LIST
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
result = Response::ToolsList::Json.call(tools:)
|
23
|
-
end
|
43
|
+
result = Response::ToolsList::Jsonrpc.call(
|
44
|
+
id: params[:id],
|
45
|
+
tools: Response::Tools.to_hash(auth_info: @auth_info)
|
46
|
+
)
|
24
47
|
when Method::TOOLS_CALL
|
25
|
-
|
26
|
-
result = Response::ToolsCall::Jsonrpc.call(id: params[:id], params:, auth_info: @auth_info)
|
27
|
-
else
|
28
|
-
result = Response::ToolsCall::Json.call(params:, auth_info: @auth_info)
|
29
|
-
end
|
48
|
+
result = Response::ToolsCall::Jsonrpc.call(id: params[:id], params:, auth_info: @auth_info)
|
30
49
|
else
|
31
50
|
result = Response::NoMethod.call
|
32
51
|
end
|
33
52
|
|
34
|
-
render json: result
|
53
|
+
render json: result, status: 200
|
35
54
|
end
|
36
55
|
|
37
|
-
|
38
|
-
|
39
|
-
def process_authentication
|
56
|
+
def authenticate
|
40
57
|
auth_header = request.headers["Authorization"]
|
41
58
|
if auth_header.present?
|
42
59
|
@auth_info = {
|
@@ -1,32 +1,29 @@
|
|
1
1
|
module ActiveMcp
|
2
2
|
module Response
|
3
3
|
class Initialize
|
4
|
-
def self.
|
4
|
+
def self.call(id:)
|
5
5
|
{
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
jsonrpc: JSON_RPC_VERSION,
|
7
|
+
id:,
|
8
|
+
result: {
|
9
|
+
protocolVersion: PROTOCOL_VERSION,
|
10
|
+
capabilities: {
|
11
|
+
logging: {},
|
11
12
|
capabilities: {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
subscribe: false,
|
16
|
-
listChanged: false
|
17
|
-
},
|
18
|
-
tools: {
|
19
|
-
listChanged: false
|
20
|
-
}
|
13
|
+
resources: {
|
14
|
+
subscribe: false,
|
15
|
+
listChanged: false
|
21
16
|
},
|
17
|
+
tools: {
|
18
|
+
listChanged: false
|
19
|
+
}
|
22
20
|
},
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
},
|
22
|
+
serverInfo: {
|
23
|
+
name: ActiveMcp.config.server_name,
|
24
|
+
version: ActiveMcp.config.server_version
|
27
25
|
}
|
28
|
-
}
|
29
|
-
status: 200
|
26
|
+
}
|
30
27
|
}
|
31
28
|
end
|
32
29
|
end
|
@@ -1,13 +1,10 @@
|
|
1
1
|
module ActiveMcp
|
2
2
|
module Response
|
3
3
|
class Initialized
|
4
|
-
def self.
|
4
|
+
def self.call
|
5
5
|
{
|
6
|
-
|
7
|
-
|
8
|
-
method: Method::INITIALIZED
|
9
|
-
},
|
10
|
-
status: 200
|
6
|
+
jsonrpc: JSON_RPC_VERSION,
|
7
|
+
method: Method::INITIALIZED
|
11
8
|
}
|
12
9
|
end
|
13
10
|
end
|
@@ -3,62 +3,7 @@ module ActiveMcp
|
|
3
3
|
module ToolsCall
|
4
4
|
class Json
|
5
5
|
def self.call(params:, auth_info:)
|
6
|
-
|
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
|
6
|
+
ActiveMcp::ToolExecutor.call(params:, auth_info:)
|
62
7
|
end
|
63
8
|
end
|
64
9
|
end
|
@@ -3,21 +3,11 @@ module ActiveMcp
|
|
3
3
|
module ToolsCall
|
4
4
|
class Jsonrpc
|
5
5
|
def self.call(id:, params:, auth_info:)
|
6
|
-
result =
|
6
|
+
result = ActiveMcp::ToolExecutor.call(params: params[:params], auth_info:)
|
7
7
|
{
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
result: {
|
12
|
-
content: [
|
13
|
-
{
|
14
|
-
type: "text",
|
15
|
-
text: result[:body][:result]
|
16
|
-
}
|
17
|
-
]
|
18
|
-
},
|
19
|
-
},
|
20
|
-
status: result[:status]
|
8
|
+
jsonrpc: JSON_RPC_VERSION,
|
9
|
+
id:,
|
10
|
+
result:
|
21
11
|
}
|
22
12
|
end
|
23
13
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module ActiveMcp
|
2
|
+
module ToolExecutor
|
3
|
+
def self.call(params:, auth_info:)
|
4
|
+
tool_name = params[:name]
|
5
|
+
|
6
|
+
unless tool_name
|
7
|
+
return {
|
8
|
+
isError: true,
|
9
|
+
content: [
|
10
|
+
{
|
11
|
+
type: "text",
|
12
|
+
text: "Invalid params: missing tool name",
|
13
|
+
}
|
14
|
+
]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
tool_class = Tool.registered_tools.find do |tc|
|
19
|
+
tc.tool_name == tool_name
|
20
|
+
end
|
21
|
+
|
22
|
+
unless tool_class
|
23
|
+
return {
|
24
|
+
isError: true,
|
25
|
+
content: [
|
26
|
+
{
|
27
|
+
type: "text",
|
28
|
+
text: "Tool not found: #{tool_name}",
|
29
|
+
}
|
30
|
+
]
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
unless tool_class.visible?(auth_info)
|
35
|
+
return {
|
36
|
+
isError: true,
|
37
|
+
content: [
|
38
|
+
{
|
39
|
+
type: "text",
|
40
|
+
text: "Unauthorized: Access to tool '#{tool_name}' denied",
|
41
|
+
}
|
42
|
+
]
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
arguments = params[:arguments].permit!.to_hash.symbolize_keys.transform_values do |value|
|
47
|
+
if !value.is_a?(String)
|
48
|
+
value
|
49
|
+
else
|
50
|
+
value.match(/^\d+$/) ? value.to_i : value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
tool = tool_class.new
|
55
|
+
validation_result = tool.validate_arguments(arguments)
|
56
|
+
|
57
|
+
if validation_result.is_a?(Hash) && validation_result[:error]
|
58
|
+
return {
|
59
|
+
isError: true,
|
60
|
+
content: [
|
61
|
+
{
|
62
|
+
type: "text",
|
63
|
+
text: validation_result[:error],
|
64
|
+
}
|
65
|
+
]
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
begin
|
70
|
+
arguments[:auth_info] = auth_info if auth_info.present?
|
71
|
+
|
72
|
+
return {
|
73
|
+
content: [
|
74
|
+
{
|
75
|
+
type: "text",
|
76
|
+
text: formatted(tool.call(**arguments.symbolize_keys))
|
77
|
+
}
|
78
|
+
]
|
79
|
+
}
|
80
|
+
rescue => e
|
81
|
+
return {
|
82
|
+
isError: true,
|
83
|
+
content: [
|
84
|
+
{
|
85
|
+
type: "text",
|
86
|
+
text: "Error: #{e.message}",
|
87
|
+
}
|
88
|
+
]
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.formatted(object)
|
94
|
+
case object
|
95
|
+
when String
|
96
|
+
object
|
97
|
+
when Hash
|
98
|
+
object.to_json
|
99
|
+
else
|
100
|
+
object.to_s
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -36,7 +36,6 @@ module ActiveMcp
|
|
36
36
|
def invoke_tool(name, arguments)
|
37
37
|
require "net/http"
|
38
38
|
|
39
|
-
# URIの検証
|
40
39
|
unless @uri.is_a?(URI) || @uri.is_a?(String)
|
41
40
|
log_error("Invalid URI type", StandardError.new("URI must be a String or URI object"))
|
42
41
|
return {
|
@@ -48,7 +47,6 @@ module ActiveMcp
|
|
48
47
|
begin
|
49
48
|
uri = URI.parse(@uri.to_s)
|
50
49
|
|
51
|
-
# 有効なスキームとホストの検証
|
52
50
|
unless uri.scheme =~ /\Ahttps?\z/ && !uri.host.nil?
|
53
51
|
log_error("Invalid URI", StandardError.new("URI must have a valid scheme and host"))
|
54
52
|
return {
|
@@ -57,7 +55,6 @@ module ActiveMcp
|
|
57
55
|
}
|
58
56
|
end
|
59
57
|
|
60
|
-
# 本番環境ではHTTPSを強制
|
61
58
|
if defined?(Rails) && Rails.env.production? && uri.scheme != "https"
|
62
59
|
return {
|
63
60
|
isError: true,
|
@@ -87,15 +84,7 @@ module ActiveMcp
|
|
87
84
|
end
|
88
85
|
|
89
86
|
if response.code == "200"
|
90
|
-
|
91
|
-
if body[:error]
|
92
|
-
{
|
93
|
-
isError: true,
|
94
|
-
content: [{type: "text", text: body[:error]}]
|
95
|
-
}
|
96
|
-
else
|
97
|
-
format_result(body[:result])
|
98
|
-
end
|
87
|
+
JSON.parse(response.body, symbolize_names: true)
|
99
88
|
else
|
100
89
|
{
|
101
90
|
isError: true,
|
@@ -103,7 +92,6 @@ module ActiveMcp
|
|
103
92
|
}
|
104
93
|
end
|
105
94
|
rescue => e
|
106
|
-
# ログに詳細を記録
|
107
95
|
log_error("Error calling tool", e)
|
108
96
|
{
|
109
97
|
isError: true,
|
@@ -117,7 +105,6 @@ module ActiveMcp
|
|
117
105
|
|
118
106
|
require "net/http"
|
119
107
|
|
120
|
-
# URIの検証
|
121
108
|
unless @uri.is_a?(URI) || @uri.is_a?(String)
|
122
109
|
log_error("Invalid URI type", StandardError.new("URI must be a String or URI object"))
|
123
110
|
return
|
@@ -126,13 +113,11 @@ module ActiveMcp
|
|
126
113
|
begin
|
127
114
|
uri = URI.parse(@uri.to_s)
|
128
115
|
|
129
|
-
# 有効なスキームとホストの検証
|
130
116
|
unless uri.scheme =~ /\Ahttps?\z/ && !uri.host.nil?
|
131
117
|
log_error("Invalid URI", StandardError.new("URI must have a valid scheme and host"))
|
132
118
|
return
|
133
119
|
end
|
134
120
|
|
135
|
-
# 本番環境ではHTTPSを強制
|
136
121
|
if defined?(Rails) && Rails.env.production? && uri.scheme != "https"
|
137
122
|
log_error("HTTPS is required in production environment", StandardError.new("Non-HTTPS URI in production"))
|
138
123
|
return
|
@@ -162,17 +147,6 @@ module ActiveMcp
|
|
162
147
|
@tools = []
|
163
148
|
end
|
164
149
|
end
|
165
|
-
|
166
|
-
def format_result(result)
|
167
|
-
case result
|
168
|
-
when String
|
169
|
-
{content: [{type: "text", text: result}]}
|
170
|
-
when Hash
|
171
|
-
{content: [{type: "text", text: result.to_json}]}
|
172
|
-
else
|
173
|
-
{content: [{type: "text", text: result.to_s}]}
|
174
|
-
end
|
175
|
-
end
|
176
150
|
|
177
151
|
def log_error(message, error)
|
178
152
|
error_details = "#{message}: #{error.message}\n"
|
@@ -181,7 +155,6 @@ module ActiveMcp
|
|
181
155
|
if defined?(Rails)
|
182
156
|
Rails.logger.error(error_details)
|
183
157
|
else
|
184
|
-
# Fallback to standard error output if Rails is not available
|
185
158
|
$stderr.puts(error_details)
|
186
159
|
end
|
187
160
|
end
|
data/lib/active_mcp/tool.rb
CHANGED
@@ -25,6 +25,10 @@ module ActiveMcp
|
|
25
25
|
@schema["required"] << name.to_s if required
|
26
26
|
end
|
27
27
|
|
28
|
+
def argument(...)
|
29
|
+
property(...)
|
30
|
+
end
|
31
|
+
|
28
32
|
def registered_tools
|
29
33
|
@registered_tools ||= []
|
30
34
|
end
|
@@ -35,7 +39,7 @@ module ActiveMcp
|
|
35
39
|
registered_tools << subclass
|
36
40
|
end
|
37
41
|
|
38
|
-
def
|
42
|
+
def visible?(auth_info)
|
39
43
|
true
|
40
44
|
end
|
41
45
|
end
|
data/lib/active_mcp/version.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
class <%= class_name %> < ActiveMcp::Tool
|
2
2
|
description "<%= file_name.humanize %>"
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
argument :param1, :string, required: true, description: "First parameter description"
|
5
|
+
argument :param2, :string, required: false, description: "Second parameter description"
|
6
6
|
# Add more parameters as needed
|
7
7
|
|
8
8
|
# Uncomment and modify this method to implement authorization control
|
9
9
|
# This controls who can see and use this tool
|
10
|
-
# def self.
|
10
|
+
# def self.visible?(auth_info)
|
11
11
|
# # Example: require authentication
|
12
12
|
# # return false unless auth_info
|
13
13
|
#
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_mcp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Moeki Kawakami
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
10
|
date: 2025-04-06 00:00:00.000000000 Z
|
@@ -45,7 +45,7 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
description: A Rails engine that provides MCP capabilities to your Rails application
|
47
47
|
email:
|
48
|
-
-
|
48
|
+
- hi@moeki.org
|
49
49
|
executables: []
|
50
50
|
extensions: []
|
51
51
|
extra_rdoc_files: []
|
@@ -63,6 +63,7 @@ files:
|
|
63
63
|
- app/models/active_mcp/response/tools_call/jsonrpc.rb
|
64
64
|
- app/models/active_mcp/response/tools_list/json.rb
|
65
65
|
- app/models/active_mcp/response/tools_list/jsonrpc.rb
|
66
|
+
- app/models/active_mcp/tool_executor.rb
|
66
67
|
- config/routes.rb
|
67
68
|
- lib/active_mcp.rb
|
68
69
|
- lib/active_mcp/configuration.rb
|
@@ -77,7 +78,6 @@ files:
|
|
77
78
|
- lib/active_mcp/version.rb
|
78
79
|
- lib/generators/active_mcp/install/install_generator.rb
|
79
80
|
- lib/generators/active_mcp/install/templates/initializer.rb
|
80
|
-
- lib/generators/active_mcp/install/templates/mcp_server.rb
|
81
81
|
- lib/generators/active_mcp/tool/templates/tool.rb.erb
|
82
82
|
- lib/generators/active_mcp/tool/tool_generator.rb
|
83
83
|
homepage: https://github.com/moekiorg/active_mcp
|
@@ -1,31 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# MCP Server script for Active MCP
|
3
|
-
require 'active_mcp'
|
4
|
-
|
5
|
-
# Load Rails application
|
6
|
-
ENV['RAILS_ENV'] ||= 'development'
|
7
|
-
require File.expand_path('../config/environment', __dir__)
|
8
|
-
|
9
|
-
# Initialize MCP server
|
10
|
-
server = ActiveMcp::Server.new(
|
11
|
-
name: "<%= Rails.application.class.module_parent_name %> MCP Server",
|
12
|
-
uri: '<%= Rails.application.config.action_controller.default_url_options&.fetch(:host, 'http://localhost:3000') %>/mcp'
|
13
|
-
)
|
14
|
-
|
15
|
-
# Optional authentication
|
16
|
-
<% if ActiveMcp.config.auth_enabled %>
|
17
|
-
server.auth = {
|
18
|
-
type: :bearer,
|
19
|
-
token: ENV['MCP_AUTH_TOKEN'] || '<%= ActiveMcp.config.auth_token %>'
|
20
|
-
}
|
21
|
-
<% end %>
|
22
|
-
|
23
|
-
# Start the server
|
24
|
-
puts "Starting MCP server for <%= Rails.application.class.module_parent_name %>..."
|
25
|
-
puts "Connect to this server in MCP clients using the following configuration:"
|
26
|
-
puts
|
27
|
-
puts " Command: #{File.expand_path(__FILE__)}"
|
28
|
-
puts " Args: []"
|
29
|
-
puts
|
30
|
-
puts "Press Ctrl+C to stop the server"
|
31
|
-
server.start
|