Skip to content

Commit 7487302

Browse files
committed
add Exa MCP guidance for OpenCode search
Wire in Exa by default and teach Sam how to explain search failures so users can recover with their own Exa account and API key.
1 parent 277a39a commit 7487302

5 files changed

Lines changed: 124 additions & 2 deletions

File tree

.opencode/agents/seo-guide.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,11 @@ If the user wants DataForSEO but it is not available in the current session:
7070
- Record that answer in `MEMORY.md`.
7171
- Read `docs/dataforseo-mcp-setup.md` before explaining the setup steps, and reference `https://app.dataforseo.com/api-access` when telling the user where to find their API login and password.
7272
- Do not present DataForSEO as active until its MCP tools are actually available.
73+
74+
### Harness Specific Notes
75+
76+
- In OpenCode, do not imply that web search is built in. Search in this workspace depends on Exa MCP.
77+
- Other search providers can also work in this harness, including Firecrawl or DuckDuckGo-based tools, but Exa is the preferred default for Sam.
78+
- If Exa-backed search tools are missing, disabled, or returning auth or rate-limit errors, read `docs/exa-seup.md` before replying.
79+
- When Exa search fails in OpenCode, explain that the shared free Exa limit is the likely cause and point the user to `docs/exa-seup.md` for the account and API key setup flow.
80+
- Do not claim that Exa search is available when the Exa MCP tools are unavailable or erroring.

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Substantial draft work means a new full draft, a full-article rewrite, or struct
3232
- `docs/article-writing.md`
3333
- `docs/article-review.md`
3434
- `docs/dataforseo-mcp-setup.md`
35+
- `docs/exa-seup.md`
3536
- `context/user-notes.md`
3637
- `context/site-profile.md`
3738
- `context/brand-voice.md`

docs/exa-seup.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Exa Setup For OpenCode
2+
3+
Use this guide when search is failing in OpenCode or the Exa tools are missing in this workspace.
4+
5+
## What is happening
6+
7+
- OpenCode does not ship with native web search.
8+
- In this workspace, Sam uses Exa through MCP for web search, code search, and page crawling.
9+
- The checked-in `opencode.jsonc` uses Exa's shared free remote MCP endpoint so search works out of the box for many users.
10+
- If searches start failing, the most likely cause is that the shared free limit has been exhausted or your current Exa access is rate limited.
11+
12+
## Recommended fix
13+
14+
1. Create an Exa account.
15+
2. Generate your own API key.
16+
3. Export `EXA_API_KEY` before launching OpenCode.
17+
4. Use your key in a personal OpenCode config override, or update the project config if that is what you want.
18+
5. Restart OpenCode and try the search again.
19+
20+
## Expected usage
21+
22+
- Exa provides some free usage without requiring an account.
23+
- After signup, Exa also gives new users about `$10` of free usage.
24+
- If you are mainly using Exa for Sam, you will probably never go through that free usage.
25+
26+
## Current workspace config
27+
28+
This repository enables Exa in `opencode.jsonc` with the shared endpoint:
29+
30+
```jsonc
31+
{
32+
"mcp": {
33+
"exa": {
34+
"type": "remote",
35+
"url": "https://mcp.exa.ai/mcp",
36+
"enabled": true
37+
}
38+
}
39+
}
40+
```
41+
42+
## Personal API key setup
43+
44+
The safest upgrade path is to keep the shared repo config as-is and add your own authenticated Exa config in your personal OpenCode config.
45+
46+
OpenCode config files are merged, so a personal override can replace the URL locally without changing the checked-in project file.
47+
48+
Use this URL when you want OpenCode to send your own Exa API key:
49+
50+
```jsonc
51+
{
52+
"mcp": {
53+
"exa": {
54+
"type": "remote",
55+
"url": "https://mcp.exa.ai/mcp?exaApiKey={env:EXA_API_KEY}",
56+
"enabled": true
57+
}
58+
}
59+
}
60+
```
61+
62+
You can place that in `~/.config/opencode/opencode.json` or another local OpenCode config override.
63+
64+
## Export the API key
65+
66+
macOS/Linux:
67+
68+
```bash
69+
export EXA_API_KEY="your_exa_api_key"
70+
opencode
71+
```
72+
73+
Windows PowerShell:
74+
75+
```powershell
76+
$env:EXA_API_KEY = "your_exa_api_key"
77+
opencode
78+
```
79+
80+
If OpenCode is already running, restart it after exporting the variable.
81+
82+
## Where to get the key
83+
84+
- Create or sign in to your Exa account.
85+
- Open the Exa dashboard.
86+
- Create or copy an API key for your account.
87+
88+
Reference docs:
89+
90+
- Exa MCP docs: <https://docs.exa.ai/docs/reference/exa-mcp>
91+
- Exa pricing: <https://exa.ai/pricing>
92+
- OpenCode MCP docs: <https://dev.opencode.ai/docs/mcp-servers>
93+
94+
## What Sam should say when search fails
95+
96+
If search tools are erroring in OpenCode, Sam should explain:
97+
98+
- OpenCode does not have native search built in.
99+
- This workspace uses Exa for search.
100+
- The shared free Exa limit is the likely reason for the failure.
101+
- The user should follow this doc to add their own Exa account and API key.

opencode.jsonc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
"instructions": [
55
"MEMORY.md",
66
"context/user-notes.md"
7-
]
7+
],
8+
"mcp": {
9+
"exa": {
10+
"type": "remote",
11+
"url": "https://mcp.exa.ai/mcp",
12+
"enabled": true
13+
}
14+
}
815
// "agent": {
916
// "build": {
1017
// "disable": true,

tests/agent-sync.test.mjs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,15 @@ function parseFrontmatter(content) {
5050
);
5151
}
5252

53+
function stripHarnessSpecificNotes(content) {
54+
return content.replace(/(?:^|\n)#{2,6} Harness Specific Notes\n[\s\S]*$/, '');
55+
}
56+
5357
function normalizeBody(content) {
5458
const normalizedLineEndings = content.replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n');
5559
const withoutFrontmatter = stripFrontmatter(normalizedLineEndings);
56-
const withoutTrailingWhitespace = withoutFrontmatter
60+
const withoutHarnessSpecificNotes = stripHarnessSpecificNotes(withoutFrontmatter);
61+
const withoutTrailingWhitespace = withoutHarnessSpecificNotes
5762
.split('\n')
5863
.map((line) => line.replace(/[ \t]+$/g, ''))
5964
.join('\n');

0 commit comments

Comments
 (0)