Kaiten

Developer Resources

MCP Server

The open-source MCP server that lets an AI agent run Kaiten — 31 tools, each an intent in Kaiten's vocabulary, acting with the caller's own token. Setup for Claude Code, Claude Desktop, Cursor, and VS Code.

The Kaiten MCP server lets an AI agent — Claude, Cursor, Copilot, any Model Context Protocol client — run Kaiten from a conversation: onboard Customers, provision Instances, shape Licenses and entitlements, meter usage, target feature flags, and ship releases. It is open source (Apache-2.0), in its own repository, kaitencloud/mcp, and works with every edition: it calls the same API your product does.

Ask the agentIt calls
Which customers are close to a limit?kaiten_get_usage(min_percent=80)
Why doesn't Sakura see the analytics dashboard?kaiten_evaluate_flags(instance="sakura-tokyo-prod")
Move Ninja Osaka to Premium and renew it for a yearkaiten_update_instance(instance="ninja-osaka-prod", plan="premium", extend_license_days=365)
Give Starter 20 more menu items, without touching existing customerskaiten_save_license(new_version_of="starter", grants={"menu-items": 25})

How it works

The server is a client of the Kaiten API, built on the official Python SDK. Its design follows five rules:

  1. A tool expresses an intent, not an endpoint. kaiten_provision_instance resolves a License family to its current version, finds the deployment zone, creates the Customer if asked, and sets the License term. Every tool takes slugs; the agent never handles an id.
  2. Reads return slices. A resource comes back with the fields that carry meaning, named by slug, and usage already set against its limit: used, limit, percent, state.
  3. Writes merge, and report what happened. Only what the agent passes changes. Every write answers with a status — created, updated, unchanged, recorded, rejected, preview, or deleted — and the exact changes, read from what Kaiten holds afterwards. A usage report past a hard cap, or a targeting rule that does not compile, answers rejected and writes nothing.
  4. Trace before change. A write that reaches other resources says so: affected_instances when a License version is edited in place, the zone's Instances when a release is deployed. kaiten_delete answers with a preview of what it would remove until it is called again with confirm=true.
  5. The agent acts as its token. The server holds no credential of its own: each request carries the caller's ksh_ token, so each tool runs with that token's scopes, and every change it makes is recorded in the audit trail under the token's service account.

The tools

AreaReadWrite
Orientationkaiten_overview · kaiten_search
Customers and Instanceskaiten_get_customer · kaiten_get_instance · kaiten_list_instanceskaiten_save_customer · kaiten_provision_instance · kaiten_update_instance
Usagekaiten_get_usagekaiten_report_usage
Catalog and Licenseskaiten_get_catalogkaiten_save_entitlement · kaiten_save_license · kaiten_set_license_state
Feature flagskaiten_get_flags · kaiten_evaluate_flags · kaiten_test_rulekaiten_save_flag
Releaseskaiten_get_deploymentskaiten_create_release · kaiten_deploy_release · kaiten_save_deployment_zone
Access and auditkaiten_get_access · kaiten_get_audit_trailkaiten_issue_token · kaiten_revoke_token
Settingskaiten_get_metadata_fields · kaiten_get_connectorskaiten_save_metadata_field · kaiten_configure_connector
Deletionkaiten_delete

kaiten_overview is the intended first call. Each tool's description and input schema, which the client reads from the server, are the reference for its arguments. In those arguments, plan names a License family — an Instance moves to its current version — and license an exact License version.

Get a token

The server needs a service-account token, ksh_…, for the organization the agent works in.

  1. In the console, open Integrations → Service Accounts and click Create Service Account — name it MCP, for instance.
  2. On the service account, click Generate Token, give the token the scopes the agent should hold, then Create Token and Copy token. The token is shown once.

read:* suits an agent that only looks; write:* lets it operate, reads included. Anything narrower is a set of per-resource scopes — the scopes page lists them, and authentication covers the token's lifecycle.

The agent can do everything its token can. Give each agent a token of its own, with the least it needs, so that revoking one — from the console, or DELETE /service-accounts/{serviceAccountSlug}/tokens/{tokenSlug} — cuts off exactly one client. A server started read-only registers the read tools alone, whatever its token allows.

Run the server

The server speaks both standard MCP transports:

  • stdio — your client starts the server on your machine. The token comes from KAITEN_API_TOKEN.
  • Streamable HTTP, at /mcp — a server you run for one or several clients. Each request brings its own Authorization: Bearer ksh_… header, which the server forwards to Kaiten untouched.

KAITEN_API_BASE_URL points it at your organization's API. Kaiten Cloud does not host the server yet Coming soon: run it yourself, against Kaiten Cloud or your own stack.

# stdio
KAITEN_API_BASE_URL=https://app.kaiten.sh/api KAITEN_API_TOKEN=ksh_... uvx kaitencloud-mcp stdio

# Streamable HTTP, on http://localhost:8000/mcp
docker run -p 8000:8000 -e KAITEN_API_BASE_URL=https://app.kaiten.sh/api ghcr.io/kaitencloud/kaiten-mcp:0.2

The default base URL, http://localhost:6060/api, is your stack's gateway. Inside a container, localhost is the container itself: reach the gateway through the host.

# stdio
KAITEN_API_TOKEN=ksh_... uvx kaitencloud-mcp stdio

# Streamable HTTP, on http://localhost:8000/mcp
docker run -p 8000:8000 --add-host host.docker.internal:host-gateway \
  -e KAITEN_API_BASE_URL=http://host.docker.internal:6060/api ghcr.io/kaitencloud/kaiten-mcp:0.2

The gateway itself has no /mcp route: the MCP server runs next to it, and clients call the server.

The package is kaitencloud-mcp, run here with uv's uvx; the image is ghcr.io/kaitencloud/kaiten-mcp. A package named kaiten-mcp on PyPI belongs to an unrelated project.

VariableDefault
KAITEN_API_BASE_URLhttp://localhost:6060/apiThe API the tools call: https://app.kaiten.sh/api on Kaiten Cloud, your stack's gateway on the Community Edition
KAITEN_API_TOKEN—The token for stdio, or for an HTTP request that brings none
KAITEN_MCP_READ_ONLYfalseRegister the 15 read tools only; also --read-only
MCP_HOST / MCP_PORT0.0.0.0 / 8000The HTTP listener
MCP_ALLOWED_HOSTS / MCP_ALLOWED_ORIGINS—Comma-separated allowlists for the HTTP transport's Host and Origin check. Without them, the check applies only when the server is bound to localhost
KAITEN_API_TIMEOUT30Seconds per API call

Connect a client

The snippets use Kaiten Cloud's base URL. On the Community Edition, leave KAITEN_API_BASE_URL out of a stdio configuration — its default is your stack — and point an HTTP one at the server you started.

Claude Code starts the server itself over stdio, or connects to a server you run over HTTP:

# stdio
claude mcp add kaiten \
  -e KAITEN_API_BASE_URL=https://app.kaiten.sh/api -e KAITEN_API_TOKEN=ksh_... \
  -- uvx kaitencloud-mcp stdio

# Streamable HTTP
claude mcp add --transport http kaiten http://localhost:8000/mcp \
  --header "Authorization: Bearer ksh_..."

claude mcp list checks the connection: each server reads Connected once it answers.

claude_desktop_config.json — in ~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows — starts local servers over stdio:

{
  "mcpServers": {
    "kaiten": {
      "command": "uvx",
      "args": ["kaitencloud-mcp", "stdio"],
      "env": {
        "KAITEN_API_BASE_URL": "https://app.kaiten.sh/api",
        "KAITEN_API_TOKEN": "ksh_..."
      }
    }
  }
}

Quit Claude Desktop completely and reopen it: the file is read at launch. A server over HTTP is added from Settings → Connectors instead.

.cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project, connects to a server over HTTP. Cursor reads the token from your environment with ${env:…}:

{
  "mcpServers": {
    "kaiten": {
      "url": "http://localhost:8000/mcp",
      "headers": { "Authorization": "Bearer ${env:KAITEN_API_TOKEN}" }
    }
  }
}

.vscode/mcp.json connects Copilot to a server over HTTP, and prompts for the token instead of storing it:

{
  "inputs": [
    { "id": "kaiten-token", "type": "promptString", "description": "Kaiten ksh_ token", "password": true }
  ],
  "servers": {
    "kaiten": {
      "type": "http",
      "url": "http://localhost:8000/mcp",
      "headers": { "Authorization": "Bearer ${input:kaiten-token}" }
    }
  }
}

Never commit a configuration that contains a token: read it from the environment or a prompt, as the Cursor and VS Code snippets do.

Verify

A server over HTTP reports its state on GET /health — here, started next to a Community Edition stack as above:

curl http://localhost:8000/health
{"status": "ok", "version": "0.2.0", "read_only": false, "api": {"url": "http://host.docker.internal:6060/api", "reachable": true, "status": 200}}

Then ask the agent something the Kaiten Sushi Shop dataset can answer, on a stack seeded with the demo profile:

  • Which customers are close to a limit? — kaiten_get_usage returns seven rows at 80% of their limit or more. Ninja Osaka's ninja-osaka-prod has reached its caps on menu items (5 of 5) and locations (1 of 1), with 18 of its 20 monthly orders used; Sakura Tokyo's sakura-tokyo-demo has reached its location cap; Kappa Kyoto's kappa-kyoto-prod runs 5 of 5 delivery drivers, with an allowance up to 6.
  • Why doesn't Sakura see the analytics dashboard? — kaiten_evaluate_flags answers that analytics-dashboard-enabled serves its default, off, and reports its rule under broken_rules: the rule reads orderCount, which the evaluation context lacks. With context={"orderCount": 14}, the same call answers on, TARGETING_MATCH — the context your product sends when it evaluates the flag.

When it does not work

SymptomWhat it means
A tool answers No Kaiten credentialThe request brought no Authorization header, and the server has no KAITEN_API_TOKEN to fall back on
A tool answers Kaiten API error (401 Unauthorized) [ValidateToken.Invalid]Kaiten refused the token: it must be ksh_…, active, and not expired. The server forwards it without checking, so /mcp answers and lists the tools whatever the token
A tool answers Kaiten API error (403 Forbidden) [Auth.MissingScope]The token lacks the scope that operation needs, which the message names. Issue a token with that scope
Every call fails to connectKAITEN_API_BASE_URL must be the API as seen from the server — inside a container, not localhost. GET /health reports whether it answers
The client shows tools that no longer existRestart the client: most keep the tool list they read at startup

Where to go next

On this page