MCP (AI agent access)
kimbap exposes an MCP server over the
streamable-HTTP transport at /mcp, so any MCP-compatible AI agent or
assistant — Claude Code, claude.ai, ChatGPT, or anything else that speaks
the protocol — can manage the host directly. No local install required,
since it's just another authenticated HTTP endpoint on your running kimbap
instance. The examples below cover Claude Code and claude.ai concretely
since they're what this was built and tested against, but nothing here is
Claude-specific — see "Other MCP clients" for the general mechanism any
compliant client can use.
Creating an MCP API key
- Log in to kimbap, go to your user's API keys, and create one with scope
mcp(orboth, if you also want to use it against the REST API). - The raw key (
kbp_...) is shown once — copy it now.
Keys inherit their owning user's role. An admin-role user's MCP key can
call every tool; a member-role user's key can manage projects/domains but
is rejected by admin-only tools (install_docker, update_docker,
provision_traefik).
Connecting Claude Code
Add kimbap as a remote MCP server, passing the key as a bearer token header:
{
"mcpServers": {
"kimbap": {
"url": "https://admin.example.com/mcp",
"headers": { "Authorization": "Bearer kbp_..." }
}
}
}
(Exact config location/format depends on your Claude Code version — see Claude Code's own MCP documentation for where this goes.)
Connecting claude.ai
Add kimbap as a remote connector pointing at https://admin.example.com/mcp.
Bearer-token auth (the same header shown above) works with any MCP client
that supports custom headers on a remote connector.
claude.ai's own remote-connector UI doesn't accept a pasted bearer token —
it only speaks OAuth. For that (and any other OAuth-only MCP client), skip
the manual API key entirely: just point the connector at
https://admin.example.com/mcp with no credentials. kimbap is its own OAuth
2.1 Authorization Server and supports Dynamic Client Registration (RFC
7591), so the client registers itself on first connect.
Other MCP clients
Nothing above is Claude-specific — it's just the two connection styles most MCP clients use, and Claude Code/claude.ai happen to be worked examples of each:
- A remote connector that accepts a bearer token (ChatGPT's connector
UI, and most others): point it at
https://admin.example.com/mcpwithAuthorization: Bearer kbp_..., same as the Claude Code example above. - A remote connector that only speaks OAuth: point it at the same URL with no credentials — kimbap's Dynamic Client Registration handles the rest, same as the claude.ai example above.
Either way, the tool set and confirmation gating below are identical regardless of which agent is calling them.
OAuth self-registration
kimbap implements enough of the OAuth 2.1 + MCP auth spec to work as a zero-config Authorization Server for any compliant MCP client:
- Dynamic Client Registration (RFC 7591) — a client that's never seen
kimbap before registers itself via
POST /oauth/register; no admin has to pre-create anything. - Authorization code + PKCE (S256) — every client is a public client
(no
client_secretis ever issued); PKCE is required on every authorization request instead. "plain" PKCE and requests missing PKCE entirely are rejected. - A consent screen, every time — the flow always lands on a logged-in
kimbap user's
/oauth/consentpage ("‹client name› wants to access this kimbap instance as ‹you› (‹role›)"). There's no silent/automatic re-approval for a previously-seen client — every authorization is a deliberate click. - Discovery —
/.well-known/oauth-authorization-server(RFC 8414) and/.well-known/oauth-protected-resource(RFC 9728) are both served, and a request to/mcpwith no/invalid token gets aWWW-Authenticateheader pointing at the latter, so compliant clients can find their way through the whole flow with zero manual configuration.
Under the hood, an OAuth-issued token is a normal kimbap API key
(scope: mcp) — it's minted through the exact same path as one you create
by hand, shows up in that user's API key list, inherits that user's role,
and never expires (kimbap doesn't do refresh tokens; API keys don't expire
either way). Revoke one by deleting it like any other key.
Since the minted key inherits the approving user's role, an admin approving
a connection grants that client admin-level tool access (install_docker,
provision_traefik, etc.) — the consent screen says so explicitly. Approve
your own client-code-editor connections as yourself, not as a shared admin
account, if you want the audit log (oauth.approve/oauth.deny/
oauth.token_issued entries) to mean anything.
Available tools
| Tool | Description |
|---|---|
list_projects |
List every project, with desired state. |
get_project |
A project's details, current compose/env content, and live container status. |
create_project |
Create a project from compose/env content. Doesn't deploy it. |
update_project |
Overwrite a project's compose/env content. Doesn't redeploy. |
delete_project |
Stop and permanently delete a project. Requires confirm: true. |
deploy_project / start_project |
docker compose up -d — deploy fresh or apply pending changes. |
stop_project |
Stop containers without removing them. |
restart_project |
Restart containers. |
get_project_logs |
Recent log output, optionally for one service. |
list_domains / add_domain / remove_domain |
Manage a project's Traefik-routed domains. add_domain errors if Traefik is disabled (KIMBAP_TRAEFIK_ENABLED=false); list_domains/remove_domain still work either way. |
get_system_status |
Docker + Traefik installation/running status, plus traefikEnabled. |
install_docker / update_docker |
Install/update Docker on the host. Admin only, requires confirm: true. |
provision_traefik |
(Re-)provision kimbap's Traefik instance. Admin only, requires confirm: true. Errors if Traefik is disabled. |
list_registries / add_registry / remove_registry |
Manage saved Docker registry credentials (see Registries). add_registry/remove_registry are admin only, require confirm: true. |
list_audit_log |
Recent audit log entries (actions taken via UI, API, or MCP). |
Every tool is a thin adapter over the same service layer the REST API and web UI use — there's no separate MCP-only logic to drift out of sync, and every mutating tool call is recorded in the audit log just like its REST/UI equivalent.
Confirmation gating
Destructive or host-level actions (delete_project, install_docker,
update_docker, provision_traefik, add_registry, remove_registry) require an explicit confirm: true
argument. This exists specifically for the MCP surface: an LLM acting on a
loosely-worded request ("clean this up") shouldn't be able to trigger a
host-level action without a clear, deliberate confirmation step in the tool
call itself.