MCP Server
Connect AI assistants like ChatGPT, Claude, and Cursor to your Starspace workspace using the Model Context Protocol.
Base URL
https://api.starspace.run/functions/v1/mcp-run-v1Two routes are available:
| Route | Capabilities | Use case |
|---|---|---|
| / | Read + Write | Full access, IDE integrations, automation |
| /readonly/ | Read only | ChatGPT connectors, read-only assistants |
/readonly/ route.search and ask alongside the run/edit/fetch tools. Sandbox workspaces share the same virtual FS but have no semantic index, so search and ask are absent fromtools/list and direct calls return a friendly inline error pointing at run_readonly with rg/grep. Always inspect tools/list on session start - don't assume.Transport
Streamable HTTP, the server accepts POST requests with JSON-RPC 2.0 payloads.
Content-Type: application/json
Accept: application/json, text/event-streamBoth Accept values are required. Omit either and the server returns 406 not_acceptable. This is mandated by the MCP Streamable HTTP transport spec, since the server may stream the response.
Supported protocol versions: 2025-11-25, 2025-03-26, 2024-11-05
The server is stateless, each request creates a fresh instance. Session headers are accepted but not required.
Response format
Responses are framed as Server-Sent Events: each JSON-RPC envelope arrives as a data: <json>\n\n line. Even single-shot tool calls (no streaming) come back this way, so don't JSON.parse(body) directly — strip the data: prefix first.
// 1. Strip SSE framing
const env = JSON.parse(
body.split('\n')
.filter(l => l.startsWith('data:'))
.map(l => l.slice(5).trim())
.filter(s => s && s !== '[DONE]')
.pop()
);
// 2. Pull structured output directly (modern path — no second parse)
const data = env.result.structuredContent; // { results: [...] }
// 3. Legacy path: same JSON, escaped as a string inside content[0].text
const legacy = JSON.parse(env.result.content[0].text);For tools with an outputSchema (search, fetch, manifest, server_health, …), prefer result.structuredContent — it's a real JSON object so you skip the second parse. result.content[0].text carries the same payload as an escaped JSON string for older clients that don't honor structured output (MCP 2025-06-18 feature).
Authentication
1. API Key (simplest)
Pass your workspace API key as a Bearer token or query parameter.
curl -X POST \
-H "Authorization: Bearer ak_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
https://api.starspace.run/functions/v1/mcp-run-v1curl -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
"https://api.starspace.run/functions/v1/mcp-run-v1?key=ak_your_key_here"Create API keys via the Workspace API.
2. OAuth 2.0 (PKCE)
For third-party integrations, the server supports OAuth 2.0 Authorization Code flow with PKCE (S256).
| Endpoint | Description |
|---|---|
| /.well-known/oauth-authorization-server | Authorization server metadata |
| /.well-known/oauth-protected-resource | Protected resource metadata |
| /oauth/authorize | Start authorization (GET) |
| /oauth/token | Exchange code for tokens (POST) |
| /oauth/register | Dynamic client registration (POST) |
| /oauth/revoke | Revoke a token (POST) |
Scopes
| Scope | Description |
|---|---|
| offline_access | Request a refresh token |
| workspace:read | Read workspace files and search |
| workspace:ask | Execute read-only commands |
| workspace:write | Modify files and execute write commands |
workspace:write implicitly grants workspace:read and workspace:ask.
Tools
tools/call → searchHybrid full-text + trigram + symbol + chunk search with intent-aware LLM reranking. Returns ranked candidates with confidence scores and one-line rationales for why each result was picked.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | ✓ | Search query |
| limit | integer | , | Max results, 1–50 (default 10) |
| path_prefix | string | , | Restrict to files under this directory |
| file_glob | string | , | Restrict to files matching this glob (e.g. '*.ts', '**/auth/*.py') |
| mode | string | , | exact | semantic | debug | auto (default auto) |
Scope: workspace:read or workspace:ask
curl -X POST \
-H "Authorization: Bearer ak_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "openai compatible api server routes chat completions",
"limit": 5
}
}
}' \
https://api.starspace.run/functions/v1/mcp-run-v1Response Shape
The object below is what arrives on result.structuredContent after you strip SSE framing. The same JSON is also escaped inside result.content[0].text for older clients — see the Transport section for a minimal parse.
{
"results": [
{
"id": "file:src/api_router.py:L7-L42",
"path": "src/api_router.py",
"title": "api_router.py (L7-L42)",
"url": "https://app.starspace.run/w/<id>/file/src/api_router.py",
"text": "snippet ...",
"score": 1.0,
"score_raw": 0.0016,
"confidence": "high",
"rerank_rank": 1,
"why": "Canonical FastAPI router for OpenAI chat completion routes",
"match_type": "chunk",
"start_line": 7,
"end_line": 42,
"matched_lines": [
{ "line": 12, "text": "@router.post('/v1/chat/completions')" }
]
}
],
"query_interpretation": {
"mode_used": "semantic",
"intent_detected": "semantic",
"filters_applied": { "limit": 5 },
"reranked": true,
"rerank_reason": "applied"
}
}| Result field | Description |
|---|---|
| id | Stable citation. Pass back to fetch. Form: file:<path>:L<start>-L<end> when range is known, plain file:<path> otherwise. |
| path | Plain file path, normalized (no line range suffix). |
| score | 0–1 normalized for display. 1.0 = top hit in this set. |
| score_raw | Original RRF (Reciprocal Rank Fusion) float. For clients that need raw signal. |
| confidence | high (≥0.7) | medium (≥0.4) | low. Bucketed from score. |
| rerank_rank | 1-indexed position from the LLM reranker (only present when rerank ran). |
| why | One-line rationale from the reranker (only present when rerank ran). |
| match_type | chunk | fts | path | symbol | content. Where the match came from. |
| start_line / end_line | Line range coherent with id. Use as-is for fetch. |
| matched_lines | Up to 3 highest-scoring lines with absolute line numbers. |
| query_interpretation | Description |
|---|---|
| mode_used | Effective mode after override or auto-classification. |
| intent_detected | What the auto-classifier picked from the query shape. |
| filters_applied | Echo of path_prefix, file_glob, and limit actually used. |
| reranked | true if at least one result carries a rerank_rank. |
| rerank_reason | applied | disabled | no_results | too_few_candidates | exact_mode | gemini_error. |
tools/call → fetchRetrieve a document by its ID. Pass an id straight from search results - the embedded line range (file:<path>:L<s>-L<e>) is parsed automatically.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | string | ✓ | Document ID from search (file:<path> or file:<path>:L<s>-L<e>) |
| start_line | integer | , | Override the embedded range (1-indexed) |
| end_line | integer | , | Override the embedded range (1-indexed). Capped at start + 2000 lines. |
Scope: workspace:read or workspace:ask
curl -X POST \
-H "Authorization: Bearer ak_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1,
"method": "tools/call",
"params": {"name": "fetch", "arguments": {"id": "file:src/api_router.py:L7-L42"}}
}' \
https://api.starspace.run/functions/v1/mcp-run-v1tools/call → server_healthReturns server diagnostics. Use this to verify connectivity and check if the tool manifest has changed.
Scope: none required
| Field | Description |
|---|---|
| instance_id | Unique ID for the workspace MCP server instance handling this session |
| server_version | Server version string |
| toolset_hash | SHA-256 hash of the tool manifest, stable across restarts |
| uptime_ms | Milliseconds since boot |
| stateless | Always true |
tools/call → run_readonlyExecute read-only Unix command chains against your workspace filesystem.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| command | string | ✓ | Command chain to execute |
Scope: workspace:read or workspace:ask
Available commands: ls, tree, cat, head, tail, find, grep, rg, outline, diff, wc, sort, uniq, xargs, cd, pwd, echo, stat, lines, help
curl -X POST \
-H "Authorization: Bearer ak_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1,
"method": "tools/call",
"params": {"name": "run_readonly", "arguments": {"command": "tree / | head 50"}}
}' \
https://api.starspace.run/functions/v1/mcp-run-v1tools/call → runExecute command chains with read-only or read-write access depending on the route.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| command | string | ✓ | Command chain to execute |
On the default route: full read-write access. On /readonly/: same as run_readonly.
Additional write-mode commands: write, rm, patch, fetch, note
tools/call → write_fileCreate or overwrite a file in the workspace.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | string | ✓ | File path relative to workspace root |
| content | string | ✓ | Complete file content |
Scope: workspace:write · Default route only
tools/call → apply_patchApply a surgical edit to an existing file.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | string | ✓ | File path relative to workspace root |
| patch | string | ✓ | Patch content in *** Begin Patch format |
Scope: workspace:write · Default route only
*** Begin Patch
*** Update File: src/main.ts
@@@ -10,3 +10,5 @@@
import { foo } from './foo';
-import { bar } from './bar';
+import { bar } from './bar';
+import { baz } from './baz';
+
const app = createApp();
*** End PatchHealth Endpoints
Simple health checks (GET, no auth required). Returns 200 OK with {"status":"ok"}.
curl https://api.starspace.run/functions/v1/mcp-run-v1/health
curl https://api.starspace.run/functions/v1/mcp-run-v1/readonly/healthRate Limiting
120 requests per minute per workspace. Exceeding the limit returns 429 Too Many Requests.
Connecting from AI Platforms
ChatGPT
- Go to Settings → Connected Apps → Add MCP Server
- Enter the readonly URL:
https://api.starspace.run/functions/v1/mcp-run-v1/readonly/?key=ak_your_key_herelink_<id> identifiers that may expire independently. If you get "Resource not found" errors, re-trigger tool discovery. Verify with server_health and compare toolset_hash.Claude
Add a custom MCP server with your API key as a query parameter:
https://api.starspace.run/functions/v1/mcp-run-v1?key=ak_your_key_hereCursor / IDEs
Configure the MCP server in your IDE settings:
{
"mcpServers": {
"starspace": {
"url": "https://api.starspace.run/functions/v1/mcp-run-v1",
"headers": {
"Authorization": "Bearer ak_your_key_here"
}
}
}
}Direct HTTP
curl -X POST \
-H "Authorization: Bearer ak_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
https://api.starspace.run/functions/v1/mcp-run-v1Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 401 Unauthorized | Missing or invalid API key | Check your ak_ key is valid |
| 403 Forbidden | Insufficient scope | Ensure your key has required scopes |
| 406 not_acceptable | Accept header missing application/json or text/event-stream | Send both: 'Accept: application/json, text/event-stream' |
| 429 Too Many Requests | Rate limit exceeded | Wait and retry |
| Body starts with "data: {…}" | SSE framing on every response (single-shot too) | Strip 'data:' prefix; read result.structuredContent for parsed output |
| "Resource not found" (ChatGPT) | Bridge wrapper expired | Re-trigger tool discovery |
| Different instance_id each call | Normal serverless behavior | Expected, server is stateless |
See Also
- Workspace Management API, Create workspaces and API keys
- MCP Specification, Official protocol docs