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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 791510bf59750086b139e1688d8cfd7367c635a359f2dfe2678756e612a20816
4
- data.tar.gz: 320cb00fa8a75622a667260477c479fd1c9df653e54af85238dc77384923b0a9
3
+ metadata.gz: 1552f0de026c1ac0790e5fa34924b9263c0ce93ed7b331d174267e2b7dc2f7da
4
+ data.tar.gz: 7450308c7d05d625aa5f51e81695afa84039a0994ff055db068794ea8c9274fa
5
5
  SHA512:
6
- metadata.gz: d65ba7458c1718d59d8b718eb8422192a1b520e72f877427feb4bdcb9057f9350718ebc8e4687eb7cc05f447962d728949cef94ed2c90937d82deb5ea3fc0727
7
- data.tar.gz: 54ed82f6c351d9e91e4e4108ed27767564c84d7d0bfc65a101598c0cdc5b879c70aa1b926d2e5c60a8181372a88ad6e9049a7232242726607ae65f58b9585816
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
- property :title, :string
63
- property :content, :string
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
- property :param1, :string, required: true, description: 'First parameter description'
133
- property :param2, :string, required: false, description: 'Second parameter description'
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
- property :name, :string, required: true, description: 'User name'
151
- property :age, :integer, required: false, description: 'User age'
152
- property :addresses, :array, required: false, description: 'User addresses'
153
- property :preferences, :object, required: false, description: 'User preferences'
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 `authorized?` class method:
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
- property :command, :string, required: true, description: "Admin command to execute"
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.authorized?(auth_info)
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
- property :resource_id, :string, required: true, description: 'ID of the resource to access'
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
- property :email, :string, required: false, description: 'Email to search for'
349
- property :name, :string, required: false, description: 'Name to search for'
350
- property :limit, :integer, required: false, description: 'Maximum number of records to return'
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
- property :title, :string, required: false, description: 'Title to search for'
371
- property :author_id, :integer, required: false, description: 'Author ID to filter by'
372
- property :limit, :integer, required: false, description: 'Maximum number of records to return'
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 :process_authentication, only: [:index]
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
- tools = Response::Tools.to_hash(auth_info: @auth_info)
19
- if params[:jsonrpc]
20
- result = Response::ToolsList::Jsonrpc.call(id: params[:id], tools:)
21
- else
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
- if params[:jsonrpc]
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[:body], status: result[:status]
53
+ render json: result, status: 200
35
54
  end
36
55
 
37
- private
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.to_hash(id:, name:, version:)
4
+ def self.call(id:)
5
5
  {
6
- body: {
7
- jsonrpc: JSON_RPC_VERSION,
8
- id:,
9
- result: {
10
- protocolVersion: PROTOCOL_VERSION,
6
+ jsonrpc: JSON_RPC_VERSION,
7
+ id:,
8
+ result: {
9
+ protocolVersion: PROTOCOL_VERSION,
10
+ capabilities: {
11
+ logging: {},
11
12
  capabilities: {
12
- logging: {},
13
- capabilities: {
14
- resources: {
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
- serverInfo: {
24
- name: ActiveMcp.config.server_name,
25
- version: ActiveMcp.config.server_version
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.to_hash
4
+ def self.call
5
5
  {
6
- body: {
7
- jsonrpc: JSON_RPC_VERSION,
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,8 +3,7 @@ module ActiveMcp
3
3
  class NoMethod
4
4
  def self.call
5
5
  {
6
- body: { error: "Method not found" },
7
- status: 404
6
+ error: "Method not found"
8
7
  }
9
8
  end
10
9
  end
@@ -3,7 +3,7 @@ module ActiveMcp
3
3
  class Tools
4
4
  def self.to_hash(auth_info:)
5
5
  Tool.registered_tools.select do |tool_class|
6
- tool_class.authorized?(auth_info)
6
+ tool_class.visible?(auth_info)
7
7
  end.map do |tool_class|
8
8
  {
9
9
  name: tool_class.tool_name,
@@ -3,62 +3,7 @@ module ActiveMcp
3
3
  module ToolsCall
4
4
  class Json
5
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
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 = Json.call(params: params[:params], auth_info:)
6
+ result = ActiveMcp::ToolExecutor.call(params: params[:params], auth_info:)
7
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]
8
+ jsonrpc: JSON_RPC_VERSION,
9
+ id:,
10
+ result:
21
11
  }
22
12
  end
23
13
  end
@@ -4,8 +4,7 @@ module ActiveMcp
4
4
  class Json
5
5
  def self.call(tools:)
6
6
  {
7
- body: { result: tools},
8
- status: 200
7
+ result: tools
9
8
  }
10
9
  end
11
10
  end
@@ -4,12 +4,9 @@ module ActiveMcp
4
4
  class Jsonrpc
5
5
  def self.call(id:, tools:)
6
6
  {
7
- body: {
8
- jsonrpc: JSON_RPC_VERSION,
9
- id:,
10
- result: {tools:}
11
- },
12
- status: 200
7
+ jsonrpc: JSON_RPC_VERSION,
8
+ id:,
9
+ result: {tools:}
13
10
  }
14
11
  end
15
12
  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
- body = JSON.parse(response.body, symbolize_names: true)
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
@@ -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 authorized?(auth_info)
42
+ def visible?(auth_info)
39
43
  true
40
44
  end
41
45
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMcp
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -1,13 +1,13 @@
1
1
  class <%= class_name %> < ActiveMcp::Tool
2
2
  description "<%= file_name.humanize %>"
3
3
 
4
- property :param1, :string, required: true, description: "First parameter description"
5
- property :param2, :string, required: false, description: "Second parameter description"
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.authorized?(auth_info)
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.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
- - Your Name
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
- - your.email@example.com
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