Class: Pikuri::Mcp::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/pikuri/mcp/registry.rb

Overview

Pure configuration for MCP servers — id → transport descriptor pairs and nothing more. No I/O, no live state. Servers consumes a registry at construction time to start the actual clients.

Split from Servers so the dependency on the mcp gem and on subprocess / network lifecycle is confined to the runtime side. Tests that only need to exercise registry value semantics never have to load the gem or open a transport.

Entry types

Two sibling value classes, picked per server. The registry holds a mixed array; Servers#start_one dispatches on the type.

  • StdioEntry — local subprocess, command: argv. The mcp gem spawns it; see CLAUDE.md “Subprocess seam” carve-out.

  • HttpEntry — remote MCP endpoint, url: + optional headers:. Plain Faraday under the hood — no subprocess, no carve-out needed.

EMPTY

The EMPTY singleton is the default for Agent#initialize‘s mcp_registry: kwarg. When the registry is empty Agent short-circuits — no Servers is built, no mcp_connect tool is registered, no <available_mcps> block is appended to the system prompt. The pikuri-chat binary relies on this short-circuit so it can omit the kwarg entirely.

Same shape as Skill::Catalog::EMPTY.

Defined Under Namespace

Classes: HttpEntry, StdioEntry

Constant Summary collapse

EMPTY =

Frozen empty registry. Used as the default for Agent#initialize‘s mcp_registry: kwarg.

new.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entries: []) ⇒ Registry

Parameters:

  • entries (Array<StdioEntry, HttpEntry>) (defaults to: [])

    zero or more server definitions. Order is preserved; duplicate ids raise.

Raises:

  • (ArgumentError)

    if two entries share an id.



84
85
86
87
88
89
90
91
92
93
# File 'lib/pikuri/mcp/registry.rb', line 84

def initialize(entries: [])
  seen = {}
  entries.each do |e|
    raise ArgumentError, "Duplicate MCP id #{e.id.inspect}" if seen.key?(e.id)

    seen[e.id] = true
  end
  @entries = entries.dup.freeze
  freeze
end

Instance Attribute Details

#commandArray<String> (readonly)

Returns argv to spawn the server, e.g. [“npx”, “mcp-maven-deps”].

Returns:

  • (Array<String>)

    argv to spawn the server, e.g. [“npx”, “mcp-maven-deps”].



52
# File 'lib/pikuri/mcp/registry.rb', line 52

StdioEntry = Data.define(:id, :command)

#entriesArray<StdioEntry, HttpEntry> (readonly)

Returns all configured entries, in declaration order.

Returns:



97
98
99
# File 'lib/pikuri/mcp/registry.rb', line 97

def entries
  @entries
end

#headersHash{String => String} (readonly)

Returns headers sent on every request. Frozen. Defaults to an empty hash.

Returns:

  • (Hash{String => String})

    headers sent on every request. Frozen. Defaults to an empty hash.



74
75
76
77
78
# File 'lib/pikuri/mcp/registry.rb', line 74

HttpEntry = Data.define(:id, :url, :headers) do
  def initialize(id:, url:, headers: {})
    super(id: id, url: url, headers: headers.freeze)
  end
end

#idString (readonly)

Returns short identifier the LLM uses to refer to this server, e.g. “hubspot”.

Returns:

  • (String)

    short identifier the LLM uses to refer to this server, e.g. “hubspot”.



52
# File 'lib/pikuri/mcp/registry.rb', line 52

StdioEntry = Data.define(:id, :command)

#urlString (readonly)

Returns full MCP endpoint URL, e.g. mcp.example.com/v1.

Returns:



74
75
76
77
78
# File 'lib/pikuri/mcp/registry.rb', line 74

HttpEntry = Data.define(:id, :url, :headers) do
  def initialize(id:, url:, headers: {})
    super(id: id, url: url, headers: headers.freeze)
  end
end

Instance Method Details

#empty?Boolean

Returns true when no servers are configured. Agent keys its MCP auto-wiring off this — empty registry ⇒ no surface change, same pattern as Skill::Catalog#empty?.

Returns:

  • (Boolean)

    true when no servers are configured. Agent keys its MCP auto-wiring off this — empty registry ⇒ no surface change, same pattern as Skill::Catalog#empty?.



102
103
104
# File 'lib/pikuri/mcp/registry.rb', line 102

def empty?
  @entries.empty?
end

#get(id) ⇒ StdioEntry, ...

Returns the entry with this id, or nil.

Parameters:

  • id (String)

Returns:



109
110
111
# File 'lib/pikuri/mcp/registry.rb', line 109

def get(id)
  @entries.find { |e| e.id == id }
end

#idsArray<String>

Returns all configured ids, in declaration order.

Returns:

  • (Array<String>)

    all configured ids, in declaration order.



114
115
116
# File 'lib/pikuri/mcp/registry.rb', line 114

def ids
  @entries.map(&:id)
end