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 agent | It 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 year | kaiten_update_instance(instance="ninja-osaka-prod", plan="premium", extend_license_days=365) |
| Give Starter 20 more menu items, without touching existing customers | kaiten_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:
- A tool expresses an intent, not an endpoint.
kaiten_provision_instanceresolves 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. - 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. - Writes merge, and report what happened. Only what the agent passes changes. Every write answers with a
status—created,updated,unchanged,recorded,rejected,preview, ordeleted— and the exactchanges, read from what Kaiten holds afterwards. A usage report past a hard cap, or a targeting rule that does not compile, answersrejectedand writes nothing. - Trace before change. A write that reaches other resources says so:
affected_instanceswhen a License version is edited in place, the zone's Instances when a release is deployed.kaiten_deleteanswers with apreviewof what it would remove until it is called again withconfirm=true. - 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
| Area | Read | Write |
|---|---|---|
| Orientation | kaiten_overview · kaiten_search | |
| Customers and Instances | kaiten_get_customer · kaiten_get_instance · kaiten_list_instances | kaiten_save_customer · kaiten_provision_instance · kaiten_update_instance |
| Usage | kaiten_get_usage | kaiten_report_usage |
| Catalog and Licenses | kaiten_get_catalog | kaiten_save_entitlement · kaiten_save_license · kaiten_set_license_state |
| Feature flags | kaiten_get_flags · kaiten_evaluate_flags · kaiten_test_rule | kaiten_save_flag |
| Releases | kaiten_get_deployments | kaiten_create_release · kaiten_deploy_release · kaiten_save_deployment_zone |
| Access and audit | kaiten_get_access · kaiten_get_audit_trail | kaiten_issue_token · kaiten_revoke_token |
| Settings | kaiten_get_metadata_fields · kaiten_get_connectors | kaiten_save_metadata_field · kaiten_configure_connector |
| Deletion | kaiten_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.
- In the console, open Integrations → Service Accounts and click Create Service Account — name it
MCP, for instance. - 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 ownAuthorization: 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.2The 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.2The 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.
| Variable | Default | |
|---|---|---|
KAITEN_API_BASE_URL | http://localhost:6060/api | The 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_ONLY | false | Register the 15 read tools only; also --read-only |
MCP_HOST / MCP_PORT | 0.0.0.0 / 8000 | The 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_TIMEOUT | 30 | Seconds 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_usagereturns seven rows at 80% of their limit or more. Ninja Osaka'sninja-osaka-prodhas reached its caps on menu items (5 of 5) and locations (1 of 1), with 18 of its 20 monthly orders used; Sakura Tokyo'ssakura-tokyo-demohas reached its location cap; Kappa Kyoto'skappa-kyoto-prodruns 5 of 5 delivery drivers, with an allowance up to 6. - Why doesn't Sakura see the analytics dashboard? —
kaiten_evaluate_flagsanswers thatanalytics-dashboard-enabledserves its default,off, and reports its rule underbroken_rules: the rule readsorderCount, which the evaluation context lacks. Withcontext={"orderCount": 14}, the same call answerson,TARGETING_MATCH— the context your product sends when it evaluates the flag.
When it does not work
| Symptom | What it means |
|---|---|
A tool answers No Kaiten credential | The 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 connect | KAITEN_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 exist | Restart the client: most keep the tool list they read at startup |
Where to go next
SDKs
The official Kaiten SDKs — the Go client, the Python client, and the two @kaitencloud TypeScript packages — how each one is built, what it covers, which credential it carries, and OpenFeature for flag evaluation. Setup lives in each repository.
Overview
Run the Community Edition on your own infrastructure — what the stack contains, what differs from Kaiten Cloud, and where each operator page sits.