actionmcp 0.19.1 → 0.22.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/action_mcp/messages_controller.rb +2 -2
  3. data/app/models/action_mcp/session/message.rb +12 -1
  4. data/app/models/action_mcp/session.rb +8 -4
  5. data/lib/action_mcp/base_response.rb +86 -0
  6. data/lib/action_mcp/capability.rb +2 -3
  7. data/lib/action_mcp/client/base.rb +222 -0
  8. data/lib/action_mcp/client/blueprint.rb +227 -0
  9. data/lib/action_mcp/client/catalog.rb +226 -0
  10. data/lib/action_mcp/client/json_rpc_handler.rb +109 -0
  11. data/lib/action_mcp/client/logging.rb +20 -0
  12. data/lib/action_mcp/{transport → client}/messaging.rb +1 -1
  13. data/lib/action_mcp/client/prompt_book.rb +183 -0
  14. data/lib/action_mcp/client/prompts.rb +33 -0
  15. data/lib/action_mcp/client/resources.rb +70 -0
  16. data/lib/action_mcp/client/roots.rb +13 -0
  17. data/lib/action_mcp/client/server.rb +60 -0
  18. data/lib/action_mcp/{transport → client}/sse_client.rb +70 -111
  19. data/lib/action_mcp/{transport → client}/stdio_client.rb +38 -38
  20. data/lib/action_mcp/client/toolbox.rb +236 -0
  21. data/lib/action_mcp/client/tools.rb +33 -0
  22. data/lib/action_mcp/client.rb +20 -231
  23. data/lib/action_mcp/engine.rb +1 -3
  24. data/lib/action_mcp/instrumentation/controller_runtime.rb +1 -1
  25. data/lib/action_mcp/instrumentation/instrumentation.rb +2 -0
  26. data/lib/action_mcp/instrumentation/resource_instrumentation.rb +1 -0
  27. data/lib/action_mcp/json_rpc_handler_base.rb +106 -0
  28. data/lib/action_mcp/log_subscriber.rb +2 -0
  29. data/lib/action_mcp/logging.rb +1 -1
  30. data/lib/action_mcp/prompt.rb +4 -3
  31. data/lib/action_mcp/prompt_response.rb +14 -58
  32. data/lib/action_mcp/{transport → server}/capabilities.rb +2 -2
  33. data/lib/action_mcp/server/json_rpc_handler.rb +121 -0
  34. data/lib/action_mcp/server/messaging.rb +28 -0
  35. data/lib/action_mcp/{transport → server}/notifications.rb +1 -1
  36. data/lib/action_mcp/{transport → server}/prompts.rb +1 -1
  37. data/lib/action_mcp/{transport → server}/resources.rb +1 -18
  38. data/lib/action_mcp/{transport → server}/roots.rb +1 -1
  39. data/lib/action_mcp/{transport → server}/sampling.rb +1 -1
  40. data/lib/action_mcp/server/sampling_request.rb +115 -0
  41. data/lib/action_mcp/{transport → server}/tools.rb +1 -1
  42. data/lib/action_mcp/server/transport_handler.rb +41 -0
  43. data/lib/action_mcp/tool_response.rb +14 -59
  44. data/lib/action_mcp/uri_ambiguity_checker.rb +6 -10
  45. data/lib/action_mcp/version.rb +1 -1
  46. data/lib/action_mcp.rb +2 -1
  47. metadata +30 -33
  48. data/lib/action_mcp/base_json_rpc_handler.rb +0 -97
  49. data/lib/action_mcp/client_json_rpc_handler.rb +0 -69
  50. data/lib/action_mcp/json_rpc_handler.rb +0 -229
  51. data/lib/action_mcp/sampling_request.rb +0 -113
  52. data/lib/action_mcp/server_json_rpc_handler.rb +0 -90
  53. data/lib/action_mcp/transport/transport_base.rb +0 -126
  54. data/lib/action_mcp/transport_handler.rb +0 -39
@@ -1,126 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionMCP
4
- module Transport
5
- class TransportBase
6
- attr_reader :logger, :client_capabilities, :server_capabilities
7
-
8
- def initialize(logger: Logger.new($stdout))
9
- @logger = logger
10
- @on_message = nil
11
- @on_error = nil
12
- @client_capabilities = default_capabilities
13
- @server_capabilities = nil
14
- @initialize_request_id = SecureRandom.hex(6)
15
- @initialization_sent = false
16
- end
17
-
18
- def on_message(&block)
19
- @on_message = block
20
- end
21
-
22
- def on_error(&block)
23
- @on_error = block
24
- end
25
-
26
- def send_initial_capabilities
27
- return if @initialization_sent
28
-
29
- log_info("Sending client capabilities: #{@client_capabilities}")
30
-
31
- request = JsonRpc::Request.new(
32
- id: @initialize_request_id,
33
- method: "initialize",
34
- params: {
35
- protocolVersion: PROTOCOL_VERSION,
36
- capabilities: @client_capabilities,
37
- clientInfo: {
38
- name: user_agent,
39
- version: ActionMCP.gem_version.to_s
40
- }
41
- }
42
- )
43
- @initialization_sent = true
44
- send_message(request.to_json)
45
- end
46
-
47
- def handle_initialize_response(response)
48
- return if @server_capabilities
49
-
50
- if response.result
51
- @server_capabilities = response.result["capabilities"]
52
- send_initialized_notification
53
- else
54
- log_error("Server initialization failed: #{response.error}")
55
- end
56
- end
57
-
58
- protected
59
-
60
- def handle_raw_message(raw)
61
- # Debug - log all raw messages
62
- log_debug("\e[31m<-- #{raw}\e[0m")
63
-
64
- begin
65
- msg_hash = MultiJson.load(raw)
66
- response = nil
67
-
68
- if msg_hash.key?("jsonrpc")
69
- response = if msg_hash.key?("id")
70
- JsonRpc::Response.new(**msg_hash.slice("id", "result", "error").symbolize_keys)
71
- else
72
- JsonRpc::Notification.new(**msg_hash.slice("method", "params").symbolize_keys)
73
- end
74
- end
75
- # Check if this is a response to our initialize request
76
- if response && @initialize_request_id && response.id == @initialize_request_id
77
- handle_initialize_response(response)
78
- elsif response
79
- @on_message&.call(response)
80
- end
81
- rescue MultiJson::ParseError => e
82
- log_error("JSON parse error: #{e} (raw: #{raw})")
83
- @on_error&.call(e)
84
- rescue StandardError => e
85
- log_error("Error handling message: #{e} (raw: #{raw})")
86
- @on_error&.call(e)
87
- end
88
- end
89
-
90
- # Send the initialized notification to the server
91
- def send_initialized_notification
92
- notification = JsonRpc::Notification.new(
93
- method: "initialized"
94
- )
95
-
96
- logger.info("Sent initialized notification to server")
97
- send_message(notification)
98
- end
99
-
100
- def default_capabilities
101
- {
102
- # Base client capabilities
103
- # roots: {}, # Remove from now.
104
- }
105
- end
106
-
107
- def log_debug(message)
108
- @logger.debug("[#{log_prefix}] #{message}")
109
- end
110
-
111
- def log_info(message)
112
- @logger.info("[#{log_prefix}] #{message}")
113
- end
114
-
115
- def log_error(message)
116
- @logger.error("[#{log_prefix}] #{message}")
117
- end
118
-
119
- private
120
-
121
- def log_prefix
122
- self.class.name.split("::").last
123
- end
124
- end
125
- end
126
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionMCP
4
- class TransportHandler
5
- attr_reader :session
6
-
7
- delegate :initialize!, :initialized?, to: :session
8
- delegate :read, :write, to: :session
9
- include Logging
10
-
11
- include Transport::Messaging
12
- include Transport::Capabilities
13
- include Transport::Tools
14
- include Transport::Prompts
15
- include Transport::Resources
16
- include Transport::Notifications
17
- include Transport::Sampling
18
- include Transport::Roots
19
-
20
- # @param [ActionMCP::Session] session
21
- def initialize(session)
22
- @session = session
23
- end
24
-
25
- def send_pong(request_id)
26
- send_jsonrpc_response(request_id, result: {})
27
- end
28
-
29
- private
30
-
31
- def write_message(data)
32
- session.write(data)
33
- end
34
-
35
- def format_registry_items(registry)
36
- registry.map { |item| item.klass.to_h }
37
- end
38
- end
39
- end