mcp 1.7.0 → 1.8.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 +1 -1
- data/lib/mcp/client/http.rb +94 -17
- data/lib/mcp/client/oauth/flow.rb +68 -21
- data/lib/mcp/client/oauth/provider.rb +11 -0
- data/lib/mcp/client/stdio.rb +23 -4
- data/lib/mcp/server/oauth/access_token.rb +89 -0
- data/lib/mcp/server/oauth/authenticator.rb +150 -0
- data/lib/mcp/server/oauth/challenge.rb +114 -0
- data/lib/mcp/server/oauth/errors.rb +58 -0
- data/lib/mcp/server/oauth/introspection_verifier.rb +151 -0
- data/lib/mcp/server/oauth/jwt_verifier.rb +330 -0
- data/lib/mcp/server/oauth/middleware.rb +60 -0
- data/lib/mcp/server/oauth/protected_resource_metadata.rb +138 -0
- data/lib/mcp/server/oauth/protected_resource_metadata_middleware.rb +86 -0
- data/lib/mcp/server/oauth/token_verifier.rb +135 -0
- data/lib/mcp/server/oauth.rb +29 -0
- data/lib/mcp/server/transports/streamable_http_transport.rb +488 -120
- data/lib/mcp/server.rb +55 -28
- data/lib/mcp/server_context.rb +26 -2
- data/lib/mcp/server_session.rb +14 -4
- data/lib/mcp/version.rb +1 -1
- metadata +13 -2
data/lib/mcp/server.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative "protocol_deprecations"
|
|
|
13
13
|
require_relative "server_context"
|
|
14
14
|
require_relative "server/capabilities"
|
|
15
15
|
require_relative "server/input_required_result"
|
|
16
|
+
require_relative "server/oauth"
|
|
16
17
|
require_relative "server/pagination"
|
|
17
18
|
require_relative "server/pending_response"
|
|
18
19
|
require_relative "server/request_state_security"
|
|
@@ -279,10 +280,13 @@ module MCP
|
|
|
279
280
|
# @param session [ServerSession, nil] Per-connection session. Passed by
|
|
280
281
|
# `ServerSession#handle` for session-scoped notification delivery.
|
|
281
282
|
# When `nil`, progress and logging notifications from tool handlers are silently skipped.
|
|
283
|
+
# @param auth_info [Server::OAuth::AccessToken, nil] The verified access token
|
|
284
|
+
# for the current request, passed by the transport layer and exposed to
|
|
285
|
+
# handlers as `server_context.auth_info`.
|
|
282
286
|
# @return [Hash, nil] The JSON-RPC response, or `nil` for notifications.
|
|
283
|
-
def handle(request, session: nil)
|
|
287
|
+
def handle(request, session: nil, auth_info: nil)
|
|
284
288
|
JsonRpcHandler.handle(request) do |method, request_id|
|
|
285
|
-
handle_request(request, method, session: session, related_request_id: request_id)
|
|
289
|
+
handle_request(request, method, session: session, related_request_id: request_id, auth_info: auth_info)
|
|
286
290
|
end
|
|
287
291
|
end
|
|
288
292
|
|
|
@@ -292,10 +296,12 @@ module MCP
|
|
|
292
296
|
# @param session [ServerSession, nil] Per-connection session. Passed by
|
|
293
297
|
# `ServerSession#handle_json` for session-scoped notification delivery.
|
|
294
298
|
# When `nil`, progress and logging notifications from tool handlers are silently skipped.
|
|
299
|
+
# @param auth_info [Server::OAuth::AccessToken, nil] The verified access token
|
|
300
|
+
# for the current request, as in `handle`.
|
|
295
301
|
# @return [String, nil] The JSON-RPC response as JSON, or `nil` for notifications.
|
|
296
|
-
def handle_json(request, session: nil)
|
|
302
|
+
def handle_json(request, session: nil, auth_info: nil)
|
|
297
303
|
JsonRpcHandler.handle_json(request) do |method, request_id|
|
|
298
|
-
handle_request(request, method, session: session, related_request_id: request_id)
|
|
304
|
+
handle_request(request, method, session: session, related_request_id: request_id, auth_info: auth_info)
|
|
299
305
|
end
|
|
300
306
|
end
|
|
301
307
|
|
|
@@ -600,7 +606,7 @@ module MCP
|
|
|
600
606
|
end
|
|
601
607
|
end
|
|
602
608
|
|
|
603
|
-
def handle_request(request, method, session: nil, related_request_id: nil)
|
|
609
|
+
def handle_request(request, method, session: nil, related_request_id: nil, auth_info: nil)
|
|
604
610
|
# A well-formed notification carries no JSON-RPC id and receives no response.
|
|
605
611
|
# If a client erroneously sends a notification-only method with an id, the message
|
|
606
612
|
# is framed as a request; since notification methods have no request handler,
|
|
@@ -691,25 +697,25 @@ module MCP
|
|
|
691
697
|
when Methods::INITIALIZE
|
|
692
698
|
init(params, session: session)
|
|
693
699
|
when Methods::RESOURCES_READ
|
|
694
|
-
contents = read_resource_contents(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
700
|
+
contents = read_resource_contents(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
695
701
|
|
|
696
702
|
# An SEP-2322 `input_required` result must not be wrapped as `contents` or stamped with SEP-2549 cache hints.
|
|
697
703
|
contents.is_a?(InputRequiredResult) ? contents : build_read_resource_result(contents)
|
|
698
704
|
when Methods::RESOURCES_SUBSCRIBE, Methods::RESOURCES_UNSUBSCRIBE
|
|
699
705
|
validate_resource_subscription_params!(params)
|
|
700
|
-
handler_result = dispatch_optional_context_handler(@handlers[method], params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
706
|
+
handler_result = dispatch_optional_context_handler(@handlers[method], params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
701
707
|
|
|
702
708
|
subscription_result(handler_result)
|
|
703
709
|
when Methods::TOOLS_CALL
|
|
704
|
-
call_tool(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
710
|
+
call_tool(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
705
711
|
when Methods::PROMPTS_GET
|
|
706
|
-
get_prompt(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
712
|
+
get_prompt(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
707
713
|
when Methods::COMPLETION_COMPLETE
|
|
708
|
-
complete(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
714
|
+
complete(params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
709
715
|
when Methods::LOGGING_SET_LEVEL
|
|
710
716
|
configure_logging_level(params, session: session)
|
|
711
717
|
else
|
|
712
|
-
dispatch_optional_context_handler(@handlers[method], params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope)
|
|
718
|
+
dispatch_optional_context_handler(@handlers[method], params, session: session, related_request_id: related_request_id, cancellation: cancellation, envelope: envelope, auth_info: auth_info)
|
|
713
719
|
end
|
|
714
720
|
client = session&.client || @client
|
|
715
721
|
add_instrumentation_data(client: client) if client
|
|
@@ -760,6 +766,15 @@ module MCP
|
|
|
760
766
|
rescue CancelledError => e
|
|
761
767
|
add_instrumentation_data(cancelled: true, cancellation_reason: e.reason)
|
|
762
768
|
next JsonRpcHandler::NO_RESPONSE
|
|
769
|
+
rescue OAuth::InsufficientScopeError => e
|
|
770
|
+
# A handler's `require_scopes!` failure is a client authorization error, not a server fault:
|
|
771
|
+
# surface it as an invalid-request JSON-RPC error whose message names the missing scopes.
|
|
772
|
+
# HTTP-level 403 challenges remain the transport `required_scopes` gate's job.
|
|
773
|
+
report_exception(e, { request: request })
|
|
774
|
+
add_instrumentation_data(error: :insufficient_scope)
|
|
775
|
+
converted = RequestHandlerError.new(e.message, request, error_type: :invalid_request, original_error: e)
|
|
776
|
+
reported_exception = converted
|
|
777
|
+
raise converted
|
|
763
778
|
rescue RequestHandlerError => e
|
|
764
779
|
report_exception(e.original_error || e, { request: request })
|
|
765
780
|
add_instrumentation_data(error: e.error_type)
|
|
@@ -1224,7 +1239,7 @@ module MCP
|
|
|
1224
1239
|
apply_cache_metadata({ tools: page[:items], nextCursor: page[:next_cursor] }.compact)
|
|
1225
1240
|
end
|
|
1226
1241
|
|
|
1227
|
-
def call_tool(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil)
|
|
1242
|
+
def call_tool(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil)
|
|
1228
1243
|
tool_name = request[:name]
|
|
1229
1244
|
|
|
1230
1245
|
tool = tools[tool_name]
|
|
@@ -1259,12 +1274,13 @@ module MCP
|
|
|
1259
1274
|
response = call_tool_with_args(
|
|
1260
1275
|
tool,
|
|
1261
1276
|
arguments,
|
|
1262
|
-
server_context_with_meta(request),
|
|
1277
|
+
server_context_with_meta(request, auth_info: auth_info),
|
|
1263
1278
|
progress_token: progress_token,
|
|
1264
1279
|
session: session,
|
|
1265
1280
|
related_request_id: related_request_id,
|
|
1266
1281
|
cancellation: cancellation,
|
|
1267
1282
|
envelope: envelope,
|
|
1283
|
+
auth_info: auth_info,
|
|
1268
1284
|
retry_fields: mrtr_retry_fields(request),
|
|
1269
1285
|
)
|
|
1270
1286
|
# An SEP-2322 `input_required` result is not a tool result: output schema
|
|
@@ -1278,9 +1294,11 @@ module MCP
|
|
|
1278
1294
|
result,
|
|
1279
1295
|
content_provided: response.respond_to?(:content_provided?) && response.content_provided?,
|
|
1280
1296
|
)
|
|
1281
|
-
rescue RequestHandlerError, CancelledError
|
|
1297
|
+
rescue RequestHandlerError, CancelledError, OAuth::InsufficientScopeError
|
|
1282
1298
|
# CancelledError is intentionally not wrapped so `handle_request` can turn it into
|
|
1283
|
-
# `JsonRpcHandler::NO_RESPONSE` per the MCP cancellation spec
|
|
1299
|
+
# `JsonRpcHandler::NO_RESPONSE` per the MCP cancellation spec, and
|
|
1300
|
+
# `OAuth::InsufficientScopeError` so `require_scopes!` failures keep their
|
|
1301
|
+
# scope-naming message instead of the generic internal-error shape.
|
|
1284
1302
|
raise
|
|
1285
1303
|
rescue => e
|
|
1286
1304
|
# `e.message` is deliberately not included: it can carry internals (class, method
|
|
@@ -1300,7 +1318,7 @@ module MCP
|
|
|
1300
1318
|
apply_cache_metadata({ prompts: page[:items], nextCursor: page[:next_cursor] }.compact)
|
|
1301
1319
|
end
|
|
1302
1320
|
|
|
1303
|
-
def get_prompt(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil)
|
|
1321
|
+
def get_prompt(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil)
|
|
1304
1322
|
prompt_name = request[:name]
|
|
1305
1323
|
prompt = @prompts[prompt_name]
|
|
1306
1324
|
unless prompt
|
|
@@ -1328,6 +1346,7 @@ module MCP
|
|
|
1328
1346
|
related_request_id: related_request_id,
|
|
1329
1347
|
cancellation: cancellation,
|
|
1330
1348
|
envelope: envelope,
|
|
1349
|
+
auth_info: auth_info,
|
|
1331
1350
|
)
|
|
1332
1351
|
|
|
1333
1352
|
call_prompt_template_with_args(prompt, prompt_args, server_context)
|
|
@@ -1440,7 +1459,7 @@ module MCP
|
|
|
1440
1459
|
{ ttlMs: @ttl_ms || 0, cacheScope: @cache_scope || "private" }.merge(result)
|
|
1441
1460
|
end
|
|
1442
1461
|
|
|
1443
|
-
def complete(params, session: nil, related_request_id: nil, cancellation: nil, envelope: nil)
|
|
1462
|
+
def complete(params, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil)
|
|
1444
1463
|
validate_completion_params!(params)
|
|
1445
1464
|
|
|
1446
1465
|
result = dispatch_optional_context_handler(
|
|
@@ -1450,6 +1469,7 @@ module MCP
|
|
|
1450
1469
|
related_request_id: related_request_id,
|
|
1451
1470
|
cancellation: cancellation,
|
|
1452
1471
|
envelope: envelope,
|
|
1472
|
+
auth_info: auth_info,
|
|
1453
1473
|
)
|
|
1454
1474
|
|
|
1455
1475
|
normalize_completion_result(result)
|
|
@@ -1458,7 +1478,7 @@ module MCP
|
|
|
1458
1478
|
# Invokes `resources/read` via the registered handler. If the handler block opts in to `server_context:`,
|
|
1459
1479
|
# pass an `MCP::ServerContext` so the handler can observe cancellation via `server_context.cancelled?` or
|
|
1460
1480
|
# `server_context.raise_if_cancelled!`.
|
|
1461
|
-
def read_resource_contents(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil)
|
|
1481
|
+
def read_resource_contents(request, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil)
|
|
1462
1482
|
dispatch_optional_context_handler(
|
|
1463
1483
|
@handlers[Methods::RESOURCES_READ],
|
|
1464
1484
|
request,
|
|
@@ -1466,6 +1486,7 @@ module MCP
|
|
|
1466
1486
|
related_request_id: related_request_id,
|
|
1467
1487
|
cancellation: cancellation,
|
|
1468
1488
|
envelope: envelope,
|
|
1489
|
+
auth_info: auth_info,
|
|
1469
1490
|
)
|
|
1470
1491
|
end
|
|
1471
1492
|
|
|
@@ -1473,7 +1494,7 @@ module MCP
|
|
|
1473
1494
|
# `completion_handler`, `resources_subscribe_handler`, `resources_unsubscribe_handler`, or `define_custom_method`.
|
|
1474
1495
|
# Existing handlers that only accept `params` are called unchanged; handlers that declare a `server_context:`
|
|
1475
1496
|
# keyword receive an `MCP::ServerContext` wrapping the raw server context with cancellation plumbing.
|
|
1476
|
-
def dispatch_optional_context_handler(handler, params, session: nil, related_request_id: nil, cancellation: nil, envelope: nil)
|
|
1497
|
+
def dispatch_optional_context_handler(handler, params, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil)
|
|
1477
1498
|
return handler.call(params) unless handler_declares_server_context?(handler)
|
|
1478
1499
|
|
|
1479
1500
|
server_context = build_server_context(
|
|
@@ -1482,6 +1503,7 @@ module MCP
|
|
|
1482
1503
|
related_request_id: related_request_id,
|
|
1483
1504
|
cancellation: cancellation,
|
|
1484
1505
|
envelope: envelope,
|
|
1506
|
+
auth_info: auth_info,
|
|
1485
1507
|
)
|
|
1486
1508
|
handler.call(params, server_context: server_context)
|
|
1487
1509
|
end
|
|
@@ -1506,13 +1528,13 @@ module MCP
|
|
|
1506
1528
|
|
|
1507
1529
|
# Builds an `MCP::ServerContext` used to give a handler access to session-scoped helpers
|
|
1508
1530
|
# (progress, cancellation, nested server-to-client requests).
|
|
1509
|
-
def build_server_context(request:, session:, related_request_id:, cancellation:, envelope: nil)
|
|
1531
|
+
def build_server_context(request:, session:, related_request_id:, cancellation:, envelope: nil, auth_info: nil)
|
|
1510
1532
|
meta_source = request.is_a?(Hash) ? request : {}
|
|
1511
1533
|
progress_token = meta_source.dig(:_meta, :progressToken)
|
|
1512
1534
|
progress = Progress.new(notification_target: session, progress_token: progress_token, related_request_id: related_request_id)
|
|
1513
1535
|
retry_fields = mrtr_retry_fields(meta_source)
|
|
1514
1536
|
ServerContext.new(
|
|
1515
|
-
server_context_with_meta(meta_source),
|
|
1537
|
+
server_context_with_meta(meta_source, auth_info: auth_info),
|
|
1516
1538
|
progress: progress,
|
|
1517
1539
|
notification_target: session,
|
|
1518
1540
|
related_request_id: related_request_id,
|
|
@@ -1520,6 +1542,7 @@ module MCP
|
|
|
1520
1542
|
envelope: envelope,
|
|
1521
1543
|
input_responses: retry_fields[:input_responses],
|
|
1522
1544
|
request_state: retry_fields[:request_state],
|
|
1545
|
+
auth_info: auth_info,
|
|
1523
1546
|
)
|
|
1524
1547
|
end
|
|
1525
1548
|
|
|
@@ -1579,7 +1602,7 @@ module MCP
|
|
|
1579
1602
|
end
|
|
1580
1603
|
end
|
|
1581
1604
|
|
|
1582
|
-
def call_tool_with_args(tool, arguments, context, progress_token: nil, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, retry_fields: nil)
|
|
1605
|
+
def call_tool_with_args(tool, arguments, context, progress_token: nil, session: nil, related_request_id: nil, cancellation: nil, envelope: nil, auth_info: nil, retry_fields: nil)
|
|
1583
1606
|
# Transports parse incoming JSON with `symbolize_names: true`, so `arguments` already arrives symbolized
|
|
1584
1607
|
# at every nesting level. This top-level transform only guards callers that hand in string-keyed top-level arguments;
|
|
1585
1608
|
# it does not recurse, and nested object keys remain symbols. Tools therefore receive symbol keys all the way down.
|
|
@@ -1597,6 +1620,7 @@ module MCP
|
|
|
1597
1620
|
envelope: envelope,
|
|
1598
1621
|
input_responses: retry_fields&.fetch(:input_responses, nil),
|
|
1599
1622
|
request_state: retry_fields&.fetch(:request_state, nil),
|
|
1623
|
+
auth_info: auth_info,
|
|
1600
1624
|
)
|
|
1601
1625
|
tool.call(**args, server_context: server_context)
|
|
1602
1626
|
else
|
|
@@ -1614,15 +1638,18 @@ module MCP
|
|
|
1614
1638
|
raw_result.is_a?(InputRequiredResult) ? raw_result : raw_result.to_h
|
|
1615
1639
|
end
|
|
1616
1640
|
|
|
1617
|
-
def server_context_with_meta(request)
|
|
1641
|
+
def server_context_with_meta(request, auth_info: nil)
|
|
1618
1642
|
meta = request[:_meta]
|
|
1619
|
-
if meta &&
|
|
1620
|
-
|
|
1621
|
-
|
|
1643
|
+
return server_context if meta.nil? && auth_info.nil?
|
|
1644
|
+
|
|
1645
|
+
if server_context.is_a?(Hash) || server_context.nil?
|
|
1646
|
+
context = (server_context || {}).dup
|
|
1647
|
+
context[:_meta] = meta if meta
|
|
1648
|
+
context[:auth_info] = auth_info if auth_info
|
|
1622
1649
|
context
|
|
1623
|
-
elsif meta && server_context.nil?
|
|
1624
|
-
{ _meta: meta }
|
|
1625
1650
|
else
|
|
1651
|
+
# A custom (non-Hash) user context is passed through untouched; handlers on that path read
|
|
1652
|
+
# the token via `server_context.auth_info` instead.
|
|
1626
1653
|
server_context
|
|
1627
1654
|
end
|
|
1628
1655
|
end
|
data/lib/mcp/server_context.rb
CHANGED
|
@@ -15,8 +15,11 @@ module MCP
|
|
|
15
15
|
# (the same access model as the envelope readers).
|
|
16
16
|
attr_reader :input_responses, :request_state
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# The verified `MCP::Server::OAuth::AccessToken` for the current request, or nil when the request was not bearer-authenticated.
|
|
19
|
+
# This reader is the canonical accessor; when the underlying context is a Hash the same value is also reachable as `server_context[:auth_info]`.
|
|
20
|
+
attr_reader :auth_info
|
|
21
|
+
|
|
22
|
+
def initialize(context, progress:, notification_target:, related_request_id: nil, cancellation: nil, envelope: nil, input_responses: nil, request_state: nil, auth_info: nil)
|
|
20
23
|
@context = context
|
|
21
24
|
@progress = progress
|
|
22
25
|
@notification_target = notification_target
|
|
@@ -25,6 +28,7 @@ module MCP
|
|
|
25
28
|
@envelope = envelope
|
|
26
29
|
@input_responses = input_responses
|
|
27
30
|
@request_state = request_state
|
|
31
|
+
@auth_info = auth_info
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
# Reads one entry of {#input_responses} by its `inputRequests` key, tolerating symbol or string keys.
|
|
@@ -89,6 +93,26 @@ module MCP
|
|
|
89
93
|
raise Server::MissingRequiredClientCapabilityError, required
|
|
90
94
|
end
|
|
91
95
|
|
|
96
|
+
# Whether the current request was bearer-authenticated.
|
|
97
|
+
def authenticated?
|
|
98
|
+
!@auth_info.nil?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Guards the current operation on OAuth scopes the token must carry, for authorization decisions finer-grained than
|
|
102
|
+
# the transport-wide `required_scopes`. Raises `Server::OAuth::InsufficientScopeError`, which surfaces as
|
|
103
|
+
# a JSON-RPC invalid-request error naming the missing scopes. HTTP-level 403 step-up challenges remain the job of
|
|
104
|
+
# the transport's `required_scopes` gate, matching how the Python and TypeScript SDKs split endpoint-level challenges
|
|
105
|
+
# from in-handler authorization. The transport's `scope_matcher:` applies here as well: the authenticator attaches it
|
|
106
|
+
# to the token it hands over, so a scope hierarchy is judged the same way at the gate and in handlers.
|
|
107
|
+
def require_scopes!(*scopes)
|
|
108
|
+
raise ArgumentError, "at least one scope is required" if scopes.empty?
|
|
109
|
+
|
|
110
|
+
missing_scopes = scopes.reject { |scope| @auth_info&.scope?(scope) }
|
|
111
|
+
return if missing_scopes.empty?
|
|
112
|
+
|
|
113
|
+
raise Server::OAuth::InsufficientScopeError.new("Token is missing required scopes: #{missing_scopes.join(", ")}", required_scopes: scopes)
|
|
114
|
+
end
|
|
115
|
+
|
|
92
116
|
# Reports progress for the current tool operation.
|
|
93
117
|
# The notification is automatically scoped to the originating session.
|
|
94
118
|
#
|
data/lib/mcp/server_session.rb
CHANGED
|
@@ -120,12 +120,22 @@ module MCP
|
|
|
120
120
|
MCP.configuration.exception_reporter.call(e, { notification: "cancelled", request_id: request_id })
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
# Accepts the request either as a positional Hash or as bare keyword arguments (`session.handle(jsonrpc: "2.0", ...)`),
|
|
124
|
+
# a calling style that predates this method having keyword parameters. `auth_info:` is honored only alongside a positional request:
|
|
125
|
+
# in the bare-keyword style every keyword belongs to the request body, and the body is attacker-authored JSON,
|
|
126
|
+
# so a captured `auth_info` keyword is folded back into the request rather than trusted as a verified credential.
|
|
127
|
+
def handle(request = nil, auth_info: nil, **request_keywords)
|
|
128
|
+
if request.nil?
|
|
129
|
+
request = request_keywords
|
|
130
|
+
request[:auth_info] = auth_info unless auth_info.nil?
|
|
131
|
+
auth_info = nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
@server.handle(request, session: self, auth_info: auth_info)
|
|
125
135
|
end
|
|
126
136
|
|
|
127
|
-
def handle_json(request_json)
|
|
128
|
-
@server.handle_json(request_json, session: self)
|
|
137
|
+
def handle_json(request_json, auth_info: nil)
|
|
138
|
+
@server.handle_json(request_json, session: self, auth_info: auth_info)
|
|
129
139
|
end
|
|
130
140
|
|
|
131
141
|
# Called by `Server#init` during the initialization handshake.
|
data/lib/mcp/version.rb
CHANGED
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: 1.
|
|
4
|
+
version: 1.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Model Context Protocol
|
|
@@ -85,6 +85,17 @@ files:
|
|
|
85
85
|
- lib/mcp/server.rb
|
|
86
86
|
- lib/mcp/server/capabilities.rb
|
|
87
87
|
- lib/mcp/server/input_required_result.rb
|
|
88
|
+
- lib/mcp/server/oauth.rb
|
|
89
|
+
- lib/mcp/server/oauth/access_token.rb
|
|
90
|
+
- lib/mcp/server/oauth/authenticator.rb
|
|
91
|
+
- lib/mcp/server/oauth/challenge.rb
|
|
92
|
+
- lib/mcp/server/oauth/errors.rb
|
|
93
|
+
- lib/mcp/server/oauth/introspection_verifier.rb
|
|
94
|
+
- lib/mcp/server/oauth/jwt_verifier.rb
|
|
95
|
+
- lib/mcp/server/oauth/middleware.rb
|
|
96
|
+
- lib/mcp/server/oauth/protected_resource_metadata.rb
|
|
97
|
+
- lib/mcp/server/oauth/protected_resource_metadata_middleware.rb
|
|
98
|
+
- lib/mcp/server/oauth/token_verifier.rb
|
|
88
99
|
- lib/mcp/server/pagination.rb
|
|
89
100
|
- lib/mcp/server/pending_response.rb
|
|
90
101
|
- lib/mcp/server/request_state_security.rb
|
|
@@ -108,7 +119,7 @@ licenses:
|
|
|
108
119
|
- Apache-2.0
|
|
109
120
|
metadata:
|
|
110
121
|
allowed_push_host: https://rubygems.org
|
|
111
|
-
changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v1.
|
|
122
|
+
changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v1.8.0
|
|
112
123
|
homepage_uri: https://ruby.sdk.modelcontextprotocol.io
|
|
113
124
|
source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
|
|
114
125
|
bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues
|