Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.artifacta.io/llms.txt

Use this file to discover all available pages before exploring further.

Your coding agent just generated a build report, a test transcript, a screenshot, or a 200 MB bundle. Where does it go? Pasted into chat (gets lost), dumped to /tmp (gets cleaned), pushed into a random S3 bucket (no session view, no metadata, no shareable link). Artifacta is the artifact store built for that — purpose-built for AI agents from the ground up — and @artifacta-mcp/mcp is how your agent talks to it. The server runs over MCP stdio, so it works in Claude Code, Codex, Cursor, Windsurf, Cline, Zed, and Claude Desktop, plus any other MCP-compatible host. Once configured, your agent can store files, list past artifacts, mint private download URLs for its own follow-up calls, and — with consent — publish public share links, all without leaving the editor. This guide gets you from zero to first artifact in under five minutes.
Heads-up for Claude Desktop and Cursor. Three tools are classified destructive — create_download_link (public share URLs), delete_artifact (soft-delete by id), and seal_session (irreversible, no unseal) — and are hidden from tools/list unless you add --allow-destructive to the launch args. See Claude Desktop & Cursor: destructive tools for the recommended config and Autonomy boundary for the full compliant / non-compliant client behavior.

Install

The server is distributed via npm. Most clients launch it with npx, so there is nothing to install globally on your machine. You will need:
  • Node.js 20 or newer. The package’s engines field rejects earlier versions before any tool executes.
  • An Artifacta API key. Create one in the dashboard’s API keys page. The key shape is ak_live_ followed by 32 alphanumeric characters.
A note on version pinning. The snippets below leave @artifacta-mcp/mcp unpinned so npx resolves to the latest published release on host restart; patch and minor fixes (including security patches) roll out without a config edit. Pin to a specific version — e.g. @artifacta-mcp/mcp@1.0.0 — only if you need a frozen install, such as a managed deployment with gated config rollouts. The current published line is 1.0.0 — the stable contract; no further breaking changes to the existing 11 tools / 4 resources without v2.

Claude Desktop

Open Claude Desktop’s settings → DeveloperEdit Config, and add an entry under mcpServers. The full file lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows.
claude_desktop_config.json
{
  "mcpServers": {
    "artifacta": {
      "command": "npx",
      "args": ["-y", "@artifacta-mcp/mcp", "--allow-path", "/Users/you/uploads", "--allow-destructive"],
      "env": {
        "ARTIFACTA_API_KEY": "ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
Claude Desktop does not advertise MCP write confirmations, so the three destructive tools — create_download_link (public share URLs), delete_artifact, and seal_session — are hidden unless you add --allow-destructive. See Autonomy boundary for the matrix and create_download_link consent for how to approve share links in chat. Restart Claude Desktop. The Artifacta tools appear in the tool palette and the agent can call them directly.

Cursor

Add the same block to ~/.cursor/mcp.json (create the file if it does not exist):
~/.cursor/mcp.json
{
  "mcpServers": {
    "artifacta": {
      "command": "npx",
      "args": ["-y", "@artifacta-mcp/mcp", "--allow-path", "/Users/you/uploads", "--allow-destructive"],
      "env": {
        "ARTIFACTA_API_KEY": "ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
Cursor does not advertise MCP write confirmations either — add --allow-destructive so create_download_link, delete_artifact, and seal_session appear in the tool list. See Autonomy boundary and create_download_link consent. Restart Cursor and the Artifacta tools become available in agent mode.

Claude Code

For a single project, drop a .mcp.json at the repo root (commit it so the whole team picks up the server):
.mcp.json
{
  "mcpServers": {
    "artifacta": {
      "command": "npx",
      "args": ["-y", "@artifacta-mcp/mcp", "--allow-path", "/Users/you/project", "--allow-destructive"],
      "env": {
        "ARTIFACTA_API_KEY": "${ARTIFACTA_API_KEY}"
      }
    }
  }
}
Claude Code expands ${ARTIFACTA_API_KEY} from your shell environment at launch, so the literal key stays out of the committed file. For a one-line equivalent without editing JSON, use the CLI:
claude mcp add artifacta -- npx -y @artifacta-mcp/mcp \
  --allow-path /Users/you/project --allow-destructive
Then export ARTIFACTA_API_KEY in the shell that launches Claude Code. The --allow-destructive rule from Claude Desktop / Cursor applies here too — without it create_download_link, delete_artifact, and seal_session are hidden from the tool list. See Autonomy boundary.

Codex

Codex (OpenAI CLI) reads MCP configuration from ~/.codex/config.tomlTOML, not JSON. Add an [mcp_servers.artifacta] table:
~/.codex/config.toml
[mcp_servers.artifacta]
command = "npx"
args = ["-y", "@artifacta-mcp/mcp", "--allow-path", "/Users/you/project", "--allow-destructive"]

[mcp_servers.artifacta.env]
ARTIFACTA_API_KEY = "ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
The section name is mcp_servers with an underscoremcp-servers or mcpservers is silently ignored. For a project-scoped install, the same table goes in .codex/config.toml at the project root (Codex must trust the project first). Restart Codex; Artifacta tools appear in the next session, with the same --allow-destructive rule.

Other MCP clients

Windsurf, Cline, Zed, and Continue all accept the same mcpServers JSON shape as Claude Desktop — drop the Claude Desktop block above into the client’s MCP config file (consult the client’s docs for the path) and restart. The --allow-path and --allow-destructive flags carry over unchanged.

Verifying the install

Run the version flag from any shell:
npx -y @artifacta-mcp/mcp --version
# 1.0.0
If that prints 1.0.0 the binary resolved correctly through npx.

Claude Desktop & Cursor: destructive tools

  • Three tools are classified destructive: create_download_link mints a public dl.artifacta.io/lnk_… URL, delete_artifact soft-deletes an artifact by id, and seal_session marks a session as irreversible (no unseal).
  • Hosts that advertise experimental.confirmations prompt before each call; Claude Desktop and Cursor do not, so all three tools are hidden from tools/list by default.
  • Add --allow-destructive to the launch args to expose them; each call then emits a one-line stderr audit [artifacta-mcp] destructive call: <tool>(<args>) instead of a host confirmation UI. The flag is never read from the environment or mcp.toml — it must be in the launch command.
  • Approve destructive calls explicitly in chat before the agent runs them. For share links, see create_download_link consent; for delete and seal, the same principle applies — read the agent’s plan, confirm, then proceed.
  • If you use store_artifact.path, combine --allow-destructive with --allow-path in the same args array — see Path confinement and --allow-path.

First call: whoami

whoami is the right starting tool: it confirms authentication, surfaces the plan tier, and reports current usage so the agent can size subsequent operations against quota. It is free of side effects and quota-cheap. A typical agent prompt that exercises it:
“Confirm we’re authenticated against my Artifacta account, then list the last 10 artifacts.”
The agent will call whoami, receive a response shaped like the example below, then chain list_artifacts with limit: 10:
whoami response
{
  "tenant_name": "maya",
  "plan": "free",
  "api_key_last_4": "abcd",
  "usage_storage_bytes": 1048576,
  "plan_storage_limit_bytes": 1073741824,
  "usage_requests_month": 142,
  "plan_requests_limit_month": 10000,
  "active_links": 3,
  "max_active_links": 10,
  "rate_limit_sustained": 100,
  "rate_limit_burst": 200
}
The response is the canonical surface — the same payload is also available as the resource artifacta://whoami. The MCP server caches the api_key_last_4 so that a later authentication failure can include the key suffix in the remediation message (“Last-known key suffix: ****abcd.”).

Using Artifacta from your coding agent

Once whoami confirms auth, here are the four flows that cover most agent work. Paste any of these prompts into your coding agent — it will pick the right tool(s) on its own.

1. Save a generated file

“Save ./out/build_report.html to session build_2118 and tag it kind=report, status=green.”
The agent calls store_artifact with path: "./out/build_report.html", session_id: "build_2118", and metadata: { kind: "report", status: "green" }, then returns the new art_… id. Re-running the same prompt after a crash returns the same artifact instead of creating a duplicate — the MCP server auto-injects an Idempotency-Key and surfaces it on success as _meta.idempotency_key. Local file paths must clear path confinement.

2. Find prior work

“Show me the test outputs from session ci_run_42 tagged kind=failure, newest first.”
The agent calls list_artifacts with session_id: "ci_run_42" and metadata: { kind: "failure" }. Results come back in created_at DESC, artifact_id DESC order — the API’s only sort contract — with opaque cursor pagination if the list is long.

3. Hand a file to a human

“Publish a 24-hour share link for artifact art_a1b2c3d4e5f6g7h8.”
The agent calls create_download_link with expires_in: 86400, then prints the resulting https://dl.artifacta.io/lnk_… URL. On Claude Desktop, Cursor, Claude Code, and Codex this requires --allow-destructive in the launch args — without it the tool is hidden from tools/list. get_artifact_download_url is not a substitute: that returns a private 1-hour presigned URL for the authenticated caller, not a shareable public link.

4. Resume a session across runs

“Re-open session nightly_eval_2026_05_25, list its artifacts, and append today’s run output from ./eval/out.jsonl.”
The agent calls list_artifacts with the session id, then store_artifact with the same session_id to append. Sessions are user-defined strings supplied at upload — there is no separate create_session tool, and the session row appears the first time an artifact is stored against that id. Subsequent runs just keep writing to the same string.

Write tools

v0.2 added four write tools and one preview resource so an agent can produce, persist, and share artifacts end-to-end. They are unchanged in v1.0.
ToolWhat it doesIdempotency / retry
store_artifactCreate an artifact from inline content or a local path.Auto Idempotency-Key; safe to replay.
request_upload_urlMint a presigned R2 upload URL for files larger than store_artifact’s 500 MB ceiling. Pro-only — Free-tier keys receive quota_exceeded with an upgrade URL.Non-idempotent — no auto-retry on 5xx.
complete_uploadFinalize a presigned upload into a committed artifact.Idempotent — auto-retries 5xx.
create_download_linkMint a public dl.artifacta.io/lnk_… share link.Non-idempotent; consent-gated.
The companion artifacta://artifact/{id}/bytes resource exposes an artifact’s bytes inline for preview. See Resources for the full resource surface, including the 100 MB cap behavior.

A note on sessions

session_id is a user-defined string supplied at upload time (store_artifact.session_id, or carried through request_upload_urlcomplete_upload). There is no separate create_session tool — a session row appears the first time an artifact is stored against that id, and surfaces in list_sessions and artifacta://session/{session_id} from that point on. Sessions can be sealed with seal_session (v1.0 — irreversible, no unseal). Once sealed, further uploads against that session_id are refused at the API layer with session_sealed. list_sessions and artifacta://session/{session_id} continue to report is_sealed for read-only visibility. See Destructive tools for the full description and the autonomy-boundary gating that protects the call.

store_artifact: content vs path

store_artifact accepts exactly one of two inputs:
  • content — the bytes inline, base64-encoded, up to 10 MB decoded. Best for small, in-memory results (a generated report, a JSON blob).
  • path — a path to a local file, streamed to the API as multipart, up to 500 MB. Best for files already on disk. The path must pass path confinement. For files larger than 500 MB, switch to request_upload_urlcomplete_upload — note that path is Pro-only; Free-tier keys receive quota_exceeded with an upgrade URL, so on Free store_artifact.path is the upload ceiling.
See Save a generated file above for an end-to-end prompt example using path.

Path confinement and --allow-path

store_artifact.path reads files from the local filesystem, so it is guarded by the path-confinement engine:
  • Default allow-list: the directory the MCP server was launched in (its working directory). A path outside it is refused.
  • Extend it with one or more --allow-path=<dir> launch flags:
claude_desktop_config.json
{
  "mcpServers": {
    "artifacta": {
      "command": "npx",
      "args": ["-y", "@artifacta-mcp/mcp", "--allow-path", "/Users/you/project/out", "--allow-destructive"],
      "env": { "ARTIFACTA_API_KEY": "ak_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
    }
  }
}
Both --allow-path and --allow-destructive belong in the same args array when you need local file uploads and public share links.
  • The deny-list always wins, even inside an allow-listed directory: ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/.kube, ~/.netrc, ~/.artifacta, /etc, ~/Library/Keychains, and any credentials.json or .env* file are refused. Symlinks are resolved with realpath() before the check, so a symlink pointing outside the allow-list (or into the deny-list) is refused after resolution. Sockets, FIFOs, and device files are refused.
--allow-path only accepts absolute paths; a relative value exits at startup with code 2. The CLI flag is not inferred from a config-file field, but the server also appends roots from the ARTIFACTA_MCP_ALLOW_PATH environment variable (colon-separated absolute paths) when present in the launched server’s env block — that env var widens the allow-list at startup the same way --allow-path does, so audit it whenever you review who can read local files through store_artifact.path.

Ambiguous completion: when a write may or may not have happened

request_upload_url and create_download_link are non-idempotent — the API does not honor an Idempotency-Key on them. So when one returns a 5xx or the network drops, the MCP server makes exactly one attempt and returns guidance instead of silently retrying:
The request may or may not have completed. Do not retry blindly — verify current state first (e.g. list links / list artifacts) or escalate to a human.
This is deliberate: a blind retry could mint a second public download link or a duplicate upload slot. The correct agent behavior is to verify or escalate, not retry. (store_artifact and complete_upload, which are idempotent, do retry 5xx automatically — a replay is safe there.) create_download_link produces a public URL, so it is classified destructive for consent purposes:
  • Clients that advertise experimental.confirmations receive requiresConfirmation: true and prompt the human before the call runs.
  • Claude Desktop and Cursor do not advertise confirmations. Without --allow-destructive in the launch args, create_download_link is omitted from tools/list entirely — see Claude Desktop & Cursor: public share links for the recommended install config.
  • Other clients that do not advertise confirmations behave the same: the tool stays hidden unless the server was launched with --allow-destructive (and each such call then emits a one-line stderr audit). This prevents an agent from silently leaking a shareable URL.

Destructive tools

v1.0 adds two destructive tools. They share the same consent surface as create_download_link: filtered from tools/list for non-compliant clients (unless --allow-destructive is set), and carrying requiresConfirmation for compliant ones. See Autonomy boundary for the full matrix.
ToolWhat it doesReplay behavior
delete_artifactSoft-delete an artifact by id (DELETE /v1/artifacts/{artifact_id}).A second call on an already-deleted artifact returns { artifact_id, deleted: true, already_deleted: true } rather than an error — safe to retry.
seal_sessionMark a session irreversible (no unseal) so further uploads against that session_id are refused.A re-seal returns the existing sealed_at — passthrough at the API.
Both are classified destructive and follow the autonomy boundary below. Neither injects Idempotency-Key (the API gates injection to POST /v1/artifacts only); both use the idempotentWrite retry policy (429 once, 5xx up to 3× with jitter) because each operation is naturally idempotent.

Example agent prompts

“Delete artifact art_a1b2c3d4e5f6g7h8 — it has the wrong session id and I am going to re-upload it under build_2118.”
The agent calls delete_artifact with artifact_id: "art_a1b2c3d4e5f6g7h8", then re-runs store_artifact with the right session_id. On a compliant client the host prompts before the delete fires; on Claude Desktop / Cursor the agent prints its plan and waits for chat confirmation, then dispatches the call (--allow-destructive must be in the launch args).
“Seal session nightly_eval_2026_05_25 — the run is finished and I don’t want any further uploads against that id.”
The agent calls seal_session with session_id: "nightly_eval_2026_05_25". After the call, list_sessions reports is_sealed: true and any further store_artifact against that session id receives session_sealed.

Autonomy boundary

The MCP server filters and prompts for tools based on the client’s declared capabilities in initialize. Three tools are classified destructive: create_download_link, delete_artifact, seal_session. The matrix:
ClientDefault tool listrequiresConfirmationWith --allow-destructive
Compliant (advertises experimental.confirmations — e.g. Claude Code)Destructive tools present.Set to true on each destructive tool; the host prompts the human before the call.No change in surface; the flag is unused (the confirmation UI is already intact).
Non-compliant (no experimental.confirmations — Claude Desktop, Cursor, Codex, most others today)Destructive tools absent from tools/list. The agent cannot call them.Not applicable.Destructive tools appear in tools/list. Each call emits a one-line stderr audit [artifacta-mcp] destructive call: <tool>(<args>) — no host UI confirmation.
Other rules that bind the flag:
  • --allow-destructive is never read from the environment or mcp.toml — it must be in the per-launch CLI args. This prevents a leftover env export from silently unlocking destructive tools.
  • The ARTIFACTA_MCP_REQUIRE_WRITE_CONFIRM=1 env override promotes requiresConfirmation on the four write tools (store_artifact, request_upload_url, complete_upload, create_download_link) for compliant clients that want a stricter surface. It does not affect destructive tools — those always require confirmation on compliant clients.
  • On compliant clients, create_download_link is destructive too — the host prompts before each share-link mint. The same one-line stderr audit still emits when --allow-destructive is the only reason a tool was exposed.

Security model

A consolidated reference for the four security mechanisms the MCP server relies on.

1. Path confinement

Applies to: store_artifact.path (the only tool that reads local files).
  • Default allow-list = server CWD. Extend with --allow-path=<absolute-dir> (relative paths exit at startup with code 2; the flag is never read from the environment).
  • Deny-list always wins: ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/.kube, ~/.netrc, ~/.artifacta, /etc, ~/Library/Keychains, any credentials.json, any .env*.
  • Symlinks are resolved via realpath() before allow-list and deny-list checks. Special files (sockets, FIFOs, devices) are refused.
  • 500 MB ceiling per file, regardless of plan tier. >500 MB → use request_upload_urlcomplete_upload.
See Path confinement and --allow-path for configuration examples.

2. Idempotency-Key auto-injection

  • POST /v1/artifacts (the store_artifact endpoint) — the only endpoint that auto-injects an Idempotency-Key. The MCP server attaches mcp_<uuid4> unless the caller passes their own idempotency_key. The effective key is surfaced on success as _meta.idempotency_key.
  • Every other write endpoint — request_upload_url, complete_upload, create_download_link, delete_artifact, seal_session — does not inject. complete_upload, delete_artifact, and seal_session are naturally idempotent at the API layer (replays return the existing record). request_upload_url and create_download_link are non-idempotent; see ambiguous-completion below.

3. Retry policy

Per plan §6.1, retries are tied to backend idempotency:
ToolRetry policy5xx auto-retry?Idempotency-Key injected?
whoami, list_artifacts, get_artifact, get_artifact_download_url, list_sessionssafeYes (3× w/ jitter)n/a (GET)
store_artifactidempotentWriteYes (3× w/ jitter)Yes
request_upload_urlnonIdempotentWriteNo (1 call, then §6.1 ambiguous-completion text)No
complete_uploadidempotentWriteYes (3× w/ jitter)No (natural idempotency)
create_download_linknonIdempotentWriteNo (1 call, then §6.1 ambiguous-completion text)No
delete_artifact, seal_sessionidempotentWriteYes (3× w/ jitter)No (natural idempotency)
429 across the board: retried once with the Retry-After header value if present, otherwise jittered backoff. The 3-consecutive-failure outage notifier writes a single Artifacta API unreachable… line to stderr after the third sequential transport-level failure and resets on the next success.

4. Destructive-tool gating

See Autonomy boundary. One-paragraph summary: tools classified destructive (create_download_link, delete_artifact, seal_session) are hidden from non-compliant clients unless the per-launch --allow-destructive flag is set, and carry requiresConfirmation: true for compliant clients. Each call emits a one-line stderr audit when the flag is the reason the tool was exposed without a confirmation surface.

Resources

In addition to tools, the MCP server exposes four resource URIs. Hosts that prefer the resource model — or want to surface Artifacta data in a side panel without firing a tool call — can read these directly.
URIReturnsNotes
artifacta://whoamiSame payload as the whoami tool.Cheap; safe to poll.
artifacta://artifact/{artifact_id}Same metadata body as get_artifact.Tenant-internal fields (tenant_id, deleted_at) are stripped at the MCP boundary.
artifacta://artifact/{artifact_id}/bytesInline bytes (text or blob, routed by content type).Hard-capped at 100 MB — see size cap below.
artifacta://session/{session_id}Aggregate view of a session’s artifacts + seal state.Read-only; sessions cannot be sealed in v0.2 (see A note on sessions).

…/bytes size cap

The bytes resource is hard-capped at 100 MB. Exactly 100 MB inline is allowed; 100 MB + 1 byte is refused. Oversize requests fail at the MCP resources/read layer with an InvalidRequest error — not a tool error envelope — whose message steers the agent to get_artifact_download_url (which mints a private 1-hour presigned URL for the authenticated caller; use create_download_link only if a public, shareable URL is required). Two refusal variants exist, both returning the same InvalidRequest class:
  • Metadata gate — caught from the artifact’s recorded size with a single get_artifact call, so an over-cap fetch never touches R2.
  • R2 oversize gate — backstop in case the metadata size under-reports the actual blob size on disk.
Agents should branch on the InvalidRequest error class and reissue the read as a get_artifact_download_url tool call; the resource cannot be widened with a flag.

Troubleshooting

unauthorized on every call

The MCP server surfaces an unauthorized error when the API rejects the configured key. Common causes:
  1. ARTIFACTA_API_KEY is not set in the MCP host’s environment. Editing your shell’s .zshrc does not propagate to Claude Desktop or Cursor — they read the env block from your mcpServers config. Put the key directly in claude_desktop_config.json or ~/.cursor/mcp.json and restart the host.
  2. The key was rotated. The remediation message includes the last-known key suffix (Last-known key suffix: ****abcd). If that suffix does not match the key you currently have in the dashboard, regenerate or paste the new key into the host config.
  3. The key is malformed. Keys must match ak_live_ plus 32 alphanumeric characters. The server exits at startup with code 2 if the shape check fails — check the host’s stderr log for the rejection message.
  4. The tenant is in deletion grace period. The server replaces the generic remediation with "Account is scheduled for deletion — see https://app.artifacta.io/dashboard/account." Restore the account from the dashboard before the grace period ends.
If none of those apply, capture the failing response — every error result carries a request_id in _meta.request_id — and contact support with that id.

Destructive tools missing from tools/list

If create_download_link, delete_artifact, or seal_session is missing while every other Artifacta tool appears, you are likely on Claude Desktop, Cursor, or another non-compliant client without --allow-destructive in the launch args. Those hosts do not implement MCP write confirmations, so the server hides destructive-classified tools by default. See Autonomy boundary for the matrix. For create_download_link specifically: get_artifact_download_url is not a substitute — it returns a time-limited presigned URL for the authenticated caller, not a public share link. Add "--allow-destructive" to the args array (alongside --allow-path if you use local file uploads), restart the host, and confirm the tool appears. See Claude Desktop & Cursor: destructive tools.

tools/list shows nothing

Make sure the host launched the server. Common causes:
  • npx could not resolve @artifacta-mcp/mcp (no network, expired npm cache). Run npx -y @artifacta-mcp/mcp --version from a shell to reproduce.
  • The host is running on Node 18 or older. The package’s engines.node is >=20.0.0; the npm install step refuses to run on older Node.

Path arguments are refused even though the file exists

The local path-confinement engine refuses any path outside the server’s allow-list (default: the host’s working directory) and refuses paths inside the built-in deny-list (~/.ssh, ~/.aws, ~/.config/gh, /etc, …) even when the allow-list is widened. Pass --allow-path=/your/dir at launch to extend the allow-list, but the deny-list always wins. This guards the store_artifact path argument (v0.2). See Path confinement and --allow-path for the full deny-list and configuration examples.

What’s next