Class: VSM::MCP::Client

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cmd:, env: {}, cwd: nil, name: nil) ⇒ Client

Returns a new instance of Client.



11
12
13
14
15
16
# File 'lib/vsm/mcp/client.rb', line 11

def initialize(cmd:, env: {}, cwd: nil, name: nil)
  @cmd, @env, @cwd, @name = cmd, env, cwd, (name || cmd.split.first)
  @stdin = @stdout = @stderr = @wait_thr = nil
  @rpc = nil
  @stderr_thread = nil
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



9
10
11
# File 'lib/vsm/mcp/client.rb', line 9

def name
  @name
end

Instance Method Details

#call_tool(name:, arguments: {}) ⇒ Object

Returns a String (first text content) or a JSON string fallback



72
73
74
75
76
77
# File 'lib/vsm/mcp/client.rb', line 72

def call_tool(name:, arguments: {})
  res = @rpc.request("tools/call", { "name" => name, "arguments" => arguments })
  content = Array(res["content"])
  item = content.find { |c| c["type"] == "text" } || content.first
  item ? (item["text"] || item.to_s) : res.to_s
end

#list_toolsObject

Returns Array<Hash> with symbol keys: :name, :description, :input_schema



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/vsm/mcp/client.rb', line 59

def list_tools
  raw = @rpc.request("tools/list")
  arr = (raw && raw["tools"]) || []
  arr.map do |t|
    {
      name: t["name"].to_s,
      description: t["description"].to_s,
      input_schema: (t["input_schema"] || {})
    }
  end
end

#startObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/vsm/mcp/client.rb', line 18

def start
  opts = {}
  opts[:chdir] = @cwd if @cwd
  args = @cmd.is_a?(Array) ? @cmd : Shellwords.split(@cmd.to_s)
  @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(@env || {}, *args, **opts)
  # Drain stderr to avoid blocking if the server writes logs
  @stderr_thread = Thread.new do
    begin
      @stderr.each_line { |_line| }
    rescue StandardError
    end
  end
  @rpc = JSONRPC::Stdio.new(r: @stdout, w: @stdin)
  self
end

#stopObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/vsm/mcp/client.rb', line 34

def stop
  begin
    @stdin&.close
  rescue StandardError
  end
  begin
    @stdout&.close
  rescue StandardError
  end
  begin
    @stderr&.close
  rescue StandardError
  end
  begin
    @stderr_thread&.kill
  rescue StandardError
  end
  begin
    @wait_thr&.kill
  rescue StandardError
  end
  nil
end