Skip to main content
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. Artifacta supports a hosted HTTP MCP endpoint and a local stdio package, 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. To store a conversation with store_artifact(..., transcript=true) and filter it with list_artifacts(..., transcript=true), see the session transcript guide.
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

Recommended for most users: the hosted MCP endpoint. Connect by URL — https://mcp.artifacta.io/mcp — and authenticate with a one-time browser login, no package install and no API key to copy. See Connect Claude Code (Hosted) or install the Codex plugin. The local stdio install below remains fully supported for CI, restricted networks, and explicit credential control—same Artifacta tools, different connection method.
The local stdio 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.4 — the stable contract; no further breaking changes to the existing 13 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
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
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
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:
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. For an end-to-end walkthrough of storing and sharing a build artifact this way, see the publish from Claude Code use case.

Codex plugin (hosted OAuth)

The Artifacta Codex plugin is the recommended Codex setup. It bundles the hosted OAuth MCP connection, persistence skills, and verified transcript capture:
No API key or local MCP process is required. Start a new thread after installation so Codex loads the plugin’s skills and hooks. Hosted OAuth permissions are enforced by the Artifacta server. Tools may remain visible when the current grant does not authorize them; an attempted call returns insufficient_scope with the required scope. The local --allow-destructive flag does not apply to the hosted plugin.

Codex (local stdio)

Codex (OpenAI CLI) reads MCP configuration from ~/.codex/config.tomlTOML, not JSON. Add an [mcp_servers.artifacta] table:
~/.codex/config.toml
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:
If that prints 1.0.4 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
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 hosted OAuth, this requires the artifacts:destroy grant. With the local stdio package, clients without MCP confirmations require --allow-destructive in the launch args. get_artifact_download_url is not a stable-link substitute: it returns a private one-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. 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.

store_artifact: attribution inputs

Alongside the payload, store_artifact accepts the attribution fields that feed listings and published-page receipts:
  • session_id — groups the artifact with others from the same run.
  • agent_id — defaults to the connected MCP client’s name (or "mcp") if omitted, so provenance is never blank.
  • model — the model that produced the content, stored as metadata.model unless that key is already set in metadata. Always pass it, using the exact model ID from your own context; if a subagent produced the artifact end-to-end, pass that subagent’s model, not yours. This is a declared producer claim — never describe it as a verified model. Published page receipts render metadata.model directly. For automatic capture from a Claude Code session transcript instead, see model capture.
  • metadata, ttl, transcript — as documented in the transcript guide and REST reference.

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
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 requires elevated consent:
  • On the hosted OAuth connection, the call requires artifacts:destroy. A lower-tier token receives insufficient_scope even if the tool remains visible.
  • Clients that advertise experimental.confirmations receive requiresConfirmation: true from the local stdio package and prompt the human before the call runs.
  • Claude Desktop and Cursor do not advertise confirmations. Without --allow-destructive in the local launch args, create_download_link is omitted from tools/list entirely—see Claude Desktop & Cursor: public share links for the recommended stdio config.
  • Other clients that do not advertise confirmations behave the same: the local 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. On local stdio 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. On hosted OAuth, all three operations require artifacts:destroy. See Autonomy boundary for both models. 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 asks the user to confirm, then calls delete_artifact with artifact_id: "art_a1b2c3d4e5f6g7h8" and confirm: true, then re-runs store_artifact with the right session_id. On a compliant client the host also 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). Without confirm: true the MCP tool rejects the call.
“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

For the local stdio package, 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 local-stdio matrix: The hosted OAuth connection and plugins do not use --allow-destructive. All registered tools may remain visible, while the server authorizes each call against the OAuth grant: artifacts:readartifacts:writeartifacts:destroy. The destroy tier authorizes public share links, soft deletion, and irreversible session sealing. A denied call returns insufficient_scope; logout and authenticate again to change the grant. 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: 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 authorization

See Autonomy boundary. On hosted OAuth, create_download_link, delete_artifact, and seal_session require artifacts:destroy; a lower-tier token receives insufficient_scope. With local stdio, those tools are hidden from non-compliant clients unless the per-launch --allow-destructive flag is set, and carry requiresConfirmation: true for compliant clients. Each local 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.

…/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 action unavailable

First identify the connection type:
  • Hosted OAuth or a plugin: The tool may appear but return insufficient_scope. Reauthorize and grant artifacts:destroy. In Codex, run codex mcp logout artifacta followed by codex mcp login artifacta. Do not add --allow-destructive; the hosted server does not read local launch flags.
  • Local stdio: If create_download_link, delete_artifact, or seal_session is missing while every other Artifacta tool appears, the host likely lacks MCP confirmation support and the server was launched without --allow-destructive. Add the flag to the launch args, restart the host, and confirm the tool appears. See Autonomy boundary for the local-stdio 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 stable public share link. On hosted OAuth, get_artifact_download_url is read-scoped while create_download_link requires artifacts:destroy.

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