Module: MCPClient::ServerStdio::JsonRpcTransport

Includes:
JsonRpcCommon
Included in:
MCPClient::ServerStdio
Defined in:
lib/mcp_client/server_stdio/json_rpc_transport.rb

Overview

JSON-RPC request/notification plumbing for stdio transport

Instance Method Summary collapse

Methods included from JsonRpcCommon

#build_jsonrpc_notification, #build_jsonrpc_request, #initialization_params, #ping, #process_jsonrpc_response, #with_retry

Instance Method Details

#call_tool_streaming(tool_name, parameters) ⇒ Enumerator

Stream tool call fallback for stdio transport (yields single result)



87
88
89
90
91
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 87

def call_tool_streaming(tool_name, parameters)
  Enumerator.new do |yielder|
    yielder << call_tool(tool_name, parameters)
  end
end

#ensure_initializedvoid

This method returns an undefined value.

Ensure the server process is started and initialized (handshake)

Raises:



13
14
15
16
17
18
19
20
21
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 13

def ensure_initialized
  return if @initialized

  connect
  start_reader
  perform_initialize

  @initialized = true
end

#next_idInteger

Generate a new unique request ID



43
44
45
46
47
48
49
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 43

def next_id
  @mutex.synchronize do
    id = @next_id
    @next_id += 1
    id
  end
end

#perform_initializevoid

This method returns an undefined value.

Handshake: send initialize request and initialized notification

Raises:



26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 26

def perform_initialize
  # Initialize request
  init_id = next_id
  init_req = build_jsonrpc_request('initialize', initialization_params, init_id)
  send_request(init_req)
  res = wait_response(init_id)
  if (err = res['error'])
    raise MCPClient::Errors::ConnectionError, "Initialize failed: #{err['message']}"
  end

  # Send initialized notification
  notif = build_jsonrpc_notification('notifications/initialized', {})
  @stdin.puts(notif.to_json)
end

#rpc_notify(method, params = {}) ⇒ void

This method returns an undefined value.

Send a JSON-RPC notification (no response expected)



115
116
117
118
119
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 115

def rpc_notify(method, params = {})
  ensure_initialized
  notif = build_jsonrpc_notification(method, params)
  @stdin.puts(notif.to_json)
end

#rpc_request(method, params = {}) ⇒ Object

Generic JSON-RPC request: send method with params and wait for result

Raises:



100
101
102
103
104
105
106
107
108
109
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 100

def rpc_request(method, params = {})
  ensure_initialized
  with_retry do
    req_id = next_id
    req = build_jsonrpc_request(method, params, req_id)
    send_request(req)
    res = wait_response(req_id)
    process_jsonrpc_response(res)
  end
end

#send_request(req) ⇒ void

This method returns an undefined value.

Send a JSON-RPC request and return nothing

Raises:



55
56
57
58
59
60
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 55

def send_request(req)
  @logger.debug("Sending JSONRPC request: #{req.to_json}")
  @stdin.puts(req.to_json)
rescue StandardError => e
  raise MCPClient::Errors::TransportError, "Failed to send JSONRPC request: #{e.message}"
end

#wait_response(id) ⇒ Hash

Wait for a response with the given request ID

Raises:



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/mcp_client/server_stdio/json_rpc_transport.rb', line 66

def wait_response(id)
  deadline = Time.now + @read_timeout
  @mutex.synchronize do
    until @pending.key?(id)
      remaining = deadline - Time.now
      break if remaining <= 0

      @cond.wait(@mutex, remaining)
    end
    msg = @pending[id]
    @pending[id] = nil
    raise MCPClient::Errors::TransportError, "Timeout waiting for JSONRPC response id=#{id}" unless msg

    msg
  end
end