mcp 0.11.0 → 0.12.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.
@@ -7,9 +7,10 @@ module MCP
7
7
 
8
8
  attr_reader :url
9
9
 
10
- def initialize(url:, headers: {})
10
+ def initialize(url:, headers: {}, &block)
11
11
  @url = url
12
12
  @headers = headers
13
+ @faraday_customizer = block
13
14
  end
14
15
 
15
16
  def send_request(request:)
@@ -78,6 +79,8 @@ module MCP
78
79
  headers.each do |key, value|
79
80
  faraday.headers[key] = value
80
81
  end
82
+
83
+ @faraday_customizer&.call(faraday)
81
84
  end
82
85
  end
83
86
 
@@ -15,7 +15,7 @@ module MCP
15
15
 
16
16
  def initialize(server, stateless: false, session_idle_timeout: nil)
17
17
  super(server)
18
- # Maps `session_id` to `{ stream: stream_object, server_session: ServerSession, last_active_at: float_from_monotonic_clock }`.
18
+ # Maps `session_id` to `{ get_sse_stream: stream_object, server_session: ServerSession, last_active_at: float_from_monotonic_clock }`.
19
19
  @sessions = {}
20
20
  @mutex = Mutex.new
21
21
 
@@ -61,7 +61,7 @@ module MCP
61
61
  end
62
62
 
63
63
  removed_sessions.each do |session|
64
- close_stream_safely(session[:stream])
64
+ close_stream_safely(session[:get_sse_stream])
65
65
  close_post_request_streams(session)
66
66
  end
67
67
  end
@@ -113,7 +113,7 @@ module MCP
113
113
  failed_sessions = []
114
114
 
115
115
  @sessions.each do |sid, session|
116
- next unless (stream = session[:stream])
116
+ next unless (stream = session[:get_sse_stream])
117
117
 
118
118
  if session_expired?(session)
119
119
  failed_sessions << sid
@@ -247,7 +247,7 @@ module MCP
247
247
  end
248
248
 
249
249
  removed_sessions.each do |session|
250
- close_stream_safely(session[:stream])
250
+ close_stream_safely(session[:get_sse_stream])
251
251
  close_post_request_streams(session)
252
252
  end
253
253
  end
@@ -267,6 +267,9 @@ module MCP
267
267
  accept_error = validate_accept_header(request, REQUIRED_POST_ACCEPT_TYPES)
268
268
  return accept_error if accept_error
269
269
 
270
+ content_type_error = validate_content_type(request)
271
+ return content_type_error if content_type_error
272
+
270
273
  body_string = request.body.read
271
274
  session_id = extract_session_id(request)
272
275
 
@@ -334,7 +337,7 @@ module MCP
334
337
  end
335
338
 
336
339
  if session
337
- close_stream_safely(session[:stream])
340
+ close_stream_safely(session[:get_sse_stream])
338
341
  close_post_request_streams(session)
339
342
  end
340
343
  end
@@ -358,7 +361,7 @@ module MCP
358
361
  def cleanup_and_collect_stream(session_id, streams_to_close)
359
362
  return unless (removed = cleanup_session_unsafe(session_id))
360
363
 
361
- streams_to_close << removed[:stream]
364
+ streams_to_close << removed[:get_sse_stream]
362
365
  removed[:post_request_streams]&.each_value { |stream| streams_to_close << stream }
363
366
  end
364
367
 
@@ -399,6 +402,18 @@ module MCP
399
402
  end
400
403
  end
401
404
 
405
+ def validate_content_type(request)
406
+ content_type = request.env["CONTENT_TYPE"]
407
+ media_type = content_type&.split(";")&.first&.strip&.downcase
408
+ return if media_type == "application/json"
409
+
410
+ [
411
+ 415,
412
+ { "Content-Type" => "application/json" },
413
+ [{ error: "Unsupported Media Type: Content-Type must be application/json" }.to_json],
414
+ ]
415
+ end
416
+
402
417
  def not_acceptable_response(required_types)
403
418
  [
404
419
  406,
@@ -449,7 +464,7 @@ module MCP
449
464
 
450
465
  @mutex.synchronize do
451
466
  @sessions[session_id] = {
452
- stream: nil,
467
+ get_sse_stream: nil,
453
468
  server_session: server_session,
454
469
  last_active_at: Process.clock_gettime(Process::CLOCK_MONOTONIC),
455
470
  }
@@ -543,7 +558,7 @@ module MCP
543
558
  if related_request_id
544
559
  session.dig(:post_request_streams, related_request_id)
545
560
  else
546
- session[:stream]
561
+ session[:get_sse_stream]
547
562
  end
548
563
  end
549
564
 
@@ -572,7 +587,7 @@ module MCP
572
587
  end
573
588
 
574
589
  if removed
575
- close_stream_safely(removed[:stream])
590
+ close_stream_safely(removed[:get_sse_stream])
576
591
 
577
592
  removed[:post_request_streams]&.each_value do |stream|
578
593
  close_stream_safely(stream)
@@ -583,7 +598,7 @@ module MCP
583
598
  end
584
599
 
585
600
  def get_session_stream(session_id)
586
- @mutex.synchronize { @sessions[session_id]&.fetch(:stream, nil) }
601
+ @mutex.synchronize { @sessions[session_id]&.fetch(:get_sse_stream, nil) }
587
602
  end
588
603
 
589
604
  def session_exists?(session_id)
@@ -626,8 +641,8 @@ module MCP
626
641
  def store_stream_for_session(session_id, stream)
627
642
  @mutex.synchronize do
628
643
  session = @sessions[session_id]
629
- if session && !session[:stream]
630
- session[:stream] = stream
644
+ if session && !session[:get_sse_stream]
645
+ session[:get_sse_stream] = stream
631
646
  else
632
647
  # Either session was removed, or another request already established a stream.
633
648
  stream.close
@@ -652,13 +667,13 @@ module MCP
652
667
  end
653
668
 
654
669
  def session_active_with_stream?(session_id)
655
- @mutex.synchronize { @sessions.key?(session_id) && @sessions[session_id][:stream] }
670
+ @mutex.synchronize { @sessions.key?(session_id) && @sessions[session_id][:get_sse_stream] }
656
671
  end
657
672
 
658
673
  def send_keepalive_ping(session_id)
659
674
  @mutex.synchronize do
660
- if @sessions[session_id] && @sessions[session_id][:stream]
661
- send_ping_to_stream(@sessions[session_id][:stream])
675
+ if @sessions[session_id] && @sessions[session_id][:get_sse_stream]
676
+ send_ping_to_stream(@sessions[session_id][:get_sse_stream])
662
677
  end
663
678
  end
664
679
  rescue *STREAM_WRITE_ERRORS => e
data/lib/mcp/transport.rb CHANGED
@@ -7,6 +7,7 @@ module MCP
7
7
  # Initialize the transport with the server instance
8
8
  def initialize(server)
9
9
  @server = server
10
+ server.transport = self
10
11
  end
11
12
 
12
13
  # Send a response to the client
data/lib/mcp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MCP
4
- VERSION = "0.11.0"
4
+ VERSION = "0.12.0"
5
5
  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.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Model Context Protocol
@@ -78,7 +78,7 @@ licenses:
78
78
  - Apache-2.0
79
79
  metadata:
80
80
  allowed_push_host: https://rubygems.org
81
- changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.11.0
81
+ changelog_uri: https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v0.12.0
82
82
  homepage_uri: https://github.com/modelcontextprotocol/ruby-sdk
83
83
  source_code_uri: https://github.com/modelcontextprotocol/ruby-sdk
84
84
  bug_tracker_uri: https://github.com/modelcontextprotocol/ruby-sdk/issues