MCP (AI agents)

Connect Claude, Cursor, and other AI agents to your Sarkoa organization, using the same API keys as the CLI.

Agents get the whole library, not a read-only view of it: organizing and uploading files, authoring and styling custom maps, running time series, leaving and resolving review comments, registering webhooks, and querying your vector layers and raster catalogue directly. That last part is the one people underestimate. An agent that can call query_features answers questions about your data instead of only drawing it.

Set up

  1. Create an API key under Profile β†’ API & Integrations in the web app (see Authentication).
  2. Add Sarkoa as a remote MCP server in your AI app.

Server URL: https://mcp.sarkoa.com/mcp

Claude Code / Claude Desktop

{
  "mcpServers": {
    "sarkoa": {
      "url": "https://mcp.sarkoa.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_TOKEN"
      }
    }
  }
}

Cursor

Use the same JSON in your MCP settings (mcp.json): set url to the server URL above and put your API key in headers.Authorization.

Confirm it works

Ask the agent to run whoami, then list_files. You should see your account and the files in your organization.

Official MCP Registry

Sarkoa is published as com.sarkoa/mcp on the official MCP Registry. Clients and directories that ingest the registry can discover the same Streamable HTTP endpoint and Bearer API-key auth described above.

What agents can do

Fifty tools, grouped by what they act on. Every tool takes the organization from the API key, so organization_id is only needed when a key spans several organizations.

Identity

Tool What it does
whoami Confirm the API key and show email, organization, scopes, and auth method

Files and folders

Tool What it does
list_files List files and folders in one location (parent_id optional; library root if omitted)
list_folders List all folders (id, name, parent) so you can pick a destination
create_folder Create a folder (parent_id optional)
move_file Move a file or folder (folder_ref, or root=true for the library root)
rename_file Change a file or folder's display name. The stored object is untouched
get_file_status Show status and details for one file
get_view_url Open the file in the Sarkoa web viewer
get_download_url Get a temporary link to download the original file
delete_file Delete a file (the agent must confirm). A folder that still has contents also needs recursive=true
retry_processing Requeue a file whose optimization failed. Call with dry_run=true first to read the failure report: a malformed source fails the same way again
check_upload_quota Ask whether an upload of a given size would exceed the plan limit, before transferring the bytes
inspect_asset Inspect fields, bands, statistics, and style options for a file before styling, including sizeChannel and strokeDashSupported

Uploads

Tool What it does
upload_presign Start an upload and return where to send the file
upload_part_url For large files: get the next upload chunk URL
upload_complete Finish the upload so Sarkoa can optimize the file (optional parent_id to place it in a folder)

Sharing

Tool What it does
create_share_link Create a public /share/… link (optional expiry / password on Essential+)
list_shares List share records for a file
revoke_share Revoke a share (the agent must confirm)

Maps

Tool What it does
list_maps List custom maps in your organization
get_map Load a full map document (layers, styles, access, chrome)
get_map_preview Return viewer and editor links for a map
get_embed_code Return a ready-to-paste iframe plus the raw embed URL, and say so when the map is not public yet
validate_map Check a map document without saving
scaffold_map Build a ready-to-edit map document stub (does not save). Layers may include attribution_text / attribution_url. Optional preferred_map_mode (2d/3d) and preferred_projection (mercator/globe)
create_map Create a map from a full document, or a minimal title + layer list (same attribution and display fields as scaffold_map)
replace_map Replace a map with a full desired-state document. Omission deletes: a per-layer key the document leaves out is removed
update_map Apply typed map operations (add/update/remove layers, set styles, setView for display defaults, setAccess for who can open the map)
clone_map Duplicate a map
delete_map Delete a map (the agent must confirm)

Styling a layer

Tool What it does
classify_vector_style Build categorized class colours (distinct by default, or Category 10 / colour-blind-safe). Optional map_id + layer_id applies the style; shuffle recolours. Keeps existing sizeBy and strokeDash
set_layer_popup Choose which attributes a click shows, and which is the heading. Without it, clicking a feature shows nothing
set_layer_legend Enable and label the legend for a raster layer. Vector legends come from the style itself, so this returns an error on a vector layer
render_tile_preview Fetch one actual rendered raster tile as an image, to check a style instead of assuming it worked

Map review

Tool What it does
list_map_comments List review comments on a map, with open and resolved counts
post_map_comment Post a comment anchored to a point, or reply to a thread (a reply inherits its parent's anchor)
resolve_map_comment Mark a comment resolved, or reopen it
delete_map_comment Delete a comment (the agent must confirm)

Time series

Tool What it does
list_series List time series with entry counts and time bounds
create_series Create a series container to hold ordered frames
series_append_presign Start adding one frame; returns a signed upload payload to PUT the bytes to
list_series_entries List the frames in a series with timestamps, status, and format
update_series_entry Change a frame's timing without re-uploading it
series_health Check whether a series will actually animate, and why not

Asking questions of the data

Tool What it does
query_features Filter a hosted vector layer by bounding box and attributes and get GeoJSON back, without downloading the file. See Feature query
stac_search Search the raster catalogue by bounding box, time range, and collection

Webhooks

Tool What it does
list_webhooks List endpoints and the event types available to subscribe to. Signing secrets are never returned
create_webhook Register an HTTPS endpoint. Returns the signing secret exactly once, so surface it to the user immediately
test_webhook Send a synthetic signed delivery now and report what the endpoint returned
delete_webhook Remove an endpoint and its pending deliveries (the agent must confirm)

Agents can also read sarkoa://files (file list), sarkoa://maps (map list), sarkoa://maps/{id} (one map), sarkoa://schemas/map/v1 (map document schema), and sarkoa://schemas/map/v1/example (minimal valid document).

Creating and styling maps

Maps use a versioned map document (sarkoa.com/maps/v1). A document describes the camera, basemap, access settings, and every layer style (fill, outline, categorized/graduated vector styles, raster palettes, popups, legends, and more). Layer titles you set appear in the layers panel; legend titles work for simple styles as well as categorized and graduated ones. Layer attribution_text / attribution_url (or layers[].attribution) set the cartographic credit in the bottom-right map control. preferred_map_mode (2d or 3d) and preferred_projection (mercator or globe) control how the map opens; visitors can still switch in the viewer.

Typical agent flow:

  1. list_files (or reuse known file IDs).
  2. scaffold_map (or read sarkoa://schemas/map/v1/example) for a starting document.
  3. inspect_asset for each layer you plan to style. For categorized vector layers, call classify_vector_style so classes get distinct colours (or pass shuffle=true to recolour). For point size or line width by a number, set vectorStyle.sizeBy using inspect_asset.sizeChannel. For dashed lines, set strokeDash when strokeDashSupported is true.
  4. validate_map with your document, then create_map (full document or minimal { title, layers }). Use dry_run=true on create/replace when you want persistence checks (including duplicate layerId within the map) without saving.
  5. Share get_map_preview links with the user.
  6. For follow-up edits, call get_map, keep the returned revision, and pass it as expected_revision to replace_map or update_map.

If validation fails, the tool returns structured JSON with errors[].path so the agent can fix the right field. Public, password-protected, or email-invite maps require confirm_publish=true. Deleting a map requires confirm=true. If a tool listed on this page does not show up in your AI app, reload the MCP connection there.

Uploading files

Uploads go straight from the agent (or your machine) to Sarkoa storage.

  1. The agent calls upload_presign with the filename and size.
  2. It uploads the file to the link that call returns (large files may use several chunk URLs via upload_part_url).
  3. It calls upload_complete so Sarkoa registers the file and starts optimization. Pass parent_id to place the file in a folder.

If your AI app cannot upload to those links, use the web app or CLI instead, then have the agent work with the file by name or ID.

Call check_upload_quota before a large upload. Otherwise the bytes transfer first and the quota error arrives at the end, after the wait.

Waiting for processing without polling

The obvious loop after upload_complete is to call get_file_status until it changes. That works, and for one file it is fine. It is the wrong shape for a batch: it burns request quota and adds latency equal to the poll interval.

If the agent (or whatever it is automating) controls an HTTPS endpoint, register it once instead:

  1. create_webhook with asset.processing.succeeded and asset.processing.failed. The signing secret comes back exactly once, so hand it to the user immediately.
  2. test_webhook to confirm the receiver actually answers before you depend on it.
  3. Stop polling. Sarkoa posts a signed event, usually within a minute.

Full event catalogue, payload shape, and signature verification: Webhooks.

When polling really is the only option, poll no faster than about every five seconds and back off on retries.

Asking questions about the data

Styling is not the only thing an agent can do with a hosted layer. Two tools read the data itself:

  • query_features filters a vector layer by bounding box and attributes and returns GeoJSON, server-side, with no download. Run inspect_asset first to see the attribute names.
  • stac_search finds rasters by bounding box, time range, and collection.

Both are covered in Feature query, including the size limits and what happens when a source is not queryable.

Checking your own work

An agent that styles a raster and reports success has not actually verified anything. render_tile_preview fetches one real rendered tile and returns it as an image, so the model can look at the result before telling you it is done.

Tips for reliable agents

These habits help agents work smoothly with your files and maps:

  1. Use the links and file IDs returned by MCP tools. Do not ask the agent to invent viewer, download, or share URLs.
  2. List one folder at a time (list_files with parent_id, or omit it for the library root). Use list_folders when choosing a destination. Reuse those IDs instead of listing again.
  3. Check one file with get_file_status. While a file is still processing, wait several seconds between checks.
  4. Request a download or upload link only when you need a new one (for example if a previous link expired).
  5. If the server asks the agent to slow down, wait before trying again.
  6. For uploads, follow the three-step flow above: get an upload link, send the file to that link, then call upload_complete. Do not send file bytes through the MCP connection.
  7. Before styling a map layer, call inspect_asset and use its fields, bands, and statistics. For categorized colours, call classify_vector_style instead of inventing hex values. Size points or lines with sizeBy; dash line layers with strokeDash. Unrecognised style keys are dropped with a warning rather than applied.
  8. After get_map, pass the revision into later edits so concurrent changes are not overwritten.
  9. Only delete a file, revoke a share, or publish a map (public, password, or email invite) when you explicitly ask for it. The agent must confirm before those tools run. Deleting a folder that still has contents also needs recursive=true.
  10. Use whoami to confirm the connection works, not on every message.
  11. If validation fails, have the agent read errors[].path in the tool error JSON instead of guessing. When a call succeeds but returns warnings, read those too: they list the parts of the request that could not be used and were dropped. The codes are listed under Map documents. 11b. Argument names are checked. An argument a tool does not recognise is rejected with an error naming the closest match, and nothing is written. Either spelling works (title_field or titleField).
  12. Ask for an embed with get_embed_code rather than assembling a URL. A hand-built embed URL is the most common way an agent produces a frame that silently shows nothing.
  13. Diagnose before retrying. retry_processing with dry_run=true reads the failure report; a malformed source will fail the same way on a second attempt.
  14. Prefer a webhook over a polling loop for batches, and verify the receiver with test_webhook before relying on it.
  15. When a webhook is created, pass the signing secret straight to the user. It is returned once and cannot be retrieved later, only rotated.

When an agent connects, the MCP server shares the same guidance. You can also install the optional Skills pack so hosts that load skill files pick it up.