Agent Skills
How to use the Starspace MCP server effectively from an AI agent. Optimized to be pasted into a system prompt - copy this whole page with the button below.
Agent Skills - Starspace MCP
How an AI agent should use the Starspace MCP server effectively. Drop this into your agent's system prompt or context.
Golden path
For a question → ask (one call, returns a synthesized answer with citations)
For deeper / multi-file work → 1. search → find candidate files (ranked, with confidence + why)
2. fetch → read the exact span suggested by search
3. rg/grep → verify exact strings if needed (via run_readonly)
4. edit → write_file / apply_patch when you're sure
A typical agent turn for "what is this codebase?"-style questions is one ask call. A typical investigation turn never needs more than 3–4 tool calls (search → fetch → optional rg → done). If you find yourself making 8+ calls, you're probably searching when you should be reading, or guessing at file paths instead of asking.
When to use what
| You want to… | Use |
|---|---|
| Get a synthesized answer to a question about the codebase | ask |
| Find files by topic, identifier, or concept | search |
| Find an exact string after you've narrowed candidates | rg (via run_readonly) |
| Read the contents of a known file | fetch |
| Browse a directory tree | run_readonly with tree/ls |
| Get a feel for a workspace (file counts, top extensions) | workspace_summary |
| Edit a file you've already read | apply_patch (preferred) or write_file |
Rules of thumb:
askis for "how does X work", "where is Y configured", "what does Z do". One call, structured answer + citations.searchis for "where is X?" when you want the candidate file list (not an answer).rgis for "show me every line that says X." Don'trgthe whole workspace looking for an unfamiliar concept -searchis faster and ranked.- If
askreturnsconfidence: "low", drop down tosearch+fetchand reason over the contents yourself.
Using search well
Pass a real query
A good query has 3–8 specific tokens. auth is too vague. stripe webhook signature verification is great.
{ "name": "search", "arguments": { "query": "stripe webhook signature verification", "limit": 5 } }
Optional inputs you should know
| Input | When to use |
|---|---|
limit | Set 3–5 when you only want the top hit; 10–20 when comparing options. |
path_prefix | When you know the area: "src/auth" or "docs/". |
file_glob | When you want one file type: "*.md" or "**/*_test.py". |
mode | Override the auto-classifier. exact for identifiers; semantic for prose; debug for error/log queries. auto is right ~95% of the time. |
Reading the response
Each result has an id, path, score (0–1), confidence (high/medium/low), and - when reranking ran - a why rationale and rerank_rank. The why field tells you whether to fetch or skip without reading the snippet.
{
"id": "file:src/api_router.py:L7-L42",
"path": "src/api_router.py",
"score": 1.0,
"confidence": "high",
"rerank_rank": 1,
"why": "Canonical FastAPI router for OpenAI chat completion routes",
"matched_lines": [{ "line": 12, "text": "@router.post('/v1/chat/completions')" }]
}
If confidence is high, fetch it. If medium, read why and matched_lines first. If low, your query is probably wrong - refine and re-search.
Citation IDs
When a result has a known span, id looks like file:<path>:L<start>-L<end>. Pass that id straight to fetch - the line range is parsed automatically; you don't need to set start_line/end_line separately. This is the fastest way to land on the relevant code.
query_interpretation - debug your queries
Every search returns a query_interpretation block:
{
"mode_used": "semantic",
"intent_detected": "semantic",
"filters_applied": { "limit": 5 },
"reranked": true,
"rerank_reason": "applied"
}
rerank_reason tells you why reranking did or didn't happen:
| Value | Meaning | What to do |
|---|---|---|
applied | Reranker ranked the results | You're set. |
no_results | Empty results | Refine the query - likely too specific or wrong terms. |
too_few_candidates | ≤3 results | Loosen the query if those 3 don't match. |
exact_mode | Identifier-shaped query | Symbol tier handled it; rerank wasn't needed. |
disabled | Reranking off on this server | Treat raw RRF order as a hint, not gospel. |
gemini_error | Reranker call failed | Order is original RRF; retry the same query if needed. |
Using fetch well
Pass the search id directly
{ "name": "fetch", "arguments": { "id": "file:src/api_router.py:L7-L42" } }
This returns exactly lines 7–42 of src/api_router.py. No prep needed.
Override the range when you need more context
{ "name": "fetch", "arguments": { "id": "file:src/api_router.py:L7-L42", "start_line": 1, "end_line": 80 } }
The explicit start_line/end_line win over the embedded range. Use this when search points at the right region but you need imports or surrounding helpers. Capped at 2000 lines per call.
Don't fetch a whole file unless you need to
If a search hit gives you L40-L80, fetch just that. Fetching whole files is the agent equivalent of cat-ing every file you suspect - burns context for no reason.
Using rg for exact strings
rg (workspace-native ripgrep) and grep are the right move when you want to verify an exact string occurs and where:
{
"name": "run_readonly",
"arguments": { "command": "rg --json -t py 'create_chat_completion' src/" }
}
Available read commands: ls, tree, cat, head, tail, find, grep, rg, outline, diff, wc, sort, uniq, xargs, stat, lines, echo. Chain with |, &&, ||, ;, or newlines.
rg supports the most common flags but is not full ripgrep. If a flag is rejected, the error message lists supported alternatives. rg --files lists files without searching content.
Editing files
Always read a file before editing it - don't write blind. The server tracks per-session reads as a guardrail.
apply_patch (preferred for surgical edits)
*** Begin Patch
*** Update File: src/api_router.py
@@@ -10,3 +10,5 @@@
import { foo } from './foo';
-import { bar } from './bar';
+import { bar } from './bar';
+import { baz } from './baz';
const app = createApp();
*** End Patch
write_file (for new files or full rewrites)
{ "name": "write_file", "arguments": { "path": "src/new.ts", "content": "..." } }
Pass complete file content, not a diff. Overwrites if the file exists.
run for shell-level edits
run (full route, not /readonly/) supports write, rm, patch, fetch, note. Use this when you need to mv/rm files or chain operations.
Common failure modes
| Symptom | Likely cause | Fix |
|---|---|---|
| Search returns no results | Query too specific or wrong terms | Drop adjectives; try fewer, more central tokens |
Top result has confidence: low | Query mismatched | Add path_prefix or use mode: "exact" if you have an identifier |
| Fetch returns wrong span | Pass the id exactly as search returned it | Don't construct file:<path> ids by hand - they may miss the line range |
apply_patch fails | File changed between read and patch, or context lines don't match | Re-fetch, re-author the patch |
| 401 Unauthorized | API key missing/invalid | Check Authorization: Bearer ak_... header |
| 403 Forbidden | Insufficient scope | Need workspace:write for write tools, workspace:read or workspace:ask for everything else |
| 429 Too Many Requests | Rate limit (120/min/workspace) | Back off and retry |
Quick reference
search → ranked discovery, returns id you pass to fetch
fetch → read a citation. id form: file:<path>:L<s>-L<e>
run_readonly → rg, grep, ls, tree, cat, head, tail, find, etc.
run → same as run_readonly + write/rm/patch/fetch/note (write route only)
write_file → create or overwrite file (write route only)
apply_patch → surgical edit (write route only)
workspace_summary → high-level workspace stats
server_health → diagnostics, toolset hash
See also
- MCP Server reference - full tool reference and request/response shapes
- CLI Reference - same surface from a terminal
- MCP Specification - protocol details