Class: Mcp::StdioTransport

Inherits:
Object
  • Object
show all
Defined in:
lib/mcp/stdio_transport.rb

Overview

Client-side stdio transport for MCP servers that communicate via JSON-RPC over stdin/stdout. Conforms to the MCP SDK transport contract (+send_request(request:)+ → Hash) so it plugs into MCP::Client identically to the built-in HTTP transport.

Spawns the server process lazily on first request. If the process crashes, the next request automatically respawns it. Thread-safe via a mutex around the entire request/response cycle.

Examples:

transport = Mcp::StdioTransport.new(command: "linear-toon-mcp")
client = MCP::Client.new(transport: transport)
client.tools  # spawns process, sends tools/list, returns tools

See Also:

  • the built-in HTTP transport this mirrors

Constant Summary collapse

GRACEFUL_SHUTDOWN_TIMEOUT =

Seconds to wait for graceful SIGTERM shutdown before escalating to SIGKILL.

2

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command:, args: [], env: {}) ⇒ StdioTransport

Returns a new instance of StdioTransport.

Parameters:

  • command (String)

    executable to spawn (resolved via $PATH)

  • args (Array<String>) (defaults to: [])

    command-line arguments for the server process

  • env (Hash<String, String>) (defaults to: {})

    environment variables merged into the child process’s inherited environment



32
33
34
35
36
37
38
39
40
# File 'lib/mcp/stdio_transport.rb', line 32

def initialize(command:, args: [], env: {})
  @command = command
  @args = args
  @env = env
  @mutex = Mutex.new
  @stdin = nil
  @stdout = nil
  @wait_thread = nil
end

Class Method Details

.cleanup_allObject

Shuts down all tracked instances. Called automatically via at_exit.



81
82
83
84
85
86
# File 'lib/mcp/stdio_transport.rb', line 81

def cleanup_all
  @instances_mutex.synchronize do
    @instances.each { |instance| instance.send(:stop_process) }
    @instances.clear
  end
end

.register(instance) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



71
72
73
# File 'lib/mcp/stdio_transport.rb', line 71

def register(instance)
  @instances_mutex.synchronize { @instances << instance }
end

.unregister(instance) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



76
77
78
# File 'lib/mcp/stdio_transport.rb', line 76

def unregister(instance)
  @instances_mutex.synchronize { @instances.delete(instance) }
end

Instance Method Details

#send_request(request:) ⇒ Hash

Sends a JSON-RPC request and returns the parsed response. Spawns the server process on first call. If the process died since the last call, respawns automatically.

Parameters:

  • request (Hash)

    complete JSON-RPC request object with :jsonrpc, :id, :method, and optional :params keys

Returns:

  • (Hash)

    parsed JSON-RPC response (string keys)

Raises:

  • (MCP::Client::RequestHandlerError)

    on transport-level errors (process crash, invalid JSON, timeout, command not found)



51
52
53
54
55
# File 'lib/mcp/stdio_transport.rb', line 51

def send_request(request:)
  @mutex.synchronize do
    perform_request(request)
  end
end

#shutdownObject

Terminates the server process and releases resources. Safe to call multiple times — subsequent calls are no-ops.



59
60
61
62
# File 'lib/mcp/stdio_transport.rb', line 59

def shutdown
  @mutex.synchronize { stop_process }
  self.class.unregister(self)
end