Skip to content

docs: ADR-0023 one-tap Exa web search MCP - #169

Merged
chinkan merged 2 commits into
mainfrom
docs/adr-0023-exa-web-search
Oct 6, 2026
Merged

chinkan merged 2 commits into
mainfrom
docs/adr-0023-exa-web-search

Conversation

@chinkan

@chinkan chinkan commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

Docs only. Adds ADR-0023: One-tap built-in Exa MCP for web search (status: Proposed) and three glossary entries (Built-in MCP, Keyless Exa, Web search stub). No code changes.

Tracked in the Notion task "Setup: one-tap built-in MCP". No GitHub issue yet; one will be opened for the implementation. Related precedent: #119 (Google MCP one-tap).

Locked decisions recorded in the ADR

Product

  • The setup wizard never asks about MCP (stays at four fields). Exa is enabled after setup by a portal tap or a Telegram button. Default off.
  • v1 is Exa only. Google (feat(portal): Google MCP one-tap #119) is not changed.
  • No baked shared key. Keyless mode works (free, rate-limited). An optional user API key adds quota and is stored in SecretStore. The key never appears in config url or logs.
  • Ollama path untouched. Enabling shows privacy copy: search content goes to Exa. One-time "Enable and agree" confirmation, remembered.
  • While Exa is off, a web_search stub tool exists. A model call replies "not enabled" and offers an "Enable web search" button, at most once per conversation; "No thanks" suppresses it for the rest of that conversation.
  • Portal and Telegram share one on/off state; off in one place is off everywhere. One Exa connection for the whole instance (all bots), like feat(portal): Google MCP one-tap #119.
  • Disable is one tap and keeps the key. Deleting the key is only in portal advanced settings.
  • On 429/quota: the turn does not fail; the model answers and says search was not available this time; a text prompt to add a key in the portal appears at most once per conversation. No OAuth, no key requests in Telegram.
  • Connect failure: retry once, then a friendly "Can't reach Exa for now"; no crash; model answers without web; not repeated in the same turn.

Technical

  • Endpoint https://mcp.exa.ai/mcp?tools=web_search_exa,web_fetch_exa (Streamable HTTP, existing rmcp client). The tools pin keeps the paid agent_run hidden even with a key.
  • Optional x-api-key header from SecretStore via rmcp custom_headers. Not Bearer, not a URL query. Logs may name the header, never the value.
  • When Exa is on, the stub is removed so the model never sees two search tools.
  • Telegram never uses a localhost / 127.0.0.1 URL button. It uses a callback button, or plain text ("open the portal on your computer → Settings → paste key") with the portal address from /portal.

Open questions (in the ADR)

  1. Per-bot tools allowlists vs Exa tool names (mcp_exa_web_search_exa, mcp_exa_web_fetch_exa).
  2. A hand-written [[mcp_servers]] name = "exa" row colliding with the built-in.
  3. Whether the stub offer should appear for bots on an Ollama provider.
  4. Portal chat behavior for the stub offer.
  5. Storage for enabled / privacy_accepted_at (config vs SQLite).

Status and next steps

  • Product GO pending from the PO after review of this ADR.
  • No implementation in this PR. Implementation waits until the ADR-0020 (mid-run queue) implementation lands and the TL assigns it.
  • No release tag. Please do not merge before Product GO.

Proposed decision for a built-in, default-off Exa MCP (keyless by
default, optional x-api-key from SecretStore, tools pinned to
web_search_exa and web_fetch_exa), shared portal/Telegram toggle,
web_search stub with a once-per-conversation offer, and graceful 429 /
connect-failure handling. Adds glossary entries: Built-in MCP, Keyless
Exa, Web search stub. Docs only.
Product GO 2026-10-06: mark Q1–Q4 Decided with locked answers; leave Q5
to implementation; set ADR status to Accepted.

chinkan commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

TL ACCEPT tip 51b9e69 (ADR-0023 Accepted; Q1–Q4 Decided per Product GO). Docs only. Merge with --merge when CI green. No tag.

@chinkan
chinkan merged commit 4f293f6 into main Oct 6, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant