Class: MCPClient::ServerBase

Inherits:
Object
  • Object
show all
Defined in:
lib/mcp_client/server_base.rb

Overview

Base class for MCP servers - serves as the interface for different server implementations

Constant Summary collapse

'io.modelcontextprotocol/related-task'
MAX_LIST_PAGES =

Safety bound on the number of pages followed when auto-paginating a cursor-based list operation, to protect against a server that returns a nextCursor indefinitely.

1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name: nil) ⇒ ServerBase

Returns a new instance of ServerBase.



28
29
30
# File 'lib/mcp_client/server_base.rb', line 28

def initialize(name: nil)
  @name = name
end

Instance Attribute Details

#instructionsString? (readonly)

Initialize the server with a name Server-declared instructions from the initialize result, if any

Parameters:

  • name (String, nil)

    server name

Returns:

  • (String, nil)


14
15
16
# File 'lib/mcp_client/server_base.rb', line 14

def instructions
  @instructions
end

#nameObject (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/mcp_client/server_base.rb', line 8

def name
  @name
end

Instance Method Details

#call_tool(tool_name, parameters) ⇒ Object

Call a tool with the given parameters

Parameters:

  • tool_name (String)

    the name of the tool to call

  • parameters (Hash)

    the parameters to pass to the tool

Returns:

  • (Object)

    the result of the tool invocation

Raises:

  • (NotImplementedError)


48
49
50
# File 'lib/mcp_client/server_base.rb', line 48

def call_tool(tool_name, parameters)
  raise NotImplementedError, 'Subclasses must implement call_tool'
end

#call_tool_streaming(tool_name, parameters) ⇒ Enumerator

Stream a tool call result (default implementation returns single-value stream)

Parameters:

  • tool_name (String)

    the name of the tool to call

  • parameters (Hash)

    the parameters to pass to the tool

Returns:

  • (Enumerator)

    stream of results



183
184
185
186
187
# File 'lib/mcp_client/server_base.rb', line 183

def call_tool_streaming(tool_name, parameters)
  Enumerator.new do |yielder|
    yielder << call_tool(tool_name, parameters)
  end
end

#capabilitiesHash?

Returns server capabilities.

Returns:

  • (Hash, nil)

    server capabilities

Raises:

  • (NotImplementedError)


121
122
123
# File 'lib/mcp_client/server_base.rb', line 121

def capabilities
  raise NotImplementedError, 'Subclasses must implement capabilities'
end

#capability?(*path) ⇒ Boolean

Whether the server declared the given (possibly nested) capability during initialization.

Parameters:

  • path (Array<String, Symbol>)

    capability key path, e.g. 'logging' or 'resources', 'subscribe'

Returns:

  • (Boolean)


130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/mcp_client/server_base.rb', line 130

def capability?(*path)
  node = begin
    capabilities
  rescue NotImplementedError
    nil
  end
  path.each do |key|
    return false unless node.is_a?(Hash)

    node = node[key.to_s]
  end
  !node.nil? && node != false
end

#cleanupObject

Clean up the server connection

Raises:

  • (NotImplementedError)


158
159
160
# File 'lib/mcp_client/server_base.rb', line 158

def cleanup
  raise NotImplementedError, 'Subclasses must implement cleanup'
end

#client_info=(info) ⇒ Object

Host-supplied Implementation info sent as clientInfo during initialize (MCP 2025-11-25 Implementation: name, version, plus optional title, description, websiteUrl, icons). Defaults to the gem's identity.

Parameters:

  • info (Hash)

    implementation info; must include name and version

Raises:

  • (ArgumentError)

    when name or version is missing



21
22
23
24
25
26
# File 'lib/mcp_client/server_base.rb', line 21

def client_info=(info)
  raise ArgumentError, 'client_info must include name' unless info['name'] || info[:name]
  raise ArgumentError, 'client_info must include version' unless info['version'] || info[:version]

  @client_info = info.transform_keys(&:to_s)
end

#connectBoolean

Initialize a connection to the MCP server

Returns:

  • (Boolean)

    true if connection successful

Raises:

  • (NotImplementedError)


34
35
36
# File 'lib/mcp_client/server_base.rb', line 34

def connect
  raise NotImplementedError, 'Subclasses must implement connect'
end

#get_prompt(prompt_name, parameters) ⇒ Object

Get a prompt with the given parameters

Parameters:

  • prompt_name (String)

    the name of the prompt to get

  • parameters (Hash)

    the parameters to pass to the prompt

Returns:

  • (Object)

    the result of the prompt interpolation

Raises:

  • (NotImplementedError)


62
63
64
# File 'lib/mcp_client/server_base.rb', line 62

def get_prompt(prompt_name, parameters)
  raise NotImplementedError, 'Subclasses must implement get_prompt'
end

#list_promptsArray<MCPClient::Prompt>

List all prompts available from the MCP server

Returns:

Raises:

  • (NotImplementedError)


54
55
56
# File 'lib/mcp_client/server_base.rb', line 54

def list_prompts
  raise NotImplementedError, 'Subclasses must implement list_prompts'
end

#list_resource_templates(cursor: nil) ⇒ Hash

List all resource templates available from the MCP server

Parameters:

  • cursor (String, nil) (defaults to: nil)

    optional cursor for pagination

Returns:

  • (Hash)

    result containing resourceTemplates array and optional nextCursor

Raises:

  • (NotImplementedError)


83
84
85
# File 'lib/mcp_client/server_base.rb', line 83

def list_resource_templates(cursor: nil)
  raise NotImplementedError, 'Subclasses must implement list_resource_templates'
end

#list_resources(cursor: nil) ⇒ Hash

List all resources available from the MCP server

Parameters:

  • cursor (String, nil) (defaults to: nil)

    optional cursor for pagination

Returns:

  • (Hash)

    result containing resources array and optional nextCursor

Raises:

  • (NotImplementedError)


69
70
71
# File 'lib/mcp_client/server_base.rb', line 69

def list_resources(cursor: nil)
  raise NotImplementedError, 'Subclasses must implement list_resources'
end

#list_toolsArray<MCPClient::Tool>

List all tools available from the MCP server

Returns:

Raises:

  • (NotImplementedError)


40
41
42
# File 'lib/mcp_client/server_base.rb', line 40

def list_tools
  raise NotImplementedError, 'Subclasses must implement list_tools'
end

Echo the related-task _meta of an incoming server request onto the outgoing result, so responses to task-related requests (elicitation or sampling during input_required) stay associated with their task.

Parameters:

  • result (Hash)

    the outgoing JSON-RPC result payload

  • params (Hash, nil)

    the incoming request params

Returns:

  • (Hash)

    result with related-task _meta merged when applicable



112
113
114
115
116
117
118
# File 'lib/mcp_client/server_base.rb', line 112

def merge_related_task_meta(result, params)
  related = params.is_a?(Hash) ? params.dig('_meta', RELATED_TASK_META_KEY) : nil
  return result unless related && result.is_a?(Hash) && !result.key?('error')

  meta = (result['_meta'] || {}).merge(RELATED_TASK_META_KEY => related)
  result.merge('_meta' => meta)
end

#on_notification {|method, params| ... } ⇒ void

This method returns an undefined value.

Register a callback to receive JSON-RPC notifications

Yields:

  • (method, params)

    invoked when a notification is received



198
199
200
# File 'lib/mcp_client/server_base.rb', line 198

def on_notification(&block)
  @notification_callback = block
end

#pingObject

Ping the MCP server to check connectivity (zero-parameter heartbeat call)

Returns:

  • (Object)

    result from the ping request



191
192
193
# File 'lib/mcp_client/server_base.rb', line 191

def ping
  rpc_request('ping')
end

#read_resource(uri) ⇒ Array<MCPClient::ResourceContent>

Read a resource by its URI

Parameters:

  • uri (String)

    the URI of the resource to read

Returns:

Raises:

  • (NotImplementedError)


76
77
78
# File 'lib/mcp_client/server_base.rb', line 76

def read_resource(uri)
  raise NotImplementedError, 'Subclasses must implement read_resource'
end

#require_capability!(*path, method:) ⇒ Object

Raise unless the server negotiated the given capability (MCP lifecycle: "Only use capabilities that were successfully negotiated").

Parameters:

  • path (Array<String, Symbol>)

    capability key path

  • method (String)

    the JSON-RPC method the caller wants to send

Raises:



149
150
151
152
153
154
155
# File 'lib/mcp_client/server_base.rb', line 149

def require_capability!(*path, method:)
  return if capability?(*path)

  raise MCPClient::Errors::CapabilityError,
        "Server #{name || self.class.name} did not declare the #{path.join('.')} capability " \
        "required for #{method}"
end

#rpc_notify(method, params = {}) ⇒ void

This method returns an undefined value.

Send a JSON-RPC notification (no response expected)

Parameters:

  • method (String)

    JSON-RPC method name

  • params (Hash) (defaults to: {})

    parameters for the notification

Raises:

  • (NotImplementedError)


175
176
177
# File 'lib/mcp_client/server_base.rb', line 175

def rpc_notify(method, params = {})
  raise NotImplementedError, 'Subclasses must implement rpc_notify'
end

#rpc_request(method, params = {}) ⇒ Object

Send a JSON-RPC request and return the result

Parameters:

  • method (String)

    JSON-RPC method name

  • params (Hash) (defaults to: {})

    parameters for the request

Returns:

  • (Object)

    result field from the JSON-RPC response

Raises:



167
168
169
# File 'lib/mcp_client/server_base.rb', line 167

def rpc_request(method, params = {})
  raise NotImplementedError, 'Subclasses must implement rpc_request'
end

#subscribe_resource(uri) ⇒ Boolean

Subscribe to resource updates

Parameters:

  • uri (String)

    the URI of the resource to subscribe to

Returns:

  • (Boolean)

    true if subscription successful

Raises:

  • (NotImplementedError)


90
91
92
# File 'lib/mcp_client/server_base.rb', line 90

def subscribe_resource(uri)
  raise NotImplementedError, 'Subclasses must implement subscribe_resource'
end

#unsubscribe_resource(uri) ⇒ Boolean

Unsubscribe from resource updates

Parameters:

  • uri (String)

    the URI of the resource to unsubscribe from

Returns:

  • (Boolean)

    true if unsubscription successful

Raises:

  • (NotImplementedError)


97
98
99
# File 'lib/mcp_client/server_base.rb', line 97

def unsubscribe_resource(uri)
  raise NotImplementedError, 'Subclasses must implement unsubscribe_resource'
end