Class: ModelContextProtocol::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/model_context_protocol/server.rb,
lib/model_context_protocol/server/redis_client_proxy.rb

Defined Under Namespace

Modules: Cancellable, Content, ContentHelpers, GlobalConfig, Progressable Classes: ClientLogger, Completion, Configuration, NotConfiguredError, NullCompletion, Pagination, ParameterValidationError, Prompt, RedisClientProxy, RedisConfig, RedisPoolManager, Registry, Resource, ResourceTemplate, ResponseArgumentsError, Router, ServerLogger, StdioConfiguration, StdioTransport, StreamableHttpConfiguration, StreamableHttpTransport, Tool

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.instanceServer?

Returns the singleton server instance created by with_stdio_transport or with_streamable_http_transport.

Returns:

  • the singleton server instance created by with_stdio_transport or with_streamable_http_transport



79
80
81
# File 'lib/model_context_protocol/server.rb', line 79

def instance
  @instance
end

Instance Attribute Details

#configurationConfiguration, ... (readonly)

Returns:

  • the transport-specific configuration (StdioConfiguration or StreamableHttpConfiguration)

  • the message router that dispatches JSON-RPC methods to handlers

  • the active transport (StdioTransport or StreamableHttpTransport), or nil if not started



16
17
18
# File 'lib/model_context_protocol/server.rb', line 16

def configuration
  @configuration
end

#routerConfiguration, ... (readonly)

Returns:

  • the transport-specific configuration (StdioConfiguration or StreamableHttpConfiguration)

  • the message router that dispatches JSON-RPC methods to handlers

  • the active transport (StdioTransport or StreamableHttpTransport), or nil if not started



16
17
18
# File 'lib/model_context_protocol/server.rb', line 16

def router
  @router
end

#transportConfiguration, ... (readonly)

Returns:

  • the transport-specific configuration (StdioConfiguration or StreamableHttpConfiguration)

  • the message router that dispatches JSON-RPC methods to handlers

  • the active transport (StdioTransport or StreamableHttpTransport), or nil if not started



16
17
18
# File 'lib/model_context_protocol/server.rb', line 16

def transport
  @transport
end

Class Method Details

.configure_server_logging {|config| ... } ⇒ void

This method returns an undefined value.

Configure global server-side logging (distinct from client-facing logs sent via JSON-RPC). Applies to all server instances; typically called once per application. For stdio transport, logdev must not be $stdout (would corrupt protocol messages).

Examples:

ModelContextProtocol::Server.configure_server_logging do |logger|
  logger.level = Logger::DEBUG
  logger.logdev = $stderr  # or a file for stdio transport
end

Yield Parameters:



127
128
129
130
# File 'lib/model_context_protocol/server.rb', line 127

def configure_server_logging(&block)
  Server::GlobalConfig::ServerLogging.configure(&block)
  instance&.configuration&.instance_variable_set(:@server_logger, nil)
end

.configured?Boolean

Query whether any server instance has been configured. Returns false when no instance exists — the server genuinely isn't configured yet, so callers can use this as a guard before calling start.

Returns:

  • true if with_stdio_transport or with_streamable_http_transport has been called



142
143
144
# File 'lib/model_context_protocol/server.rb', line 142

def configured?
  instance&.configured? || false
end

.reset!void

This method returns an undefined value.

Tear down the transport and clear the singleton instance to allow reconfiguration. Safe-navigates when no instance exists because test teardown (before/after hooks) must succeed even when a test fails before the server is initialized.



196
197
198
199
# File 'lib/model_context_protocol/server.rb', line 196

def reset!
  instance&.shutdown
  self.instance = nil
end

.running?Boolean

Query whether any server instance is actively processing messages. Returns false when no instance exists, allowing callers to guard both start (to avoid redundant starts) and shutdown (to skip if not running).

Returns:

  • true if a server instance exists and its transport is initialized



151
152
153
# File 'lib/model_context_protocol/server.rb', line 151

def running?
  instance&.running? || false
end

.serve(env:, session_context: {}) ⇒ Hash

Handle a single HTTP request by forwarding to the instance's serve method. Used by Rails/Sinatra/Rack controllers as an alternative to calling Server.instance.serve directly. Raises when no instance exists for the same reason as start — a controller receiving requests without a configured server is always a misconfiguration.

Parameters:

  • the Rack environment hash containing request details

  • (defaults to: {})

    per-session data (e.g., user_id) stored during initialization

Returns:

  • Rack response with :status, :headers, and either :json or :stream/:stream_proc

Raises:

  • if with_streamable_http_transport hasn't been called



176
177
178
179
# File 'lib/model_context_protocol/server.rb', line 176

def serve(env:, session_context: {})
  raise NotConfiguredError, "Server not configured. Call with_streamable_http_transport first." unless instance
  instance.serve(env: env, session_context: session_context)
end

.shutdownvoid

This method returns an undefined value.

Tear down the transport and release resources if a server is running. Safe-navigates when no instance exists because callers in cleanup paths (signal handlers, web server shutdown hooks, test teardown) need this to work unconditionally.



187
188
189
# File 'lib/model_context_protocol/server.rb', line 187

def shutdown
  instance&.shutdown
end

.startvoid

This method returns an undefined value.

Activate the transport layer to begin processing MCP protocol messages. Raises when no instance exists because a caller who forgot to invoke a factory method would otherwise get silent nil. Web server integrations like the Puma plugin guard with configured? first, but direct callers need the error.

Raises:

  • if with_stdio_transport or with_streamable_http_transport hasn't been called



162
163
164
165
# File 'lib/model_context_protocol/server.rb', line 162

def start
  raise NotConfiguredError, "Server not configured. Call with_stdio_transport or with_streamable_http_transport first." unless instance
  instance.start
end

.with_stdio_transport {|config| ... } ⇒ Server

Factory method for creating a server with standard input/output transport. For standalone scripts that communicate over stdin/stdout (e.g., Claude Desktop integration). Yields a StdioConfiguration for setting name, version, registry, and environment variables.

Examples:

server = ModelContextProtocol::Server.with_stdio_transport do |config|
  config.name = "My MCP Server"
  config.registry { tools { register MyTool } }
end
server.start  # blocks while handling stdio

Yield Parameters:

Returns:

  • the configured server instance (also stored in Server.instance)



93
94
95
# File 'lib/model_context_protocol/server.rb', line 93

def with_stdio_transport(&block)
  build_server(StdioConfiguration.new, &block)
end

.with_streamable_http_transport {|config| ... } ⇒ Server

Factory method for creating a server with streamable HTTP transport. For Rack applications that serve multiple clients over HTTP with Redis-backed session coordination. Yields a StreamableHttpConfiguration for setting name, version, registry, session requirements, and CORS.

Examples:

server = ModelContextProtocol::Server.with_streamable_http_transport do |config|
  config.name = "My HTTP MCP Server"
  config.redis_url = ENV.fetch("REDIS_URL")
  config.require_sessions = true
  config.allowed_origins = ["*"]
end
server.start  # spawns background threads, returns immediately

Yield Parameters:

Returns:

  • the configured server instance (also stored in Server.instance)

Raises:

  • if redis_url is not set or invalid



112
113
114
# File 'lib/model_context_protocol/server.rb', line 112

def with_streamable_http_transport(&block)
  build_server(StreamableHttpConfiguration.new, &block)
end

Instance Method Details

#configured?Boolean

Query whether the server has been configured with a transport type. The Puma plugin checks this before attempting to start the server.

Returns:

  • true if with_stdio_transport or with_streamable_http_transport has been called



65
66
67
# File 'lib/model_context_protocol/server.rb', line 65

def configured?
  !@configuration.nil?
end

#running?Boolean

Query whether the server's transport layer is actively processing messages. The Puma plugin checks this to avoid redundant start calls and to guard shutdown.

Returns:

  • true if start has been called and transport is initialized



73
74
75
# File 'lib/model_context_protocol/server.rb', line 73

def running?
  !@transport.nil?
end

#serve(env:, session_context: {}) ⇒ Hash

Handle a single HTTP request through the streamable HTTP transport. Rack applications delegate each incoming request to this method.

Parameters:

  • the Rack environment hash containing request details

  • (defaults to: {})

    per-session data (e.g., user_id) stored during initialization

Returns:

  • Rack response with :status, :headers, and either :json or :stream/:stream_proc

Raises:

  • if transport hasn't been started via start

  • if called on stdio transport (HTTP-only method)



44
45
46
47
48
49
# File 'lib/model_context_protocol/server.rb', line 44

def serve(env:, session_context: {})
  raise "Server not running. Call start first." unless @transport
  raise "serve is only available for streamable_http transport" unless configuration.transport_type == :streamable_http

  @transport.handle(env: env, session_context: session_context)
end

#shutdownvoid

This method returns an undefined value.

Tear down the transport and release resources. For stdio: no-ops (StdioTransport doesn't implement shutdown). For HTTP: stops background threads and closes active SSE streams.



56
57
58
59
# File 'lib/model_context_protocol/server.rb', line 56

def shutdown
  @transport.shutdown if @transport.respond_to?(:shutdown)
  @transport = nil
end

#startvoid

This method returns an undefined value.

Activate the transport layer to begin processing MCP protocol messages. For stdio: blocks the calling thread while handling stdin/stdout communication. For HTTP: spawns background threads for Redis polling and stream monitoring, then returns immediately.

Raises:

  • if transport is already running (prevents double-initialization)



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/model_context_protocol/server.rb', line 24

def start
  raise "Server already running. Call shutdown first." if @transport

  case configuration.transport_type
  when :stdio
    @transport = StdioTransport.new(router: @router, configuration: @configuration)
    @transport.handle
  when :streamable_http
    @transport = StreamableHttpTransport.new(router: @router, configuration: @configuration)
  end
end