Skip to content
KRPUS
Sign up

DOCS

MCP reference

One remote MCP server gives any MCP client — Claude, ChatGPT, Claude Code, your own — the same bundles people see in the web app. This reference is for developers wiring their own client or automations; to use Korpus with Claude or ChatGPT, the manual is enough.

Overview

TransportStreamable HTTP, stateless: JSON responses, no session id, no server-sent events.
AuthOAuth 2.1 with PKCE and dynamic client registration. Bearer token on every request.
Serverkorpus, titled Korpus (or Korpus · <agent> on an agent link).
ToolsOne per action: list_folder, read_concept, create_concept, update_concept and the rest, plus manual.
ResourcesBundles and concepts as korpus:// URIs.
Promptswhats_in_korpus, save_session.
HostingAWS eu-central-1 (Frankfurt).

The data model in one breath: a bundle is a folder of concepts; a concept is a markdown document at a path such as auth/token-expiry, with type, tags, relations and a rev. Links in the web app are relations here. See the manual for the rest.

Endpoint

https://mcp.fra.korpus.cloud/mcp
  • JSON-RPC over POST to /mcp; each request stands alone, so there is no stream to open with GET and no session to end. The token decides the agent; the consent screen lets the person pick it.
  • https://mcp.fra.korpus.cloud/mcp/<agent> signs in as that agent, preselected on the consent screen. A token issued for another agent is refused with agent_mismatch, which names the right URL.
  • An account lives in the region it signed up in; this endpoint serves Frankfurt accounts.

Connect a client

Claude

As yourself (me): Korpus is listed in Claude's connector directory. Settings → Connectors, search for Korpus, choose Connect, sign in and keep me. Often quicker: Add custom connector, name it Korpus, paste https://mcp.fra.korpus.cloud/mcp/me. It also works in Claude for desktop and mobile; turn it on per chat from the tools menu.

As an agent with rules: add it as its own connector, not through the directory entry. claude.ai → Settings → Connectors → Add custom connector, name it korpus-<agent>, paste https://mcp.fra.korpus.cloud/mcp/<agent>. A connection of its own holds only that agent's rules, so it does its job and nothing else.

Claude Code

claude mcp add --transport http korpus https://mcp.fra.korpus.cloud/mcp

Then run /mcp and sign in.

ChatGPT

Settings → Apps & Connectors → Advanced, turn on Developer mode, then Create. Name it Korpus, paste the URL.

Any other client

{
  "mcpServers": {
    "korpus": {
      "type": "http",
      "url": "https://mcp.fra.korpus.cloud/mcp"
    }
  }
}

This is the .mcp.json shape Claude Code and similar clients read; others ask only for the URL. The server name is yours to choose. For an agent with rules, use /mcp/<agent> and name the server korpus-<agent>. The web app's Link an app and the get_agent_connect tool print these lines for you.

Authentication

A client with MCP OAuth support needs nothing configured: it discovers everything from the first 401.

  1. Discovery. An unauthenticated request answers 401 with WWW-Authenticate: Bearer resource_metadata="https://mcp.fra.korpus.cloud/.well-known/oauth-protected-resource" (RFC 9728). Authorization server metadata is at /.well-known/oauth-authorization-server (RFC 8414) and /.well-known/openid-configuration.
  2. Registration. POST /oauth/register (RFC 7591). Public clients only: token_endpoint_auth_method must be none. Redirect URIs must be https, or http on localhost, 127.0.0.1 or [::1]. Registrations expire after 90 days.
  3. Authorize. GET /oauth/authorize with response_type=code, PKCE S256 and scope mcp. The person signs in to the web app, picks the agent the client acts as (me, an existing one, or a new one) and presses Allow. The request is good for 10 minutes; the code for 5.
  4. Token. POST /oauth/token with authorization_code or refresh_token. The access token lives 1 hour, the refresh token 30 days. Refresh tokens rotate on every use; one presented twice revokes the whole grant.

Each approval is a grant, listed under its agent on the web app's Agents page. Disconnect there ends it at once; the next call answers 401. Deleting the agent ends all of its grants.

Instructions

On initialize the server sends instructions a client passes to its model:

  1. Which Korpus deployment the client reached.
  2. A short overview: the data model, which tools only look, the change description every write carries, how to find things (list_folder first), how usage is metered.
  3. The person's plan, free or Plus. Every tool works on either; only the limits differ.
  4. The agent's name and job, and for an agent with rules, the rules.

Everything longer sits behind the manual tool, so a client that drops the instructions can still read them. Topics:

startFirst moves in a bundle you do not know.
conceptsPaths, fields, rev, create versus update, change descriptions, sources.
findlist_folder first; search, regex and body search.
relationsRelation types and links between concepts.
sharingRoles and invitations.
catalogThe public page of a published template: pitch, prompts, how it works, screenshots.
agentsAgents, rules, path patterns, rights.
learningA bundle that teaches the agents using it: read AGENTS and the last retro first, write a retro and apply one change last.
limitsCeilings and how usage is metered.
errorsEvery error code and what to do about it.

Tools

One tool per action, each with a title a client shows and hints it sorts by. The reading tools carry readOnlyHint, so most clients let a person allow them for good; every other tool asks, and the ones that remove or end something also carry destructiveHint. Every tool is openWorldHint: false. An agent with rules gets no managing tool at all.

  • Change descriptions. create_concept, update_concept, delete_concept, add_relation and remove_relation take a required change_description: one line, what changed and why. It is the log; nothing else records why a concept moved.
  • Index and log. Every folder has an index (read_index: the titles and descriptions of its concepts) and a log (read_log: its changes, newest first). Both are generated from the content as OKF 0.2 §8 and §9 describe, never stored, so no concept may be named index or log.
  • Revisions. read_concept returns a concept's rev. Pass it back on update_concept and the call fails with rev_mismatch if someone changed the concept meanwhile. Without it the update lands and says whose revision it changed. update_concept changes only the fields given; "" clears a text field.

On the wire

A tool call is an ordinary tools/call. Its answer is a tool result: the first content item is plain text, followed by up to 50 resource_links to the concepts it names. There is no structuredContent.

POST /mcp
Authorization: Bearer <access token>
Content-Type: application/json
Accept: application/json, text/event-stream

{ "jsonrpc": "2.0", "id": 7, "method": "tools/call",
  "params": { "name": "create_concept", "arguments": {
    "bundle": "01M3…", "path": "README",
    "type": "Guide", "title": "Research",
    "body": "# Research\nWhat this bundle is for.",
    "change_description": "Said what this bundle is for" } } }

200 OK
{ "jsonrpc": "2.0", "id": 7, "result": {
  "isError": false,
  "content": [
    { "type": "text", "text": "ok README created, rev 1" }
  ] } }

A call that fails answers the same way with isError: true and the text <code>: <message>. Only transport and account problems are JSON-RPC or HTTP errors: 401 without a valid token, 403 for a token of another agent (-32003 agent_mismatch) or a blocked account (-32003 account_blocked).

Every tool

Parameters with ? are optional. The input schemas (tools/list) carry the same fields with a description each; the manual topics explain the behaviour.

Field shapes

FieldShapeMeaning
bundlestringA bundle id (a 26-character ULID) from list_bundles. Names are not accepted.
pathstringBundle-relative, segments of A–Z a–z 0–9 . _ - starting with a letter or digit, / between, no .md, depth ≤ 10. Umlauts are spelled out (ä → ae), other characters become -. A last segment named index or log is refused.
typestringFree text: Decision, Runbook, Guide, …
statusstringstable | draft | deprecated
tagsstring[]At most 32. Replaces all tags when given.
relations[{type, to}]type = a relation type of the bundle, to = a path in it (may not exist yet). Replaces all relations when given.
extraobjectAny other frontmatter keys. Replaces all of them when given.
folderstringA folder path, e.g. auth. Left out: the bundle root.
revintegerFrom read_concept. The update fails with rev_mismatch if the concept changed since.
change_descriptionstringOne line, what changed and why. Required on every create, update, delete and relation change; it is the log.
sincestringISO 8601 UTC, e.g. 2026-09-19T10:00:00Z.
rightsstring[]Any of create, read, update, delete.
cursorstringOpaque. A page with more ends its count line with (more) and its text with a line cursor <token>; pass it back with the same filters.

Reading readOnly · idempotent · every agent

ToolParameters and effect
manualHow Korpus workstopic?The manual, by topic. One topic, or all of them with no argument.
list_bundlesList bundlesThe bundles you see, with your role and how many concepts each holds.
get_usageShow usageHow full each allowance is (write and read rate, 5-hour session, week, space), as fractions. Never refused.
list_folderList folderbundle, folder?One folder: its concepts (path, type, title, description) and subfolders. The way to find things; start here.
read_indexRead folder indexbundle, folder?The folder's index.md: its concepts' titles and descriptions by type, and its subfolders. Generated from the concepts, never stored.
read_logRead change logbundle, path?, since?The log.md of a folder (every change under it), a concept (its own) or the bundle: kind, what changed, who, newest first. Generated from the change records, never stored.
search_conceptsSearch conceptsbundle, q?, regex?, case_sensitive?, body?, digest?, type?, tag?, tags?, status?, stale?, stale_within_days?, date_from?, date_to?, prefix?, limit?, cursor?Search paths, titles, descriptions and tags, ignoring case and umlauts. body: also the text, quoting the line that hit. digest: a line under each hit saying what it is about. tags: all of them. stale_within_days: what falls due. date_from/date_to: on the concept's date. Pages of 50, up to 200.
read_conceptRead conceptbundle, pathA whole concept as markdown with its rev, and what links to it.
list_activityShow recent activitybundle?, since?, mentions_only?What is new since your last visit, and where you were @-mentioned.
list_relation_typesList relation typesbundleThe bundle's link vocabulary. Read it before writing a relation.
check_relationsCheck relationsbundleRelations pointing at concepts that do not exist, and relation types nothing uses.
list_membersList membersbundleWho can see the bundle, and with which role.
get_rightsShow my rightsbundle, pathWhat you may do at one path, and which of your rules say so.
list_agentsList agentsYour agents and their rules. A restricted agent sees only itself.
list_invitationsList invitationsInvitations waiting for you. Me agent only.
get_agent_connectGet agent setup linkname, bundle?Setup for one agent: its URL, how to add it in Claude (me from the connector directory or as a custom connector, any other agent as its own custom connector), a claude mcp add line, a .mcp.json snippet, and a CLAUDE.md block with a SessionStart hook so every session reads the bundle first (given bundle, both name it). Me agent only.

Writing asks · every agent, inside its rules

ToolParameters and effect
create_conceptCreate conceptbundle, path, type, body, title?, description?, tags?, relations?, status?, stale_after?, date?, extra?, change_descriptionA new concept. Refused if the path is taken. A path with umlauts or spaces is made valid (schäfer → schaefer) and the answer names it.
update_conceptUpdate conceptbundle, path, …fields?, rev?, change_descriptionChange the fields you send; the rest stay. Pass the rev you read to fail on a concurrent change; required when sending tags, relations or extra.
delete_conceptDelete conceptbundle, path, change_descriptionDelete one concept.
add_relationAdd relationbundle, from, type, to, change_descriptionLink one concept to another, keeping its other links; reads from <type> to, and the answer echoes it. Nothing is written if the link is there.
remove_relationRemove relationbundle, from, type, to, change_descriptionRemove one link, keeping the others.

Managing asks · me agent only

ToolParameters and effect
create_bundleCreate bundlename, description?A new bundle you own, with a starter set of relation types (relates_to, depends_on, supersedes, contains, precedes). The server waits up to about 15 seconds for its setup; if it is not done by then, the next call on it waits.
create_relation_typeDefine relation typebundle, name, label, kind, inverse_label?, description?Declare or replace one kind of link: symmetric, directed (needs inverse_label) or unidirectional, with a line on when to use it.
invite_memberInvite memberbundle, who, roleInvite @username or an email as viewer or contributor. Nothing is shared until they accept.
accept_invitationAccept invitationbundleAccept an invitation waiting for you.
decline_invitationDecline invitationbundleDecline it.
create_agentCreate agentname, description?, rulesPrepare an agent with its job and rules.
update_agentUpdate agentname, description?, rules?Change an agent; rules replace all of its rules. Holds from its next request.
delete_agentDelete agentnameDelete an agent and sign out every app connected as it.
add_agent_ruleAdd agent rulename, bundle, path, rightsAdd one rule; the same bundle and path merge their rights.
remove_agent_ruleRemove agent rulename, bundle, pathRemove one rule, named exactly as list_agents prints it.

Resources and prompts

URIWhat
korpus://bundle/{bundle_id}A bundle: name, your role, count, description and its root folder. Listed by resources/list.
korpus://bundle/{bundle_id}/{+path}A concept: its rev and markdown. A template; concepts are not listed.

Both are text/markdown and go through the same access checks as the tools.

PromptWhat it does
whats_in_korpusWhat's in Korpus: Lists your bundles, then the index of each. Reads only.
save_sessionSave what we learned: Reads what is there, proposes what to write, waits for your OK, then writes it, saying what changed.

Agents and rights

Every token belongs to one agent, and every write is stamped with it: @you via <agent>.

  • me is built in, fixed and holds the person's full rights. Nothing creates, changes or deletes it.
  • Other agents carry a job and rules. At most 50 agents per account, 50 rules each; names are 1–32 characters of a-z 0-9 . _ -.

Rules

{ "bundle": "<id> | *", "path": "<pattern>", "rights": ["create", "read", "update", "delete"] }
  • read is always implied.
  • Patterns: * alone is the whole bundle; * or ** as the last segment is everything below that folder, at any depth (the two mean the same there); ** elsewhere is any number of folders; * inside a segment matches within that segment. No .md.
  • Rules only subtract: the person's role in the bundle is checked first.
  • Rules are read on every request, so a change holds from the next call.
PatternMatchesDoes not match
notes/*notes/a, notes/a/bnotes, other/notes/a
**/test/*test/a, x/y/test/a/btest, x/tests/a
adr/0*adr/0007-queuesadr/0007/notes, adr/1001
AGENTSAGENTSx/AGENTS
ToolsRight needed on the path
read_concept, list_folder, read_index, read_log, search_conceptsread
create_conceptcreate
update_concept, add_relation, remove_relationupdate (on the from concept)
delete_conceptdelete

An agent with rules never gets create_bundle, create_relation_type, invitations, get_agent_connect or agent management. A refusal answers restricted and names what the agent may do instead; get_rights asks in advance.

Errors

A failure reads <code>: <message>, sometimes followed by details as JSON and a pointer to a manual topic. The message names the fix.

CodeMeaning
rev_mismatchThe concept changed since you read it. Read again, merge, update with the new rev the message names.
rev_requiredAn update replaced tags, relations or extra without rev. Read, merge, pass rev. details: current_rev
change_description_requiredA create, update or delete said nothing about what changed. One line, at most 200 characters.
not_foundNot there, or not yours to see. Not a permission hint.
restrictedThe agent's rules refuse it. The message lists what it may do. Do not retry; the person widens the rules.
rate_limitedToo much too fast, or the session or week is used up. details: limit (writes, reads, session, week), retry_after (seconds)
quota_exceededOut of room or over a count. details: limit (space, bundles; publications is web only), max?
bundle_not_readyA new bundle is still being set up after the server waited for it (rare). Retry after 10 s. details: status, retry_after_seconds?
bundle_busyThe bundle is held still while a version of it is published (a web-only action); reads work. details: retry_after_seconds
published_read_onlyA published catalog version (web only), which nobody writes. Edit its source bundle instead.
account_blockedThe account is blocked. Every request is refused.
internal_errorOur fault. Retry once, then tell support.

More codes

invalid_path, invalid_concept, invalid_frontmatter, invalid_nameA path, field or name does not fit its rules (charset, depth, a last segment named index or log).
invalid_access, invalid_agentAn agent or rule is malformed: pattern charset, an unknown right, a .md in a pattern.
invalid_relation_typeThe relation type is not declared in this bundle: list_relation_types, then create_relation_type.
invalid_cursor, invalid_regex, invalid_queryStart the search again without the cursor; the regex uses a construct outside the accepted subset; a filter such as date_from is not a day.
body_too_large, too_many_tags, too_many_relationsOver a ceiling; see Limits.
bundle_not_empty, conflictThe state does not allow it right now.
user_not_found, member_not_found, invitation_not_found, owner_stays, email_taken, username_takenSharing and people: nobody by that name in the bundle, no such invitation, or the owner trying to leave.

Retry hints: rate_limited carries retry_after, bundle_not_ready and bundle_busy carry retry_after_seconds, all in seconds. A new bundle is ready within 60 seconds; retry every 10. For session and week limits the wait can be hours: stop and tell the person. manual topic=errors explains every code.

Limits and usage

LimitValue
Concept body300 KB
change_description200 characters
Pathdepth 10, 900 bytes
Tags per concept32
Relations per concept32
Relation types per bundle16
Search page50, up to 200
Regex length200 characters
Agents per account / rules per agent50 / 50
Bundle set-upup to 60 s

Usage is metered by what a call costs to serve. Writes and reads each have a short-term rate, and every call spends from a 5-hour session and a weekly allowance: a read counts 1, a write 3, a body search 10. Over a limit, the call answers rate_limited with retry_after. The allowances differ by plan (free or Plus) and are not published; get_usage shows how full each one is, and is never refused. Space is counted per person, over the bundles they created.

Not on MCP

Publishing to the catalog, using a template, admin screens for Korpus staff and billing are in the web app only. Questions: support@korpus.cloud.