---
title: "Krowk MCP server — upload files, get public URLs"
canonical_url: "https://krowk.com/docs/mcp"
last_updated: "2026-09-02T08:08:42.288Z"
meta:
  description: "krowk-mcp gives an agent six tools over MCP stdio: push a file and get a permalink, list and read artifacts, claim an anonymous upload. Pushes are confined to a root and refuse credential files."
  "og:description": "krowk-mcp gives an agent six tools over MCP stdio: push a file and get a permalink, list and read artifacts, claim an anonymous upload. Pushes are confined to a root and refuse credential files."
  "og:title": "Krowk MCP server — upload files, get public URLs"
---

**Docs**

# **An MCP server that uploads a file and returns a public URL**

krowk-mcp speaks the same API over stdio, for agents that cannot shell out. Six tools, both paste forms on every result, and pushes confined to a root.

[The CLI reference](https://krowk.com/docs/cli) [Security posture](https://krowk.com/security)

**Ships in the same install as the CLI. No account needed to push.**

`krowk-mcp` is the same client over MCP stdio, for agents that cannot shell out. It ships in the same install as the CLI — one script puts both binaries on the path.

It is a client, not a second implementation. No logic lives there that is not also in the CLI, and failures come back as tool results carrying the registry's own fix line rather than as transport errors, so the model can read the reason and correct the call.

## Setup

Claude Code: `claude mcp add krowk -- krowk-mcp`, or the equivalent in `.mcp.json`:

.mcp.json

```
{
  "mcpServers": {
    "krowk": {
      "command": "krowk-mcp",
      "env": { "KROWK_TOKEN": "krowk_sk_..." }
    }
  }
}
```

The token is optional. Without it, pushes are keyless: the link works immediately and expires 24 hours later, and `krowk_claim_artifact` is how it is kept. With it, uploads land in your workspace, runs are available and nothing expires.

`-root <dir>` sets the directory pushes are confined to; it defaults to the working directory. Set it deliberately when the server is started somewhere other than the checkout — see the next section for why it is not optional in spirit.

## Tools

- `krowk_push` — upload one or more files and get back the links plus both paste forms.
- `krowk_list_artifacts` — the workspace's uploads, newest first. Needs a key.
- `krowk_get_artifact` — read one artifact back, including its run metadata.
- `krowk_claim_artifact` — spend a claim token to keep an anonymous upload. Needs a key.
- `krowk_get_run` — a run and everything recorded on it.
- `krowk_verify_key` — which key this is and which workspace it acts in.

Every result carries both paste forms, labelled by destination, so the agent pastes what the tool it is writing into actually renders rather than guessing.

Declare, upload and finalize are deliberately *not* three separate tools. The upload step needs the local file, which an MCP client does not have — so the sequence stays behind `krowk_push`.

## Why the root matters more here

On the command line a person types the path. Over MCP the path is chosen by a model that has spent the session reading untrusted text — issue bodies, web pages, repository files. Anything pushed is readable without a credential, so an unbounded `krowk_push` would be an exfiltration channel with a tidy interface.

Four refusals follow from that: paths outside the root, symlinks that resolve outside it, files with more than one name, and credential files wherever they sit — including inside the root.

Each of those has a specific hole behind it, and a plain prefix check misses three of the four. The reasoning is set out in full on [the security page](https://krowk.com/security).

## **Add it once, and the agent has somewhere to put its output.**

No account for the first push. With a key the uploads land in your workspace and the links stop expiring.

[The CLI reference](https://krowk.com/docs/cli) [See the pricing](https://krowk.com/pricing)