Class: VSM::Ports::MCP::ServerStdio
- Defined in:
- lib/vsm/ports/mcp/server_stdio.rb
Overview
Exposes the capsule’s tools as an MCP server over stdio (NDJSON JSON-RPC). Implemented methods: tools/list, tools/call.
Instance Method Summary collapse
- #egress_subscribe ⇒ Object
-
#initialize(capsule:) ⇒ ServerStdio
constructor
A new instance of ServerStdio.
- #loop ⇒ Object
Methods inherited from VSM::Port
#ingress, #render_out, #should_render?
Constructor Details
#initialize(capsule:) ⇒ ServerStdio
Returns a new instance of ServerStdio.
11 12 13 14 15 |
# File 'lib/vsm/ports/mcp/server_stdio.rb', line 11 def initialize(capsule:) super(capsule: capsule) @waiters = {} @waiters_mutex = Mutex.new end |
Instance Method Details
#egress_subscribe ⇒ Object
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/vsm/ports/mcp/server_stdio.rb', line 17 def egress_subscribe # Single subscriber that resolves tool_result waiters by corr_id @capsule.bus.subscribe do |m| next unless m.kind == :tool_result q = nil @waiters_mutex.synchronize { q = @waiters.delete(m.corr_id.to_s) } q&.enqueue(m) end super end |
#loop ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/vsm/ports/mcp/server_stdio.rb', line 28 def loop $stdout.sync = true while (line = $stdin.gets) begin req = JSON.parse(line) rescue => e write_err(nil, code: -32700, message: "Parse error: #{e.message}") next end id = req["id"] method = req["method"] params = req["params"] || {} case method when "tools/list" write_ok(id, { tools: list_tools }) when "tools/call" name = params["name"].to_s args = params["arguments"] || {} res = call_local_tool(id, name, args) write_ok(id, { content: [{ type: "text", text: res.to_s }] }) else write_err(id, code: -32601, message: "Method not found: #{method}") end end end |