# AI agents

seekrit speaks [MCP](https://modelcontextprotocol.io) through **two servers**, split
along the zero-knowledge line:

- **Hosted metadata server** — `mcp.seekrit.dev`. An agent authenticates *itself*
  (no human, no browser) and can explore and provision structure (orgs, apps,
  environments, groups, composition), read audit and billing, and manage keyless
  resources. No install.
- **Local crypto server** — `npx -y @seekrit/mcp` (or `seekrit mcp` if you already
  have the [CLI](/docs/reference/cli)). Runs on the agent's machine and does
  everything that touches a secret *value*: set/read secrets, create environments,
  mint and grant tokens, and run commands with secrets injected.

**One credential drives both.** An agent signs up once for a machine credential
(a client id + secret) and uses the *same* pair on both servers — the two share
the same org, so they compose: provision on the hosted server, encrypt on the
local one.

## Fastest path: install the plugin

If your agent supports [Agent Plugins](https://agent-plugins.org) — Claude Code,
Codex, Cursor, GitHub Copilot, Kiro, VS Code, ChatGPT, Gemini CLI — one command
installs both servers *and* the skills that teach an agent to keep values out of
files and shell history:

```bash
npx plugins add seekritdev/agent-plugin
```

See [Agent plugin](/docs/guides/ai-agents/plugin). The rest of this page is the
manual wiring, which is still the right route for a client the installer does
not know about, or when you want only one of the two servers.

## Why there are two

seekrit is zero-knowledge: secret values, data keys, and private keys never reach
the server. Decryption only ever happens where the credential lives. So anything
that produces plaintext — a secret value, a data key, a decryption-capable grant —
runs **on your machine**, on the local crypto server, next to your keys. The
hosted server serves only metadata and can *never* decrypt; it refuses service
tokens outright (they carry a private key). That division is the whole point of
seekrit, preserved.

## 1. Connect the hosted metadata server

Point your MCP client at the hosted server. **No credential is needed to
connect** — `initialize` and `tools/list` are open, so an agent can read the
server's instructions and its whole tool list before it has an account.

```jsonc
{
  "mcpServers": {
    "seekrit": {
      "type": "http",
      "url": "https://mcp.seekrit.dev/mcp"
    }
  }
}
```

Anonymously you get the guidance tools (`get_started`, `setup_local_crypto`,
`local_tool_for`) and `signup`. Everything else returns an error telling you to
call `signup` first.

## 2. Get a machine credential (once)

Call the **`signup`** tool — no human, no browser. Name the org for the **real
project or company** you're working on: `orgName` and `orgSlug` are both required,
and a human later claims the org by that name, so a placeholder like `test` makes
it unmanageable.

```jsonc
signup { "orgName": "Acme Storefront", "orgSlug": "acme-storefront" }
// → { org: { … }, credential: { clientId: "…", clientSecret: "…" }, sessionBound: true }
```

Signup mints a fresh organization (with no human member yet) and a machine client
bound to it with admin role, then **binds that credential to the current MCP
session** — so the metadata tools work on the very next call, with no config
change and no reconnect. Save the `clientSecret`: it is shown only once, and it's
what you need to reconnect later.

The same thing over plain HTTP, if you'd rather bootstrap outside MCP:

```bash
curl -sX POST https://mcp.seekrit.dev/signup \
  -H 'content-type: application/json' \
  -d '{"orgName": "Acme Storefront", "orgSlug": "acme-storefront"}'
# → { "org": { … }, "m2m": { "clientId": "…", "clientSecret": "…" } }
```

> **Note:** `orgSlug` is lowercase letters, numbers, and hyphens (e.g. `acme-storefront`); it's disambiguated automatically if already taken. `clientName` is optional. The organization starts memberless; a human joins later via invite (see [Handing off to a human](#hand-off-to-a-human)).

## 3. Reconnect with the credential

A session binding lasts for that session. To come back later — or to connect a
second client — authenticate with HTTP Basic auth, your client id and secret:

```jsonc
{
  "mcpServers": {
    "seekrit": {
      "type": "http",
      "url": "https://mcp.seekrit.dev/mcp",
      "headers": { "Authorization": "Basic <base64(clientId:clientSecret)>" }
    }
  }
}
```

The hosted server runs the OAuth 2.0 client-credentials exchange for you, so the
agent never manages token refresh. It gets the metadata tools: `whoami`, the
`list_*` discovery tools, `create_app` / `create_group` / `compose_group`,
`invite_member`, `audit`, `billing`, and keyless management (`revoke_token`,
`delete_secret`, `revoke_lease`, …) — including `list_secret_versions` and
`restore_secret`, so an agent can undo a bad write without ever holding a key
(a restore replays stored ciphertext; nothing is decrypted). It can't read or
set a secret value — for that it points you at the local server:

- `get_started` — the recommended first-project recipe, end to end.
- `setup_local_crypto` — how to add the local `@seekrit/mcp` server (with a
  copy-paste `.mcp.json`) so you can set and use secret values.
- `local_tool_for` — given a crypto operation, the exact local tool that does it.

## 4. Add the local crypto server (same credential)

Register the local server with your agent and give it the **same** machine
credential. On first use it mints a long-lived admin token from those credentials
automatically and caches it — minting is keyless (the keypair is generated
locally and only its public half is registered), so the machine credential is
enough. There's no token to copy between servers. `npx` fetches `@seekrit/mcp` on
first run, so no prior install is needed:

```jsonc
{
  "mcpServers": {
    "seekrit-local": {
      "command": "npx",
      "args": ["-y", "@seekrit/mcp"],
      "env": {
        "SEEKRIT_CLIENT_ID": "<your client id>",
        "SEEKRIT_CLIENT_SECRET": "<your client secret>"
      }
    }
  }
}
```

Already have the CLI installed? Use `seekrit mcp` as the command instead of
`npx -y @seekrit/mcp` — it's the identical server. Your credentials and keys stay
on this machine; they are never sent to the hosted server.

### As a container

For an agent sandbox with no Node toolchain, the server also ships as a
multi-arch Docker image — [`seekritdev/mcp`](https://hub.docker.com/r/seekritdev/mcp).
Register a stdio server that shells out to `docker run -i` — the `-i` is
required, since stdin is the MCP transport:

```json
{
  "mcpServers": {
    "seekrit": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "SEEKRIT_TOKEN",
        "-v", "${PWD}:/work",
        "seekritdev/mcp"
      ]
    }
  }
}
```

The bare `-e SEEKRIT_TOKEN` forwards the token from the client's own environment,
so it never lands in the config file. Mount a workdir at `/work` if you want
`run_command` to operate on your files (it runs *inside* the container). Pin a
release (`seekritdev/mcp:0.2.0`) or track `:edge`. The container still decrypts
locally — the credential and every plaintext stay inside it, never on a remote.

## Choosing the credential

The local server authenticates exactly like the CLI. Pick per what the agent
needs to do:

| Credential | Good for | Notes |
| --- | --- | --- |
| **Machine credentials** (`SEEKRIT_CLIENT_ID` + `SEEKRIT_CLIENT_SECRET`) | Fully autonomous agents — one credential for both servers | Auto-mints and caches an admin token on first use. Get them from signup. |
| **Admin token** (`--admin`) | A fixed headless credential for provisioning | Org-scoped; create apps/groups/envs, compose, grant, mint tokens. |
| **Runtime token** (bound to an env) | Reading/writing/injecting one environment's secrets | Self-decrypts — no passphrase. Cannot provision. |

Prefer a fixed admin token instead of machine credentials? Mint one and set
`SEEKRIT_TOKEN=skt_…`:

```bash
seekrit token create --name agent-session --admin
```

## Tools

The **local crypto server** exposes the full toolset below (the hosted server has
the keyless subset listed above). Tool names are the same on both.

> **Note:** Tool names may be prefixed by your client (e.g. `seekrit:create_app`).

- **Start** — `signup` (hosted) — a workspace and your own machine credential in
  one call, bound to the session; and `get_started` — the recommended
  first-project recipe, end to end.
- **Discover** — `whoami`, `list_orgs`, `list_apps`, `list_envs`, `list_groups`,
  `list_group_envs`, `list_env_groups`, `list_members`, `list_secrets`,
  `list_secret_versions`, `list_tokens`, `audit`.
- **Provision** — `create_org`, `create_app`, `create_group`, `create_env`,
  `create_group_env`, `compose_group`, `uncompose_group`.
- **Secrets** — `set_secret`, `get_secret`, `restore_secret`, `delete_secret`.
- **Tokens & access** — `create_token`, `revoke_token`, `grant_env`.
- **Use & wire up** — `run_command`, `export_env`, `configure_project`.

Every tool carries MCP annotations, so a client that honors them can let the
read-only ones (`list_*`, `whoami`, `audit`) run unattended while still prompting
before anything that removes or overwrites — `delete_secret`, `revoke_token`,
`export_env` (it writes a file), and `run_command` (it runs a command). The
annotations describe *modification*, not sensitivity: `get_secret reveal:true`
changes nothing and is marked read-only even though it returns plaintext, so keep
using the guidance above to decide when revealing is warranted.

## Use secrets without exposing them

Prefer **`run_command`**: it resolves the environment, injects the secrets into a
child process, and returns only the command's exit code and output — the secret
values never enter the agent's context.

`get_secret` returns metadata by default; it only decrypts the plaintext into the
response when you pass `reveal: true`. Reach for that only when the value itself
is the thing you need. Pass `version` to look at an earlier one.

Wrote a bad value? `list_secret_versions` shows the history and
`restore_secret` rolls it back — as a new version, so the rollback is itself
undoable. Both work on the hosted server too: replaying stored ciphertext needs
no key.

A `set_secret` value may contain `${OTHER_SECRET}`
[references](/docs/guides/references); they are stored literally and expanded
whenever the secret is read (including by `run_command` and `export_env`), so an
agent can wire a connection string together without ever reading its parts.

> **Warning:** Revealing a secret puts its plaintext in the agent's conversation, where it may be logged or retained. Use `run_command` (or `export_env` to a gitignored file) whenever the agent needs to *use* a secret rather than *read* it.

## A typical session

An agent, standing up a new service from scratch:

1. Connect to the hosted server with no credential, then call `signup` → machine
   credentials + a fresh org, already active for this session. Configure the local
   server with the same credentials.
2. On the hosted server: `create_app`, then (locally) `create_env` (production) —
   the data key is generated locally.
3. `set_secret` for `DATABASE_URL`, `API_KEY`, … (encrypted on this machine).
4. `create_token` bound to that env — a runtime token, auto-granted its keys.
5. `configure_project` to write `seekrit.json`, then hand the runtime token to CI
   or a container to run `seekrit run` / `seekrit-run`.
6. `run_command -- pnpm test` to verify the app boots with its secrets injected.

## Hand off to a human

The org an agent creates has no human member. So a person can take over — and so
nothing is lost if the agent disappears — do the handoff **before the agent stops
running**:

- `invite_member <email> role:owner` (hosted) — they sign in and own the org.
- `grant_env --user <email>` (local) — re-wrap each environment's data key to
  their key so they can actually decrypt. Only a current key-holder can grant.
- Optionally configure **recovery** (M-of-N custodians) locally, so access
  survives even if the agent's admin token is gone.

## Limits worth knowing

- **Capability doesn't escalate.** A runtime (member) token is denied every
  admin route; granting a token or user decryption requires the caller to already
  hold that environment's key, so access only propagates from an existing holder.
- **Signup is rate-limited.** It's the one unauthenticated entry point, so it's
  throttled per source and globally — a real agent's single signup is never
  affected.
