Class: Seo::AhrefsMcpClient
- Inherits:
-
Object
- Object
- Seo::AhrefsMcpClient
- Defined in:
- app/services/seo/ahrefs_mcp_client.rb
Overview
Direct MCP client for Ahrefs API using raw HTTP JSON-RPC.
Implements the MCP (Model Context Protocol) spec for tool discovery and execution.
Defined Under Namespace
Classes: AuthenticationError, Error, ToolNotFoundError
Constant Summary collapse
- MCP_URL =
'https://api.ahrefs.com/mcp/mcp'- PROTOCOL_VERSION =
'2025-06-18'
Instance Method Summary collapse
-
#call_tool(tool_name, **arguments) ⇒ Hash
Call an MCP tool.
-
#close ⇒ Object
Close the session.
-
#domain_metrics(target:) ⇒ Hash
Get domain metrics (Domain Rating, etc.).
-
#initialize(token: nil) ⇒ AhrefsMcpClient
constructor
A new instance of AhrefsMcpClient.
-
#initialize_session ⇒ Hash
Initialize the MCP session.
-
#list_tools ⇒ Array<Hash>
List available tools.
-
#organic_keywords(target:, limit: 50, date: nil, select: nil) ⇒ Hash
Get organic keywords for a URL Available columns: keyword, best_position, best_position_url, volume, sum_traffic, cpc, keyword_difficulty, serp_features, best_position_kind, words, etc.
-
#tool_doc(tool_name) ⇒ String
Get documentation for a tool.
-
#top_pages(target:, limit: 100, date: nil, select: nil) ⇒ Hash
Get top pages by organic traffic.
Constructor Details
#initialize(token: nil) ⇒ AhrefsMcpClient
Returns a new instance of AhrefsMcpClient.
28 29 30 31 32 33 34 35 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 28 def initialize(token: nil) @token = token || Heatwave::Configuration.fetch(:ahrefs, :mcp_token) raise AuthenticationError, 'Ahrefs MCP token not configured' if @token.blank? @session_id = nil @request_id = 0 @tools_cache = nil end |
Instance Method Details
#call_tool(tool_name, **arguments) ⇒ Hash
Call an MCP tool
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 66 def call_tool(tool_name, **arguments) ensure_session! response = send_request('tools/call', { name: tool_name, arguments: arguments }) result = response['result'] return nil unless result # Extract content from MCP response content = result['content'] return result unless content.is_a?(Array) # Parse JSON from text content text_content = content.find { |c| c['type'] == 'text' } return result unless text_content JSON.parse(text_content['text']) rescue JSON::ParserError text_content['text'] end |
#close ⇒ Object
Close the session
148 149 150 151 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 148 def close @session_id = nil @tools_cache = nil end |
#domain_metrics(target:) ⇒ Hash
Get domain metrics (Domain Rating, etc.)
134 135 136 137 138 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 134 def domain_metrics(target:) call_tool('site-explorer-metrics', target: target, mode: 'subdomains') end |
#initialize_session ⇒ Hash
Initialize the MCP session
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 39 def initialize_session response = send_request('initialize', { protocolVersion: PROTOCOL_VERSION, capabilities: {}, clientInfo: { name: 'heatwave-seo', version: '1.0.0' } }) # Send initialized notification send_notification('notifications/initialized') response['result'] end |
#list_tools ⇒ Array<Hash>
List available tools
54 55 56 57 58 59 60 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 54 def list_tools @tools_cache ||= begin ensure_session! response = send_request('tools/list') response.dig('result', 'tools') || [] end end |
#organic_keywords(target:, limit: 50, date: nil, select: nil) ⇒ Hash
Get organic keywords for a URL
Available columns: keyword, best_position, best_position_url, volume, sum_traffic, cpc,
keyword_difficulty, serp_features, best_position_kind, words, etc.
118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 118 def organic_keywords(target:, limit: 50, date: nil, select: nil) date ||= Date.yesterday.strftime('%Y-%m-%d') # Note: Ahrefs uses 'best_position' not 'position', 'sum_traffic' for estimated traffic select ||= 'keyword,best_position,sum_traffic,volume,cpc,keyword_difficulty,serp_features,best_position_kind' call_tool('site-explorer-organic-keywords', target: target, mode: 'exact', date: date, select: select, limit: limit) end |
#tool_doc(tool_name) ⇒ String
Get documentation for a tool
143 144 145 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 143 def tool_doc(tool_name) call_tool('doc', tool: tool_name) end |
#top_pages(target:, limit: 100, date: nil, select: nil) ⇒ Hash
Get top pages by organic traffic
96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/services/seo/ahrefs_mcp_client.rb', line 96 def top_pages(target:, limit: 100, date: nil, select: nil) date ||= Date.yesterday.strftime('%Y-%m-%d') # Default columns: URL, traffic, keywords, top keyword, position, value (in cents) select ||= 'url,sum_traffic,keywords,top_keyword,top_keyword_best_position,value' call_tool('site-explorer-top-pages', target: target, mode: 'subdomains', date: date, select: select, limit: limit) end |