VOLAT

Connect your AI tool to VOLAT

VOLAT never runs an agent or calls a model. Your own tool connects with a key, reads the plan and the rules, takes a ticket, reports back and asks for approval. Every example here uses a placeholder: never paste a real key into a repo, a ticket or a chat. What VOLAT can and cannot touch is on the trust page.

The address

MCP is one stateless streamable HTTP endpoint with JSON replies. There is no SSE and no session to keep alive. REST lives next to it under /api/v1.

MCP URL
https://mishka-kappa.vercel.app/api/mcp
REST base
https://mishka-kappa.vercel.app/api/v1
Auth
Authorization: Bearer mk_YOUR_KEY

Create a key

Each agent gets its own key, shaped mk_ followed by random characters and a checksum. VOLAT shows it once and keeps only a hash. A key carries scopes, can be limited to one app, and expires (90 days by default).

  1. Open Settings, Agents and keys in your workspace (the owner sees it) and add an agent.
  2. Choose its scopes, and an app if it should work on one app only. The default is below.
  3. Copy the key when it is shown. It will not be shown again.
  4. Put it in your environment, not in a file in a repo:
Shell
export MISHKA_KEY="mk_YOUR_KEY"

Running your own copy against a local database? npm run key:create -- --workspace demo --agent Claude prints a key once; add --scopes issues:write,docs:read or --app KID to narrow it.

Scopes

A scope is resource:level. Levels rise from read to write to admin, and a higher level includes the lower ones. * as the resource covers every resource. A key limited to one app cannot touch another app’s tickets or releases.

ResourceCovers
issuesTickets, the ticket lock, receipts and code status.
releasesReleases and their pre-release checklist.
commentsComments on tickets.
sessionsYour work sessions on tickets: steps, questions, pause, finish.
approvalsAsking Yan for approval. Deciding is for people only, whatever the scope.
docsPages, the decisions log and the agent rules.
ideasIdeas: capture, research, links to tickets and apps.
usageSpend reports and your own limits.
keysAsking for a new key or a scope change. Always goes through an approval.
metricsPushing business numbers per app (revenue, users, crashes, App Store status). REST only.
feedbackPushing App Store reviews, in-app feedback and emails per app, and drafting replies. VOLAT never sends a reply: you post it yourself, and asking a person first is an instruction, not something VOLAT enforces. REST only.
LevelMeans
readLook, never change.
writeIncludes read; create and change.
adminIncludes write; the few actions that change rules or other agents' work.

A new key gets these unless the owner says otherwise: issues:write, releases:read, comments:write, sessions:write, approvals:write, docs:read, ideas:write, usage:write. The reference lists the scope each action needs.

Set up your tool

One block per tool. The address above is already filled in. The config formats come from each tool’s own docs.

Claude Code

One command, once per machine.

Command
claude mcp add --transport http mishka https://mishka-kappa.vercel.app/api/mcp \
  --header "Authorization: Bearer ${MISHKA_KEY}" --scope user
Or .mcp.json in a project (the key stays in your environment)
{
  "mcpServers": {
    "mishka": {
      "type": "http",
      "url": "https://mishka-kappa.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer ${MISHKA_KEY}"
      }
    }
  }
}

Check Claude Code's MCP docs for the current format; this snippet has not been re-checked against them.

Hooks can ping VOLAT during long builds to keep ticket locks alive. See docs/connect-an-agent.md in the repo.

Claude Code MCP

Codex

~/.codex/config.toml

config.toml
[mcp_servers.mishka]
url = "https://mishka-kappa.vercel.app/api/mcp"
bearer_token_env_var = "MISHKA_KEY"

Check Codex's MCP docs for the current format. Codex also documents http_headers and env_http_headers for custom headers on streamable HTTP servers; bearer_token_env_var here is not re-checked.

Codex has no tool hooks yet. In a long build, call checkout with action ping now and then.

Codex MCP

Cursor

.cursor/mcp.json (one project) or ~/.cursor/mcp.json (everywhere)

mcp.json
{
  "mcpServers": {
    "mishka": {
      "url": "https://mishka-kappa.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:MISHKA_KEY}"
      }
    }
  }
}

Check Cursor's MCP docs for the current format and how it references environment variables.

Start Cursor from a terminal where echo $MISHKA_KEY shows the key. If VOLAT answers key_missing or key_malformed, Cursor is sending the ${env:...} text as it is.

Cursor MCP

Gemini CLI

~/.gemini/settings.json

settings.json
{
  "mcpServers": {
    "mishka": {
      "httpUrl": "https://mishka-kappa.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer mk_YOUR_KEY"
      }
    }
  }
}
Or one command (writes the same entry; add --scope user to use it everywhere)
gemini mcp add --transport http --header "Authorization: Bearer mk_YOUR_KEY" mishka https://mishka-kappa.vercel.app/api/mcp

Gemini CLI's docs describe variable expansion for the env block only, not for headers, so put your real key where mk_YOUR_KEY is and keep ~/.gemini/settings.json out of every repo.

Gemini CLI MCP

GitHub Copilot (agent mode in VS Code)

.vscode/mcp.json

mcp.json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "mishka-key",
      "description": "VOLAT agent key",
      "password": true
    }
  ],
  "servers": {
    "mishka": {
      "type": "http",
      "url": "https://mishka-kappa.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer ${input:mishka-key}"
      }
    }
  }
}

Check VS Code's MCP docs for the current format; this snippet has not been re-checked against them.

VS Code asks for the key once and keeps it out of the file.

VS Code MCP servers

Amp

One command.

Command
amp mcp add mishka --header "Authorization=Bearer ${MISHKA_KEY}" https://mishka-kappa.vercel.app/api/mcp

Check Amp's MCP docs for the current command and flags; this snippet has not been re-checked against them.

Amp stores the header in its own settings. Run the command from a shell where MISHKA_KEY is set.

Amp manual

Cline

cline_mcp_settings.json (Cline's MCP Servers panel, Configure; for the Cline CLI, ~/.cline/data/settings/cline_mcp_settings.json)

cline_mcp_settings.json
{
  "mcpServers": {
    "mishka": {
      "type": "streamableHttp",
      "url": "https://mishka-kappa.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Bearer mk_YOUR_KEY"
      },
      "disabled": false
    }
  }
}

Cline's docs do not say remote entries expand environment variables, so the key goes in this file. Keep the file out of every repo.

Cline MCP servers

Check it works

Ask your agent to call briefing with action: "today". You should get what changed, the releases by version, who holds which ticket and what waits on Yan. From a terminal, the same thing over REST:

curl
curl -sS https://mishka-kappa.vercel.app/api/v1/briefing \
  -H "Authorization: Bearer ${MISHKA_KEY}"

A session usually goes in three calls: briefing.today, then issue.start (takes the lock and returns the context pack), then issue.finish with a receipt when the work is done. The reference lists every tool and action.

When it says no

Refusals are typed and say what to do next. REST returns the code in error.code with the HTTP status below; MCP returns the same text.

CodeHTTPMeaningWhat to do
key_missing401No Authorization: Bearer header reached VOLAT.Check the header and the environment variable that fills it.
key_malformed401Not an mk_ key, or its checksum fails.Copy the whole key again.
key_unknown401VOLAT does not know this key.Ask for a new key.
key_expired401The key has expired (90 days by default).Ask for a new key.
key_revoked401The key was revoked.Ask for a new key.
key_paused403The owner paused this key (HTTP 403).Stop and tell Yan. Keep the same key; it works again once resumed.
key_check_failed503VOLAT could not check the key just now (HTTP 503). The call was refused and nothing changed.Retry once; if it repeats, tell Yan.
scope_denied403The key lacks the scope for that action, or it is limited to one app and the action writes workspace-wide docs. A key limited to one app gets not_found for anything of another app.Use a read action, or approval.request with type change_agent_permissions.
forbidden403This needs a person.Ask Yan, or request an approval.
not_found404No such ticket, release or page for this key.Check the identifier with issue.list or release.list.
invalid400An argument is missing or wrong.Fix the argument named in the message and call again.
rate_limited429Too many calls for this key.Wait for the retry-after header, or pause with a note.
budget_exceeded429The key's daily write budget is used up.Wait, or pause with a note.
loop_detected429The same call failed three times in a row.Change the approach; Yan has been flagged.
checkout_held409Another agent holds the ticket.Pick another ticket; the refusal names who holds it.
checkout_required409You must take the ticket first.Call issue.start or checkout.take.
release_frozen409The release is frozen.Ask for an approval instead of retrying.
undo_conflict409Later work touched the same thing, so undo would overwrite it.Leave it, or change it by hand.
conflict409Someone changed this first.Read it again, then retry.
receipt_required422Moving to review needs a receipt for the current commit.File issue.receipt (or use issue.finish).
finish_incomplete422issue.finish or release.close_tickets found several things missing; the message lists every one.Fix them all, then call issue.finish once more.
done_means_unmet422A done-means item has no evidence.Add the evidence to the receipt.
scan_blocked409The commit has an open high security finding, so it cannot be approved.Fix it and record a new issue.scan for the new commit, or ask Yan to accept the finding on the ticket.
approval_not_pending409The approval was already decided.Read it with approval.get.
approval_expired410The approval expired without a decision (HTTP 410).Do not go ahead. If still needed, approval.request again.
relation_cycle409That relation would make a ticket depend on itself.Pick a different relation.
person_only403A checklist item only a person can tick.Send release.tick with a note of what you checked; Yan ticks it from the note.
level_too_low403The ticket is harder than this key's level allows (MSH-208).Pick a ticket at or below your level (briefing.today can_take). Yan can let lower-level agents take this one.
difficulty_locked403Agents may raise a ticket's difficulty, never lower or clear it.Leave it, or ask Yan to change it.
not_ready409The release is not ready to ship.Read release.readiness for what blocks it.
internal_only409The release is internal only, so it is never shipped as public.Ship the next version, or clear internal_only with release.update.
release_focus409Agents work on the app's current release only (release focus, MSH-226); this ticket is in a later version, or has no release.Pick a ticket in the current release (briefing.today, GET /api/v1/tasks). Hotfixes are always open; Yan can allow a ticket early.
internal500VOLAT hit an unexpected error and changed nothing.Retry once; if it repeats, tell Yan.