MachineMachine
MachineMachine
MachineGetting startedQuickstartAccounts & access
Your project
AgentsLegacy kortix.tomlManifest referenceModelsAgent permissionsSecrets
Running work
Change requestsRuntime & sandboxSessions
Connect & automate
ComputersConnectorsInkbox: iMessage, SMS, email & callsMCP serverPixio: images, video & audioRemindersSlack & channelsMicrosoft TeamsTriggers
Feature flags
Apps

Develop

CLI
TypeScript SDKFull exampleAuthenticationSign in with KortixSessionsAppsReact hooksSDK reference
Machine as a BackendAPI reference
GitHub
Connect & automate

MCP server

Connect Claude, ChatGPT, Cursor, VS Code, Codex or any MCP client to Machine 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.

Machine has one hosted MCP server:

text
https://machineapi.myapps.ai/v1/mcp

Add that URL to an MCP client once. The first call asks you to sign in to Machine 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

bash
claude mcp add --transport http machine https://machineapi.myapps.ai/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):

json
{ "mcpServers": { "machine": { "url": "https://machineapi.myapps.ai/v1/mcp" } } }

VS Code

Add the server to .vscode/mcp.json. VS Code uses servers, not mcpServers, and needs the type:

json
{ "servers": { "machine": { "type": "http", "url": "https://machineapi.myapps.ai/v1/mcp" } } }

Codex

bash
codex mcp add machine --url https://machineapi.myapps.ai/v1/mcp
codex mcp login machine

Or edit ~/.codex/config.toml. For a personal access token, name the environment variable that holds it:

toml
[mcp_servers.machine]
url = "https://machineapi.myapps.ai/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:

  1. A call without a token answers 401 with WWW-Authenticate: Bearer resource_metadata="…", scope="kortix".
  2. The client reads the RFC 9728 document at /.well-known/oauth-protected-resource/v1/mcp. It names Machine as the authorization server.
  3. The client registers itself at POST /v1/oauth/register (RFC 7591). It gets a public client that authenticates with PKCE alone.
  4. You approve the client on the Machine 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.
  5. 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:

json
{ "mcpServers": { "machine": { "url": "https://machineapi.myapps.ai/v1/mcp", "headers": { "Authorization": "Bearer kortix_pat_…" } } } }

Tools

tools/list returns 23 tools. Parameters marked * are required.

ToolParametersWhat it does
list_projectsnoneLists every project you can open, across all your accounts, with its project_id and your role.
start_sessionproject_id, prompt, name, agentStarts a session in a project with a first prompt. Returns the session_id.
send_messagesession_id, textQueues a message for a session and starts the session if it is stopped.
read_sessionsession_id*, limit, wait_secondsReturns 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_sessionsproject_id*, limit, cursorLists the sessions you can see in a project: id, title, status, agent, owner, branch, dates. limit is 20 by default, 200 at most.
run_commandsession_id*, command, cwd, timeout_seconds, job_id, cancelRuns 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_filepath*, session_id, project_id, ref, offset, limitReads a file from a session's sandbox, or from a project's git repository at ref. Images return as images.
write_filesession_id, path, content*, encodingWrites a file in a session's sandbox and creates its parent directories. encoding is utf8 (default) or base64.
list_filespath, session_id, project_id, ref, offsetLists one directory of a session's sandbox, or every file of a project's repository under a path.
read_skillname, file, project_idLists the Machine 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_connectorsproject_id*, connectorLists 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_actionsproject_id*, query, connector, limitFinds connector actions by intent. Returns tool (<connector>.<action>), risk and a one-line description. Never returns schemas.
describe_connector_actionproject_id, toolReturns one action's input JSON Schema, risk and description.
call_connectorproject_id, tool, args, account, reasonRuns 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_attachmentproject_id, connector, filename*, content_base64 or session_id + pathStages a file and returns the {"$kortix_attachment": "<id>"} ref to put in args.
connect_connectorproject_id, connector, owner, labelReturns the link a person opens to connect the connector's account.
search_connector_appsproject_id, query, limit, cursorSearches the catalogue of managed apps a connector can be added from.
add_connectorproject_id*, app or provider + slug, name, url, transport, endpoint, spec, base_urlAdds a connector to the project now (committed to kortix.yaml on main, then synced).
remove_connectorproject_id, connectorRemoves a connector from the project.
kortixargs*, project_id, session_idRuns the real kortix CLI as you and returns exit_code, stdout (or json for --json output) and stderr. See Run any CLI command.
search_apiquery*, limitSearches the Machine API routes by keyword.
describe_apimethod, pathReturns one route's parameters, request body and response schema.
call_apimethod, path, project_id, query, bodyCalls 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.

json
{ "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 --json to output you parse.
  • project_id sets the project of a project-scoped command. session_id sets 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 in json instead of stdout. Output that does not fit is cut and marked truncated; cut JSON is not valid JSON, so narrow the command. A non-zero exit_code is an MCP error. Each stream is cut at 24,000 (stdout) and 8,000 (stderr) characters, and the result says so in truncated.
  • 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.

CommandWhyUse instead
any --host or --host= flag, hostsPoints the CLI at another server and would send your token there.This server already acts as you.
login, logoutBrowser sign-in and stored tokens.You are signed in through the MCP connection.
init, ship, deployRead or write a local directory.run_command in a session sandbox, where the source lives.
apps deployDeploys a local directory, and the server has none.run_command in a session sandbox: run kortix apps deploy <path> there.
env pull, env pushWrite or read a local file.secrets ls, secrets set KEY=value.
token, whoami --token-onlyPrint the raw access token.whoami --json.
update, uninstall, self-hostChange the machine that runs the CLI.None.
tui, t, connect, attach, `sessions connectshellforward`
chat and sessions chat without --promptOpen an interactive chat.start_session, send_message, or add --prompt "<text>".
connectors mcpStarts 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.

  1. list_connectors shows what is connected. A connector with connected: false cannot run actions: call connect_connector, open the returned link, then list again.
  2. search_connector_actions finds an action by intent, for example send an email. describe_connector_action returns its arguments.
  3. call_connector runs it. The result names the account that ran the call. A connector with several accounts and no default needs account.
  4. Pass reason on 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_file returns a long text file in pages of up to about 50,000 characters. A cut result ends with the offset that continues it. offset skips lines and limit caps the lines returned. A binary file is not returned as text: read it with run_command.
  • list_files cuts a long list the same way. Pass the offset it names.
  • list_sessions returns next_cursor when more sessions exist. Pass it back as cursor.
  • read_session returns the latest limit messages. It cuts each tool input and output, and drops the oldest messages when the result does not fit (omitted_older). last_turn_error names a failed turn.
  • One MCP request answers within 55 seconds. read_session with wait_seconds and 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 the public /mcp

https://beta.machine.myapps.ai/mcp is a different server. It serves the public Machine documentation and marketing pages (list_public_content, get_public_markdown) without sign-in and reaches no account data. Use https://machineapi.myapps.ai/v1/mcp to work with your projects and sessions.

PreviousInkbox: iMessage, SMS, email & callsNextPixio: images, video & audio

On this page

Add it to a clientClaude CodeClaude Desktop and claude.aiChatGPTCursorVS CodeCodexOther clientsSign-inRevoke a clientWhat a connected app cannot doPersonal access tokenToolsRun any CLI commandProject skillsUse your connectorsResult size and pagingSandboxesNot the same as the public /mcp