Class: Marketing::AdlabsMcpClient
- Inherits:
-
Object
- Object
- Marketing::AdlabsMcpClient
- Defined in:
- app/services/marketing/adlabs_mcp_client.rb
Overview
Thin client for the AdLabs MCP server (Amazon Ads / PPC management).
AdLabs exposes a stateful, conversational MCP surface at
https://mcp.adlabs.app, authenticated with a custom +X-ADLABS-MCP-KEY+
header. Unlike a one-shot REST API, its tools thread a +chat_session_id+ and
pass server-side +mcp://data/...+ references between calls, so a single
client instance (one MCP connection) must back every tool call within one
assistant conversation turn for those references to resolve.
Wraps the official MCP Ruby SDK's HTTP transport — the same plumbing as
UpstreamProxy. The API key is read from Rails credentials
(+adlabs_mcp.api_key+) via Heatwave::Configuration, the same secret the
standalone +.mcp.json+ server (Claude Code / Cursor / Zed) reads from
+ADLABS_MCP_KEY+.
Defined Under Namespace
Classes: AuthenticationError, Error
Constant Summary collapse
- URL =
AdLabs MCP endpoint (streamable HTTP).
'https://mcp.adlabs.app'- AUTH_HEADER =
Custom auth header carrying the API key.
'X-ADLABS-MCP-KEY'- OPEN_TIMEOUT =
Connect timeout (seconds) for the underlying HTTP transport.
8- READ_TIMEOUT =
Read timeout (seconds) — queries over large ad accounts can be slow.
60- CATALOG_CACHE_KEY =
Rails.cache key for the (conversation-independent) tool catalog.
'adlabs:mcp:catalog:v1'- CATALOG_TTL =
How long to cache the catalog. Tool definitions are static between
AdLabs deploys; a deploy of this app also clears the in-memory cache. 1.hour
Class Method Summary collapse
-
.catalog ⇒ Array<Hash>
The AdLabs tool catalog as plain, cacheable hashes (+{ 'name', 'description', 'input_schema' }+).
-
.reset_catalog! ⇒ void
Drop the cached catalog (tests, or after an AdLabs tool change).
Instance Method Summary collapse
-
#call_tool(tool_name, arguments = {}) ⇒ String
Call an AdLabs tool by its upstream name and return its textual result.
-
#initialize(api_key: nil) ⇒ AdlabsMcpClient
constructor
A new instance of AdlabsMcpClient.
-
#list_tools ⇒ Array<MCP::Client::Tool>
List the tools the AdLabs server exposes.
Constructor Details
#initialize(api_key: nil) ⇒ AdlabsMcpClient
Returns a new instance of AdlabsMcpClient.
77 78 79 80 |
# File 'app/services/marketing/adlabs_mcp_client.rb', line 77 def initialize(api_key: nil) @api_key = api_key.presence || Heatwave::Configuration.fetch(:adlabs_mcp, :api_key) raise AuthenticationError, 'AdLabs MCP API key not configured (adlabs_mcp.api_key)' if @api_key.blank? end |
Class Method Details
.catalog ⇒ Array<Hash>
The AdLabs tool catalog as plain, cacheable hashes
(+{ 'name', 'description', 'input_schema' }+). Conversation-independent
and shared across every build, so the per-turn client doesn't pay a
+tools/list+ round-trip just to enumerate tools. Returns +[]+ (uncached)
on any failure so a transient outage doesn't poison the cache.
57 58 59 60 61 62 63 64 65 66 |
# File 'app/services/marketing/adlabs_mcp_client.rb', line 57 def catalog Rails.cache.fetch(CATALOG_CACHE_KEY, expires_in: CATALOG_TTL) do new.list_tools.map do |t| { 'name' => t.name, 'description' => t.description.to_s, 'input_schema' => t.input_schema } end end rescue StandardError => e Rails.logger.warn("[AdlabsMcpClient] catalog fetch failed: #{e.}") [] end |
.reset_catalog! ⇒ void
This method returns an undefined value.
Drop the cached catalog (tests, or after an AdLabs tool change).
71 72 73 |
# File 'app/services/marketing/adlabs_mcp_client.rb', line 71 def reset_catalog! Rails.cache.delete(CATALOG_CACHE_KEY) end |
Instance Method Details
#call_tool(tool_name, arguments = {}) ⇒ String
Call an AdLabs tool by its upstream name and return its textual result.
Never raises — upstream/transport failures come back as a JSON error
payload the model can read and react to.
96 97 98 99 100 101 102 103 |
# File 'app/services/marketing/adlabs_mcp_client.rb', line 96 def call_tool(tool_name, arguments = {}) response = client.call_tool(name: tool_name, arguments: arguments.to_h) extract_text(response) rescue MCP::Client::RequestHandlerError => e { error: "AdLabs error: #{e.}" }.to_json rescue StandardError => e { error: "AdLabs client error: #{e.}" }.to_json end |
#list_tools ⇒ Array<MCP::Client::Tool>
List the tools the AdLabs server exposes. Memoized per instance; the
first call performs the MCP +initialize+ handshake.
85 86 87 |
# File 'app/services/marketing/adlabs_mcp_client.rb', line 85 def list_tools @list_tools ||= client.tools end |