Module: Tep::MCP
- Defined in:
- lib/tep/mcp.rb
Defined Under Namespace
Classes: ResourceContent, Result
Constant Summary collapse
- PROTOCOL_VERSION =
MCP protocol version this server claims to speak. Tracks the 2025-03 (“Streamable HTTP”) revision of the spec.
"2025-03-26"
Class Method Summary collapse
- .error(s) ⇒ Object
-
.initialize_envelope(req_id, server_name, server_version) ⇒ Object
JSON-RPC 2.0 response envelope for ‘initialize`.
-
.method_not_found_envelope(req_id, method_name) ⇒ Object
Error envelope for an unrecognized JSON-RPC method.
-
.nested_extract(json, key) ⇒ Object
Pull a nested JSON value out of ‘json` by top-level key, returning the value’s JSON-string form.
-
.resource_text(uri, text) ⇒ Object
Build a text-mime resource content block.
-
.resources_list_envelope(req_id, resources_array_json) ⇒ Object
Wrap a pre-built resources-array JSON string into the resources/list response envelope.
-
.resources_read_envelope(req_id, uri, mime, text) ⇒ Object
Wrap a ResourceContent into a resources/read response envelope.
- .text(s) ⇒ Object
-
.tools_call_envelope(req_id, text, is_error) ⇒ Object
Wrap a tool’s text + error-flag into the tools/call response envelope.
-
.tools_list_envelope(req_id, tools_array_json) ⇒ Object
Wrap a pre-built tools-array JSON string into the tools/list response envelope.
-
.unknown_resource_envelope(req_id, uri) ⇒ Object
Error envelope for resources/read on an unknown URI.
-
.unknown_tool_envelope(req_id, tool_name) ⇒ Object
Error envelope for tools/call on an unknown tool name.
Class Method Details
.error(s) ⇒ Object
50 51 52 53 54 55 |
# File 'lib/tep/mcp.rb', line 50 def self.error(s) r = Tep::MCP::Result.new r.text = s r.is_error = 1 r end |
.initialize_envelope(req_id, server_name, server_version) ⇒ Object
JSON-RPC 2.0 response envelope for ‘initialize`. The MCP client expects serverInfo + capabilities + protocolVersion. capabilities lists which method groups this server speaks.
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/tep/mcp.rb', line 106 def self.initialize_envelope(req_id, server_name, server_version) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"result\":{" + "\"protocolVersion\":\"" + Tep::MCP::PROTOCOL_VERSION + "\"," + "\"capabilities\":{\"tools\":{},\"resources\":{}}," + "\"serverInfo\":{" + "\"name\":" + Tep::Json.quote(server_name) + "," + "\"version\":" + Tep::Json.quote(server_version) + "}" + "}" + "}" end |
.method_not_found_envelope(req_id, method_name) ⇒ Object
Error envelope for an unrecognized JSON-RPC method. Spec code -32601 (method not found).
195 196 197 198 199 200 201 |
# File 'lib/tep/mcp.rb', line 195 def self.method_not_found_envelope(req_id, method_name) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"error\":{\"code\":-32601," + "\"message\":" + Tep::Json.quote("method not found: " + method_name) + "}" + "}" end |
.nested_extract(json, key) ⇒ Object
Pull a nested JSON value out of ‘json` by top-level key, returning the value’s JSON-string form. Used by the translator-emitted dispatcher to dig ‘params` out of the JSON-RPC envelope, then `arguments` out of params, before handing the arguments sub-object to the per-tool cmeth.
Returns “{}” when the key isn’t present (so downstream Tep::Json.get_str / get_int calls see an empty object that returns their zero-default cleanly).
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/tep/mcp.rb', line 91 def self.nested_extract(json, key) pos = Tep::Json.find_value_start(json, key) if pos < 0 return "{}" end end_pos = Tep::Json.skip_value(json, pos) if end_pos <= pos return "{}" end json[pos, end_pos - pos] end |
.resource_text(uri, text) ⇒ Object
Build a text-mime resource content block. URI is the resource’s identifier (echoed back to the client so clients can correlate the response with the request).
74 75 76 77 78 79 80 |
# File 'lib/tep/mcp.rb', line 74 def self.resource_text(uri, text) c = Tep::MCP::ResourceContent.new c.uri = uri c.mime = "text/plain" c.text = text c end |
.resources_list_envelope(req_id, resources_array_json) ⇒ Object
Wrap a pre-built resources-array JSON string into the resources/list response envelope. Same shape as tools_list_envelope – translator emits the array literally at compile time so spinel doesn’t need to walk it at runtime.
152 153 154 155 156 |
# File 'lib/tep/mcp.rb', line 152 def self.resources_list_envelope(req_id, resources_array_json) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"result\":{\"resources\":" + resources_array_json + "}" + "}" end |
.resources_read_envelope(req_id, uri, mime, text) ⇒ Object
Wrap a ResourceContent into a resources/read response envelope. contents is a one-element array per MCP spec; the uri / mimeType / text fields are read off as scalars (same spinel-friendly pattern as tools_call_envelope) before being spliced into the JSON.
163 164 165 166 167 168 169 170 171 |
# File 'lib/tep/mcp.rb', line 163 def self.resources_read_envelope(req_id, uri, mime, text) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"result\":{\"contents\":[" + "{\"uri\":" + Tep::Json.quote(uri) + "," + "\"mimeType\":" + Tep::Json.quote(mime) + "," + "\"text\":" + Tep::Json.quote(text) + "}" + "]}" + "}" end |
.text(s) ⇒ Object
43 44 45 46 47 48 |
# File 'lib/tep/mcp.rb', line 43 def self.text(s) r = Tep::MCP::Result.new r.text = s r.is_error = 0 r end |
.tools_call_envelope(req_id, text, is_error) ⇒ Object
Wrap a tool’s text + error-flag into the tools/call response envelope. content is a one-element array with a text block. Takes scalars rather than the Result struct directly so spinel tracks the String param locally through json_quote without going through attr_accessor return-type inference.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/tep/mcp.rb', line 133 def self.tools_call_envelope(req_id, text, is_error) is_err_str = "false" if is_error == 1 is_err_str = "true" end "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"result\":{" + "\"content\":[" + "{\"type\":\"text\",\"text\":" + Tep::Json.quote(text) + "}" + "]," + "\"isError\":" + is_err_str + "}" + "}" end |
.tools_list_envelope(req_id, tools_array_json) ⇒ Object
Wrap a pre-built tools-array JSON string into the tools/list response envelope. tools_array_json is the literal ‘[…, …]` the translator emits at compile time.
122 123 124 125 126 |
# File 'lib/tep/mcp.rb', line 122 def self.tools_list_envelope(req_id, tools_array_json) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"result\":{\"tools\":" + tools_array_json + "}" + "}" end |
.unknown_resource_envelope(req_id, uri) ⇒ Object
Error envelope for resources/read on an unknown URI. Same JSON-RPC code as unknown_tool (-32602 invalid params).
175 176 177 178 179 180 181 |
# File 'lib/tep/mcp.rb', line 175 def self.unknown_resource_envelope(req_id, uri) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"error\":{\"code\":-32602," + "\"message\":" + Tep::Json.quote("unknown resource: " + uri) + "}" + "}" end |
.unknown_tool_envelope(req_id, tool_name) ⇒ Object
Error envelope for tools/call on an unknown tool name. Sent as a JSON-RPC error (-32602 invalid params) per the spec.
185 186 187 188 189 190 191 |
# File 'lib/tep/mcp.rb', line 185 def self.unknown_tool_envelope(req_id, tool_name) "{\"jsonrpc\":\"2.0\",\"id\":" + req_id.to_s + "," + "\"error\":{\"code\":-32602," + "\"message\":" + Tep::Json.quote("unknown tool: " + tool_name) + "}" + "}" end |