MCP server
Connect Claude, ChatGPT, Cursor, VS Code, Codex or any MCP client to Kortix over OAuth or a personal access token. One URL reaches every project you can open. Nothing to install.
Experimental. Its tools can change without a deprecation.
Kortix has one hosted MCP server:
https://api.kortix.com/v1/mcp
Add that URL to an MCP client once. The first call asks you to sign in to
Kortix in the browser. After that, the client acts as you, with your
permissions, across every account and project you can open — the same reach as
the CLI. The URL names no project: the tools take a project_id
or a session_id, and list_projects lists them. There is nothing to install.
Add it to a client
Every client below signs you in with OAuth on first use, unless the steps name a token. Replace nothing: the URL is the same for every project.
Claude Code
claude mcp add --transport http kortix https://api.kortix.com/v1/mcp
Run /mcp in Claude Code and sign in. To use a personal access token instead,
add --header "Authorization: Bearer $KORTIX_TOKEN" to the command.
Claude Desktop and claude.ai
Settings → Connectors → Add custom connector. Paste the URL and sign in.
ChatGPT
Custom MCP connectors need developer mode. Per OpenAI’s developer mode guide, turn on Developer mode in Settings → Security and login, then create a developer-mode app from the ChatGPT plugins page (plus button). Enter the URL and choose OAuth authentication. OpenAI lists the plans and menu names, and they change: follow that guide if a label differs.
Cursor
Use the Add to Cursor button in Connect MCP, or add the server to
~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):
{ "mcpServers": { "kortix": { "url": "https://api.kortix.com/v1/mcp" } } }
VS Code
Add the server to .vscode/mcp.json. VS Code uses servers, not
mcpServers, and needs the type:
{ "servers": { "kortix": { "type": "http", "url": "https://api.kortix.com/v1/mcp" } } }
Codex
codex mcp add kortix --url https://api.kortix.com/v1/mcp
codex mcp login kortix
Or edit ~/.codex/config.toml. For a personal access token, name the
environment variable that holds it:
[mcp_servers.kortix]
url = "https://api.kortix.com/v1/mcp"
bearer_token_env_var = "KORTIX_TOKEN"
Other clients
Add a remote (Streamable HTTP) MCP server with the URL. A client that cannot run OAuth sends a personal access token as a header (below).
Open the workspace menu (the project name, top left) and select Connect MCP to copy the URL and the steps for Claude, Claude Code, Cursor and Codex.
Sign-in
The server uses the OAuth 2.1 flow the MCP specification defines. A client does it without configuration:
- A call without a token answers
401withWWW-Authenticate: Bearer resource_metadata="…", scope="kortix". - The client reads the RFC 9728 document at
/.well-known/oauth-protected-resource/v1/mcp. It names Kortix as the authorization server. - The client registers itself at
POST /v1/oauth/register(RFC 7591). It gets a public client that authenticates with PKCE alone. - You approve the client on the Kortix consent screen. A self-registered client is marked Unverified app, with the host it sends you back to. Approve it only when you are connecting it yourself.
- The client exchanges the code for a
kortix_oat_access token (1 hour) and a refresh token (30 days, rotated on use). When the access token expires, the client refreshes it without asking you again.
Revoke a client
Settings → Personal access keys → Connected apps lists every app you approved, across
all your accounts: its name, where it signs in, and when it was last active. A
self-registered MCP client is marked Unverified app. Revoke access
deletes your approval and revokes its tokens: its next request fails, and it
must ask you again. From a terminal: kortix tokens apps ls and
kortix tokens apps rm <client-id>. Both work only from a browser session or a
personal access token, never from an app’s own token.
What a connected app cannot do
The kortix scope acts as you: a connected app reads and changes what you can
read and change. It cannot create a credential that outlives its own
revocable token. These routes answer 403 for a kortix_oat_ token:
- personal access tokens (
POST /v1/accounts/tokens) and project CLI tokens; - gateway keys;
- SCIM tokens;
- OAuth clients, and the rotation of their secrets;
- service accounts;
- the list of connected apps and their revocation (
/v1/oauth/grants).
Revoke a client and its access ends. A personal access token is different: it
does not expire unless you pass --expires, and revoking an app does not revoke
it.
Personal access token
A client without OAuth, or a script, sends a kortix_pat_ token instead — the
token the CLI uses. Create one with kortix tokens new <name> or in
Settings → Personal access keys, then send it as a header:
{ "mcpServers": { "kortix": { "url": "https://api.kortix.com/v1/mcp", "headers": { "Authorization": "Bearer kortix_pat_…" } } } }
Tools
tools/list returns 23 tools. Parameters marked * are required.
| Tool | Parameters | What it does |
|---|---|---|
list_projects |
none | Lists every project you can open, across all your accounts, with its project_id and your role. |
start_session |
project_id, prompt, name, agent |
Starts a session in a project with a first prompt. Returns the session_id. |
send_message |
session_id, text |
Queues a message for a session and starts the session if it is stopped. |
read_session |
session_id*, limit, wait_seconds |
Returns a session’s status, whether its turn is idle, booting, running or queued, and its latest messages with each tool call’s input and output. limit is 10 by default, 100 at most. wait_seconds (up to 45) waits for the turn to end. |
list_sessions |
project_id*, limit, cursor |
Lists the sessions you can see in a project: id, title, status, agent, owner, branch, dates. limit is 20 by default, 200 at most. |
run_command |
session_id*, command, cwd, timeout_seconds, job_id, cancel |
Runs a bash command in a session’s sandbox and returns stdout, stderr and the exit code. A long command returns a job_id to keep waiting on. |
read_file |
path*, session_id, project_id, ref, offset, limit |
Reads a file from a session’s sandbox, or from a project’s git repository at ref. Images return as images. |
write_file |
session_id, path, content*, encoding |
Writes a file in a session’s sandbox and creates its parent directories. encoding is utf8 (default) or base64. |
list_files |
path, session_id, project_id, ref, offset |
Lists one directory of a session’s sandbox, or every file of a project’s repository under a path. |
read_skill |
name, file, project_id |
Lists the Kortix platform guides, or returns one guide (name) or one of its reference files (file). With project_id, the project’s own skills are listed first, and a project skill name returns its SKILL.md and its reference file paths. |
list_connectors |
project_id*, connector |
Lists a project’s connectors: slug, provider, whether each is connected (usable by you now), action count and accounts. With connector, lists that connector’s accounts in full. |
search_connector_actions |
project_id*, query, connector, limit |
Finds connector actions by intent. Returns tool (<connector>.<action>), risk and a one-line description. Never returns schemas. |
describe_connector_action |
project_id, tool |
Returns one action’s input JSON Schema, risk and description. |
call_connector |
project_id, tool, args, account, reason |
Runs an action as you. Returns the data and the account that ran it, a pending_approval result with the approval link, or a denial with its reason. |
upload_connector_attachment |
project_id, connector, filename*, content_base64 or session_id + path |
Stages a file and returns the {"$kortix_attachment": "<id>"} ref to put in args. |
connect_connector |
project_id, connector, owner, label |
Returns the link a person opens to connect the connector’s account. |
search_connector_apps |
project_id, query, limit, cursor |
Searches the catalogue of managed apps a connector can be added from. |
add_connector |
project_id*, app or provider + slug, name, url, transport, endpoint, spec, base_url |
Adds a connector to the project now (committed to kortix.yaml on main, then synced). |
remove_connector |
project_id, connector |
Removes a connector from the project. |
kortix |
args*, project_id, session_id |
Runs the real kortix CLI as you and returns exit_code, stdout (or json for --json output) and stderr. See Run any CLI command. |
search_api |
query*, limit |
Searches the Kortix API routes by keyword. |
describe_api |
method, path |
Returns one route’s parameters, request body and response schema. |
call_api |
method, path, project_id, query, body |
Calls any /v1/ route as you. project_id fills {projectId} in the path. |
search_api, describe_api and call_api cover everything the web app and the
CLI do, because both are clients of the same API. call_api
refuses /v1/oauth/* and any path that reaches an MCP endpoint. Fill every
other {placeholder} in the path yourself. Each call passes the same
authorization and audit as a request from the web app. The audit records each
call with credential_kind: "oauth_app" and the connected app’s name, because
the API records the credential it authenticated, not a label the client sends.
Run any CLI command
The kortix tool runs the real kortix CLI as you. Every CLI
command works through it, so the MCP server has the same reach as a terminal:
secrets, triggers, cr, review, reminders, agents, models, gateway,
providers, channels, sandboxes, apps, marketplace, files, access, roles,
permissions, audit, grants, members, groups, tokens, billing, projects,
sessions and system-skills. One tool replaces about 200 subcommand tools,
which would exceed the tool limit of clients such as Cursor.
args is the argv after kortix, one array element per argument. It is never
a shell line.
{ "name": "kortix", "arguments": { "args": ["--help"] } }
{ "name": "kortix", "arguments": { "args": ["secrets", "ls", "--json"], "project_id": "<project_id>" } }
{ "name": "kortix", "arguments": { "args": ["triggers", "ls", "--json"], "project_id": "<project_id>" } }
{ "name": "kortix", "arguments": { "args": ["system-skills"] } }
- Discover with
["--help"]and["<group>", "--help"]. Add--jsonto output you parse. project_idsets the project of a project-scoped command.session_idsets the session of a command that acts on one.- The result is JSON:
exit_code,stdout,stderr. With--json, the command’s output arrives as a JSON value injsoninstead ofstdout. Output that does not fit is cut and markedtruncated; cut JSON is not valid JSON, so narrow the command. A non-zeroexit_codeis an MCP error. Each stream is cut at 24,000 (stdout) and 8,000 (stderr) characters, and the result says so intruncated. - A command that runs longer than about 45 seconds is killed. The result has
timed_out. - The server runs at most 4 CLI commands at once. A fifth call returns
Busy: retry. - Sessions, sandbox files and connectors have first-class tools
(
start_session,run_command,read_file,call_connector). Prefer them.
The CLI runs on the server with your own token, against this API. It gets no
server credentials: its environment holds only your token, the API URL, the
project and session ids, and an empty temporary home and working directory.
The server removes both after the command. Authorization and audit are the
API’s: an outsider’s token gets the same 403 as from a terminal.
These commands are refused before anything runs. The error names the reason and the alternative.
| Command | Why | Use instead |
|---|---|---|
any --host or --host= flag, hosts |
Points the CLI at another server and would send your token there. | This server already acts as you. |
login, logout |
Browser sign-in and stored tokens. | You are signed in through the MCP connection. |
init, ship, deploy |
Read or write a local directory. | run_command in a session sandbox, where the source lives. |
apps deploy |
Deploys a local directory, and the server has none. | run_command in a session sandbox: run kortix apps deploy <path> there. |
env pull, env push |
Write or read a local file. | secrets ls, secrets set KEY=value. |
token, whoami --token-only |
Print the raw access token. | whoami --json. |
update, uninstall, self-host |
Change the machine that runs the CLI. | None. |
tui, t, connect, attach, `sessions connect |
shell | forward` |
chat and sessions chat without --prompt |
Open an interactive chat. | start_session, send_message, or add --prompt "<text>". |
connectors mcp |
Starts a stdio MCP server. | list_connectors, call_connector. |
The audit records a CLI command with the same credential as every other call
on the connection (credential_kind: "oauth_app"). It cannot tell the kortix
tool from call_api: both reach the API with your token.
Project skills
read_skill with a project_id lists the project’s own skills (the
skills/<slug>/SKILL.md files of the repository, or the legacy
.kortix/opencode/skills/) before the platform guides. Pass the skill name
to read its SKILL.md and the paths of its reference files, and file to read
one reference. You see the skills your role and grants allow.
Use your connectors
The connector tools are the kortix connectors CLI as MCP
tools. They call the same API routes as the CLI and the SDK, so a connector
policy, an approval and the audit behave the same on every surface.
list_connectorsshows what is connected. A connector withconnected: falsecannot run actions: callconnect_connector, open the returned link, then list again.search_connector_actionsfinds an action by intent, for examplesend an email.describe_connector_actionreturns its arguments.call_connectorruns it. The result names theaccountthat ran the call. A connector with several accounts and no default needsaccount.- Pass
reasonon a write whose arguments are only ids (send_draft, delete by id). The approver sees it next to the real arguments.
A policy can hold a call for approval. call_connector then returns
status: "pending_approval" with an approval_url. A person opens it and
approves. Call again with the same tool, arguments and account within 15
minutes: the approved call runs once. A policy_block denial is final.
A result over about 40,000 characters comes back as a marked preview
(data_truncated). Narrow the arguments and call again. To attach a file,
stage it with upload_connector_attachment and put the returned ref in
args. Composio connectors do not accept attachment refs.
Result size and paging
- A tool result is cut at 60,000 characters and ends with
…[truncated at 60000 chars]. read_filereturns a long text file in pages of up to about 50,000 characters. A cut result ends with theoffsetthat continues it.offsetskips lines andlimitcaps the lines returned. A binary file is not returned as text: read it withrun_command.list_filescuts a long list the same way. Pass theoffsetit names.list_sessionsreturnsnext_cursorwhen more sessions exist. Pass it back ascursor.read_sessionreturns the latestlimitmessages. It cuts each tool input and output, and drops the oldest messages when the result does not fit (omitted_older).last_turn_errornames a failed turn.- One MCP request answers within 55 seconds.
read_sessionwithwait_secondsand a sandbox that is still starting both stop before that: call again.
Sandboxes
run_command, read_file, write_file and list_files with a session_id
reach the session’s live sandbox, the same way the web terminal and file panel
do. Relative paths resolve under /workspace, the session’s git checkout. A
stopped sandbox starts on the first call. The kortix CLI in the sandbox is
signed in as the session. With a project_id and no session_id, read_file
and list_files read the project’s git repository and start no sandbox.
A command can run for minutes. One tool call waits about 50 seconds. When the
command is still running then, run_command returns status: running, a
job_id, and the output so far. Call run_command with that job_id to keep
waiting, or with cancel: true to stop it. timeout_seconds (default 600,
maximum 86400) stops a command that runs too long, with exit code 124. Output
is kept in ~/.cache/kortix-mcp/jobs/<job_id>/ in the sandbox; a tool result
shows the last 24,000 bytes of each stream. A sandbox that stops takes its
running commands with it.
The server is stateless: it answers POST with JSON, and GET and DELETE
with 405.
Not the same as kortix.com/mcp
https://kortix.com/mcp is a different server. It serves the public Kortix
documentation and marketing pages (list_public_content,
get_public_markdown) without sign-in and reaches no account data. Use
https://api.kortix.com/v1/mcp to work with your projects and sessions.