Add SerpAPI Flights connector: mcp_remote, flight search via Google Flights, verify.py with MCP initialize probe

This commit is contained in:
2026-07-19 14:46:20 +01:00
parent e469f48b52
commit 513483e81b
6 changed files with 172 additions and 1 deletions
+2 -1
View File
@@ -470,6 +470,7 @@ sudo find /var/www/connectors.skaldagent.net/ -type f -exec chmod 644 {} \;
| `tavily` | Tavily | `mcp_remote` | `global` | api_key (`{SECRET:tavilyApiKey}` in URL) | `verify.py` (HTTP probe `/search`) |
| `gmail` | Gmail | `mcp_local` | `user` | oauth2 (Google) + deliver: `env/google_authorized_user` (via `GMAIL_CREDS_JSON`) | ⏳ Fase 2 — OAuth via loopback listener |
| `gcal` | Google Calendar | `mcp_local` | `user` | oauth2 (Google) + deliver: `env/google_authorized_user` (via `GCAL_CREDS_JSON`) | `verify.py` (creds load + API probe) |
| `drive` | Google Drive | `mcp_local` | `user` | oauth2 (Google) + deliver: `env/google_authorized_user` (via `DRIVE_CREDS_JSON`) | `verify.py` (creds load + Drive API probe) |
| `email` | Email (IMAP/SMTP) | `mcp_local` | `user` | password (env) | `verify.py` (IMAP+SMTP probe) |
| `firecrawl` | Firecrawl | `mcp_local` | `global` | api_key (env) | — |
| `http-fetch` | HTTP Fetch | `mcp_local` | `global` | none | — |
@@ -477,6 +478,6 @@ sudo find /var/www/connectors.skaldagent.net/ -type f -exec chmod 644 {} \;
| `weather` | Weather (Open-Meteo) | `mcp_local` | `global` | none | — |
| `wikipedia` | Wikipedia | `mcp_local` | `global` | none | — |
| `whatsapp` | WhatsApp | `mcp_local` | `user` | qr | — |
**Stato del verify-before-save in skald**: `exa`, `email`, `tavily`, e `gcal` hanno `verify` completo
**Stato del verify-before-save in skald**: `exa`, `drive`, `email`, `tavily`, e `gcal` hanno `verify` completo
(script + JSON output); `gmail` aspetta la Fase 2 (OAuth via loopback listener).
Un connector senza `verify` viene attivato senza test — vedi § Senza verify.
+45
View File
@@ -372,6 +372,51 @@
}
]
},
{
"id": "serpapi-flights",
"name": "SerpAPI Flights",
"type": "mcp_remote",
"scope": "global",
"icon_small": "serpapi-flights/icon_sm.svg",
"icon_large": "serpapi-flights/icon_lg.svg",
"user_description": "Search and compare flights, lookup airport codes, and explore routes via SerpAPI\u2019s Google Flights integration.",
"tags": [
"flights",
"travel",
"mcp",
"remote",
"search"
],
"auth": {
"type": "api_key"
},
"folder": "serpapi-flights",
"version": 1,
"version_string": "1.0.0",
"version_release_date": "2026-07-19",
"files": [
{
"path": "connector.json",
"sha256": "7c2bd621f461001483787036c5692021f34f3838b90e215be00cae470103526a",
"size": 1352
},
{
"path": "verify.py",
"sha256": "eca6298a01cc1c8ce2aece9170a0b228efda7cb8a5c469d1ca3b62932fb7ea51",
"size": 2003
},
{
"path": "icon_sm.svg",
"sha256": "6dbd397e7e06d0431089b12e590c0a5dafa362dcb7117af122e240ea9231edc3",
"size": 570
},
{
"path": "icon_lg.svg",
"sha256": "5a2ffa7f2502fd27dc0027395db2c863bb544c8de1eef8131a5228d87402c8e6",
"size": 574
}
]
},
{
"id": "ssh",
"name": "SSH Remote Access",
+47
View File
@@ -0,0 +1,47 @@
{
"id": "serpapi-flights",
"name": "SerpAPI Flights",
"version": 1,
"version_string": "1.0.0",
"version_release_date": "2026-07-19",
"type": "mcp_remote",
"scope": "global",
"tags": [
"flights",
"travel",
"mcp",
"remote",
"search"
],
"docs": [
{
"lang": "en",
"description": "Search and compare flights, lookup airport codes, explore routes and prices via SerpAPI's Google Flights integration. Covers departure/arrival search, price comparison, and routing across dates.",
"llm_short_description": "Flight search via SerpAPI: search flights, lookup airport codes, compare prices and routes using Google Flights data."
}
],
"auth": {
"type": "api_key"
},
"env": [
{
"name": "serpapiApiKey",
"label": "SerpAPI API key",
"description": "Get one at https://serpapi.com/manage-api-key (free plan includes 100 searches/month).",
"required": true,
"secret": true,
"example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}
],
"mcp_config": {
"url": "https://mcp.serpapi.com/{SECRET:serpapiApiKey}/mcp",
"transport": "streamable-http"
},
"verify": {
"command": "python3 verify.py",
"timeout_secs": 15
},
"homepage": "https://serpapi.com/google-flights-api",
"icon_small": "icon_sm.svg",
"icon_large": "icon_lg.svg"
}
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none">
<rect width="96" height="96" rx="16" fill="#1a73e8"/>
<g transform="translate(48,48) rotate(-45)" fill="#fff">
<path d="M0-36c-1.2 0-2.4.6-3 1.6l-5 8.6c-.6 1-.2 2.4.8 3 .4.2.8.4 1.2.4h3l7.6 13-14.6 4.4c-1.2.4-2 1.4-2 2.6v4c0 1.2.8 2.2 2 2.6l19 5.6 5.6 19c.4 1.2 1.4 2 2.6 2h4c1.2 0 2.2-.8 2.6-2l4.4-14.6 13 7.6v3c0 .4.2.8.4 1.2.6 1 2 1.4 3 .8l8.6-5c1-.6 1.6-1.8 1.6-3V-4c0-1.2-.6-2.4-1.6-3l-8.6-5c-1-.6-2.4-.2-3 .8-.4.6-.4 1.2-.4 1.8v3l-13 7.6-4.4-14.6c-.4-1.2-1.4-2-2.6-2H4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 574 B

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<rect width="48" height="48" rx="8" fill="#1a73e8"/>
<g transform="translate(24,24) rotate(-45)" fill="#fff">
<path d="M0-18c-.6 0-1.2.3-1.5.8l-2.5 4.3c-.3.5-.1 1.2.4 1.5.2.1.4.2.6.2h1.5l3.8 6.5-7.3 2.2c-.6.2-1 .7-1 1.3v2c0 .6.4 1.1 1 1.3l9.5 2.8 2.8 9.5c.2.6.7 1 1.3 1h2c.6 0 1.1-.4 1.3-1l2.2-7.3 6.5 3.8v1.5c0 .2.1.4.2.6.3.5 1 .7 1.5.4l4.3-2.5c.5-.3.8-.9.8-1.5V-2c0-.6-.3-1.2-.8-1.5l-4.3-2.5c-.5-.3-1.2-.1-1.5.4-.2.3-.2.6-.2.9v1.5l-6.5 3.8-2.2-7.3c-.2-.6-.7-1-1.3-1h-2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 570 B

+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""Verify SerpAPI Flights MCP connectivity.
Reads serpapiApiKey from the environment, sends a lightweight JSON-RPC
initialize to https://mcp.serpapi.com/{key}/mcp, and prints:
{"ok": true, "message": "SerpAPI Flights MCP endpoint is reachable"}
{"ok": false, "message": "SerpAPI Flights MCP endpoint is unreachable: <reason>"}
stdlib only (urllib).
"""
import json
import os
import sys
import urllib.error
import urllib.request
def _result(ok, message):
print(json.dumps({"ok": ok, "message": message}))
sys.exit(0 if ok else 1)
def main():
api_key = os.environ.get("serpapiApiKey", "").strip()
if not api_key:
api_key = os.environ.get("SERPAPI_API_KEY", "").strip()
if not api_key:
_result(False, "No SerpAPI API key provided (serpapiApiKey env var is empty)")
url = f"https://mcp.serpapi.com/{api_key}/mcp"
body = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "skald-verify", "version": "1.0.0"},
},
}).encode("utf-8")
req = urllib.request.Request(
url,
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=15) as resp:
if 200 <= resp.status < 300:
_result(True, "SerpAPI Flights MCP endpoint is reachable")
_result(False, f"SerpAPI returned HTTP {resp.status}")
except urllib.error.HTTPError as e:
if e.code in (401, 403):
_result(False, "SerpAPI API key is invalid or unauthorized "
f"(HTTP {e.code})")
_result(False, f"SerpAPI returned HTTP {e.code}: {e.reason}")
except Exception as e:
_result(False, f"SerpAPI Flights MCP endpoint is unreachable: {e}")
if __name__ == "__main__":
main()