Class: GroqRuby::MCP::Transports::Stdio

Inherits:
Object
  • Object
show all
Includes:
GroqRuby::MCP::Transport
Defined in:
lib/groq_ruby/mcp/transports/stdio.rb

Overview

Stdio transport — spawns the configured executable, talks newline-delimited JSON over its stdin/stdout, drains stderr to /dev/null. A background reader thread fans inbound messages out to the callback registered via #on_message.

Examples:

transport = Stdio.spawn(ServerConfig.new(name: "fs", command: "..."))
transport.on_message { |msg| puts msg.inspect }
transport.send_message({jsonrpc: "2.0", id: 1, method: "ping"})
...
transport.stop

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Stdio

Returns a new instance of Stdio.

Parameters:



30
31
32
33
34
35
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 30

def initialize(config)
  @config = config
  @on_message = nil
  @write_mutex = Mutex.new
  @stopped = false
end

Class Method Details

.spawn(config) ⇒ Stdio

Build and start a Stdio transport for the given server config.

Parameters:

Returns:

Raises:



25
26
27
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 25

def self.spawn(config)
  new(config).tap(&:start)
end

Instance Method Details

#on_message(&block) ⇒ Object



58
59
60
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 58

def on_message(&block)
  @on_message = block
end

#send_message(message) ⇒ Object



48
49
50
51
52
53
54
55
56
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 48

def send_message(message)
  line = JSON.generate(message)
  @write_mutex.synchronize do
    @stdin.puts(line)
    @stdin.flush
  end
rescue IOError, Errno::EPIPE => e
  raise TransportError, "stdin closed for MCP server #{@config.name.inspect}: #{e.message}"
end

#startself

Spawn the child process and start the reader thread.

Returns:

  • (self)


39
40
41
42
43
44
45
46
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 39

def start
  @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(@config.env, @config.command, *@config.args)
  @stderr_thread = Thread.new { drain(@stderr) }
  @reader_thread = Thread.new { read_loop }
  self
rescue SystemCallError => e
  raise TransportError, "could not spawn MCP server #{@config.name.inspect}: #{e.message}"
end

#stopObject



62
63
64
65
66
67
68
69
# File 'lib/groq_ruby/mcp/transports/stdio.rb', line 62

def stop
  return if @stopped
  @stopped = true
  @reader_thread&.kill
  @stderr_thread&.kill
  [@stdin, @stdout, @stderr].each { |io| io&.close }
  @wait_thr&.kill if @wait_thr&.alive?
end