k0smos MCP Project Context
This document explains the k0smos MCP service in customer-facing terms. It can be shared with AI tools or implementation partners as project context when they need to understand what the service does, how to connect to it, and which safeguards govern tool access.
What The MCP Service Is For
k0smos exposes a hosted Model Context Protocol (MCP) endpoint so approved AI clients can inspect and act on tenant data through controlled tools. The MCP service is useful when a client wants an assistant such as ChatGPT, Claude Code, Hermes, IronClaw, OpenClaw, MCP Inspector, or another HTTP MCP-compatible agent to:
- list and inspect operational tickets;
- create or update tickets through existing k0smos business rules;
- list and inspect actionable tasks, move them through their configured workflow, and add attributed comments;
- inspect projects, folders, and project document metadata;
- query finance dashboards, accounts, transactions, budgets, bills, tags, categories, piggy banks, and spending reports;
- record or update finance transactions when the authenticated user has the required permission;
- conduct private Brainstorming discussions and discover, read or revise their permanent result plans, including after a discussion has ended.
The MCP endpoint is not a database export and not an unrestricted automation backdoor. It is a permission-gated API surface built on top of the same application services and ACL rules used by the k0smos admin UI.
Endpoint
Use the tenant API endpoint:
https://k0smos.example.com/api/mcp
Transport and protocol:
- Streamable HTTP, stateless.
- JSON-RPC 2.0.
POSTonly.- Supported methods:
initialize,ping,tools/list,tools/call, andnotifications/*. - No stdio, SSE, query-string credentials, URL tokens, or session IDs.
Prerequisites
Before a client connects:
- The tenant must be migrated.
- The MCP server must be enabled from
/admin/settings/mcp. - The connecting user must be active.
- The connecting user must have
mcp.use. - The connecting user must also have the permissions required by each tool they
should see or call, such as
ticket.view,project.edit, orfinance.create,todo.view, ortodo.edit.
Only active runtime modules contribute tools. If a module is disabled for a tenant, its MCP tools are not exposed.
Inspect and validate the exact active catalog without calling the HTTP endpoint:
php bin/console mcp:catalog --check
php bin/console mcp:catalog --check --format=json
The command and tools/list share the same catalog projection, preventing
drift in names, module ownership, permissions, annotations, and schemas.
Authentication Options
OAuth 2.1 For Interactive Clients
Use OAuth for ChatGPT and for clients that support remote MCP OAuth discovery. k0smos provides:
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-protected-resource |
MCP protected-resource metadata for /api/mcp. |
GET /.well-known/oauth-protected-resource/api/mcp |
RFC 9728 path-aware discovery alias for /api/mcp. |
GET /.well-known/oauth-authorization-server |
OAuth authorization-server metadata. |
GET /.well-known/openid-configuration |
OIDC-compatible discovery metadata. |
POST /oauth/register |
Dynamic client registration for public clients. |
GET /oauth/authorize |
Browser login and consent. |
POST /oauth/token |
Authorization-code + PKCE exchange and rotating refresh-token grant. |
GET/POST /oauth/userinfo |
OIDC UserInfo for openid identity checks. |
The current MCP authorization specification prefers a predefined client when available, then Client ID Metadata Documents (CIMD), and uses DCR as a fallback. k0smos deliberately advertises DCR and does not advertise CIMD support: Claude and the other supported clients can use DCR, so an outbound, SSRF-sensitive metadata fetch would add risk without a required compatibility benefit.
ChatGPT should be configured with OAuth or mixed authentication for private tenant data. Do not configure private or mutating k0smos tools as no-auth.
OAuth access tokens issued by k0smos start with k0s_oat_.... They are
short-lived, opaque, bound to the public client and tenant MCP resource, and
accepted only for the MCP endpoint and OIDC UserInfo. Clients that register the
refresh_token grant (or explicitly request offline_access) also receive a
k0s_ort_... refresh token so Claude, Hermes, IronClaw, OpenClaw, and other
persistent clients can renew access without another browser login.
Refresh tokens are stored only as hashes, expire after 30 days, rotate on every
use, and revoke the whole grant family when a consumed token is replayed.
Scoped Personal API Tokens For Header-Based Clients
Clients that can send an HTTP bearer header can use a scoped personal API token:
Authorization: Bearer k0s_pat_...
Create these tokens from /admin/settings/mcp where possible. Prefer the
"MCP tools only" scope and include only the permissions the client needs:
mcp.use ticket.view project.view finance.view
A scoped token cannot exceed the live permissions of the user who created it. If the user loses a permission, the token loses that permission too. Revoke or rotate tokens from the k0smos admin UI when a client should no longer connect.
Client Examples
ChatGPT
Use the tenant MCP URL:
https://k0smos.example.com/api/mcp
If advanced OAuth fields are requested, use:
Protected resource metadata:
https://k0smos.example.com/.well-known/oauth-protected-resource
Authorization server metadata:
https://k0smos.example.com/.well-known/oauth-authorization-server
OIDC UserInfo endpoint:
https://k0smos.example.com/oauth/userinfo
The OAuth client is public, uses no client secret, and uses PKCE S256.
Claude Code With A Static Bearer Token
claude mcp add --transport http k0smos https://k0smos.example.com/api/mcp \
--header "Authorization: Bearer k0s_pat_..."
Claude Code With OAuth
claude mcp add-json k0smos \
'{"type":"http","url":"https://k0smos.example.com/api/mcp","oauth":{"scopes":"mcp.use ticket.view project.view finance.view"}}'
claude mcp login k0smos
Claude And Claude Desktop Custom Connectors
Add https://k0smos.example.com/api/mcp from Settings → Connectors → Add
custom connector, then connect with OAuth. Claude supports Streamable HTTP,
DCR, PKCE, expiring access tokens, and refresh. Its current exact callback is:
https://claude.ai/api/mcp/auth_callback
The announced future-domain callback is accepted through the same exact-URI DCR validation:
https://claude.com/api/mcp/auth_callback
The automated HTTP-kernel interoperability contract registers both callbacks
and completes the full DCR → authorization/consent → PKCE exchange → UserInfo →
scope-narrowing refresh → MCP tools flow with the current claude.ai callback.
Set scopes deliberately. openid, profile, and email describe identity.
Tool access comes from mcp.use plus k0smos permission scopes such as
ticket.view, project.edit, or finance.create.
Hermes Agent
Static token:
mcp_servers:
k0smos:
url: "https://k0smos.example.com/api/mcp"
headers:
Authorization: "Bearer k0s_pat_..."
OAuth discovery, DCR, PKCE, persistence, and refresh:
mcp_servers:
k0smos:
url: "https://k0smos.example.com/api/mcp"
auth: oauth
Hermes derives OAuth scopes from server metadata. For strict least privilege, prefer a scoped PAT when the Hermes version in use does not expose an explicit OAuth scope override.
IronClaw
Static token:
ironclaw mcp add k0smos https://k0smos.example.com/api/mcp \
--header "Authorization:Bearer k0s_pat_..."
For OAuth, first register IronClaw's exact loopback callback. The port and path below are examples and must match the callback configured in IronClaw:
curl -sS -X POST https://k0smos.example.com/oauth/register \
-H 'Content-Type: application/json' \
--data '{"client_name":"IronClaw","redirect_uris":["http://127.0.0.1:8765/callback"],"token_endpoint_auth_method":"none","grant_types":["authorization_code","refresh_token"]}'
ironclaw mcp add k0smos https://k0smos.example.com/api/mcp \
--client-id k0s_oauth_client_... \
--scopes "mcp.use,ticket.view,project.view,finance.view"
ironclaw mcp auth k0smos
ironclaw mcp test k0smos
OpenClaw
Static bearer headers are supported, but OAuth avoids embedding a token in the saved server definition:
openclaw mcp set k0smos \
'{"url":"https://k0smos.example.com/api/mcp","transport":"streamable-http","auth":"oauth","oauth":{"scope":"mcp.use ticket.view project.view finance.view"}}'
openclaw mcp login k0smos
openclaw mcp doctor k0smos --probe
Keep transport set to streamable-http; OpenClaw otherwise may select its SSE
transport for a generic HTTP URL.
Tool Discovery
Clients discover available tools with tools/list. k0smos hides tools the user
cannot call, so the list is already filtered by:
- tenant MCP enablement;
- active module status;
- route-level
mcp.use; - per-tool ACL permission.
Each tool includes standard MCP fields:
name;title;description;inputSchema.
Where possible, k0smos also exposes metadata:
annotations: read-only, destructive, idempotent, and closed-world hints for safer client behavior.outputSchema: successful structured-result schema._meta.k0smos/module: contributing module._meta.k0smos/requiredPermission: ACL permission needed to call the tool._meta.k0smos/oauthScope: OAuth scope to request for the same authority._meta.k0smos/domain: functional domain such asticket,project, orfinance._meta.k0smos/resultShape: result envelope hint such asticket_collection,project_detail, orfinance_report.
These metadata fields help an AI client explain what it can do, ask for confirmation before risky actions, and request the least-privilege scopes needed for a session.
Current Tool Areas
| Area | Typical tools | Required permission family |
|---|---|---|
| Tickets | list, get, create, add comment, change status, assign, close | ticket.* |
| Projects | list, get, create, update, delete, folder CRUD, document metadata list/search | project.* |
| Tasks | bounded list, workspace detail, workflow move, attributed comment | todo.* |
| Finance | overview, lists, reports, record/update/delete transactions, move piggy-bank money | finance.* |
| Brainstorming | private discussion/workflow control, permanent plan discovery, full reading and revision writing | brainstorming.view, brainstorming.chat; execution also needs agent.run |
The exact tool list depends on the tenant's active modules and the authenticated user's permissions.
Brainstorming From Hermes Or Another MCP Client
The compact participant/worker/client setup guide is in
modules/Brainstorming/src/README.Brainstorming.md. Its connection check retains
runtime UI/Hermes qualification as operator guidance.
Enable Brainstorming and MCP for the tenant and grant the caller mcp.use.
Reading requires brainstorming.view; writing also requires
brainstorming.chat. Invoking an agent additionally requires agent.run, an
active default queue worker and configured, authenticated connectors. All access
is restricted to the authenticated owner's conversations and plans.
Hermes uses these tools through the same authenticated /api/mcp endpoint as
other clients. It does not attach to a native CLI session. Requests return durable
IDs promptly; poll for new messages and progress. The UI observes the same SQL
state and can intervene while Hermes is connected or after it disconnects.
| Tool | Purpose |
|---|---|
brainstorming_get |
With no ID, discover conversations and connector options. With conversation_id and cursor, read new messages. With execution_id, inspect workflow progress and its pinned result-plan reference. |
brainstorming_create |
Create an owned discussion with one to eight configured connector IDs. |
brainstorming_submit |
Send to selected recipients; during a workflow, save a pending intervention and pause advancement. |
brainstorming_plan_save |
Save a reusable discussion sequence; this does not start it or create a result document. |
brainstorming_plan_start |
Start a saved sequence or a hybrid/parallel-critique preset. |
brainstorming_control |
Pause, resume, advance, stop or explicitly continue with partial results using execution_id and expected_revision. A single run_id supports stop/retry. |
brainstorming_artifact_list |
Search permanent plans without a conversation ID; page using limit, offset and returned next_offset. |
brainstorming_artifact_get |
Read full Markdown and an exact or latest revision, provenance, review and human approval. before_revision instead pages revision history. |
brainstorming_artifact_save |
Write a plan or a new immutable revision as the authenticated external actor; never approve it or execute models. |
Example: Independent Answers, Individual Comparison, Permanent Plan
The following are tool names and their arguments objects, passed through the
client's normal tools/call operation. IDs are synthetic: use connector IDs
returned by discovery and opaque conversation/execution/artifact IDs returned by
the service.
-
Call
brainstorming_getwith{}to discover available connector IDs. Then callbrainstorming_create:{"title":"Release proposal","connector_ids":["connector_a","connector_b"]} -
Use the returned
conversation.idinbrainstorming_plan_start:{ "conversation_id":"11111111111111111111111111111111", "body":"Write a release plan with alternatives, risks and unresolved disagreements.", "participants":["connector_a","connector_b"], "preset":"hybrid", "mode":"moderated", "synthesizer":"connector_a", "review":true, "idempotency_key":"release-discussion-001", "sources":[{"id":"memory-note-17","label":"Selected Memory note","revision":"3","text":"The release must preserve existing integrations."}] }Both agents receive the same frozen analysis context without each other's answer. Hybrid comparison then addresses them individually in participant order.
parallel_critiqueinstead gives reviewers the same completed analyses. Selecting recipients controls who answers; it does not create a private message invisible to later shared phases. -
Poll
brainstorming_getusing the returned executionid:{"execution_id":"22222222222222222222222222222222"}To read the chat, call
brainstorming_getwithconversation_idandcursor: 0, then reuse its returned cursor whilehas_moreis true and for subsequent polls. Atawaiting_user, use the current execution revision and its allowed actions withbrainstorming_control:{"execution_id":"22222222222222222222222222222222","expected_revision":3,"action":"advance"}The number
3is illustrative; always use the returned current revision. Failed or truncated replies block successors. Retry the affectedrun_id, stop, or explicitly choosecontinue_partialwhen offered.automaticmode advances the finite sequence without manual phase approval; it has the same failure barriers and limits of twelve steps, thirty-two attempts and one hour. -
To intervene, call
brainstorming_submit:{"conversation_id":"11111111111111111111111111111111","body":"Include a rollback procedure.","recipients":["connector_a"],"idempotency_key":"release-intervention-001"}This pauses advancement and saves the instruction. Existing calls finish with their original prompts. Read the current execution revision, then
resumeto apply the pending instruction.stopalso cancels active/queued work. -
Completed execution returns
result_plan_idandresult_plan_revision. Read that exact document withbrainstorming_artifact_get:{"artifact_id":"33333333333333333333333333333333","revision":1}
Later, even in a new client session or after transcript deletion, discover it
with brainstorming_artifact_list using {"kind":"plan","query":"release"}.
Read/list operations invoke no model and need no worker. The full Markdown,
trusted provenance, immutable revision history and approval status remain in
tenant SQL with no completion expiry. Deleting a transcript never deletes its
plans; permanent plan deletion is a separate confirmed UI action.
Hermes can also write a plan directly with brainstorming_artifact_save:
{"title":"Release plan","kind":"plan","markdown":"# Release plan\n\n1. Verify compatibility.\n2. Deploy and monitor.","idempotency_key":"external-plan-001"}
To revise it, set artifact_id to the returned id and include the current expected_revision,
full replacement Markdown and a new idempotency key. Reusing a key with changed
content or editing a stale version returns a conflict. Documents are limited to
240,000 UTF-8 bytes and returned whole. Revision history is paginated separately;
before_revision cannot be combined with an exact revision. Document-only
writes need view/chat authority, but no agent.run. Approval is a separate human
UI action on an exact version; a new revision starts as a proposal.
Execution requires a bound personal token or OAuth access token, whose original scope, expiry and revocation remain effective after the initial HTTP request. Each later delegated intervention/advance can further narrow future work. Refreshing OAuth does not extend the authority of a workflow started with an expired access token. Tokens used only for document access need no execution scope. Private MCP bodies are excluded from generic diagnostics.
Permanent SQL storage requires no external Memory server. Selected Memory
excerpts can be supplied explicitly in sources, with IDs and revisions, and
are frozen once for all participants. Hermes can separately export a saved
version using its own configured Memory tools; direct server synchronization is
not implemented. Calendar scheduling and additional provider adapters are also
separate from these finite discussion sequences.
Custom synthesize and review steps require context_policy: previous_steps
(or its omitted default); analyses is rejected for those phases. The review must
receive the synthesis before its output can be attached to that plan revision.
Reusable definitions are revalidated at launch, and the MCP step schema declares
the same constraint. Completion also verifies that the frozen review input
contains the synthesis run identity. Legacy review input lacking it returns an
invalid_output execution state without attaching a review or losing the plan;
start a new execution to obtain a valid review.
Authenticated HTTP acceptance on 2026-10-03 uses disposable scoped PATs and SQL/workspaces. It covers tool discovery, reusable workflow save, idempotent automatic launch, a Codex/Claude reviewed synthesis, browser reload, and read-only plan discovery/full retrieval after transcript deletion with no worker. The native check passes on Codex 0.160.0 and Claude Code 2.1.287. This protocol client is separate from the owner's Hermes session; remote client acceptance remains open.
Safety Model
k0smos applies multiple gates before an AI client can call a tool:
- The tenant MCP kill switch must be enabled.
- The request must authenticate as an active user.
- The user or token must have
mcp.use. - The contributing module must be active for the tenant.
- The user or token must have the tool's required permission.
- Mutating tools execute as the authenticated user, so writes remain attributable.
Invalid tool arguments are returned as tool errors that the AI client can correct and retry. Protocol errors are returned as JSON-RPC errors.
Operating Guidance
- Use OAuth for ChatGPT and interactive clients that persist credentials.
- Use scoped PATs for managed/unattended clients that can inject bearer headers securely.
- Prefer least-privilege scopes.
- Keep finance mutation permissions narrow.
- Review the tool list after changing a user's role or enabling/disabling a module.
- Revoke client tokens that are no longer in use.
- Do not share full-authority personal tokens with third-party AI clients.
- Treat repeated HTTP 429 OAuth responses as back-pressure and honor
Retry-After. Current per-minute limits are 30 authorize, 60 token, and 10 dynamic-registration requests per source or authenticated actor.
Troubleshooting
If the client cannot connect:
- Verify
/admin/settings/mcpshows the MCP server as enabled. - Verify the tenant migrations have run.
- Verify the user has
mcp.use. - Verify the user has the per-tool permissions expected in
tools/list. - For dynamic client registration errors, check that
/oauth/registerreturns HTTP 201 with ak0s_oauth_client_...client id. - For bearer clients, confirm the header is exactly
Authorization: Bearer k0s_pat_.... - For OAuth clients that fail after one hour, verify the tenant has the
oauth_refresh_tokenstable and that/oauth/tokenmetadata advertisesrefresh_token. - OAuth clients registered before k0smos 0.17.11 keep their original authorization-code-only registration. Clear that client's saved OAuth credentials/client registration and authorize again to opt into refresh.
- After
invalid_granton refresh, clear the client's stored OAuth credentials and authorize again; refresh-token replay intentionally revokes the grant.
If a client authenticates but sees no useful tools, the most common cause is a
missing permission scope: OAuth and scoped PAT authority must include mcp.use
plus the specific tool permissions.