From 8805fe5f1c17bd7824b1c464b468ef69e1d4b219 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 29 May 2026 21:21:02 +0000 Subject: [PATCH 1/6] feat: add helperText and helperLink to all integration credential fields All password fields in integration catalog entries now include: - helperText: a short description of what the credential is - helperLink: a direct URL to the page where users can obtain the credential This ensures users can find instructions for getting tokens and API keys directly in the interface when setting up integrations. Updated integrations: airtable, apify, brave-search, clickhouse, elevenlabs, exa, figma, firecrawl, github, kagi, mongodb, neon, notion, obsidian, redis, resend, slack, supabase, tavily Also added helperLink field to MarketplaceField TypeScript type definition, and a new test (test_credential_fields_have_helper_text_and_link) that enforces all password fields have both helperText and helperLink. Fixes #279 Co-authored-by: openhands --- integrations/catalog/airtable.json | 4 +++- integrations/catalog/apify.json | 4 +++- integrations/catalog/brave-search.json | 4 +++- integrations/catalog/clickhouse.json | 4 +++- integrations/catalog/elevenlabs.json | 4 +++- integrations/catalog/exa.json | 4 +++- integrations/catalog/figma.json | 4 +++- integrations/catalog/firecrawl.json | 4 +++- integrations/catalog/github.json | 4 +++- integrations/catalog/kagi.json | 4 +++- integrations/catalog/mongodb.json | 4 +++- integrations/catalog/neon.json | 4 +++- integrations/catalog/notion.json | 4 +++- integrations/catalog/obsidian.json | 3 ++- integrations/catalog/redis.json | 3 ++- integrations/catalog/resend.json | 4 +++- integrations/catalog/slack.json | 4 +++- integrations/catalog/supabase.json | 3 ++- integrations/catalog/tavily.json | 4 +++- integrations/index.d.ts | 1 + tests/test_catalogs.py | 22 ++++++++++++++++++++++ 21 files changed, 77 insertions(+), 19 deletions(-) diff --git a/integrations/catalog/airtable.json b/integrations/catalog/airtable.json index 3526737..76b8033 100644 --- a/integrations/catalog/airtable.json +++ b/integrations/catalog/airtable.json @@ -30,7 +30,9 @@ "key": "AIRTABLE_API_KEY", "label": "Airtable personal access token", "type": "password", - "required": true + "required": true, + "helperText": "Personal access token from your Airtable account.", + "helperLink": "https://airtable.com/create/tokens" } ] }, diff --git a/integrations/catalog/apify.json b/integrations/catalog/apify.json index 75c6c5e..42b2957 100644 --- a/integrations/catalog/apify.json +++ b/integrations/catalog/apify.json @@ -29,7 +29,9 @@ "key": "APIFY_TOKEN", "label": "Apify token", "type": "password", - "required": true + "required": true, + "helperText": "API token from your Apify account settings.", + "helperLink": "https://console.apify.com/account/integrations" } ] }, diff --git a/integrations/catalog/brave-search.json b/integrations/catalog/brave-search.json index f161f48..c586ba6 100644 --- a/integrations/catalog/brave-search.json +++ b/integrations/catalog/brave-search.json @@ -29,7 +29,9 @@ "key": "BRAVE_API_KEY", "label": "Brave API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from the Brave Search API portal.", + "helperLink": "https://api.search.brave.com/app/keys" } ] }, diff --git a/integrations/catalog/clickhouse.json b/integrations/catalog/clickhouse.json index 160cffd..951758c 100644 --- a/integrations/catalog/clickhouse.json +++ b/integrations/catalog/clickhouse.json @@ -42,7 +42,9 @@ "key": "CLICKHOUSE_PASSWORD", "label": "Password", "type": "password", - "required": true + "required": true, + "helperText": "Password for your ClickHouse user.", + "helperLink": "https://clickhouse.com/docs/en/cloud/manage/users-and-roles" } ] }, diff --git a/integrations/catalog/elevenlabs.json b/integrations/catalog/elevenlabs.json index fc87a9e..bd84422 100644 --- a/integrations/catalog/elevenlabs.json +++ b/integrations/catalog/elevenlabs.json @@ -28,7 +28,9 @@ "key": "ELEVENLABS_API_KEY", "label": "ElevenLabs API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your ElevenLabs account settings.", + "helperLink": "https://elevenlabs.io/app/settings/api-keys" } ] }, diff --git a/integrations/catalog/exa.json b/integrations/catalog/exa.json index adf637f..baca6a5 100644 --- a/integrations/catalog/exa.json +++ b/integrations/catalog/exa.json @@ -29,7 +29,9 @@ "key": "EXA_API_KEY", "label": "Exa API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your Exa dashboard.", + "helperLink": "https://dashboard.exa.ai/" } ] }, diff --git a/integrations/catalog/figma.json b/integrations/catalog/figma.json index f52460d..8068d00 100644 --- a/integrations/catalog/figma.json +++ b/integrations/catalog/figma.json @@ -30,7 +30,9 @@ "key": "FIGMA_API_KEY", "label": "Figma personal access token", "type": "password", - "required": true + "required": true, + "helperText": "Personal access token from your Figma account settings.", + "helperLink": "https://www.figma.com/developers/api#access-tokens" } ] }, diff --git a/integrations/catalog/firecrawl.json b/integrations/catalog/firecrawl.json index 98daf79..108aff2 100644 --- a/integrations/catalog/firecrawl.json +++ b/integrations/catalog/firecrawl.json @@ -29,7 +29,9 @@ "key": "FIRECRAWL_API_KEY", "label": "Firecrawl API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your Firecrawl dashboard.", + "helperLink": "https://www.firecrawl.dev/app/api-keys" } ] }, diff --git a/integrations/catalog/github.json b/integrations/catalog/github.json index 5fb95c9..02f422c 100644 --- a/integrations/catalog/github.json +++ b/integrations/catalog/github.json @@ -37,7 +37,9 @@ "label": "Personal access token", "type": "password", "placeholder": "github_pat_...", - "required": true + "required": true, + "helperText": "Classic or fine-grained personal access token from GitHub settings.", + "helperLink": "https://github.com/settings/personal-access-tokens/new" } ] }, diff --git a/integrations/catalog/kagi.json b/integrations/catalog/kagi.json index 9a727e4..138a048 100644 --- a/integrations/catalog/kagi.json +++ b/integrations/catalog/kagi.json @@ -28,7 +28,9 @@ "key": "KAGI_API_KEY", "label": "Kagi API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your Kagi account settings.", + "helperLink": "https://kagi.com/settings?p=api" } ] }, diff --git a/integrations/catalog/mongodb.json b/integrations/catalog/mongodb.json index 6a6b5f0..373d9bc 100644 --- a/integrations/catalog/mongodb.json +++ b/integrations/catalog/mongodb.json @@ -29,7 +29,9 @@ "label": "MongoDB connection string", "type": "password", "placeholder": "mongodb+srv://user:pass@cluster.mongodb.net", - "required": true + "required": true, + "helperText": "Connection string from your MongoDB Atlas cluster.", + "helperLink": "https://www.mongodb.com/docs/atlas/connect-to-your-cluster/" } ] }, diff --git a/integrations/catalog/neon.json b/integrations/catalog/neon.json index 38e729f..0050ef6 100644 --- a/integrations/catalog/neon.json +++ b/integrations/catalog/neon.json @@ -30,7 +30,9 @@ "key": "NEON_API_KEY", "label": "Neon API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your Neon account settings.", + "helperLink": "https://neon.tech/docs/manage/api-keys" } ] }, diff --git a/integrations/catalog/notion.json b/integrations/catalog/notion.json index 65c76cc..5c8d316 100644 --- a/integrations/catalog/notion.json +++ b/integrations/catalog/notion.json @@ -32,7 +32,9 @@ "label": "Internal integration token", "type": "password", "placeholder": "ntn_...", - "required": true + "required": true, + "helperText": "Internal integration token from your Notion integrations page.", + "helperLink": "https://www.notion.so/profile/integrations" } ] }, diff --git a/integrations/catalog/obsidian.json b/integrations/catalog/obsidian.json index 10d3812..7c85f6d 100644 --- a/integrations/catalog/obsidian.json +++ b/integrations/catalog/obsidian.json @@ -30,7 +30,8 @@ "label": "Local REST API key", "type": "password", "required": true, - "helperText": "From the Obsidian 'Local REST API' community plugin." + "helperText": "From the Obsidian 'Local REST API' community plugin.", + "helperLink": "https://github.com/coddingtonbear/obsidian-local-rest-api" } ] }, diff --git a/integrations/catalog/redis.json b/integrations/catalog/redis.json index 44bda27..f05d802 100644 --- a/integrations/catalog/redis.json +++ b/integrations/catalog/redis.json @@ -33,7 +33,8 @@ "type": "password", "placeholder": "redis://localhost:6379", "required": true, - "helperText": "Appended as --url ." + "helperText": "Connection URL for your Redis instance. Appended as --url .", + "helperLink": "https://redis.io/docs/latest/operate/rs/references/client_references/client_reference_redis-py/#connectionpool" } ] }, diff --git a/integrations/catalog/resend.json b/integrations/catalog/resend.json index 7b54452..af4c3ff 100644 --- a/integrations/catalog/resend.json +++ b/integrations/catalog/resend.json @@ -28,7 +28,9 @@ "key": "RESEND_API_KEY", "label": "Resend API key", "type": "password", - "required": true + "required": true, + "helperText": "API key from your Resend dashboard.", + "helperLink": "https://resend.com/api-keys" }, { "key": "SENDER_EMAIL_ADDRESS", diff --git a/integrations/catalog/slack.json b/integrations/catalog/slack.json index a28ab5c..b4db8c1 100644 --- a/integrations/catalog/slack.json +++ b/integrations/catalog/slack.json @@ -31,7 +31,9 @@ "label": "Bot token", "type": "password", "placeholder": "xoxb-...", - "required": true + "required": true, + "helperText": "Bot token from your Slack app's OAuth & Permissions page.", + "helperLink": "https://api.slack.com/apps" }, { "key": "SLACK_TEAM_ID", diff --git a/integrations/catalog/supabase.json b/integrations/catalog/supabase.json index 7791795..0992e1b 100644 --- a/integrations/catalog/supabase.json +++ b/integrations/catalog/supabase.json @@ -30,7 +30,8 @@ "label": "Supabase access token", "type": "password", "required": true, - "helperText": "Personal access token from your Supabase dashboard." + "helperText": "Personal access token from your Supabase dashboard.", + "helperLink": "https://supabase.com/dashboard/account/tokens" } ] }, diff --git a/integrations/catalog/tavily.json b/integrations/catalog/tavily.json index 5ec8b61..f3b8457 100644 --- a/integrations/catalog/tavily.json +++ b/integrations/catalog/tavily.json @@ -32,7 +32,9 @@ "label": "Tavily API key", "type": "password", "placeholder": "tvly-...", - "required": true + "required": true, + "helperText": "API key from your Tavily dashboard.", + "helperLink": "https://app.tavily.com/home" } ] }, diff --git a/integrations/index.d.ts b/integrations/index.d.ts index c94be8c..b53fa86 100644 --- a/integrations/index.d.ts +++ b/integrations/index.d.ts @@ -6,6 +6,7 @@ export interface MarketplaceField { type?: MarketplaceFieldType; placeholder?: string; helperText?: string; + helperLink?: string; required?: boolean; } diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index 3f533c2..ae777a5 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -71,6 +71,28 @@ def test_catalog_entries_have_required_fields(): assert isinstance(entry["estimatedSetupMinutes"], int) +def test_credential_fields_have_helper_text_and_link(): + """All password fields must have helperText and helperLink so users know how to get credentials.""" + for entry in load_catalog_entries("integrations/catalog"): + for option in entry["connectionOptions"]: + transport = option.get("transport", {}) + for field_group in ("envFields", "argFields"): + for field in transport.get(field_group, []): + if field.get("type") == "password": + assert "helperText" in field, ( + f"{entry['id']}: password field '{field['key']}' is missing helperText" + ) + assert "helperLink" in field, ( + f"{entry['id']}: password field '{field['key']}' is missing helperLink" + ) + assert field["helperText"], ( + f"{entry['id']}: password field '{field['key']}' has empty helperText" + ) + assert field["helperLink"].startswith("https://"), ( + f"{entry['id']}: password field '{field['key']}' helperLink must start with https://" + ) + + def test_node_package_exports_catalogs(): script = """ import { INTEGRATION_CATALOG, AUTOMATION_CATALOG } from './index.js'; From e3706dc293bdebfd7e1a7e36dd028ac3fb564453 Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 31 May 2026 18:21:27 +0000 Subject: [PATCH 2/6] fix: update integration credential helper links Co-authored-by: openhands --- integrations/catalog/brave-search.json | 2 +- integrations/catalog/clickhouse.json | 2 +- integrations/catalog/exa.json | 4 ++-- integrations/catalog/figma.json | 2 +- integrations/catalog/mongodb.json | 2 +- integrations/catalog/redis.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/integrations/catalog/brave-search.json b/integrations/catalog/brave-search.json index c586ba6..073bd89 100644 --- a/integrations/catalog/brave-search.json +++ b/integrations/catalog/brave-search.json @@ -31,7 +31,7 @@ "type": "password", "required": true, "helperText": "API key from the Brave Search API portal.", - "helperLink": "https://api.search.brave.com/app/keys" + "helperLink": "https://api-dashboard.search.brave.com/app/keys" } ] }, diff --git a/integrations/catalog/clickhouse.json b/integrations/catalog/clickhouse.json index 951758c..9bb37a8 100644 --- a/integrations/catalog/clickhouse.json +++ b/integrations/catalog/clickhouse.json @@ -44,7 +44,7 @@ "type": "password", "required": true, "helperText": "Password for your ClickHouse user.", - "helperLink": "https://clickhouse.com/docs/en/cloud/manage/users-and-roles" + "helperLink": "https://clickhouse.com/docs/cloud/security/manage-database-users" } ] }, diff --git a/integrations/catalog/exa.json b/integrations/catalog/exa.json index baca6a5..72208d3 100644 --- a/integrations/catalog/exa.json +++ b/integrations/catalog/exa.json @@ -30,8 +30,8 @@ "label": "Exa API key", "type": "password", "required": true, - "helperText": "API key from your Exa dashboard.", - "helperLink": "https://dashboard.exa.ai/" + "helperText": "API key from your Exa API dashboard; see the getting started docs.", + "helperLink": "https://exa.ai/docs/reference/getting-started" } ] }, diff --git a/integrations/catalog/figma.json b/integrations/catalog/figma.json index 8068d00..61d1e6b 100644 --- a/integrations/catalog/figma.json +++ b/integrations/catalog/figma.json @@ -32,7 +32,7 @@ "type": "password", "required": true, "helperText": "Personal access token from your Figma account settings.", - "helperLink": "https://www.figma.com/developers/api#access-tokens" + "helperLink": "https://developers.figma.com/docs/rest-api/authentication/#personal-access-tokens" } ] }, diff --git a/integrations/catalog/mongodb.json b/integrations/catalog/mongodb.json index 373d9bc..0c23004 100644 --- a/integrations/catalog/mongodb.json +++ b/integrations/catalog/mongodb.json @@ -31,7 +31,7 @@ "placeholder": "mongodb+srv://user:pass@cluster.mongodb.net", "required": true, "helperText": "Connection string from your MongoDB Atlas cluster.", - "helperLink": "https://www.mongodb.com/docs/atlas/connect-to-your-cluster/" + "helperLink": "https://www.mongodb.com/docs/atlas/connect-to-database-deployment/#connect-with-a-connection-string" } ] }, diff --git a/integrations/catalog/redis.json b/integrations/catalog/redis.json index f05d802..8442b33 100644 --- a/integrations/catalog/redis.json +++ b/integrations/catalog/redis.json @@ -34,7 +34,7 @@ "placeholder": "redis://localhost:6379", "required": true, "helperText": "Connection URL for your Redis instance. Appended as --url .", - "helperLink": "https://redis.io/docs/latest/operate/rs/references/client_references/client_reference_redis-py/#connectionpool" + "helperLink": "https://redis.io/docs/latest/develop/clients/redis-py/connect/#connect-to-a-redis-database" } ] }, From 57533f7c1a806578866a9a785282a5a2707d71c5 Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 31 May 2026 18:30:45 +0000 Subject: [PATCH 3/6] chore: address PR review feedback (#281) Co-authored-by: openhands --- integrations/catalog/github.json | 2 +- integrations/catalog/redis.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/catalog/github.json b/integrations/catalog/github.json index 02f422c..5dd3cc1 100644 --- a/integrations/catalog/github.json +++ b/integrations/catalog/github.json @@ -39,7 +39,7 @@ "placeholder": "github_pat_...", "required": true, "helperText": "Classic or fine-grained personal access token from GitHub settings.", - "helperLink": "https://github.com/settings/personal-access-tokens/new" + "helperLink": "https://github.com/settings/tokens" } ] }, diff --git a/integrations/catalog/redis.json b/integrations/catalog/redis.json index 8442b33..3b4185d 100644 --- a/integrations/catalog/redis.json +++ b/integrations/catalog/redis.json @@ -34,7 +34,7 @@ "placeholder": "redis://localhost:6379", "required": true, "helperText": "Connection URL for your Redis instance. Appended as --url .", - "helperLink": "https://redis.io/docs/latest/develop/clients/redis-py/connect/#connect-to-a-redis-database" + "helperLink": "https://redis.io/docs/latest/operate/rc/databases/connect/" } ] }, From fc8bca49baae2e50fc5d888cb4754688baa9d788 Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 31 May 2026 18:38:52 +0000 Subject: [PATCH 4/6] chore: address remaining PR review nits (#281) Co-authored-by: openhands --- integrations/catalog/clickhouse.json | 2 +- integrations/catalog/tavily.json | 4 ++-- tests/test_catalogs.py | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/integrations/catalog/clickhouse.json b/integrations/catalog/clickhouse.json index 9bb37a8..4d6e64e 100644 --- a/integrations/catalog/clickhouse.json +++ b/integrations/catalog/clickhouse.json @@ -44,7 +44,7 @@ "type": "password", "required": true, "helperText": "Password for your ClickHouse user.", - "helperLink": "https://clickhouse.com/docs/cloud/security/manage-database-users" + "helperLink": "https://clickhouse.com/docs/operations/access-rights" } ] }, diff --git a/integrations/catalog/tavily.json b/integrations/catalog/tavily.json index f3b8457..5d6af85 100644 --- a/integrations/catalog/tavily.json +++ b/integrations/catalog/tavily.json @@ -11,7 +11,7 @@ "research" ], "popularityRank": 90, - "installHint": "Paste your Tavily API key — the official tavily-mcp package runs via npx.", + "installHint": "Paste your Tavily API key - the official tavily-mcp package runs via npx.", "kind": "mcp", "defaultConnectionOptionId": "api", "connectionOptions": [ @@ -34,7 +34,7 @@ "placeholder": "tvly-...", "required": true, "helperText": "API key from your Tavily dashboard.", - "helperLink": "https://app.tavily.com/home" + "helperLink": "https://app.tavily.com/home?tab=keys" } ] }, diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index ae777a5..c36362a 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -79,17 +79,18 @@ def test_credential_fields_have_helper_text_and_link(): for field_group in ("envFields", "argFields"): for field in transport.get(field_group, []): if field.get("type") == "password": + field_key = field.get("key", "") assert "helperText" in field, ( - f"{entry['id']}: password field '{field['key']}' is missing helperText" + f"{entry['id']}: password field '{field_key}' is missing helperText" ) assert "helperLink" in field, ( - f"{entry['id']}: password field '{field['key']}' is missing helperLink" + f"{entry['id']}: password field '{field_key}' is missing helperLink" ) assert field["helperText"], ( - f"{entry['id']}: password field '{field['key']}' has empty helperText" + f"{entry['id']}: password field '{field_key}' has empty helperText" ) assert field["helperLink"].startswith("https://"), ( - f"{entry['id']}: password field '{field['key']}' helperLink must start with https://" + f"{entry['id']}: password field '{field_key}' helperLink must start with https://" ) From 516f6fe467bdd836b524a1b6f0b864480c4b8f21 Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 31 May 2026 18:46:29 +0000 Subject: [PATCH 5/6] chore: align Exa credential helper text (#281) Co-authored-by: openhands --- integrations/catalog/exa.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/catalog/exa.json b/integrations/catalog/exa.json index 72208d3..c59b650 100644 --- a/integrations/catalog/exa.json +++ b/integrations/catalog/exa.json @@ -30,7 +30,7 @@ "label": "Exa API key", "type": "password", "required": true, - "helperText": "API key from your Exa API dashboard; see the getting started docs.", + "helperText": "API key from your Exa account; see the getting-started guide for setup instructions.", "helperLink": "https://exa.ai/docs/reference/getting-started" } ] From b7bc69e5e50c2da08508d6ff01511664087ad85b Mon Sep 17 00:00:00 2001 From: openhands Date: Sun, 31 May 2026 18:51:45 +0000 Subject: [PATCH 6/6] chore: simplify Exa credential helper text (#281) Co-authored-by: openhands --- integrations/catalog/exa.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/catalog/exa.json b/integrations/catalog/exa.json index c59b650..f48473c 100644 --- a/integrations/catalog/exa.json +++ b/integrations/catalog/exa.json @@ -30,7 +30,7 @@ "label": "Exa API key", "type": "password", "required": true, - "helperText": "API key from your Exa account; see the getting-started guide for setup instructions.", + "helperText": "API key from your Exa account.", "helperLink": "https://exa.ai/docs/reference/getting-started" } ]