MCP server
K-Stra is also a Model Context Protocol server: connect Claude, ChatGPT, an IDE agent or any MCP client to https://www.k-stra.com/mcp and it can search addresses, draw catchments, quote and run analyses, and read saved results — with the same API key and the same rules as the REST API.
| Endpoint | https://www.k-stra.com/mcp |
| Transport | Streamable HTTP, stateless (no session id, every request stands alone) |
| Authentication | Authorization: Bearer ks_live_… — the key from Account → API |
| Tools, resources | generated from the action registry on every request: the same schemas as /api/v1 |
Connect
Clients that take a remote server as URL plus headers (Claude Code, Cursor, VS Code, most SDKs):
{
"mcpServers": {
"k-stra": {
"type": "http",
"url": "https://www.k-stra.com/mcp",
"headers": { "Authorization": "Bearer ks_live_…" }
}
}
}
With Claude Code from a terminal:
claude mcp add --transport http k-stra https://www.k-stra.com/mcp --header "Authorization: Bearer ks_live_…"
Claude Desktop reaches remote servers through the mcp-remote bridge (it needs Node.js). Edit claude_desktop_config.json (Settings → Developer → Edit Config; on Windows it lives in %APPDATA%\Claude), then restart Claude Desktop:
{
"mcpServers": {
"k-stra": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://www.k-stra.com/mcp", "--transport", "http-only", "--header", "Authorization:${KSTRA_AUTH}"],
"env": { "KSTRA_AUTH": "Bearer ks_live_…" }
}
}
}
On Windows, if npx is not found, use "command": "cmd" and put "/c", "npx" in front of the arguments. The key goes in env because the bridge does not accept spaces inside a header argument. The server is stateless and has no OAuth: a key is the only way in, and without one the endpoint answers 401 with WWW-Authenticate: Bearer.
Tools
The tools are the same actions as the REST API — the geomarketing computations and the lookups that build their input (see the table in the Quickstart) — so what an assistant can do over MCP is exactly what a program can do over REST. Action ids become tool names with _ instead of . (search.addresses → search_addresses).
| Tool | What it does | Scope |
|---|---|---|
<action> for every free action |
runs it directly: search_addresses, search_resolve_address, areas_list, markets_sectors, … |
read |
quote_<action> for every charged action |
quotes it in credits without charging or computing; returns quotedCredits |
read |
run_<action> for every charged action |
runs it and charges. Requires quotedCredits from the quote; refused without charging if the quote changed (quote_changed) or credits are insufficient (insufficient_credits) |
run |
list_analyses |
your saved analyses and the ones shared with you, with the last run of each | read |
get_analysis |
one analysis with its latest saved results, for free | read |
get_credits |
balance, limits and this key's monthly usage | read |
get_data_versions |
the data versions available today | read |
get_job, get_job_results |
the state of a background job (an enrich.points batch) and its results, one row per point or one point in full |
read |
The quote/run pair is the web app's confirmation dialog in protocol form: no agent spends credits without having declared how many. A typical exchange for People & Economy:
quote_analysis_people_economywith the input (origins, bands, mode, traffic, topics) →{ "quotedCredits": 4, "quote": { … }, "polesInvolved": 27543 }run_analysis_people_economywith the same input plus"quotedCredits": 4→{ "actionId": "analysis.people_economy", "result": { "charged": true, "creditsCharged": 4, … } }
Every tool result carries the JSON both as text and as structuredContent. Free and run_ tools whose action returns an object declare an outputSchema ({ actionId, result }); quote_ tools declare the quote (actionId, quotedCredits, quote, polesInvolved, blockedBy).
Errors
A tool that cannot do its job returns a result with isError: true whose text is the same problem the REST API would send: error (the code), status, type, title, detail and the extra data — missing for a required field left out, quotedCredits for a changed quote, blockedBy for insufficient credits. A name that matches no tool gives unknown_tool. The catalogue is in Errors, limits & versions.
Resources
Every saved analysis visible to the key (the 100 most recently updated, as in list_analyses) is a resource kstra://analyses/<code> (application/json): the analysis with its latest saved results, the same document GET /api/v1/analyses/{code} returns. Reading a resource never spends credits.
Binding a run to a saved analysis
Pass analysisCode (the 12-character code from list_analyses) in the input of a run_ tool: when the run is charged it is stored as a new version of that analysis, exactly like the X-Analysis-Id header over REST, and the tool result carries the version summary. The analysis must be yours; run_analysis_isochrone is never stored as a version. Read it back later with get_analysis or the resource, for free.
Limits
The key's limits apply unchanged: 600 requests a minute per key, the monthly cap you set on the key, and the organization, team and personal credit limits. The per-key limit of 60 charged executions a minute applies to REST; over MCP the general quota is the ceiling.