Class: Insika::McpHttpClient

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/mcp_http_client.rb

Overview

MINIMAL MCP client over HTTP JSON-RPC. Discovers the tools of an MCP instance with HTTP transport by making a JSON-RPC 2.0 tools/list POST to the instance endpoint, behind the EgressGuard (SSRF — the url comes from editable config). It is the DEFAULT client injected into the McpToolIngestor; tests pass a Fake (duck-typed) in its place.

Contract (MCP client duck-type): #list_tools -> [{name, description, inputSchema}] — the same MCP envelope that the ToolManifest adapter normalizes.

SCOPE (bounded): only the minimal handshake of ONE stateless tools/list POST. Does NOT implement the full MCP session lifecycle (initialize/protocol negotiation/session-id/notifications) nor the stdio transport — that is the "real MCP transport", later work (out-of-scope, see spec). It serves simple HTTP MCP servers (direct JSON-RPC) and proves the ingestion seam.

Constant Summary collapse

JSONRPC_VERSION =
"2.0"

Instance Method Summary collapse

Constructor Details

#initialize(url:, http: Insika::HttpClient.new, egress: Insika::EgressGuard, egress_options: {}, headers: {}, timeout: nil) ⇒ McpHttpClient

Returns a new instance of McpHttpClient.



23
24
25
26
27
28
29
30
31
# File 'lib/insika/mcp_http_client.rb', line 23

def initialize(url:, http: Insika::HttpClient.new, egress: Insika::EgressGuard,
               egress_options: {}, headers: {}, timeout: nil)
  @url = url.to_s
  @http = http
  @egress = egress
  @egress_options = egress_options
  @headers = { "Content-Type" => "application/json", "Accept" => "application/json" }.merge(headers || {})
  @timeout = timeout
end

Instance Method Details

#list_toolsObject

-> [ { "name", "description", "inputSchema" } ]. Raises Insika::Error on blocked egress, HTTP != 2xx, invalid JSON or a JSON-RPC error.

Raises:



35
36
37
38
39
40
41
42
# File 'lib/insika/mcp_http_client.rb', line 35

def list_tools
  reason = @egress.violation(@url, **@egress_options)
  raise Insika::Error, "MCP target blocked: #{reason}" if reason

  result = @http.request(method: "POST", url: @url, headers: @headers,
                         body: request_body("tools/list", {}), timeout: @timeout)
  Array(rpc_result(result).fetch("tools", []))
end