actionmcp 0.51.0 → 0.52.0
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 +83 -0
- data/app/controllers/action_mcp/application_controller.rb +12 -6
- data/lib/action_mcp/client/session_store.rb +117 -26
- data/lib/action_mcp/configuration.rb +16 -1
- data/lib/action_mcp/current.rb +19 -0
- data/lib/action_mcp/current_helpers.rb +19 -0
- data/lib/action_mcp/gateway.rb +85 -0
- data/lib/action_mcp/json_rpc_handler_base.rb +6 -1
- data/lib/action_mcp/jwt_decoder.rb +26 -0
- data/lib/action_mcp/prompt.rb +1 -0
- data/lib/action_mcp/resource_template.rb +1 -0
- data/lib/action_mcp/server/base_messaging.rb +14 -0
- data/lib/action_mcp/server/error_aware.rb +8 -1
- data/lib/action_mcp/server/handlers/tool_handler.rb +2 -1
- data/lib/action_mcp/server/json_rpc_handler.rb +12 -4
- data/lib/action_mcp/server/messaging.rb +12 -1
- data/lib/action_mcp/server/registry_management.rb +0 -1
- data/lib/action_mcp/server/response_collector.rb +40 -0
- data/lib/action_mcp/server/session_store.rb +762 -0
- data/lib/action_mcp/server/tools.rb +14 -3
- data/lib/action_mcp/server/transport_handler.rb +9 -5
- data/lib/action_mcp/server.rb +7 -0
- data/lib/action_mcp/tagged_stream_logging.rb +0 -4
- data/lib/action_mcp/test_helper/progress_notification_assertions.rb +105 -0
- data/lib/action_mcp/test_helper/session_store_assertions.rb +130 -0
- data/lib/action_mcp/test_helper.rb +4 -0
- data/lib/action_mcp/tool.rb +1 -0
- data/lib/action_mcp/version.rb +1 -1
- data/lib/action_mcp.rb +0 -1
- data/lib/generators/action_mcp/install/install_generator.rb +4 -0
- data/lib/generators/action_mcp/install/templates/application_gateway.rb +40 -0
- metadata +25 -1
@@ -39,14 +39,25 @@ module ActionMCP
|
|
39
39
|
tool_class = session.registered_tools.find { |t| t.tool_name == tool_name }
|
40
40
|
|
41
41
|
if tool_class
|
42
|
-
# Create tool and set execution context
|
42
|
+
# Create tool and set execution context with request info
|
43
43
|
tool = tool_class.new(arguments)
|
44
|
-
tool.with_context({
|
44
|
+
tool.with_context({
|
45
|
+
session: session,
|
46
|
+
request: {
|
47
|
+
params: {
|
48
|
+
name: tool_name,
|
49
|
+
arguments: arguments,
|
50
|
+
_meta: _meta
|
51
|
+
}
|
52
|
+
}
|
53
|
+
})
|
45
54
|
|
46
55
|
result = tool.call
|
47
56
|
|
48
57
|
if result.is_error
|
49
|
-
|
58
|
+
# Convert ToolResponse error to proper JSON-RPC error format
|
59
|
+
error_hash = result.to_h
|
60
|
+
send_jsonrpc_response(request_id, error: error_hash)
|
50
61
|
else
|
51
62
|
send_jsonrpc_response(request_id, result: result)
|
52
63
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "response_collector"
|
4
|
+
require_relative "base_messaging"
|
5
|
+
|
3
6
|
module ActionMCP
|
4
7
|
module Server
|
5
8
|
class TransportHandler
|
@@ -9,6 +12,7 @@ module ActionMCP
|
|
9
12
|
delegate :read, :write, to: :session
|
10
13
|
include Logging
|
11
14
|
|
15
|
+
include BaseMessaging # Provides basic write_message
|
12
16
|
include Messaging
|
13
17
|
include Capabilities
|
14
18
|
include Tools
|
@@ -17,10 +21,14 @@ module ActionMCP
|
|
17
21
|
include Notifications
|
18
22
|
include Sampling
|
19
23
|
include Roots
|
24
|
+
include ResponseCollector # Must be included last to override write_message
|
20
25
|
|
21
26
|
# @param [ActionMCP::Session] session
|
22
|
-
|
27
|
+
# @param messaging_mode [:write, :return] The mode for message handling
|
28
|
+
def initialize(session, messaging_mode: :write)
|
23
29
|
@session = session
|
30
|
+
@messaging_mode = messaging_mode
|
31
|
+
initialize_response_collector if messaging_mode == :return
|
24
32
|
end
|
25
33
|
|
26
34
|
def send_pong(request_id)
|
@@ -29,10 +37,6 @@ module ActionMCP
|
|
29
37
|
|
30
38
|
private
|
31
39
|
|
32
|
-
def write_message(data)
|
33
|
-
session.write(data)
|
34
|
-
end
|
35
|
-
|
36
40
|
def format_registry_items(registry)
|
37
41
|
registry.map { |item| item.klass.to_h }
|
38
42
|
end
|
data/lib/action_mcp/server.rb
CHANGED
@@ -28,6 +28,13 @@ module ActionMCP
|
|
28
28
|
@server = nil
|
29
29
|
end
|
30
30
|
|
31
|
+
# Access the session store
|
32
|
+
def session_store
|
33
|
+
@session_store ||= SessionStoreFactory.create(
|
34
|
+
ActionMCP.configuration.session_store_type
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
31
38
|
# Available pubsub adapter types
|
32
39
|
ADAPTERS = {
|
33
40
|
"test" => "SimplePubSub",
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionMCP
|
4
|
+
module TestHelper
|
5
|
+
module ProgressNotificationAssertions
|
6
|
+
# Assert that at least one progress notification was sent with the given token
|
7
|
+
def assert_progress_notification_sent(token, message = nil)
|
8
|
+
notifications = get_progress_notifications(token)
|
9
|
+
assert notifications.any?,
|
10
|
+
message || "Expected at least one progress notification with token #{token}, but none were sent"
|
11
|
+
end
|
12
|
+
|
13
|
+
# Assert that no progress notifications were sent with the given token
|
14
|
+
def assert_no_progress_notification_sent(token, message = nil)
|
15
|
+
notifications = get_progress_notifications(token)
|
16
|
+
assert notifications.empty?,
|
17
|
+
message || "Expected no progress notifications with token #{token}, but #{notifications.size} were sent"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Assert that progress values increase monotonically
|
21
|
+
def assert_progress_sequence_valid(token, message = nil)
|
22
|
+
notifications = get_progress_notifications(token)
|
23
|
+
progress_values = notifications.map { |n| n.params[:progress] }
|
24
|
+
|
25
|
+
assert progress_values.each_cons(2).all? { |a, b| b > a },
|
26
|
+
message || "Progress values must increase monotonically, but got: #{progress_values.inspect}"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Assert specific fields in the latest progress notification
|
30
|
+
def assert_progress_notification_includes(token, expected, message = nil)
|
31
|
+
notifications = get_progress_notifications(token)
|
32
|
+
assert notifications.any?, "No progress notifications found for token #{token}"
|
33
|
+
|
34
|
+
notification = notifications.last
|
35
|
+
expected.each do |key, value|
|
36
|
+
actual = notification.params[key]
|
37
|
+
assert_equal value, actual,
|
38
|
+
message || "Expected notification to have #{key}: #{value.inspect}, but got: #{actual.inspect}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Assert the total count of progress notifications for a token
|
43
|
+
def assert_progress_notification_count(token, expected_count, message = nil)
|
44
|
+
notifications = get_progress_notifications(token)
|
45
|
+
actual_count = notifications.size
|
46
|
+
|
47
|
+
assert_equal expected_count, actual_count,
|
48
|
+
message || "Expected #{expected_count} progress notifications for token #{token}, but got #{actual_count}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Assert notification follows MCP spec structure
|
52
|
+
def assert_progress_notification_valid(notification, message = nil)
|
53
|
+
# Convert to hash if it's a notification object
|
54
|
+
data = notification.respond_to?(:to_h) ? notification.to_h : notification
|
55
|
+
|
56
|
+
# Verify JSON-RPC structure
|
57
|
+
assert_equal "2.0", data["jsonrpc"] || data[:jsonrpc],
|
58
|
+
message || "Notification must have jsonrpc: 2.0"
|
59
|
+
assert_equal "notifications/progress", data[:method],
|
60
|
+
message || "Notification method must be notifications/progress"
|
61
|
+
assert_nil data[:id],
|
62
|
+
message || "Notifications must not have an id field"
|
63
|
+
|
64
|
+
# Verify params
|
65
|
+
params = data[:params]
|
66
|
+
assert params, "Notification must have params"
|
67
|
+
assert params[:progressToken], "Notification must have progressToken"
|
68
|
+
assert params[:progress], "Notification must have progress value"
|
69
|
+
|
70
|
+
# Type checks
|
71
|
+
assert [ String, Integer ].include?(params[:progressToken].class),
|
72
|
+
"progressToken must be string or integer"
|
73
|
+
assert params[:progress].is_a?(Numeric),
|
74
|
+
"progress must be numeric"
|
75
|
+
|
76
|
+
# Optional field type checks if present
|
77
|
+
if params.key?(:total)
|
78
|
+
assert params[:total].is_a?(Numeric),
|
79
|
+
"total must be numeric when present"
|
80
|
+
end
|
81
|
+
|
82
|
+
if params.key?(:message)
|
83
|
+
assert params[:message].is_a?(String),
|
84
|
+
"message must be string when present"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the current session store (with helpful error if not using test store)
|
89
|
+
def progress_session_store
|
90
|
+
store = ActionMCP::Server.session_store
|
91
|
+
unless store.respond_to?(:notifications_for_token)
|
92
|
+
raise "Session store #{store.class} does not support notification tracking. " \
|
93
|
+
"Use TestSessionStore for progress notification tests."
|
94
|
+
end
|
95
|
+
store
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def get_progress_notifications(token)
|
101
|
+
progress_session_store.notifications_for_token(token)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionMCP
|
4
|
+
module TestHelper
|
5
|
+
module SessionStoreAssertions
|
6
|
+
# Server session store assertions
|
7
|
+
def assert_session_created(session_id, message = nil)
|
8
|
+
assert server_session_store.session_created?(session_id),
|
9
|
+
message || "Expected session #{session_id} to have been created"
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_session_not_created(session_id, message = nil)
|
13
|
+
assert_not server_session_store.session_created?(session_id),
|
14
|
+
message || "Expected session #{session_id} not to have been created"
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_session_loaded(session_id, message = nil)
|
18
|
+
assert server_session_store.session_loaded?(session_id),
|
19
|
+
message || "Expected session #{session_id} to have been loaded"
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_session_not_loaded(session_id, message = nil)
|
23
|
+
assert_not server_session_store.session_loaded?(session_id),
|
24
|
+
message || "Expected session #{session_id} not to have been loaded"
|
25
|
+
end
|
26
|
+
|
27
|
+
def assert_session_saved(session_id, message = nil)
|
28
|
+
assert server_session_store.session_saved?(session_id),
|
29
|
+
message || "Expected session #{session_id} to have been saved"
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_session_not_saved(session_id, message = nil)
|
33
|
+
assert_not server_session_store.session_saved?(session_id),
|
34
|
+
message || "Expected session #{session_id} not to have been saved"
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_session_deleted(session_id, message = nil)
|
38
|
+
assert server_session_store.session_deleted?(session_id),
|
39
|
+
message || "Expected session #{session_id} to have been deleted"
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_session_not_deleted(session_id, message = nil)
|
43
|
+
assert_not server_session_store.session_deleted?(session_id),
|
44
|
+
message || "Expected session #{session_id} not to have been deleted"
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_session_operation_count(expected, type = nil, message = nil)
|
48
|
+
actual = server_session_store.operation_count(type)
|
49
|
+
type_desc = type ? " of type #{type}" : ""
|
50
|
+
assert_equal expected, actual,
|
51
|
+
message || "Expected #{expected} session operations#{type_desc}, got #{actual}"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Client session store assertions
|
55
|
+
def assert_client_session_saved(session_id, message = nil)
|
56
|
+
assert client_session_store.session_saved?(session_id),
|
57
|
+
message || "Expected client session #{session_id} to have been saved"
|
58
|
+
end
|
59
|
+
|
60
|
+
def assert_client_session_not_saved(session_id, message = nil)
|
61
|
+
assert_not client_session_store.session_saved?(session_id),
|
62
|
+
message || "Expected client session #{session_id} not to have been saved"
|
63
|
+
end
|
64
|
+
|
65
|
+
def assert_client_session_loaded(session_id, message = nil)
|
66
|
+
assert client_session_store.session_loaded?(session_id),
|
67
|
+
message || "Expected client session #{session_id} to have been loaded"
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_client_session_not_loaded(session_id, message = nil)
|
71
|
+
assert_not client_session_store.session_loaded?(session_id),
|
72
|
+
message || "Expected client session #{session_id} not to have been loaded"
|
73
|
+
end
|
74
|
+
|
75
|
+
def assert_client_session_updated(session_id, message = nil)
|
76
|
+
assert client_session_store.session_updated?(session_id),
|
77
|
+
message || "Expected client session #{session_id} to have been updated"
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_client_session_not_updated(session_id, message = nil)
|
81
|
+
assert_not client_session_store.session_updated?(session_id),
|
82
|
+
message || "Expected client session #{session_id} not to have been updated"
|
83
|
+
end
|
84
|
+
|
85
|
+
def assert_client_session_deleted(session_id, message = nil)
|
86
|
+
assert client_session_store.session_deleted?(session_id),
|
87
|
+
message || "Expected client session #{session_id} to have been deleted"
|
88
|
+
end
|
89
|
+
|
90
|
+
def assert_client_session_not_deleted(session_id, message = nil)
|
91
|
+
assert_not client_session_store.session_deleted?(session_id),
|
92
|
+
message || "Expected client session #{session_id} not to have been deleted"
|
93
|
+
end
|
94
|
+
|
95
|
+
def assert_client_session_operation_count(expected, type = nil, message = nil)
|
96
|
+
actual = client_session_store.operation_count(type)
|
97
|
+
type_desc = type ? " of type #{type}" : ""
|
98
|
+
assert_equal expected, actual,
|
99
|
+
message || "Expected #{expected} client session operations#{type_desc}, got #{actual}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def assert_client_session_data_includes(session_id, expected_data, message = nil)
|
103
|
+
saved_data = client_session_store.last_saved_data(session_id)
|
104
|
+
assert saved_data, "No saved data found for session #{session_id}"
|
105
|
+
|
106
|
+
expected_data.each do |key, value|
|
107
|
+
assert_equal value, saved_data[key],
|
108
|
+
message || "Expected session #{session_id} data to include #{key}: #{value}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def server_session_store
|
115
|
+
store = ActionMCP::Server.session_store
|
116
|
+
raise "Server session store is not a TestSessionStore" unless store.is_a?(ActionMCP::Server::TestSessionStore)
|
117
|
+
store
|
118
|
+
end
|
119
|
+
|
120
|
+
def client_session_store
|
121
|
+
# This would need to be set by the test or could use a thread-local variable
|
122
|
+
# For now, we'll assume it's available as an instance variable
|
123
|
+
store = @client_session_store || Thread.current[:test_client_session_store]
|
124
|
+
raise "Client session store not set. Set @client_session_store or Thread.current[:test_client_session_store]" unless store
|
125
|
+
raise "Client session store is not a TestSessionStore" unless store.is_a?(ActionMCP::Client::TestSessionStore)
|
126
|
+
store
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/testing/assertions"
|
4
|
+
require_relative "test_helper/session_store_assertions"
|
5
|
+
require_relative "test_helper/progress_notification_assertions"
|
4
6
|
|
5
7
|
module ActionMCP
|
6
8
|
#---------------------------------------------------------------------------
|
@@ -23,6 +25,8 @@ module ActionMCP
|
|
23
25
|
#---------------------------------------------------------------------------
|
24
26
|
module TestHelper
|
25
27
|
include ActiveSupport::Testing::Assertions
|
28
|
+
include SessionStoreAssertions
|
29
|
+
include ProgressNotificationAssertions
|
26
30
|
|
27
31
|
# ──── Registry assertions ────────────────────────────────────────────────
|
28
32
|
def assert_mcp_tool_findable(name, msg = nil)
|
data/lib/action_mcp/tool.rb
CHANGED
@@ -7,6 +7,7 @@ module ActionMCP
|
|
7
7
|
# Tools are registered automatically in the ToolsRegistry unless marked as abstract.
|
8
8
|
class Tool < Capability
|
9
9
|
include ActionMCP::Callbacks
|
10
|
+
include ActionMCP::CurrentHelpers
|
10
11
|
# --------------------------------------------------------------------------
|
11
12
|
# Class Attributes for Tool Metadata and Schema
|
12
13
|
# --------------------------------------------------------------------------
|
data/lib/action_mcp/version.rb
CHANGED
data/lib/action_mcp.rb
CHANGED
@@ -23,6 +23,10 @@ module ActionMcp
|
|
23
23
|
def create_mcp_profile_file
|
24
24
|
template "mcp.yml", File.join("config", "mcp.yml")
|
25
25
|
end
|
26
|
+
|
27
|
+
def create_application_gateway_file
|
28
|
+
template "application_gateway.rb", File.join("app/mcp", "application_gateway.rb")
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ApplicationGateway < ActionMCP::Gateway
|
4
|
+
# Specify what attributes identify a connection
|
5
|
+
# Multiple identifiers can be used (e.g., user, account, organization)
|
6
|
+
identified_by :user
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# Override this method to implement your authentication logic
|
11
|
+
# Must return a hash with keys matching the identified_by attributes
|
12
|
+
# or raise ActionMCP::UnauthorizedError
|
13
|
+
def authenticate!
|
14
|
+
# Example using JWT:
|
15
|
+
token = extract_bearer_token
|
16
|
+
raise ActionMCP::UnauthorizedError, "Missing token" unless token
|
17
|
+
|
18
|
+
payload = ActionMCP::JwtDecoder.decode(token)
|
19
|
+
user = resolve_user(payload)
|
20
|
+
|
21
|
+
raise ActionMCP::UnauthorizedError, "Unauthorized" unless user
|
22
|
+
|
23
|
+
# Return a hash with all identified_by attributes
|
24
|
+
{ user: user }
|
25
|
+
rescue ActionMCP::JwtDecoder::DecodeError => e
|
26
|
+
raise ActionMCP::UnauthorizedError, e.message
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Example method to resolve user from JWT payload
|
32
|
+
def resolve_user(payload)
|
33
|
+
return nil unless payload.is_a?(Hash)
|
34
|
+
user_id = payload["user_id"] || payload["sub"]
|
35
|
+
return nil unless user_id
|
36
|
+
|
37
|
+
# Replace with your User model lookup
|
38
|
+
User.find_by(id: user_id)
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionmcp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.52.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abdelkader Boudih
|
@@ -93,6 +93,20 @@ dependencies:
|
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '2.6'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: jwt
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '2.10'
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.10'
|
96
110
|
description: It offers base classes and helpers for creating MCP applications, making
|
97
111
|
it easier to integrate your Ruby/Rails application with the MCP standard
|
98
112
|
email:
|
@@ -150,13 +164,17 @@ files:
|
|
150
164
|
- lib/action_mcp/content/image.rb
|
151
165
|
- lib/action_mcp/content/resource.rb
|
152
166
|
- lib/action_mcp/content/text.rb
|
167
|
+
- lib/action_mcp/current.rb
|
168
|
+
- lib/action_mcp/current_helpers.rb
|
153
169
|
- lib/action_mcp/engine.rb
|
170
|
+
- lib/action_mcp/gateway.rb
|
154
171
|
- lib/action_mcp/gem_version.rb
|
155
172
|
- lib/action_mcp/instrumentation/controller_runtime.rb
|
156
173
|
- lib/action_mcp/instrumentation/instrumentation.rb
|
157
174
|
- lib/action_mcp/instrumentation/resource_instrumentation.rb
|
158
175
|
- lib/action_mcp/integer_array.rb
|
159
176
|
- lib/action_mcp/json_rpc_handler_base.rb
|
177
|
+
- lib/action_mcp/jwt_decoder.rb
|
160
178
|
- lib/action_mcp/log_subscriber.rb
|
161
179
|
- lib/action_mcp/logging.rb
|
162
180
|
- lib/action_mcp/prompt.rb
|
@@ -169,6 +187,7 @@ files:
|
|
169
187
|
- lib/action_mcp/resource_template.rb
|
170
188
|
- lib/action_mcp/resource_templates_registry.rb
|
171
189
|
- lib/action_mcp/server.rb
|
190
|
+
- lib/action_mcp/server/base_messaging.rb
|
172
191
|
- lib/action_mcp/server/capabilities.rb
|
173
192
|
- lib/action_mcp/server/configuration.rb
|
174
193
|
- lib/action_mcp/server/error_aware.rb
|
@@ -182,9 +201,11 @@ files:
|
|
182
201
|
- lib/action_mcp/server/prompts.rb
|
183
202
|
- lib/action_mcp/server/registry_management.rb
|
184
203
|
- lib/action_mcp/server/resources.rb
|
204
|
+
- lib/action_mcp/server/response_collector.rb
|
185
205
|
- lib/action_mcp/server/roots.rb
|
186
206
|
- lib/action_mcp/server/sampling.rb
|
187
207
|
- lib/action_mcp/server/sampling_request.rb
|
208
|
+
- lib/action_mcp/server/session_store.rb
|
188
209
|
- lib/action_mcp/server/simple_pub_sub.rb
|
189
210
|
- lib/action_mcp/server/solid_cable_adapter.rb
|
190
211
|
- lib/action_mcp/server/tools.rb
|
@@ -193,6 +214,8 @@ files:
|
|
193
214
|
- lib/action_mcp/string_array.rb
|
194
215
|
- lib/action_mcp/tagged_stream_logging.rb
|
195
216
|
- lib/action_mcp/test_helper.rb
|
217
|
+
- lib/action_mcp/test_helper/progress_notification_assertions.rb
|
218
|
+
- lib/action_mcp/test_helper/session_store_assertions.rb
|
196
219
|
- lib/action_mcp/tool.rb
|
197
220
|
- lib/action_mcp/tool_response.rb
|
198
221
|
- lib/action_mcp/tools_registry.rb
|
@@ -203,6 +226,7 @@ files:
|
|
203
226
|
- lib/generators/action_mcp/config/config_generator.rb
|
204
227
|
- lib/generators/action_mcp/config/templates/mcp.yml
|
205
228
|
- lib/generators/action_mcp/install/install_generator.rb
|
229
|
+
- lib/generators/action_mcp/install/templates/application_gateway.rb
|
206
230
|
- lib/generators/action_mcp/install/templates/application_mcp_prompt.rb
|
207
231
|
- lib/generators/action_mcp/install/templates/application_mcp_res_template.rb
|
208
232
|
- lib/generators/action_mcp/install/templates/application_mcp_tool.rb
|