mcp 0.6.0 → 0.7.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/.github/workflows/ci.yml +6 -0
- data/CHANGELOG.md +18 -0
- data/README.md +89 -29
- data/examples/streamable_http_client.rb +4 -0
- data/examples/streamable_http_server.rb +1 -0
- data/lib/json_rpc_handler.rb +20 -0
- data/lib/mcp/annotations.rb +21 -0
- data/lib/mcp/client.rb +14 -0
- data/lib/mcp/logging_message_notification.rb +30 -0
- data/lib/mcp/resource/embedded.rb +1 -0
- data/lib/mcp/server.rb +66 -9
- data/lib/mcp/version.rb +1 -1
- data/lib/mcp.rb +1 -9
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de660064625f4c983293603731aad08da2dc60fe6efdc92a79c11501182610e4
|
|
4
|
+
data.tar.gz: 663b210aee91776875b90c06457651ff33fe2c125826ee188a8143bf5569e5e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77e28efcff07e26bf49e1509b988f137008ae19391dd86e4ebb31be7d63fdfdcb740a4d49840b4b28b319f3ccd757e8034207eedfed72e2b33b3b464ebd4ff2a
|
|
7
|
+
data.tar.gz: 3d83677fe719a766f73b2e91fe6e8c5109bbbb7143ef5c674a154226d0f517fb28ed3b8cce6bbac37136770892258bde3267963000f8aa43d77faaa2a83a1083
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -4,6 +4,8 @@ on: [push, pull_request]
|
|
|
4
4
|
jobs:
|
|
5
5
|
test:
|
|
6
6
|
runs-on: ubuntu-latest
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
7
9
|
strategy:
|
|
8
10
|
matrix:
|
|
9
11
|
entry:
|
|
@@ -27,6 +29,8 @@ jobs:
|
|
|
27
29
|
|
|
28
30
|
rubocop:
|
|
29
31
|
runs-on: ubuntu-latest
|
|
32
|
+
permissions:
|
|
33
|
+
contents: read
|
|
30
34
|
name: RuboCop
|
|
31
35
|
steps:
|
|
32
36
|
- uses: actions/checkout@v6
|
|
@@ -38,6 +42,8 @@ jobs:
|
|
|
38
42
|
|
|
39
43
|
yard:
|
|
40
44
|
runs-on: ubuntu-latest
|
|
45
|
+
permissions:
|
|
46
|
+
contents: read
|
|
41
47
|
name: YARD Documentation
|
|
42
48
|
steps:
|
|
43
49
|
- uses: actions/checkout@v6
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.7.0] - 2026-02-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `logging` support (#103)
|
|
15
|
+
- Protocol version negotiation to server initialization (#223)
|
|
16
|
+
- Tool arguments to instrumentation data (#218)
|
|
17
|
+
- Client info to instrumentation callback (#221)
|
|
18
|
+
- `resource_templates` to `MCP::Client` (#225)
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Extract `MCP::Annotations` into a dedicated file (#224)
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `Resource::Embedded` not setting `@resource` in `initialize` (#220)
|
|
27
|
+
|
|
10
28
|
## [0.6.0] - 2026-01-16
|
|
11
29
|
|
|
12
30
|
### Changed
|
data/README.md
CHANGED
|
@@ -113,6 +113,7 @@ The server provides three notification methods:
|
|
|
113
113
|
- `notify_tools_list_changed` - Send a notification when the tools list changes
|
|
114
114
|
- `notify_prompts_list_changed` - Send a notification when the prompts list changes
|
|
115
115
|
- `notify_resources_list_changed` - Send a notification when the resources list changes
|
|
116
|
+
- `notify_log_message` - Send a structured logging notification message
|
|
116
117
|
|
|
117
118
|
#### Notification Format
|
|
118
119
|
|
|
@@ -121,6 +122,82 @@ Notifications follow the JSON-RPC 2.0 specification and use these method names:
|
|
|
121
122
|
- `notifications/tools/list_changed`
|
|
122
123
|
- `notifications/prompts/list_changed`
|
|
123
124
|
- `notifications/resources/list_changed`
|
|
125
|
+
- `notifications/message`
|
|
126
|
+
|
|
127
|
+
### Logging
|
|
128
|
+
|
|
129
|
+
The MCP Ruby SDK supports structured logging through the `notify_log_message` method, following the [MCP Logging specification](https://modelcontextprotocol.io/specification/latest/server/utilities/logging).
|
|
130
|
+
|
|
131
|
+
The `notifications/message` notification is used for structured logging between client and server.
|
|
132
|
+
|
|
133
|
+
#### Log Levels
|
|
134
|
+
|
|
135
|
+
The SDK supports 8 log levels with increasing severity:
|
|
136
|
+
|
|
137
|
+
- `debug` - Detailed debugging information
|
|
138
|
+
- `info` - General informational messages
|
|
139
|
+
- `notice` - Normal but significant events
|
|
140
|
+
- `warning` - Warning conditions
|
|
141
|
+
- `error` - Error conditions
|
|
142
|
+
- `critical` - Critical conditions
|
|
143
|
+
- `alert` - Action must be taken immediately
|
|
144
|
+
- `emergency` - System is unusable
|
|
145
|
+
|
|
146
|
+
#### How Logging Works
|
|
147
|
+
|
|
148
|
+
1. **Client Configuration**: The client sends a `logging/setLevel` request to configure the minimum log level
|
|
149
|
+
2. **Server Filtering**: The server only sends log messages at the configured level or higher severity
|
|
150
|
+
3. **Notification Delivery**: Log messages are sent as `notifications/message` to the client
|
|
151
|
+
|
|
152
|
+
For example, if the client sets the level to `"error"` (severity 4), the server will send messages with levels: `error`, `critical`, `alert`, and `emergency`.
|
|
153
|
+
|
|
154
|
+
For more details, see the [MCP Logging specification](https://modelcontextprotocol.io/specification/latest/server/utilities/logging).
|
|
155
|
+
|
|
156
|
+
**Usage Example:**
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
server = MCP::Server.new(name: "my_server")
|
|
160
|
+
transport = MCP::Server::Transports::StdioTransport.new(server)
|
|
161
|
+
server.transport = transport
|
|
162
|
+
|
|
163
|
+
# The client first configures the logging level (on the client side):
|
|
164
|
+
transport.send_request(
|
|
165
|
+
request: {
|
|
166
|
+
jsonrpc: "2.0",
|
|
167
|
+
method: "logging/setLevel",
|
|
168
|
+
params: { level: "info" },
|
|
169
|
+
id: session_id # Unique request ID within the session
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Send log messages at different severity levels
|
|
174
|
+
server.notify_log_message(
|
|
175
|
+
data: { message: "Application started successfully" },
|
|
176
|
+
level: "info"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
server.notify_log_message(
|
|
180
|
+
data: { message: "Configuration file not found, using defaults" },
|
|
181
|
+
level: "warning"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
server.notify_log_message(
|
|
185
|
+
data: {
|
|
186
|
+
error: "Database connection failed",
|
|
187
|
+
details: { host: "localhost", port: 5432 }
|
|
188
|
+
},
|
|
189
|
+
level: "error",
|
|
190
|
+
logger: "DatabaseLogger" # Optional logger name
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Key Features:**
|
|
195
|
+
|
|
196
|
+
- Supports 8 log levels (debug, info, notice, warning, error, critical, alert, emergency) based on https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging#log-levels
|
|
197
|
+
- Server has capability `logging` to send log messages
|
|
198
|
+
- Messages are only sent if a transport is configured
|
|
199
|
+
- Messages are filtered based on the client's configured log level
|
|
200
|
+
- If the log level hasn't been set by the client, no messages will be sent
|
|
124
201
|
|
|
125
202
|
#### Transport Support
|
|
126
203
|
|
|
@@ -153,7 +230,6 @@ transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, statele
|
|
|
153
230
|
|
|
154
231
|
### Unsupported Features (to be implemented in future versions)
|
|
155
232
|
|
|
156
|
-
- Log Level
|
|
157
233
|
- Resource subscriptions
|
|
158
234
|
- Completions
|
|
159
235
|
- Elicitation
|
|
@@ -320,10 +396,16 @@ The instrumentation callback receives a hash with the following possible keys:
|
|
|
320
396
|
|
|
321
397
|
- `method`: (String) The protocol method called (e.g., "ping", "tools/list")
|
|
322
398
|
- `tool_name`: (String, optional) The name of the tool called
|
|
399
|
+
- `tool_arguments`: (Hash, optional) The arguments passed to the tool
|
|
323
400
|
- `prompt_name`: (String, optional) The name of the prompt called
|
|
324
401
|
- `resource_uri`: (String, optional) The URI of the resource called
|
|
325
402
|
- `error`: (String, optional) Error code if a lookup failed
|
|
326
403
|
- `duration`: (Float) Duration of the call in seconds
|
|
404
|
+
- `client`: (Hash, optional) Client information with `name` and `version` keys, from the initialize request
|
|
405
|
+
|
|
406
|
+
> [!NOTE]
|
|
407
|
+
> `tool_name`, `prompt_name` and `resource_uri` are only populated if a matching handler is registered.
|
|
408
|
+
> This is to avoid potential issues with metric cardinality.
|
|
327
409
|
|
|
328
410
|
**Type:**
|
|
329
411
|
|
|
@@ -335,9 +417,11 @@ instrumentation_callback = ->(data) { ... }
|
|
|
335
417
|
**Example:**
|
|
336
418
|
|
|
337
419
|
```ruby
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
420
|
+
MCP.configure do |config|
|
|
421
|
+
config.instrumentation_callback = ->(data) {
|
|
422
|
+
puts "Instrumentation: #{data.inspect}"
|
|
423
|
+
}
|
|
424
|
+
end
|
|
341
425
|
```
|
|
342
426
|
|
|
343
427
|
### Server Protocol Version
|
|
@@ -787,31 +871,6 @@ The server will handle prompt listing and execution through the MCP protocol met
|
|
|
787
871
|
- `prompts/list` - Lists all registered prompts and their schemas
|
|
788
872
|
- `prompts/get` - Retrieves and executes a specific prompt with arguments
|
|
789
873
|
|
|
790
|
-
### Instrumentation
|
|
791
|
-
|
|
792
|
-
The server allows registering a callback to receive information about instrumentation.
|
|
793
|
-
To register a handler pass a proc/lambda to as `instrumentation_callback` into the server constructor.
|
|
794
|
-
|
|
795
|
-
```ruby
|
|
796
|
-
MCP.configure do |config|
|
|
797
|
-
config.instrumentation_callback = ->(data) {
|
|
798
|
-
puts "Got instrumentation data #{data.inspect}"
|
|
799
|
-
}
|
|
800
|
-
end
|
|
801
|
-
```
|
|
802
|
-
|
|
803
|
-
The data contains the following keys:
|
|
804
|
-
|
|
805
|
-
- `method`: the method called, e.g. `ping`, `tools/list`, `tools/call` etc
|
|
806
|
-
- `tool_name`: the name of the tool called
|
|
807
|
-
- `prompt_name`: the name of the prompt called
|
|
808
|
-
- `resource_uri`: the uri of the resource called
|
|
809
|
-
- `error`: if looking up tools/prompts etc failed, e.g. `tool_not_found`
|
|
810
|
-
- `duration`: the duration of the call in seconds
|
|
811
|
-
|
|
812
|
-
`tool_name`, `prompt_name` and `resource_uri` are only populated if a matching handler is registered.
|
|
813
|
-
This is to avoid potential issues with metric cardinality
|
|
814
|
-
|
|
815
874
|
### Resources
|
|
816
875
|
|
|
817
876
|
MCP spec includes [Resources](https://modelcontextprotocol.io/specification/latest/server/resources).
|
|
@@ -877,6 +936,7 @@ This class supports:
|
|
|
877
936
|
- Tool listing via the `tools/list` method (`MCP::Client#tools`)
|
|
878
937
|
- Tool invocation via the `tools/call` method (`MCP::Client#call_tools`)
|
|
879
938
|
- Resource listing via the `resources/list` method (`MCP::Client#resources`)
|
|
939
|
+
- Resource template listing via the `resources/templates/list` method (`MCP::Client#resource_templates`)
|
|
880
940
|
- Resource reading via the `resources/read` method (`MCP::Client#read_resources`)
|
|
881
941
|
- Prompt listing via the `prompts/list` method (`MCP::Client#prompts`)
|
|
882
942
|
- Prompt retrieval via the `prompts/get` method (`MCP::Client#get_prompt`)
|
|
@@ -122,6 +122,10 @@ def main
|
|
|
122
122
|
exit(1)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
if init_response[:body].dig("result", "capabilities", "logging")
|
|
126
|
+
make_request(session_id, "logging/setLevel", { level: "info" })
|
|
127
|
+
end
|
|
128
|
+
|
|
125
129
|
logger.info("Session initialized: #{session_id}")
|
|
126
130
|
logger.info("Server info: #{init_response[:body]["result"]["serverInfo"]}")
|
|
127
131
|
|
|
@@ -107,6 +107,7 @@ app = proc do |env|
|
|
|
107
107
|
mcp_logger.error("Response error: #{parsed_response["error"]["message"]}")
|
|
108
108
|
elsif parsed_response["accepted"]
|
|
109
109
|
# Response was sent via SSE
|
|
110
|
+
server.notify_log_message(data: { details: "Response accepted and sent via SSE" }, level: "info")
|
|
110
111
|
sse_logger.info("Response sent via SSE stream")
|
|
111
112
|
else
|
|
112
113
|
mcp_logger.info("Response: success (id: #{parsed_response["id"]})")
|
data/lib/json_rpc_handler.rb
CHANGED
|
@@ -105,6 +105,8 @@ module JsonRpcHandler
|
|
|
105
105
|
result = method.call(params)
|
|
106
106
|
|
|
107
107
|
success_response(id: id, result: result)
|
|
108
|
+
rescue MCP::Server::RequestHandlerError => e
|
|
109
|
+
handle_request_error(e, id, id_validation_pattern)
|
|
108
110
|
rescue StandardError => e
|
|
109
111
|
error_response(id: id, id_validation_pattern: id_validation_pattern, error: {
|
|
110
112
|
code: ErrorCode::INTERNAL_ERROR,
|
|
@@ -114,6 +116,24 @@ module JsonRpcHandler
|
|
|
114
116
|
end
|
|
115
117
|
end
|
|
116
118
|
|
|
119
|
+
def handle_request_error(error, id, id_validation_pattern)
|
|
120
|
+
error_type = error.respond_to?(:error_type) ? error.error_type : nil
|
|
121
|
+
|
|
122
|
+
code, message = case error_type
|
|
123
|
+
when :invalid_request then [ErrorCode::INVALID_REQUEST, "Invalid Request"]
|
|
124
|
+
when :invalid_params then [ErrorCode::INVALID_PARAMS, "Invalid params"]
|
|
125
|
+
when :parse_error then [ErrorCode::PARSE_ERROR, "Parse error"]
|
|
126
|
+
when :internal_error then [ErrorCode::INTERNAL_ERROR, "Internal error"]
|
|
127
|
+
else [ErrorCode::INTERNAL_ERROR, "Internal error"]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
error_response(id: id, id_validation_pattern: id_validation_pattern, error: {
|
|
131
|
+
code: code,
|
|
132
|
+
message: message,
|
|
133
|
+
data: error.message,
|
|
134
|
+
})
|
|
135
|
+
end
|
|
136
|
+
|
|
117
137
|
def valid_version?(version)
|
|
118
138
|
version == Version::V2_0
|
|
119
139
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MCP
|
|
4
|
+
class Annotations
|
|
5
|
+
attr_reader :audience, :priority, :last_modified
|
|
6
|
+
|
|
7
|
+
def initialize(audience: nil, priority: nil, last_modified: nil)
|
|
8
|
+
@audience = audience
|
|
9
|
+
@priority = priority
|
|
10
|
+
@last_modified = last_modified
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_h
|
|
14
|
+
{
|
|
15
|
+
audience: audience,
|
|
16
|
+
priority: priority,
|
|
17
|
+
lastModified: last_modified,
|
|
18
|
+
}.compact
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/mcp/client.rb
CHANGED
|
@@ -58,6 +58,20 @@ module MCP
|
|
|
58
58
|
response.dig("result", "resources") || []
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# Returns the list of resource templates available from the server.
|
|
62
|
+
# Each call will make a new request – the result is not cached.
|
|
63
|
+
#
|
|
64
|
+
# @return [Array<Hash>] An array of available resource templates.
|
|
65
|
+
def resource_templates
|
|
66
|
+
response = transport.send_request(request: {
|
|
67
|
+
jsonrpc: JsonRpcHandler::Version::V2_0,
|
|
68
|
+
id: request_id,
|
|
69
|
+
method: "resources/templates/list",
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
response.dig("result", "resourceTemplates") || []
|
|
73
|
+
end
|
|
74
|
+
|
|
61
75
|
# Returns the list of prompts available from the server.
|
|
62
76
|
# Each call will make a new request – the result is not cached.
|
|
63
77
|
#
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MCP
|
|
4
|
+
class LoggingMessageNotification
|
|
5
|
+
LOG_LEVEL_SEVERITY = {
|
|
6
|
+
"debug" => 0,
|
|
7
|
+
"info" => 1,
|
|
8
|
+
"notice" => 2,
|
|
9
|
+
"warning" => 3,
|
|
10
|
+
"error" => 4,
|
|
11
|
+
"critical" => 5,
|
|
12
|
+
"alert" => 6,
|
|
13
|
+
"emergency" => 7,
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
def initialize(level:)
|
|
17
|
+
@level = level
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def valid_level?
|
|
21
|
+
LOG_LEVEL_SEVERITY.keys.include?(@level)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def should_notify?(log_level)
|
|
25
|
+
return false unless LOG_LEVEL_SEVERITY.key?(log_level)
|
|
26
|
+
|
|
27
|
+
LOG_LEVEL_SEVERITY[log_level] >= LOG_LEVEL_SEVERITY[@level]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/mcp/server.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "../json_rpc_handler"
|
|
4
4
|
require_relative "instrumentation"
|
|
5
5
|
require_relative "methods"
|
|
6
|
+
require_relative "logging_message_notification"
|
|
6
7
|
|
|
7
8
|
module MCP
|
|
8
9
|
class ToolNotUnique < StandardError
|
|
@@ -17,6 +18,9 @@ module MCP
|
|
|
17
18
|
class Server
|
|
18
19
|
DEFAULT_VERSION = "0.1.0"
|
|
19
20
|
|
|
21
|
+
UNSUPPORTED_PROPERTIES_UNTIL_2025_06_18 = [:description, :icons].freeze
|
|
22
|
+
UNSUPPORTED_PROPERTIES_UNTIL_2025_03_26 = [:title, :websiteUrl].freeze
|
|
23
|
+
|
|
20
24
|
class RequestHandlerError < StandardError
|
|
21
25
|
attr_reader :error_type
|
|
22
26
|
attr_reader :original_error
|
|
@@ -40,7 +44,7 @@ module MCP
|
|
|
40
44
|
|
|
41
45
|
include Instrumentation
|
|
42
46
|
|
|
43
|
-
attr_accessor :description, :icons, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
|
|
47
|
+
attr_accessor :description, :icons, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport, :logging_message_notification
|
|
44
48
|
|
|
45
49
|
def initialize(
|
|
46
50
|
description: nil,
|
|
@@ -74,10 +78,12 @@ module MCP
|
|
|
74
78
|
@resource_index = index_resources_by_uri(resources)
|
|
75
79
|
@server_context = server_context
|
|
76
80
|
@configuration = MCP.configuration.merge(configuration)
|
|
81
|
+
@client = nil
|
|
77
82
|
|
|
78
83
|
validate!
|
|
79
84
|
|
|
80
85
|
@capabilities = capabilities || default_capabilities
|
|
86
|
+
@logging_message_notification = nil
|
|
81
87
|
|
|
82
88
|
@handlers = {
|
|
83
89
|
Methods::RESOURCES_LIST => method(:list_resources),
|
|
@@ -90,12 +96,12 @@ module MCP
|
|
|
90
96
|
Methods::INITIALIZE => method(:init),
|
|
91
97
|
Methods::PING => ->(_) { {} },
|
|
92
98
|
Methods::NOTIFICATIONS_INITIALIZED => ->(_) {},
|
|
99
|
+
Methods::LOGGING_SET_LEVEL => method(:configure_logging_level),
|
|
93
100
|
|
|
94
101
|
# No op handlers for currently unsupported methods
|
|
95
102
|
Methods::RESOURCES_SUBSCRIBE => ->(_) {},
|
|
96
103
|
Methods::RESOURCES_UNSUBSCRIBE => ->(_) {},
|
|
97
104
|
Methods::COMPLETION_COMPLETE => ->(_) {},
|
|
98
|
-
Methods::LOGGING_SET_LEVEL => ->(_) {},
|
|
99
105
|
Methods::ELICITATION_CREATE => ->(_) {},
|
|
100
106
|
}
|
|
101
107
|
@transport = transport
|
|
@@ -162,6 +168,18 @@ module MCP
|
|
|
162
168
|
report_exception(e, { notification: "resources_list_changed" })
|
|
163
169
|
end
|
|
164
170
|
|
|
171
|
+
def notify_log_message(data:, level:, logger: nil)
|
|
172
|
+
return unless @transport
|
|
173
|
+
return unless logging_message_notification&.should_notify?(level)
|
|
174
|
+
|
|
175
|
+
params = { "data" => data, "level" => level }
|
|
176
|
+
params["logger"] = logger if logger
|
|
177
|
+
|
|
178
|
+
@transport.send_notification(Methods::NOTIFICATIONS_MESSAGE, params)
|
|
179
|
+
rescue => e
|
|
180
|
+
report_exception(e, { notification: "log_message" })
|
|
181
|
+
end
|
|
182
|
+
|
|
165
183
|
def resources_list_handler(&block)
|
|
166
184
|
@handlers[Methods::RESOURCES_LIST] = block
|
|
167
185
|
end
|
|
@@ -244,7 +262,9 @@ module MCP
|
|
|
244
262
|
def handle_request(request, method)
|
|
245
263
|
handler = @handlers[method]
|
|
246
264
|
unless handler
|
|
247
|
-
instrument_call("unsupported_method")
|
|
265
|
+
instrument_call("unsupported_method") do
|
|
266
|
+
add_instrumentation_data(client: @client) if @client
|
|
267
|
+
end
|
|
248
268
|
return
|
|
249
269
|
end
|
|
250
270
|
|
|
@@ -252,7 +272,7 @@ module MCP
|
|
|
252
272
|
|
|
253
273
|
->(params) {
|
|
254
274
|
instrument_call(method) do
|
|
255
|
-
case method
|
|
275
|
+
result = case method
|
|
256
276
|
when Methods::TOOLS_LIST
|
|
257
277
|
{ tools: @handlers[Methods::TOOLS_LIST].call(params) }
|
|
258
278
|
when Methods::PROMPTS_LIST
|
|
@@ -266,6 +286,9 @@ module MCP
|
|
|
266
286
|
else
|
|
267
287
|
@handlers[method].call(params)
|
|
268
288
|
end
|
|
289
|
+
add_instrumentation_data(client: @client) if @client
|
|
290
|
+
|
|
291
|
+
result
|
|
269
292
|
rescue => e
|
|
270
293
|
report_exception(e, { request: request })
|
|
271
294
|
if e.is_a?(RequestHandlerError)
|
|
@@ -284,6 +307,7 @@ module MCP
|
|
|
284
307
|
tools: { listChanged: true },
|
|
285
308
|
prompts: { listChanged: true },
|
|
286
309
|
resources: { listChanged: true },
|
|
310
|
+
logging: {},
|
|
287
311
|
}
|
|
288
312
|
end
|
|
289
313
|
|
|
@@ -298,15 +322,48 @@ module MCP
|
|
|
298
322
|
}.compact
|
|
299
323
|
end
|
|
300
324
|
|
|
301
|
-
def init(
|
|
325
|
+
def init(params)
|
|
326
|
+
@client = params[:clientInfo] if params
|
|
327
|
+
|
|
328
|
+
protocol_version = params[:protocolVersion] if params
|
|
329
|
+
negotiated_version = if Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
|
|
330
|
+
protocol_version
|
|
331
|
+
else
|
|
332
|
+
configuration.protocol_version
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
info = server_info.reject do |property|
|
|
336
|
+
negotiated_version <= "2025-06-18" && UNSUPPORTED_PROPERTIES_UNTIL_2025_06_18.include?(property) ||
|
|
337
|
+
negotiated_version <= "2025-03-26" && UNSUPPORTED_PROPERTIES_UNTIL_2025_03_26.include?(property)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
response_instructions = instructions
|
|
341
|
+
|
|
342
|
+
if negotiated_version == "2024-11-05"
|
|
343
|
+
response_instructions = nil
|
|
344
|
+
end
|
|
345
|
+
|
|
302
346
|
{
|
|
303
|
-
protocolVersion:
|
|
347
|
+
protocolVersion: negotiated_version,
|
|
304
348
|
capabilities: capabilities,
|
|
305
|
-
serverInfo:
|
|
306
|
-
instructions:
|
|
349
|
+
serverInfo: info,
|
|
350
|
+
instructions: response_instructions,
|
|
307
351
|
}.compact
|
|
308
352
|
end
|
|
309
353
|
|
|
354
|
+
def configure_logging_level(request)
|
|
355
|
+
if capabilities[:logging].nil?
|
|
356
|
+
raise RequestHandlerError.new("Server does not support logging", request, error_type: :internal_error)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
logging_message_notification = LoggingMessageNotification.new(level: request[:level])
|
|
360
|
+
unless logging_message_notification.valid_level?
|
|
361
|
+
raise RequestHandlerError.new("Invalid log level #{request[:level]}", request, error_type: :invalid_params)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
@logging_message_notification = logging_message_notification
|
|
365
|
+
end
|
|
366
|
+
|
|
310
367
|
def list_tools(request)
|
|
311
368
|
@tools.values.map(&:to_h)
|
|
312
369
|
end
|
|
@@ -322,7 +379,7 @@ module MCP
|
|
|
322
379
|
end
|
|
323
380
|
|
|
324
381
|
arguments = request[:arguments] || {}
|
|
325
|
-
add_instrumentation_data(tool_name: tool_name)
|
|
382
|
+
add_instrumentation_data(tool_name: tool_name, tool_arguments: arguments)
|
|
326
383
|
|
|
327
384
|
if tool.input_schema&.missing_required_arguments?(arguments)
|
|
328
385
|
add_instrumentation_data(error: :missing_required_arguments)
|
data/lib/mcp/version.rb
CHANGED
data/lib/mcp.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "json_rpc_handler"
|
|
4
|
+
require_relative "mcp/annotations"
|
|
4
5
|
require_relative "mcp/configuration"
|
|
5
6
|
require_relative "mcp/content"
|
|
6
7
|
require_relative "mcp/icon"
|
|
@@ -39,13 +40,4 @@ module MCP
|
|
|
39
40
|
@configuration ||= Configuration.new
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
|
-
|
|
43
|
-
class Annotations
|
|
44
|
-
attr_reader :audience, :priority
|
|
45
|
-
|
|
46
|
-
def initialize(audience: nil, priority: nil)
|
|
47
|
-
@audience = audience
|
|
48
|
-
@priority = priority
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
43
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mcp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Model Context Protocol
|
|
@@ -60,6 +60,7 @@ files:
|
|
|
60
60
|
- examples/streamable_http_server.rb
|
|
61
61
|
- lib/json_rpc_handler.rb
|
|
62
62
|
- lib/mcp.rb
|
|
63
|
+
- lib/mcp/annotations.rb
|
|
63
64
|
- lib/mcp/client.rb
|
|
64
65
|
- lib/mcp/client/http.rb
|
|
65
66
|
- lib/mcp/client/tool.rb
|
|
@@ -67,6 +68,7 @@ files:
|
|
|
67
68
|
- lib/mcp/content.rb
|
|
68
69
|
- lib/mcp/icon.rb
|
|
69
70
|
- lib/mcp/instrumentation.rb
|
|
71
|
+
- lib/mcp/logging_message_notification.rb
|
|
70
72
|
- lib/mcp/methods.rb
|
|
71
73
|
- lib/mcp/prompt.rb
|
|
72
74
|
- lib/mcp/prompt/argument.rb
|
|
@@ -96,7 +98,7 @@ licenses:
|
|
|
96
98
|
- Apache-2.0
|
|
97
99
|
metadata:
|
|
98
100
|
allowed_push_host: https://rubygems.org
|
|
99
|
-
changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.
|
|
101
|
+
changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.7.0
|
|
100
102
|
homepage_uri: https://github.com/modelcontextprotocol/ruby-sdk
|
|
101
103
|
source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
|
|
102
104
|
bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues
|