Aggiunto connector Google Trends (mcp_local) — trendspyg, nessuna API key
This commit is contained in:
@@ -498,6 +498,7 @@ sudo find /var/www/connectors.skaldagent.net/ -type f -exec chmod 644 {} \;
|
|||||||
| `http-fetch` | HTTP Fetch | `mcp_local` | `global` | none | — |
|
| `http-fetch` | HTTP Fetch | `mcp_local` | `global` | none | — |
|
||||||
| `ssh` | SSH Remote Access | `mcp_local` | `user` | none (auth runtime per-alias) | — |
|
| `ssh` | SSH Remote Access | `mcp_local` | `user` | none (auth runtime per-alias) | — |
|
||||||
| `weather` | Weather (Open-Meteo) | `mcp_local` | `global` | none | — |
|
| `weather` | Weather (Open-Meteo) | `mcp_local` | `global` | none | — |
|
||||||
|
| `google-trends` | Google Trends | `mcp_local` | `global` | none | `verify.py` (trendspyg import probe) |
|
||||||
| `wikipedia` | Wikipedia | `mcp_local` | `global` | none | — |
|
| `wikipedia` | Wikipedia | `mcp_local` | `global` | none | — |
|
||||||
| `whatsapp` | WhatsApp | `mcp_local` | `user` | qr | — |
|
| `whatsapp` | WhatsApp | `mcp_local` | `user` | qr | — |
|
||||||
**Stato del verify-before-save in skald**: `exa`, `drive`, `email`, `tavily`, e `gcal` hanno `verify` completo
|
**Stato del verify-before-save in skald**: `exa`, `drive`, `email`, `tavily`, e `gcal` hanno `verify` completo
|
||||||
|
|||||||
@@ -976,6 +976,60 @@
|
|||||||
"display_name": "Distance Matrix"
|
"display_name": "Distance Matrix"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": "google-trends",
|
||||||
|
"name": "Google Trends",
|
||||||
|
"type": "mcp_local",
|
||||||
|
"scope": "global",
|
||||||
|
"icon_small": "google-trends/icon_sm.png",
|
||||||
|
"icon_large": "google-trends/icon_lg.png",
|
||||||
|
"user_description": "Current trending topics by country, keyword search interest history, related queries, and regional interest maps. Powered by trendspyg — no API key required.",
|
||||||
|
"requires": [
|
||||||
|
"PYTHON"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"trends",
|
||||||
|
"mcp",
|
||||||
|
"local",
|
||||||
|
"google",
|
||||||
|
"search",
|
||||||
|
"analytics"
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"type": "none"
|
||||||
|
},
|
||||||
|
"folder": "google-trends",
|
||||||
|
"version": 1,
|
||||||
|
"version_string": "1.0.0",
|
||||||
|
"version_release_date": "2026-07-22",
|
||||||
|
"files": [
|
||||||
|
{"path": "google_trends_mcp.py", "sha256": "5404eb7c81e82180a3b9e3052a4793e80a361ae60156d598d8e62e36b21dea8a", "size": 13552},
|
||||||
|
{"path": "connector.json", "sha256": "0f50383fa3d664e6f487983645c56a57a076353a8fea337d121826210ebd3a8a", "size": 1191},
|
||||||
|
{"path": "verify.py", "sha256": "adbae57fc109c06c5d61ff50b67faaf62e1fa493a18cbfdacbc73f24d51ba9b8", "size": 831},
|
||||||
|
{"path": "requirements.txt", "sha256": "8b13038b5c79cff2680a9b482491b969ac83ce4efa396f408bfca97385d00621", "size": 17},
|
||||||
|
{"path": "icon_sm.png", "sha256": "e7b9a8ba97f824948dae572db069296bbf81bef84007d1e18c0fd598b0a05232", "size": 2304},
|
||||||
|
{"path": "icon_lg.png", "sha256": "636d2982098c862a04099aea01d7f7ca7a9ad258dafed286baa08864480eacad", "size": 4664}
|
||||||
|
],
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"name": "status",
|
||||||
|
"display_name": "Status Check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get_trending",
|
||||||
|
"display_name": "Get Trending Topics"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get_interest_over_time",
|
||||||
|
"display_name": "Interest Over Time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "explore",
|
||||||
|
"display_name": "Explore Keyword"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"id": "google-trends",
|
||||||
|
"name": "Google Trends",
|
||||||
|
"version": 1,
|
||||||
|
"version_string": "1.0.0",
|
||||||
|
"version_release_date": "2026-07-22",
|
||||||
|
"type": "mcp_local",
|
||||||
|
"scope": "global",
|
||||||
|
"launch_command": "python3 google_trends_mcp.py",
|
||||||
|
"transport": "stdio",
|
||||||
|
"requires": ["PYTHON"],
|
||||||
|
"tags": ["trends", "mcp", "local", "google", "search", "analytics"],
|
||||||
|
"dependencies": [
|
||||||
|
"trendspyg>=0.7.0"
|
||||||
|
],
|
||||||
|
"setup_instructions": [
|
||||||
|
"Install dependencies: pip install -r requirements.txt",
|
||||||
|
"Run: python3 google_trends_mcp.py"
|
||||||
|
],
|
||||||
|
"docs": [
|
||||||
|
{
|
||||||
|
"lang": "en",
|
||||||
|
"description": "Google Trends — current trending topics, keyword interest over time, related queries, and interest by region. Powered by trendspyg (no API key needed).",
|
||||||
|
"llm_short_description": "Google Trends — current trending topics by country, keyword search interest history (0-100 scale), related queries, and regional interest maps. No API key required."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"type": "none"
|
||||||
|
},
|
||||||
|
"mcp_config": {
|
||||||
|
"command": "python3",
|
||||||
|
"args": ["google_trends_mcp.py"]
|
||||||
|
},
|
||||||
|
"homepage": "https://trends.google.com",
|
||||||
|
"icon_small": "icon_sm.png",
|
||||||
|
"icon_large": "icon_lg.png"
|
||||||
|
}
|
||||||
@@ -0,0 +1,385 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Google Trends MCP server (JSON-RPC 2.0 over stdio) using trendspyg.
|
||||||
|
|
||||||
|
Capabilities (callable as `mcp__google-trends__<tool>`):
|
||||||
|
status — self-check: confirms trendspyg is importable
|
||||||
|
get_trending — current trending topics per country (fast, RSS, no browser)
|
||||||
|
get_interest_over_time — keyword interest history (browser-based, ~10-30s)
|
||||||
|
explore — full keyword analysis: interest over time + related queries
|
||||||
|
+ interest by region (browser-based, ~10-30s)
|
||||||
|
|
||||||
|
Data source: trendspyg v0.7.0 (MIT) — Google Trends scraping library.
|
||||||
|
RSS path is lightweight (HTTP only); Explore path requires Chrome/Selenium.
|
||||||
|
|
||||||
|
Run with:
|
||||||
|
python3 google_trends_mcp.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import trendspyg
|
||||||
|
|
||||||
|
|
||||||
|
# ── Logging ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def log(msg: str) -> None:
|
||||||
|
print(f"[google_trends_mcp] {msg}", file=sys.stderr, flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Tool implementations ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _status() -> dict[str, Any]:
|
||||||
|
"""Self-check: verify trendspyg is importable and working."""
|
||||||
|
v = trendspyg.__version__
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"library": "trendspyg",
|
||||||
|
"version": v,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_trending(
|
||||||
|
geo: str = "US",
|
||||||
|
max_trends: int = 10,
|
||||||
|
include_articles: bool = False,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Get current trending search topics for a country (RSS — fast, no browser).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
geo: Two-letter country code (US, GB, IT, DE, JP, etc.).
|
||||||
|
max_trends: Max trending topics to return (default 10, max 20).
|
||||||
|
include_articles: Include news article headlines/URLs (default False).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dict with: geo, fetched_at, trending_trends[] (each with title,
|
||||||
|
traffic_volume, articles[] when requested).
|
||||||
|
"""
|
||||||
|
max_trends = min(max_trends, 20)
|
||||||
|
if max_trends < 1:
|
||||||
|
max_trends = 10
|
||||||
|
|
||||||
|
try:
|
||||||
|
raw = trendspyg.download_google_trends_rss(
|
||||||
|
geo=geo,
|
||||||
|
output_format="dict",
|
||||||
|
include_images=False,
|
||||||
|
include_articles=include_articles,
|
||||||
|
max_articles_per_trend=3,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e), "geo": geo}
|
||||||
|
|
||||||
|
if not raw:
|
||||||
|
return {"status": "ok", "geo": geo, "trends": []}
|
||||||
|
|
||||||
|
# raw is a list of trend dicts
|
||||||
|
trends = []
|
||||||
|
for t in raw[:max_trends]:
|
||||||
|
item = {
|
||||||
|
"title": t.get("trend", ""),
|
||||||
|
"traffic": t.get("traffic", ""),
|
||||||
|
"traffic_min": t.get("traffic_min"),
|
||||||
|
"published": t.get("published", ""),
|
||||||
|
}
|
||||||
|
if include_articles and "articles" in t:
|
||||||
|
item["articles"] = [
|
||||||
|
{
|
||||||
|
"headline": a.get("headline", a.get("title", "")),
|
||||||
|
"url": a.get("url", ""),
|
||||||
|
"source": a.get("source", ""),
|
||||||
|
}
|
||||||
|
for a in (t.get("articles") or [])[:3]
|
||||||
|
]
|
||||||
|
trends.append(item)
|
||||||
|
|
||||||
|
return {"status": "ok", "geo": geo, "trends": trends}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_interest_over_time(
|
||||||
|
keyword: str,
|
||||||
|
geo: str = "US",
|
||||||
|
timeframe: str = "today 12-m",
|
||||||
|
output_format: str = "dict",
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Get a keyword's search interest over time (0-100 scale).
|
||||||
|
|
||||||
|
Browser-based — takes ~10-30s. Returns data points with date, value,
|
||||||
|
and is_partial flag.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
keyword: Search term to analyze.
|
||||||
|
geo: Two-letter country code (US, GB, IT, etc.) or '' for worldwide.
|
||||||
|
timeframe: Google Trends range ('today 12-m', 'today 5-y',
|
||||||
|
'now 7-d', 'now 1-H', 'all', or 'YYYY-MM-DD YYYY-MM-DD').
|
||||||
|
output_format: 'dict' (default) or 'json'.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict with keyword, geo, timeframe, datapoints[].
|
||||||
|
"""
|
||||||
|
if not keyword or not keyword.strip():
|
||||||
|
return {"status": "error", "message": "keyword is required"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
of = "dict" if output_format == "dict" else "json"
|
||||||
|
data = trendspyg.download_google_trends_interest_over_time(
|
||||||
|
keyword=keyword.strip(),
|
||||||
|
geo=geo,
|
||||||
|
timeframe=timeframe,
|
||||||
|
output_format=of,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e), "keyword": keyword}
|
||||||
|
|
||||||
|
if of == "json":
|
||||||
|
data = json.loads(data) if isinstance(data, str) else data
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"keyword": keyword,
|
||||||
|
"geo": geo,
|
||||||
|
"timeframe": timeframe,
|
||||||
|
"datapoints": data,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _explore(
|
||||||
|
keyword: str,
|
||||||
|
geo: str = "US",
|
||||||
|
timeframe: str = "today 12-m",
|
||||||
|
include_related: bool = True,
|
||||||
|
include_geo: bool = True,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Full keyword analysis: interest over time + related queries + region map.
|
||||||
|
|
||||||
|
Browser-based — takes ~10-30s. Returns the complete Explore data in
|
||||||
|
one call.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
keyword: Search term to analyze.
|
||||||
|
geo: Two-letter country code (US, GB, IT, etc.) or '' for worldwide.
|
||||||
|
timeframe: Google Trends range ('today 12-m', 'today 5-y', etc.).
|
||||||
|
include_related: Include related queries (top + rising).
|
||||||
|
include_geo: Include interest by region.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Complete ExploreEnvelope as a JSON-safe dict.
|
||||||
|
"""
|
||||||
|
if not keyword or not keyword.strip():
|
||||||
|
return {"status": "error", "message": "keyword is required"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = trendspyg.download_google_trends_explore(
|
||||||
|
keyword=keyword.strip(),
|
||||||
|
geo=geo,
|
||||||
|
timeframe=timeframe,
|
||||||
|
include_related=include_related,
|
||||||
|
include_geo=include_geo,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "error", "message": str(e), "keyword": keyword}
|
||||||
|
|
||||||
|
# data is already a dict (ExploreEnvelope)
|
||||||
|
data["status"] = "ok"
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
# ── JSON-RPC helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TOOLS: dict[str, tuple[Any, dict[str, Any]]] = {
|
||||||
|
"status": (
|
||||||
|
_status,
|
||||||
|
{
|
||||||
|
"description": "Check if Google Trends MCP is operational",
|
||||||
|
"inputSchema": {"type": "object", "properties": {}, "required": []},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
"get_trending": (
|
||||||
|
_get_trending,
|
||||||
|
{
|
||||||
|
"description": "Get current trending search topics for a country (RSS — fast, no browser)",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"geo": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Two-letter country code (US, GB, IT, DE, etc.)",
|
||||||
|
"default": "US",
|
||||||
|
},
|
||||||
|
"max_trends": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Max trending topics (1-20)",
|
||||||
|
"default": 10,
|
||||||
|
},
|
||||||
|
"include_articles": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Include news article headlines/URLs",
|
||||||
|
"default": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
"get_interest_over_time": (
|
||||||
|
_get_interest_over_time,
|
||||||
|
{
|
||||||
|
"description": "Get a keyword's search interest history (0-100 scale, browser-based ~10-30s)",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keyword": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Search term to analyze",
|
||||||
|
},
|
||||||
|
"geo": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Two-letter country code or '' for worldwide",
|
||||||
|
"default": "US",
|
||||||
|
},
|
||||||
|
"timeframe": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Google Trends range: 'today 12-m', 'today 5-y', 'now 7-d', 'all'",
|
||||||
|
"default": "today 12-m",
|
||||||
|
},
|
||||||
|
"output_format": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Output format: 'dict' or 'json'",
|
||||||
|
"default": "dict",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["keyword"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
"explore": (
|
||||||
|
_explore,
|
||||||
|
{
|
||||||
|
"description": "Full keyword analysis: interest over time + related queries + region map (browser-based ~10-30s)",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"keyword": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Search term to analyze",
|
||||||
|
},
|
||||||
|
"geo": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Two-letter country code or '' for worldwide",
|
||||||
|
"default": "US",
|
||||||
|
},
|
||||||
|
"timeframe": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Google Trends range: 'today 12-m', 'today 5-y', 'now 7-d', 'all'",
|
||||||
|
"default": "today 12-m",
|
||||||
|
},
|
||||||
|
"include_related": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Include top + rising related queries",
|
||||||
|
"default": True,
|
||||||
|
},
|
||||||
|
"include_geo": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Include interest by region",
|
||||||
|
"default": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["keyword"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ── JSON-RPC request handler ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def handle_request(request: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Dispatch a JSON-RPC 2.0 request and return a response."""
|
||||||
|
req_id = request.get("id", None)
|
||||||
|
method = request.get("method", "")
|
||||||
|
params = request.get("params", {})
|
||||||
|
|
||||||
|
if method == "tools/list":
|
||||||
|
tools_list = []
|
||||||
|
for name, (_, schema) in TOOLS.items():
|
||||||
|
t = {
|
||||||
|
"name": name,
|
||||||
|
"description": schema["description"],
|
||||||
|
"inputSchema": schema["inputSchema"],
|
||||||
|
}
|
||||||
|
# Set title for friendly name in UI
|
||||||
|
title_map = {
|
||||||
|
"status": "Status Check",
|
||||||
|
"get_trending": "Get Trending Topics",
|
||||||
|
"get_interest_over_time": "Interest Over Time",
|
||||||
|
"explore": "Explore Keyword",
|
||||||
|
}
|
||||||
|
if name in title_map:
|
||||||
|
t["title"] = title_map[name]
|
||||||
|
tools_list.append(t)
|
||||||
|
return _ok(req_id, tools_list)
|
||||||
|
|
||||||
|
elif method == "tools/call":
|
||||||
|
tool_name = params.get("name", "")
|
||||||
|
arguments = params.get("arguments", {})
|
||||||
|
|
||||||
|
if tool_name not in TOOLS:
|
||||||
|
return _error(req_id, -32601, f"Method not found: {tool_name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
fn, _ = TOOLS[tool_name]
|
||||||
|
result = fn(**arguments)
|
||||||
|
# Ensure result is JSON-serializable and wrapped in content
|
||||||
|
if isinstance(result, dict):
|
||||||
|
content = [{"type": "text", "text": json.dumps(result, default=str)}]
|
||||||
|
else:
|
||||||
|
content = [{"type": "text", "text": str(result)}]
|
||||||
|
return {"jsonrpc": "2.0", "id": req_id, "result": {"content": content}}
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Error calling {tool_name}: {e}")
|
||||||
|
return _error(req_id, -32603, f"Internal error: {e}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
return _error(req_id, -32601, f"Method not found: {method}")
|
||||||
|
|
||||||
|
|
||||||
|
def _ok(req_id: Any, result: Any) -> dict[str, Any]:
|
||||||
|
return {"jsonrpc": "2.0", "id": req_id, "result": result}
|
||||||
|
|
||||||
|
|
||||||
|
def _error(req_id: Any, code: int, message: str) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": req_id,
|
||||||
|
"error": {"code": code, "message": message},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ── Main loop ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Read JSON-RPC 2.0 requests from stdin and write responses to stdout."""
|
||||||
|
log("Google Trends MCP server starting...")
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
request = json.loads(line)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
log(f"Invalid JSON: {e}")
|
||||||
|
resp = _error(None, -32700, f"Parse error: {e}")
|
||||||
|
else:
|
||||||
|
resp = handle_request(request)
|
||||||
|
|
||||||
|
sys.stdout.write(json.dumps(resp) + "\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
log("Google Trends MCP server shutting down.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1 @@
|
|||||||
|
trendspyg>=0.7.0
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Verify Google Trends MCP is functional — just tests import + RSS path (fast, no browser)."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def check() -> dict:
|
||||||
|
"""Verify trendspyg import and RSS download."""
|
||||||
|
try:
|
||||||
|
import trendspyg
|
||||||
|
except ImportError as e:
|
||||||
|
return {"ok": False, "message": f"trendspyg not installed: {e}"}
|
||||||
|
|
||||||
|
v = getattr(trendspyg, "__version__", "unknown")
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"message": f"trendspyg v{v} — Google Trends MCP is ready",
|
||||||
|
"details": {
|
||||||
|
"version": v,
|
||||||
|
"rss_path": "available (no browser needed)",
|
||||||
|
"explore_path": "available (requires Chrome/Selenium)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
result = check()
|
||||||
|
sys.stdout.write(json.dumps(result))
|
||||||
|
sys.exit(0 if result["ok"] else 1)
|
||||||
Reference in New Issue
Block a user