Skip to content

Commit 27bdc9b

Browse files
committed
review feedback: reorder Exa as primary web search; use YOUR_EXA_API_KEY placeholder; add api-key link
1 parent a538847 commit 27bdc9b

8 files changed

Lines changed: 39 additions & 39 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ It is built for scientists, analysts, and curious people who want a powerful AI
2222
- **Organise your work in projects.** Each project has its own files, chat history, and settings. Upload files, browse folders, preview documents, and download results - all from inside the app.
2323
- **Rich file previews.** Built-in viewers for code, Markdown (with math and diagrams), CSVs, PDFs, images, Jupyter notebooks, and bioinformatics formats (FASTA, FASTQ, VCF, BED, GFF, SAM, BCF).
2424
- **LaTeX editor.** Split-pane editor with live PDF compilation (pdfLaTeX, XeLaTeX, LuaLaTeX).
25-
- **Web search and document conversion.** Kady can search the web (via [Parallel](https://parallel.ai/) or [Exa](https://exa.ai/)) and convert documents between formats (PDF, DOCX, HTML, etc.) with no extra setup.
25+
- **Web search and document conversion.** Kady can search the web (via [Exa](https://exa.ai/) or [Parallel](https://parallel.ai/)) and convert documents between formats (PDF, DOCX, HTML, etc.) with no extra setup.
2626
- **Voice input, drag-and-drop attachments, `@` file mentions,** and a **message queue** for batching up to 5 messages while the agent is working.
2727
- **Publication-ready provenance.** A timeline of every step in your session, plus a one-click "Copy as Methods" button that exports a paragraph ready to paste into a paper.
2828
- **Optional remote compute.** Plug in [Modal](https://modal.com/) to run heavy jobs on cloud GPUs (T4, L4, A10G, A100, H100) or serverless CPUs - selected right from the input bar.
@@ -34,8 +34,8 @@ It is built for scientists, analysts, and curious people who want a powerful AI
3434
|------|-----|-----------------|
3535
| A computer running **macOS or Linux** | The app runs locally on your machine | Windows works too - use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) |
3636
| An **OpenRouter API key** | This is how the AI models are accessed | [openrouter.ai](https://openrouter.ai/) - sign up and create a key |
37-
| A **Parallel API key** *(optional)* | Lets Kady search the web | [parallel.ai](https://parallel.ai/) |
38-
| An **Exa API key** *(optional)* | Alternative web search provider; neural (embedding-based) retrieval tuned for scientific content | [exa.ai](https://exa.ai/) |
37+
| An **Exa API key** *(optional)* | Lets Kady search the web with neural (embedding-based) retrieval tuned for scientific content | Get your Exa API key: [dashboard.exa.ai/api-keys](https://dashboard.exa.ai/api-keys) |
38+
| A **Parallel API key** *(optional)* | Alternative web search provider | [parallel.ai](https://parallel.ai/) |
3939
| **Modal** credentials *(optional)* | Only needed for remote GPU/CPU compute | [modal.com](https://modal.com/) |
4040

4141
You do not need any coding experience. The startup script installs everything else for you.
@@ -55,7 +55,7 @@ cd k-dense-byok
5555

5656
Inside the `kady_agent` folder you'll find a file called `env.example`. Make a copy and rename the copy to `.env` (note the dot at the start). Open `.env` in any text editor and paste your **OpenRouter API key** on the first line - that's the only key you need to get started.
5757

58-
The file also has sections for other optional keys (Parallel or Exa for web search, Modal for remote compute, and many scientific and government database keys). Leave blank anything you don't need.
58+
The file also has sections for other optional keys (Exa or Parallel for web search, Modal for remote compute, and many scientific and government database keys). Leave blank anything you don't need.
5959

6060
### Step 3 - Start the app
6161

docs/custom-mcp-servers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Custom MCP Servers
22

3-
K-Dense BYOK comes with built-in [MCP](https://modelcontextprotocol.io/) servers: Docling for document conversion, and two optional web-search providers — Parallel and Exa — each enabled by supplying the corresponding API key in `.env`. You can add your own MCP servers to give Kady's expert agents more tools - for example, connecting to internal databases, custom APIs, or specialised scientific tooling.
3+
K-Dense BYOK comes with built-in [MCP](https://modelcontextprotocol.io/) servers: Docling for document conversion, and two optional web-search providers — Exa and Parallel — each enabled by supplying the corresponding API key in `.env` (get an Exa key at [dashboard.exa.ai/api-keys](https://dashboard.exa.ai/api-keys)). You can add your own MCP servers to give Kady's expert agents more tools - for example, connecting to internal databases, custom APIs, or specialised scientific tooling.
44

55
## Adding a server through the UI
66

@@ -30,6 +30,6 @@ Two transport types are supported:
3030

3131
## How it's stored
3232

33-
- Your custom servers are **merged** with the built-in defaults (Docling, plus Parallel and/or Exa when their API keys are set) and passed to the Gemini CLI.
33+
- Your custom servers are **merged** with the built-in defaults (Docling, plus Exa and/or Parallel when their API keys are set) and passed to the Gemini CLI.
3434
- The configuration is saved **per project** in `projects/<project-id>/custom_mcps.json` (outside the `sandbox/` folder) so it survives sandbox deletion and app restarts.
3535
- Switching projects automatically swaps the MCP set - each project has its own.

kady_agent/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
or "openrouter/google/gemini-3.1-pro-preview"
3737
)
3838
EXTRA_HEADERS = {"X-Title": "Kady", "HTTP-Referer": "https://www.k-dense.ai"}
39-
PARALLEL_API_KEY = os.getenv("PARALLEL_API_KEY")
4039
EXA_API_KEY = os.getenv("EXA_API_KEY")
40+
PARALLEL_API_KEY = os.getenv("PARALLEL_API_KEY")
4141

4242
logger = logging.getLogger(__name__)
4343

kady_agent/env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ OLLAMA_BASE_URL=http://localhost:11434
3030

3131
## Highly Recommended (Delete if not needed and filled in correctly)
3232

33+
# Exa Search (get your key at https://dashboard.exa.ai/api-keys)
34+
EXA_API_KEY=
35+
3336
# Parallel Search
3437
PARALLEL_API_KEY=
3538

36-
# Exa Search
37-
EXA_API_KEY=
38-
3939
# Modal
4040
MODAL_TOKEN_ID=
4141
MODAL_TOKEN_SECRET=

kady_agent/instructions/main_agent.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Choose the lightest reliable path:
2020
You do **NOT** have the ability to activate or execute skills. Skills are capabilities that only the expert (Gemini CLI) inside `delegate_task` can use via its `activate_skill` tool. The skill reference table at the end of these instructions exists **solely** so you can:
2121

2222
1. **Recognize** when a user names a skill (e.g. "use the parallel-web skill", "use literature-review").
23-
2. **Match** a user request to the most relevant skill(s) even when the user does not name one explicitly (e.g. a request for "research best places in SF" should suggest the `parallel-web` or `exa-search` skill; a request to "write a report" should suggest the `writing` skill).
23+
2. **Match** a user request to the most relevant skill(s) even when the user does not name one explicitly (e.g. a request for "research best places in SF" should suggest the `exa-search` or `parallel-web` skill; a request to "write a report" should suggest the `writing` skill).
2424
3. **Pass the skill name(s) verbatim** in the `delegate_task` prompt so the expert can activate them.
2525

2626
**Never** attempt to use, activate, or simulate a skill yourself. If a task needs a skill, delegate it.
@@ -31,15 +31,15 @@ You do **NOT** have the ability to activate or execute skills. Skills are capabi
3131
- In `prompt`, pass the user's request, the expert's role/objective/constraints, relevant context, file paths, URLs, and explicit success criteria.
3232
- Do not prescribe implementation approaches, libraries, or fallback methods unless the user explicitly requires them.
3333
- **Skills passthrough (MANDATORY):** If the user's message names specific skills (e.g. "use the parallel-web skill" or "use the skills: 'writing', 'literature-review'"), you MUST include an explicit instruction in the delegate prompt telling the expert to activate those skills. Use the format: `"You MUST activate and follow these skills: 'skill-name-1', 'skill-name-2'."` Do not paraphrase, omit, reorder, or summarize the skill list. The expert relies on exact names to activate the correct skills.
34-
- **Proactive skill matching:** Even when the user does not name a skill, consult the skill reference table and identify skills that match the task. Include them in the delegate prompt the same way: `"You should activate and follow these skills: 'skill-name'."` For example, if the user asks to "search the web for X", include whichever web-search skill matches the enabled MCP (`parallel-web` for Parallel Search MCP, `exa-search` for Exa Search MCP); if they ask for a "literature review", include `literature-review` and `writing`.
34+
- **Proactive skill matching:** Even when the user does not name a skill, consult the skill reference table and identify skills that match the task. Include them in the delegate prompt the same way: `"You should activate and follow these skills: 'skill-name'."` For example, if the user asks to "search the web for X", include whichever web-search skill matches the enabled MCP (`exa-search` for Exa Search MCP, `parallel-web` for Parallel Search MCP); if they ask for a "literature review", include `literature-review` and `writing`.
3535
- **Modal compute passthrough (MANDATORY):** If the user's prompt requests specific compute infrastructure and mentions **Modal** (e.g. "run this on Modal", "use Modal GPUs", "deploy on Modal"), you MUST:
3636
1. Include the compute requirement explicitly in the `delegate_task` prompt.
3737
2. State that the expert **MUST activate and follow the `modal` skill** before writing or running any Modal-related code.
3838
3. Do not assume the expert will infer Modal usage on its own — spell it out: "You must activate and follow the skill: 'modal' to execute this code on a Modal instance."
3939

4040
## Tool preferences
4141

42-
- Prefer Parallel Search MCP or Exa Search MCP for open-web search and URL content retrieval — whichever is available. Both expose MCP tools for search and content fetch; the user's `.env` determines which one (or both) are enabled.
42+
- Prefer Exa Search MCP or Parallel Search MCP for open-web search and URL content retrieval — whichever is available. Both expose MCP tools for search and content fetch; the user's `.env` determines which one (or both) are enabled.
4343
- Prefer Docling for document conversion, text extraction, and markdown export.
4444
- Users may install custom MCP tools (e.g. memory/knowledge-graph, filesystem, databases, specialized APIs) via the Settings panel. These tools appear alongside the built-in ones — use them directly whenever the request matches their capabilities instead of routing through `delegate_task`.
4545
- For reports, papers, literature reviews, or other structured prose, instruct the expert to use the `writing` skill.

kady_agent/manifest.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -188,29 +188,29 @@ def _mcp_servers_snapshot() -> list[dict]:
188188
entries: list[dict] = []
189189
for name in sorted(merged):
190190
entries.append({"name": name, "spec": merged[name]})
191-
if os.getenv("PARALLEL_API_KEY"):
192-
entries.append(
193-
{
194-
"name": "parallel-search",
195-
"spec": {
196-
"httpUrl": "https://search-mcp.parallel.ai/mcp",
197-
"headers": {"Authorization": "Bearer <redacted>"},
198-
},
199-
}
200-
)
201191
if os.getenv("EXA_API_KEY"):
202192
entries.append(
203193
{
204194
"name": "exa-search",
205195
"spec": {
206196
"httpUrl": "https://mcp.exa.ai/mcp",
207197
"headers": {
208-
"x-api-key": "<redacted>",
198+
"x-api-key": "YOUR_EXA_API_KEY",
209199
"x-exa-integration": "k-dense-byok",
210200
},
211201
},
212202
}
213203
)
204+
if os.getenv("PARALLEL_API_KEY"):
205+
entries.append(
206+
{
207+
"name": "parallel-search",
208+
"spec": {
209+
"httpUrl": "https://search-mcp.parallel.ai/mcp",
210+
"headers": {"Authorization": "Bearer <redacted>"},
211+
},
212+
}
213+
)
214214
return entries
215215

216216

kady_agent/mcps.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,19 +168,6 @@ async def close(self) -> None:
168168

169169
all_mcps: list[BaseToolset] = []
170170

171-
if os.getenv("PARALLEL_API_KEY"):
172-
parallel_search_mcp = ResilientMcpToolset(
173-
McpToolset(
174-
connection_params=StreamableHTTPConnectionParams(
175-
url="https://search-mcp.parallel.ai/mcp",
176-
headers={"Authorization": f"Bearer {os.getenv('PARALLEL_API_KEY')}"},
177-
timeout=600,
178-
),
179-
),
180-
label="Parallel Search MCP",
181-
)
182-
all_mcps.append(parallel_search_mcp)
183-
184171
if os.getenv("EXA_API_KEY"):
185172
exa_search_mcp = ResilientMcpToolset(
186173
McpToolset(
@@ -197,6 +184,19 @@ async def close(self) -> None:
197184
)
198185
all_mcps.append(exa_search_mcp)
199186

187+
if os.getenv("PARALLEL_API_KEY"):
188+
parallel_search_mcp = ResilientMcpToolset(
189+
McpToolset(
190+
connection_params=StreamableHTTPConnectionParams(
191+
url="https://search-mcp.parallel.ai/mcp",
192+
headers={"Authorization": f"Bearer {os.getenv('PARALLEL_API_KEY')}"},
193+
timeout=600,
194+
),
195+
),
196+
label="Parallel Search MCP",
197+
)
198+
all_mcps.append(parallel_search_mcp)
199+
200200
docling_mcp = ResilientMcpToolset(
201201
McpToolset(
202202
connection_params=StdioConnectionParams(

tests/test_manifest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ def test_mcp_snapshot_includes_exa_when_key_set(active_project, monkeypatch):
206206
assert "parallel-search" not in names
207207
exa = next(e for e in entries if e["name"] == "exa-search")
208208
assert exa["spec"]["httpUrl"] == "https://mcp.exa.ai/mcp"
209-
# API key redacted; integration header preserved verbatim.
210-
assert exa["spec"]["headers"]["x-api-key"] == "<redacted>"
209+
# API key redacted to a clear placeholder; integration header preserved verbatim.
210+
assert exa["spec"]["headers"]["x-api-key"] == "YOUR_EXA_API_KEY"
211211
assert exa["spec"]["headers"]["x-exa-integration"] == "k-dense-byok"
212212

213213

0 commit comments

Comments
 (0)