google-trends: fix broken MCP handshake and RSS articles (v2 / 1.1.0)

The server never implemented `initialize`, so every MCP client got
-32601 to its opening request and aborted before listing a tool. Also
missing: `notifications/initialized` and `ping`; `tools/list` returned a
bare array instead of {"tools": [...]}; notifications (no `id`) got a
full response written to stdout.

Rewritten to the shape the other local connectors already use (TOOLS
manifest + TOOL_DISPATCH, `_text_result` with isError, handle_request
returning None for notifications).

Also fixed:
- include_articles always returned nothing: trendspyg emits
  `news_articles`, the mapper read `articles`. explore_link kept too.
- fn(**arguments) turned a bad argument into -32603; handlers now take
  an args dict and coerce/clamp.
- errors were returned as successful results; now isError: true, with
  trendspyg's typed exceptions translated into actionable messages.
- browser calls could run ~100s (10 retries x 8s); capped at ~25s.
- verify.py shipped but connector.json declared no `verify` block; wired
  it and upgraded the script to a real RSS fetch.
- explore mutated trendspyg's ExploreEnvelope; dropped the no-op
  output_format param; trendspyg pinned >=1.6.0 and imported defensively.
This commit is contained in:
Daniele
2026-08-24 17:29:36 +01:00
parent 0c04ba2e4c
commit 5e4c41183c
7 changed files with 401 additions and 311 deletions
+25
View File
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## 2026-08-24
### Fixed
- **google-trends: the MCP server never completed a handshake (v2 / 1.1.0)** — the connector was unusable since it shipped. `handle_request` implemented exactly two methods, `tools/list` and `tools/call`; everything else fell through to `-32601 Method not found`. Since `initialize` is the *first* message any MCP client sends, the client got an error to its opening request and aborted before a single tool could be listed. Three further protocol defects sat behind it:
- **`tools/list` returned a bare array** instead of the `{"tools": [...]}` object the spec requires — so even a client that tolerated the missing handshake would have parsed zero tools.
- **No `notifications/initialized`, no `ping`.** The former is the notification a client sends immediately *after* `initialize`; the latter is the standard liveness probe.
- **Notifications got answered.** Any message without an `id` (a notification, by definition) still produced a full JSON-RPC response written to stdout — a protocol violation that desynchronises a strict client. `handle_request` now returns `None` for every id-less message.
- Fix: the server now mirrors the shape every other local connector in this repo already uses (`wikipedia`, `weather`, `gmaps`): `initialize``protocolVersion 2024-11-05` + `serverInfo`, silent `notifications/initialized`, `ping``{}`, `tools/list``{"tools": TOOLS}`, and a `TOOLS` manifest list + `TOOL_DISPATCH` map replacing the old dict-of-tuples and the `title_map` that was rebuilt inside the request handler on every call.
- Verified end-to-end by piping a real handshake into the process: `initialize``tools/list``tools/call` for each tool, plus a notification and an unknown method ✅
- **google-trends: `include_articles: true` always returned zero articles** — a silent data bug independent of the handshake. The RSS mapper read `t.get("articles")`, but trendspyg emits the key as **`news_articles`**. The lookup never matched, so the field came back as an empty list for every trend and the caller had no way to tell "no articles" from "wrong key". Now reads `news_articles`; `explore_link` (the trend's Google Trends URL, previously discarded) is included too.
- **google-trends: a malformed tool argument crashed the call as a protocol error** — tools were invoked as `fn(**arguments)` against typed keyword parameters, so an unexpected key or a string where a number belonged raised `TypeError` and surfaced as `-32603 Internal error`, which reads to the agent as a broken server rather than a bad argument. Handlers now take a single `args: dict` and coerce through `_str_arg` / `_int_arg` / `_bool_arg` (clamping `max_trends` to 1-20 instead of resetting a negative value to 10).
### Changed
- **google-trends: tool failures are now marked as failures.** Errors were returned as `{"status": "error", ...}` inside a *successful* result — structurally indistinguishable from data. They now follow the repo convention: an `Error: …` text result carrying `isError: true`. trendspyg's typed exceptions are translated into actionable messages (`RateLimitError` → retry later, `BrowserError` → Chrome missing, `InvalidParameterError` → bad input) instead of a bare `str(e)`.
- **google-trends: browser calls now fail fast.** `explore` and `get_interest_over_time` used trendspyg's defaults of 10 retries × 8s, allowing a ~100s call — well past any agent's tool timeout. Capped at 3 × 6.0s (~25s worst case), matching the "~10-25s" the tool descriptions promise.
- **google-trends: `trendspyg` pinned to `>=1.6.0`** (was `>=0.7.0`) and imported defensively — an import failure no longer kills the process at startup, so the handshake still succeeds and the missing dependency is reported as a readable tool error.
- **google-trends: `verify` is now actually wired.** `verify.py` shipped in `files[]` since day one but `connector.json` declared no `verify` block, so skald never ran it. Added (`python3 verify.py`, 20s), and the script was upgraded from a bare `import trendspyg` check to a real RSS fetch against Google Trends that fails if zero trends come back.
- **google-trends: `explore` no longer mutates trendspyg's envelope.** It injected `data["status"] = "ok"` into the returned `ExploreEnvelope`, assuming the return was always a dict. The envelope is now passed through untouched.
- **google-trends: dropped the `output_format` parameter** from `get_interest_over_time`. It was exposed in the input schema but was a no-op for the caller — the `"json"` branch immediately re-parsed the string back into the same dict the `"dict"` branch produced.
- **google-trends: tool descriptions rewritten** to state what each tool is *for* and when to prefer one over another (`explore` over `get_interest_over_time` when related queries or the regional breakdown are wanted), and that `get_trending` is always-current and cannot look at past dates.
## 2026-08-23
### Added