@feniix/pi-exa
Exa API extension for pi — web search, content fetching, and advanced search via Exa AI
Package details
Install @feniix/pi-exa from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@feniix/pi-exa- Package
@feniix/pi-exa- Version
6.0.1- Published
- Sep 30, 2026
- Downloads
- 192/mo · 32/wk
- Author
- feniix
- License
- MIT
- Types
- extension, skill
- Size
- 357.4 KB
- Dependencies
- 2 dependencies · 4 peers
Pi manifest JSON
{
"skills": [
"./skills"
],
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@feniix/pi-exa
Exa AI extension for pi with search, fetch, research, and answer capabilities.
Features
- web_search_exa: default web search (highlights + short text snippets).
- web_fetch_exa: fetch page content by URL.
- web_search_advanced_exa: filtered search and synchronous Deep Search through
/search(disabled by default). - web_research_exa: asynchronous Agent research with polling and remote cancellation once a run ID is known (disabled by default).
- web_answer_exa: quick grounded answers.
- web_find_similar_exa: discover related URLs.
- exa_research_step/status/summary/reset: local, stateful research-planning tools that recommend explicit Exa retrieval calls without executing them.
Why pi-exa vs the hosted Exa MCP?
The hosted Exa MCP at https://mcp.exa.ai/mcp is a fine default for one-shot search and fetch. pi-exa exists for cases the hosted MCP cannot address by design:
- Tools the hosted MCP does not expose.
web_answer_exa(Exa's/answerendpoint) andweb_find_similar_exa(/findSimilar) are not advertised by the hosted MCP under any flag. If you need grounded answers with citations or "more like this" discovery, you call them directly through pi-exa. - Local stateful planning.
exa_research_step / status / summary / resetkeep an in-memory research plan that survives across calls in a single pi session. A stateless remote MCP cannot offer this — there is no per-session memory to update. - Local key custody and allowlists. Your
EXA_API_KEYandenabledToolsallowlist stay on the workstation. The hosted MCP requires sending your key to a third party on every request. - Pre-flight validation. pi-exa rejects category/filter combinations Exa silently ignores (e.g.,
category: "people"with non-LinkedInincludeDomains), so you find out at the call site instead of in a quiet, empty result set. - Agent-native research lifecycle.
web_research_exasubmits an Agent run, polls it to a terminal state, and cancels the remote run when the host aborts or its deadline expires after a run ID is known. Other tools stay on Exa's purpose-built/search,/contents,/answer, and/findSimilarAPIs.
| Capability | Hosted Exa MCP | pi-exa |
|---|---|---|
web_search_exa |
yes | yes |
web_fetch_exa |
yes | yes |
web_search_advanced_exa |
opt-in | opt-in |
web_answer_exa (/answer) |
no | yes |
web_find_similar_exa (/findSimilar) |
no | yes |
Local research planner (exa_research_*) |
no | yes |
| Local API key custody | no | yes |
| Agent Runs API with timeout cancellation | no | yes |
Install
pi install npm:@feniix/pi-exa
For ephemeral use:
pi -e npm:@feniix/pi-exa
Configuration
You need an Exa API key from dashboard.exa.ai/api-keys for retrieval tools. The local exa_research_* planning tools work without an API key because they do not call Exa network APIs.
If you configure enabledTools, it acts as a strict allowlist. Include the exa_research_* names if you want the planner tools available with an explicit allowlist.
Recommended: environment variable
export EXA_API_KEY="your-key"
Recommended for private overrides: explicit config file
Use a private config file when you want to store an API key outside shared project settings:
{
"apiKey": "your-key",
"enabledTools": [
"exa_research_step",
"exa_research_status",
"exa_research_summary",
"exa_research_reset",
"web_search_exa",
"web_fetch_exa",
"web_answer_exa",
"web_find_similar_exa"
],
"advancedEnabled": false,
"researchEnabled": false
}
Then run pi with:
pi -e npm:@feniix/pi-exa -- --exa-config-file ~/.config/pi/exa.json
Shared non-secret settings
Supports standard pi settings locations:
- project:
.pi/settings.json - global:
~/.pi/agent/settings.json
Example:
{
"pi-exa": {
"enabledTools": [
"exa_research_step",
"exa_research_status",
"exa_research_summary",
"exa_research_reset",
"web_search_exa",
"web_fetch_exa",
"web_answer_exa",
"web_find_similar_exa"
],
"advancedEnabled": false,
"researchEnabled": false
}
}
apiKey is accepted in settings files for compatibility, but pi-exa will warn when it is loaded there. Prefer EXA_API_KEY or --exa-config-file for secrets.
CLI flags
--exa-api-key <key>: API key override.--exa-enable-advanced: enableweb_search_advanced_exa.--exa-enable-research: enableweb_research_exa.--exa-config-file <path>: load configuration from file.--exa-config <path>(deprecated alias for--exa-config-file).--exa-timeout-ms <ms>: default per-call timeout for Exa-backed tools (built-in 60000).--exa-research-timeout-ms <ms>: override forweb_research_exaAgent runs (built-in 180000).
For ordinary Exa SDK calls, the timeout bounds the JS-side wait because
exa-jsdoes not yet acceptAbortSignal(exa-labs/exa-js#158).web_research_exaowns the Agent run lifecycle and calls Exa's cancel endpoint on host abort or timeout once Exa has returned a run ID.
Tools
exa_research_step
Records one step in an in-memory research-planning session. Params include topic, stage, note, optional criteria, sources, gaps, assumptions, nextAction, branch/revision metadata, thought_number, total_thoughts, and next_step_needed.
exa_research_status
Reports the current local planning state: topic, step count, active stage, branches, criteria coverage, source pack summary, open gaps, assumptions, and recommended next action.
exa_research_summary
Generates human-readable research planning output. Modes: brief, execution_plan, source_pack, and payload. Payload mode suggests a web_research_exa payload only; it does not run retrieval.
exa_research_reset
Clears the active in-memory planning session.
web_search_exa
Params: query (required), numResults.
Returns: formatted snippets with optional highlights and metadata (costDollars, searchTime).
web_fetch_exa
Params: urls (required array), maxCharacters, highlights, summary (query), maxAgeHours.
web_search_advanced_exa
Params:
query(required)numResults(1-100, default 10)category: one ofcompany,publication,research paper,news,pdf,personal site,financial report,peopletype:instant | fast | auto | deep-lite | deep | deep-reasoning.systemPrompt: instructions guiding search behavior, source selection, and synthesis.outputSchema:{ "type": "text" }for prose or an object JSON Schema for structured synthesis.- Date filters:
startPublishedDate,endPublishedDate(ISO dates). - Domain filters:
includeDomains,excludeDomains. - Text filters:
includeText(single-element array; only return results whose text contains this string, up to 5 words),excludeText(single-element array; exclude results whose text contains this string, up to 5 words). The Exa API accepts at most one string per filter. userLocation: two-letter ISO country code (e.g.,US,GB,DE).moderation: whentrue, filter unsafe content.additionalQueries: alternative query formulations fordeep-lite,deep, ordeep-reasoningonly.textMaxCharacters: max chars of page text per result (default 3000).contextMaxCharacters: max chars for the aggregated context string. Maps to Exa's deprecatedcontextoption and may be removed in a future Exa API release.- Highlights:
enableHighlights(gate),highlightsMaxCharacters(preferred),highlightsNumSentences(legacy fallback),highlightsQuery(overrides the search query for highlight ranking). ProvidinghighlightsQueryorhighlightsMaxCharactersimpliesenableHighlights: true; passingenableHighlights: falseexplicitly always disables highlights. - Summary:
enableSummaryand/orsummaryQuery(providingsummaryQueryimpliesenableSummary: true; passingenableSummary: falseexplicitly always disables the summary). - Freshness:
maxAgeHours(0 = always fresh, -1 = cache-only),livecrawlTimeout(ms; capped at 60000 = 60s). - Subpages:
subpages(1-10),subpageTarget(single keyword or list of keywords used to select which subpages to crawl, e.g.'about'or['about', 'pricing']).
Notes:
- Deep Search is synchronous
/searchsynthesis. Deep modes default to text synthesis whenoutputSchemais omitted. - Use
web_research_exainstead when the task needs an asynchronous Agent run, continuation, Connect data sources, effort/budget controls, or remote cancellation. - Invalid categories return an error instead of silently falling back to an unfiltered search.
- The
companyandpeoplecategories do not supportstartPublishedDate,endPublishedDate, orexcludeDomains; thepeoplecategory only accepts LinkedIn domains forincludeDomains. These are enforced pre-flight. startCrawlDate/endCrawlDateare intentionally not exposed — Exa silently ignores them as of 2026-04-15.
web_research_exa
Params include:
query(required)systemPrompteffort:minimal | low | medium | high | xhigh | auto | max(defaultmedium).autoandmaxare metered; usebudget.maxCostDollarsto cap them.outputSchema:{ "type": "text" }(default) readsoutput.text; an object JSON Schema is sent to Exa and returnsoutput.structured.input.data/input.exclusion: records to process or exclude.previousRunId: continue from a completed Agent run.metadata: string key/value metadata stored with the run.dataSources: up to five Exa Connect providers.budget.maxCostDollars: spend ceiling forautoormax.
The tool submits POST /agent/runs, polls the run to completion, returns the run ID and cost/usage metadata, and attempts POST /agent/runs/{id}/cancel on host abort or timeout. max effort automatically opts into Exa's required max-effort beta.
web_answer_exa
Params include query (required), systemPrompt, text, and outputSchema.
web_find_similar_exa
Params include url (required), numResults, textMaxCharacters, excludeSourceDomain, date filters, and domain filters.
Exa marks /findSimilar deprecated and recommends /search for new discovery flows. This compatibility tool remains available for URL-seeded similarity workflows.
Integration tests
Live integration coverage is available for web_search_exa, web_fetch_exa, web_search_advanced_exa, and web_research_exa.
These tests are:
- skipped by default
- only enabled when you opt in manually
- always skipped in CI
Run them locally with a real API key:
PI_EXA_LIVE=1 EXA_API_KEY=your-key pnpm exec vitest run packages/pi-exa/__tests__/integration.test.ts
The live suite incurs real Exa usage and is never enabled in CI.
MCP server
pi-exa also exposes its tool surface as an MCP stdio server, suitable for any MCP-aware host (Claude Desktop, Claude Code, etc.). The server uses the same portable tool implementations as the Pi adapter — only the gating and credential resolution differ.
Run with:
npx pi-exa
Environment configuration
| Variable | Effect |
|---|---|
EXA_API_KEY |
Exa API key. Required for retrieval tools; planner tools work without it. |
EXA_ENABLE_ADVANCED |
Truthy (1 / true / yes) enables web_search_advanced_exa. |
EXA_ENABLE_RESEARCH |
Truthy enables web_research_exa. |
EXA_ENABLED_TOOLS |
Comma-separated allowlist. Highest precedence. Empty/whitespace-only values emit a warning and fall through to the per-tool toggle defaults. |
EXA_CONFIG_FILE |
Path to a JSON config file (same shape as the CLI --exa-config-file). Use for apiKey, enabledTools, advancedEnabled, researchEnabled. |
EXA_CONFIG |
Deprecated alias for EXA_CONFIG_FILE. Still read; prefer EXA_CONFIG_FILE. |
EXA_TIMEOUT_MS |
Default per-call timeout in ms for Exa-backed tools. Built-in 60000, or 180000 for advanced search and Agent research. Underlying HTTP request continues until Exa resolves it; see exa-labs/exa-js#158. |
EXA_RESEARCH_TIMEOUT_MS |
Override for web_research_exa only. Built-in 180000. |
Precedence
Same rules as the Pi adapter:
EXA_ENABLED_TOOLS(env) — strict allowlist.enabledTools(config file) — strict allowlist; an empty array means "no tools".EXA_ENABLE_ADVANCED/EXA_ENABLE_RESEARCH(env) oradvancedEnabled/researchEnabled(config file).- Default: 8 tools on (4 cheap Exa + 4 planner);
web_search_advanced_exaandweb_research_exahidden.
Example: Claude Desktop / claude_desktop_config.json
{
"mcpServers": {
"pi-exa": {
"command": "npx",
"args": ["-y", "@feniix/pi-exa"],
"env": {
"EXA_API_KEY": "your-key",
"EXA_ENABLE_ADVANCED": "1"
}
}
}
}
Example: generic mcp.json
{
"mcpServers": {
"pi-exa": {
"command": "npx",
"args": ["pi-exa"],
"env": { "EXA_API_KEY": "your-key" }
}
}
}
Notes
exa_research_*planning tools are enabled by default when no explicitenabledToolsallowlist is configured, local-only, and do not require an Exa API key.web_search_advanced_exaandweb_research_exaare opt-in and disabled by default.- Research/tool output may include both
textanddetails.parsedOutputdepending onoutputSchema.type.