@cantinasecurity/apex-cli
v0.1.28
Published
Standalone CLI and MCP server for Apex.
Readme
Apex CLI
Standalone CLI client for Apex.
Installing And Updating
For a public install, use a global package manager install:
npm install -g @cantinasecurity/apex-cli
# or: pnpm add -g @cantinasecurity/apex-cliThen run:
apex setupapex setup is the lowest-friction path for agent clients. It:
- registers Apex as an MCP server in any installed Codex CLI, Claude Code, and GitHub Copilot CLI clients
- installs the Codex skill into
$CODEX_HOME/skills/apex-cli - installs the Claude project skill into
.claude/skills/apex-cliin the current repository - installs the GitHub Copilot CLI skill into
$COPILOT_HOME/skills/apex-clior~/.copilot/skills/apex-cli
If you only want one client, run:
apex setup codex
apex setup claude
apex setup copilotIf one client is not installed yet, apex setup skips it automatically. If you target a client explicitly, its CLI must already be installed.
Update a global install with:
apex updateYou can also update directly with your package manager:
npm install -g @cantinasecurity/apex-cli
# or: pnpm add -g @cantinasecurity/apex-cliIf you are running Apex CLI from a local checkout instead, update it with:
git pull --ff-only
pnpm installFor published installs, setup-managed MCP registrations launch the current npm
release, so restarting the client picks up the current server instead of keeping
an old global apex-mcp process indefinitely. Re-run apex setup after
upgrading to refresh copied skill files, and run apex setup claude in each
repository where you want the Claude project skill.
Restart any already-running MCP client after an Apex CLI upgrade before using trial redemption or claim. A process that loaded an older credential writer cannot adopt the new merge and generation-safety rules until it restarts.
When apex is run in an interactive terminal, it checks for updates periodically and offers to install them.
Local Development
- Install dependencies:
pnpm install- Run the CLI:
pnpm apexBy default, the CLI targets https://ai.cantina.xyz/.
Use APEX_BASE_URL only when targeting a non-default Apex host. For on-prem deployments,
set it to the same external HTTPS Bedrock origin configured as ONPREM_PUBLIC_BASE_URL;
browser handoffs such as apex connect github and apex-connect-provider need that
public origin for GitHub callback and success redirects.
APEX_BASE_URL=https://bedrock.customer.example pnpm apexTry Apex With A Trial Code
A Cantina-issued trial code can start a temporary guest scan without a Cantina account, browser, or device login. Redeem it from the repository root, run the normal scan lifecycle, and create a Cantina account only after reviewing the findings:
apex redeem SPBT-DEVREL-XXXXXXXX --json
apex scan --non-interactive --json
apex status --json
apex findings --json
apex claimapex redeem never opens a browser. It saves a machine-local onboarding
fingerprint before the first request, exchanges the code for a seven-day guest
session, and stores the single-use claim proof only in the mode-0600 Apex
credentials file. A one-way code hash distinguishes safe same-code retries
without retaining the trial code. apex claim is the one onboarding command
that may open a browser; it creates or signs into a Cantina account, then moves
the guest workspace, scans, and findings into the currently selected Cantina
workspace when that account can run scans there. Personal workspace owners
receive the trial in their existing workspace instead of getting a duplicate.
Run it on the same machine within 30 days. Unclaimed guest data is retained only
for the limited period disclosed during redemption and is then queued for
deletion. If the selected Cantina workspace cannot run scans, switch to one
that can and retry before the claim deadline.
Trial redemption, claim, and revocation are hosted-only and fail before sending
any onboarding secret when APEX_BASE_URL is not https://ai.cantina.xyz.
If the local claim proof is lost while the seven-day guest session is still
active, run apex redeem <the-same-code> again on the same machine to rotate
the guest credentials and re-mint the claim proof over the authenticated guest
channel. After the guest session expires, Apex cannot safely recover a lost
claim proof from the public trial code and machine fingerprint alone.
If the current credentials already belong to a real account, apex redeem
exits with code 2 and outcome: "already_authenticated"; it never silently
spends that account's credits. Re-redeeming the same code on the same machine
is idempotent while the guest session remains active. A different active trial
requires the explicit --replace flag, which revokes the outgoing guest
session before redeeming the new code.
Guest standard scans validate the complete local archive before resolving or
reserving a workspace. apex doctor is read-only for guest sessions. For an
unbound renamed checkout, Apex may recover only the sole empty guest workspace
when no explicit workspace name was supplied; it will not silently switch an
explicit workspace selection or reuse a workspace that already contains scan
history.
Logging out of an active guest trial, or discarding a proof-only trial stub,
requires explicit confirmation (apex logout --force in non-interactive
flows). Apex first attempts a proof-bound server revoke; an explicitly
confirmed logout may discard a stale local proof when the server can no longer
verify it. Logging out of a separately authenticated account preserves any
unclaimed local trial proof so apex claim can still use it.
Agent-safe copy/paste prompt (substitute the issued code):
Install and run Cantina Apex CLI 0.1.28 to start one free standard security scan of this repository immediately.
Use this trial code only where <TRIAL_CODE> appears below: SPBT-DEVREL-XXXXXXXX
Run the commands yourself from the repository root; do not stop after setup or only explain the steps. Use terminal CLI commands only. Do not use an Apex MCP tool or run `apex setup`, `apex mcp`, `apex login`, `apex-auth-start`, or `apex-auth-wait`. Never use `--replace` or `--force`.
Use this exact command prefix for every Apex command:
npx -y -p @cantinasecurity/[email protected] apex
1. Before redeeming, confirm every command will use the same persistent, user-accessible machine or container, HOME, filesystem, and repository root. Confirm Node.js 20+ and npx are available. If `APEX_BASE_URL` is set, continue only when its origin is `https://ai.cantina.xyz`. Run the exact prefix with `--help` and continue only if help lists both `redeem` and `claim`. If any check fails, STOP before sending the code; do not install system packages.
2. Redeem, with at most one response-loss recovery retry:
npx -y -p @cantinasecurity/[email protected] apex redeem <TRIAL_CODE> --json
This terminal command is the only allowed tool call containing the code. Never echo or restate the code, store it in a file or environment variable, put it in a URL or MCP call, or include it in your response. Parse the JSON from stdout only; do not merge stderr into stdout, because npm may write warnings to stderr. Continue when the command exits 0 and stdout is JSON with `redeemed: true` and `outcome` equal to `redeemed` or `idempotent`. `idempotent` means the existing guest session resumed and it may already own a workspace. If and only if the first attempt ends with an ambiguous transport/connection failure or an interrupted/missing response and no typed server error code, retry this exact same command once on the same machine, HOME, and repository root. Never retry a typed server rejection and never make more than one recovery retry. If the allowed retry does not return a successful JSON outcome, STOP.
3. Immediately start exactly one scan; do not wait for another instruction:
npx -y -p @cantinasecurity/[email protected] apex scan --mode standard --non-interactive --no-open --json
The CLI validates the complete guest local archive before it reserves a workspace. An unbound renamed checkout may recover only the sole empty guest workspace when no explicit workspace name was supplied. On any error or nonzero exit, STOP. After a successful scan JSON response, inspect `localPersistence.workspaceBindingSaved`. If it is `false`, the server scan already started: capture and report `binding.lastScanId`, then STOP; do not run status or findings until local repository permissions are repaired. Otherwise capture `binding.lastScanId` from the JSON as <SCAN_ID>; if it is absent, STOP.
4. About every 60 seconds, poll that exact scan:
npx -y -p @cantinasecurity/[email protected] apex status --scan <SCAN_ID> --json
Read `progress.progress.status`. Wait while it is `created`, `pending`, `queued`, `starting`, `running`, `in_progress`, or `processing`. Continue on `completed`. STOP on `failed`, `cancelled`, a missing or unknown status, or a command failure.
5. Fetch that exact scan's findings:
npx -y -p @cantinasecurity/[email protected] apex findings --scan <SCAN_ID> --json
On success, summarize findings by severity, most severe first, including identifier, title, status, and confidence. This command does not return file locations, so do not invent them. On failure, STOP.
6. Do not claim automatically. Tell me the claim deadline from step 2 and remind me to run this exact command myself from the same repository root, machine, and HOME:
npx -y -p @cantinasecurity/[email protected] apex claim
It may open a browser so I can create or sign in to a Cantina account and keep the results. Claim moves the trial into the currently selected Cantina workspace when I can run scans there, or into my existing personal workspace. If the selected workspace cannot run scans, tell me to switch to one that can and retry before the claim deadline.
Never paste raw command transcripts. For any failure, report only the step, exit code, and sanitized error. Redact the trial code and every `apex_at_`, `apex_rt_`, or `apex_ct_` value from all reports.Trial codes and claim tokens must never be logged, telemetered, printed in JSON
output, placed in URLs, or sent through MCP tool calls. The MCP server does not
expose redemption or claim tools. After terminal redemption, its read-only
apex-trial-status tool can report local guest and claim deadlines without
returning either secret.
Interactive Shell
Bare apex opens the interactive shell:
$ apex
Apex CLI
Connected to https://ai.cantina.xyz/
Type /scan to start a scan for this directory, /workspaces to browse workspace names, /workspace use "<name>" to switch, /help for commands.
apex>In interactive terminals, Apex now shows a loading indicator while it resolves workspaces, loads scans, and starts commands.
If Apex asks for a workspace name, that is the Apex workspace name for the current directory. Press Enter to accept the current folder name, or pass --workspace-name <name> explicitly.
Supported shell commands:
/credits/scan [standard|audit|lite]/scan pr <pr-number>/scans/findings [scan-id]/findings workspace [filter...]/findings comment <finding-id|finding-identifier> <comment>/findings feedback <finding-id|finding-identifier> valid [comment]/findings feedback <finding-id|finding-identifier> invalid <false-positive|by-design|not-relevant> [comment]/findings fix-review <finding-id|finding-identifier>/export [scan-id]/workspaces/cancel-scan [scan-id]/status [scan-id]/doctor/update/claim/logout/repos/workspace/workspace use <workspace-name|workspace-prefix|workspace-id>/workspace name <name>/company [id|handle]/connect github/connect gitlab/open/clear/help/exit
/workspace use accepts a workspace name, prefix, or ID. Quote workspace names that contain spaces, for example /workspace use "Core Platform".
Scripted Commands
apex creditsapex scanapex scan --mode liteapex scan --mode pr --pr <number> [--pr <number>] [--pr-path <path>]apex scansapex findings [--scan <scan-id>]apex findings --workspace [--company <handle>] [--workspace-ref <name|prefix|id>] [--finding-state all|open] [--filter <[!]facet:value>]apex findings comment <finding-id|finding-identifier> --content <markdown> [--parent-comment <comment-id>] [--scan <scan-id>]apex findings feedback <finding-id|finding-identifier> <valid|invalid> [comment] [--comment <markdown>] [--scan <scan-id>] [--suggested-severity extreme|critical|high|medium|low|informational] [--dismissal-reason false-positive|by-design|not-relevant] [--label acknowledged|fixed] [--fix-pr-url <github-pr-url>]apex findings fix-review <finding-id|finding-identifier> [--scan <scan-id>] [--review-target pull-request|repository-current] [--fix-pr-url <github-pr-url>]apex export findings [--scan <scan-id>] [--format markdown|json|gitlab-sast] [--output <path>]apex workspacesapex workspaceapex workspace use <workspace-name|workspace-prefix|workspace-id>apex cancel-scan [scan-id]apex status [--scan <scan-id>]apex doctorapex loginapex redeem <code> [--json] [--replace]apex claim [--json] [--no-open]apex logoutapex service-key create --name <name> [--company <id-or-handle>] [--scope <scope[,scope]>] [--expires-at <ISO-8601>] [--json]apex service-key list [--company <id-or-handle>] [--json]apex service-key revoke <key-id> [--company <id-or-handle>] [--json]apex setup [all|codex|claude|copilot]apex telemetry [status|enable|disable]apex updateapex connect githubapex connect gitlab
--workspace-ref is scoped to apex findings --workspace. For apex scans or apex export findings, bind the intended workspace first with apex workspace use <name|prefix|id>; unsupported or unknown flags fail instead of falling back to the local binding.
Helpful workspace flags:
--company <id-or-handle>to choose the Apex company when more than one is available--workspace-name <name>to set the Apex workspace name for this directory
apex credits shows standard, audit, fix review, and Lite scan entitlements when the server returns them.
Service Keys, Hosted MCP, And The REST API
Use hosted MCP for production agents that need a normal HTTPS endpoint. Use the REST API for explicit HTTP/JSON integrations such as serverless functions, cron jobs, and internal audit hubs. Use the CLI or local stdio MCP server when an agent needs direct access to a repository checkout or local archive. The complete hosted integration contract is in the Apex API documentation.
An organization manager can create a service key with an existing Apex device-login session. Service-key commands never start device login implicitly, so run apex login first if needed:
apex service-key create \
--name internal-audit-hub \
--scope scans:create,scans:read,findings:read \
--expires-at 2027-01-01T00:00:00ZThe CLI automatically uses your company when only one is available. If you belong to multiple companies, it prompts you to choose one. Pass --company <id-or-handle> to skip that prompt, or when a non-interactive or --json command cannot prompt.
The secret is returned only by create and cannot be retrieved later. Store it directly in a secret manager and do not put it in source control, prompts, chat messages, or logs. --json also includes the shown-once secret so it can be captured programmatically; handle that output as a credential.
Service keys are organization-level credentials. Grant only the scopes the integration needs: scans:create reads credit availability and triggers scans, scans:read polls status, and findings:read retrieves findings. Omit --scope to grant all three scopes. For a P1-only adapter that reads manually started scans, create a read-only key with --scope scans:read,findings:read.
A key with findings:read can retrieve unpublished draft findings for scans in its organization so an external hub can perform triage. Give the key only to systems that are allowed to handle those drafts.
List metadata or revoke a key without exposing its secret:
apex service-key list
apex service-key revoke <key-id>Service-key management is intentionally available only through the scripted CLI. It is not exposed as an MCP tool or interactive-shell command, which keeps raw secrets out of model tool results and transcripts. The CLI requires an existing device-login bearer session, never initiates login from these commands, and never stores a created service key locally.
APEX_SERVICE_KEY authenticates hosted MCP and REST requests; it does not authenticate the local CLI or stdio MCP and does not replace apex login there. When apex doctor finds a service key but no active local device-login session, it reports that split before starting a login flow. APEX_API_KEY is also recognized for this diagnostic so older integrations receive migration guidance, but APEX_SERVICE_KEY is the documented hosted-integration variable.
Hosted HTTPS MCP
Point any Streamable HTTP MCP client at https://ai.cantina.xyz/mcp and send the service key as Authorization: Bearer <TOKEN>. No local apex-mcp process, browser, TTY, or device-login session is required.
Keep the key in the environment. For Codex:
export APEX_SERVICE_KEY='<service-key>'
codex mcp add apex \
--url https://ai.cantina.xyz/mcp \
--bearer-token-env-var APEX_SERVICE_KEYClaude Code can expand the same environment variable from .mcp.json:
{
"mcpServers": {
"apex": {
"type": "http",
"url": "https://ai.cantina.xyz/mcp",
"headers": {
"Authorization": "Bearer ${APEX_SERVICE_KEY}"
}
}
}
}The hosted server exposes apex-credits, apex-workspaces, apex-scan, apex-status, apex-cancel-scan, apex-findings, and apex-workspace-findings. It operates only on repositories and workspaces available to the service key's organization. Use local stdio MCP for device auth, local filesystem/archive access, provider connection, setup, comments, feedback, fix reviews, and trial flows.
Hosted REST API
Use the service key as a bearer token with the hosted scan lifecycle:
curl \
-H "Authorization: Bearer $APEX_SERVICE_KEY" \
https://ai.cantina.xyz/api/apex/v1/credits
curl -X POST https://ai.cantina.xyz/api/apex/v1/scans \
-H "Authorization: Bearer $APEX_SERVICE_KEY" \
-H "Idempotency-Key: $APEX_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{
"repoUrl": "https://github.com/acme/example.git",
"commit": "0123456789abcdef0123456789abcdef01234567",
"paths": ["services/payments"]
}'
curl \
-H "Authorization: Bearer $APEX_SERVICE_KEY" \
https://ai.cantina.xyz/api/apex/v1/scans/$SCAN_ID
curl \
-H "Authorization: Bearer $APEX_SERVICE_KEY" \
https://ai.cantina.xyz/api/apex/v1/scans/$SCAN_ID/findingsFor a remote GitHub scan, the repository must be connected to the service key's Apex organization. Apex reuses an active linked workspace when one exists; if none exists, the request creates and links a workspace named after the canonical repository before the scan starts. Pass workspaceId to disambiguate multiple matches. An explicit workspace/repository mismatch returns HTTP 409 instead of silently rewriting that workspace.
For a local or non-Git checkout, use the service API's source-upload flow instead. It can create or reuse a workspace, uploads a tar.gz archive, and starts the scan with a local_archive source. A newly created local workspace has no threat model to reuse, so its first scan must send generateThreatModel: true. See the Apex service API guide for the current request schemas and limits.
The optional paths array is a set of best-effort focus hints, not a hard repository boundary. Apex may inspect or report code outside those paths. Version one does not yet provide strict path isolation.
Every trigger request requires an Idempotency-Key. Generate one stable key for each intended scan and reuse that same key with the identical request body when retrying after a transport error, timeout, or 5xx. Idempotency is organization-scoped, so a retry remains safe if the service key is rotated between attempts. A definitive 4xx response is retained; after correcting its precondition, submit the request with a new key. Use a new key for every genuinely new scan. The trigger returns a scanId; poll the scan resource until it reaches a terminal status, then fetch findings. The findings response uses the GitLab SAST JSON shape, including unpublished drafts, finding IDs that remain stable when the same scan is re-fetched, titles, descriptions, severities, and source locations when available.
Example prompt for Claude Code:
Build an Apex adapter for our serverless audit hub using the hosted REST API, not the Apex CLI or local stdio MCP server. Read
APEX_SERVICE_KEYfrom the environment, generate one stableIdempotency-Keyper intended scan, and reuse it with the identical request body only after a transport error, timeout, or5xx; after correcting a definitive4xx, use a new key. POST the connected GitHub repository URL and exact commit to/api/apex/v1/scans, includeworkspaceIdwhen needed to disambiguate matches, and handle a409workspace-resolution response. Treat optionalpathsas non-binding focus hints, not a security boundary. Poll/api/apex/v1/scans/{scanId}until terminal, then fetch/api/apex/v1/scans/{scanId}/findings. Preserve the raw GitLab SAST payload, including drafts, and deduplicate findings by stable ID. Never print or log the service key.
Example prompt for Codex:
Add Apex to this headless auditor integration using the hosted REST API. Use bearer auth from
APEX_SERVICE_KEY; do not shell out toapexor start a local stdio MCP process. Implement scan trigger,409workspace-resolution handling, status polling with bounded backoff, terminal failure handling, and findings retrieval. Send the connected GitHubrepoUrl, exactcommit, optionalpaths, and optionalworkspaceId; treatpathsas non-binding focus hints rather than a hard security boundary. Generate a stableIdempotency-Keyfor each intended scan. Preserve it only for an identical transport/timeout/5xxretry; after correcting a definitive4xx, submit with a new key. Keep the returnedscanId, and store the unmodified findings payload, including drafts, alongside normalized findings. Add tests with mocked HTTP responses and ensure credentials are redacted from errors and logs.
For a P1-only integration where scans are started in the Apex UI:
Given an Apex
scanId, fetch/api/apex/v1/scans/{scanId}/findingswithAPEX_SERVICE_KEY, save the GitLab SAST JSON unchanged, and import each finding once using its stable ID. Do not trigger a new scan and never log the bearer token.
Finding Review Feedback
Finding review collaboration now has explicit write commands:
apex findings comment <finding-id|finding-identifier> --content "Needs auth check"apex findings feedback <finding-id|finding-identifier> valid --comment "Reproduced on latest build"apex findings feedback <finding-id|finding-identifier> invalid --dismissal-reason false-positive --comment "This path is unreachable"apex findings feedback <finding-id|finding-identifier> valid --label fixed --fix-pr-url https://github.com/acme/app/pull/123 --comment "Fixed in PR #123"apex findings fix-review <finding-id|finding-identifier>/findings comment <finding-ref> <comment>/findings feedback <finding-ref> valid [comment]/findings feedback <finding-ref> invalid <false-positive|by-design|not-relevant> [comment]/findings fix-review <finding-ref>
Identifiers such as KERN2-25 are resolved against the selected or latest scan for the current workspace binding. Pass --scan <scan-id> when you need a specific scan, or pass the finding UUID directly to skip workspace-based resolution.
Finding comments, valid/invalid feedback, and fix review scan starts use the same Apex login credentials as read commands. In MCP clients, call apex-auth-start, then pass both its returned deviceCode and opaque credentialGeneration to apex-auth-wait to authenticate these write tools safely.
Never copy a browser cookie or set CANTINA_AUTH_TOKEN for these tools. If an
MCP server asks for that variable, it is an outdated pre-device-auth server.
Update Apex CLI, re-run apex setup <client>, restart the client, and retry.
Invalid feedback requires a dismissal reason. Valid feedback can include --suggested-severity extreme|critical|high|medium|low|informational.
Fix review scans can review either a Fix PR or the current repository state:
- For PR-based reviews, either save fixed feedback on the finding with
--label fixedand one or more--fix-pr-urlvalues, or pass--fix-pr-urldirectly toapex findings fix-review. - For current-repository reviews, run
apex findings fix-review <finding-id|finding-identifier>without Fix PR URLs. Bedrock must have original scan repository context for the finding.
The matching MCP flow is apex-finding-fix-review with optional fixPrUrls. Agents that need to record fixed feedback first can still call apex-finding-feedback with status: "valid", labels: ["fixed"], and fixPrUrls, then call apex-finding-fix-review.
The matching CLI and MCP flows intentionally use the same device-login session so agents should not ask users to paste browser cookies or auth tokens.
Local Source Scans
apex scan now works against any local source root you point it at. By default, that source root is the current working directory:
- clean GitHub or GitLab checkouts can stay on the remote-materialization path
- dirty git worktrees fall back to a local snapshot upload by default
- plain directories that are not git repositories are scanned through a local snapshot upload
Useful flags:
--repo <path>to scan one or more explicit local roots instead of the current directory--source-mode auto|remote|localto control remote-first fallback behavior--mode standard|audit|lite|prto choose the scan mode--pr <number>to select one or more GitHub pull requests for--mode pr--pr <number:path,path>or--pr-path <path>to limit a PR scan to changed paths
auto is the default. remote requires Apex to materialize from a remote repository. local forces a local snapshot upload even when a clean remote path is available.
Audit scans use audit as the scan mode and still require provider-backed GitHub or GitLab repositories that Apex can materialize remotely without a local snapshot fallback. ultra remains accepted as a backwards-compatible alias.
Lite scans use lite as the scan mode and require the Lite Scan beta feature plus provider-backed GitHub or GitLab repositories that Apex can materialize remotely. Local snapshot uploads are not supported for Lite scans.
PR scans require exactly one provider-backed GitHub repository. If the current directory resolves to multiple sources, pass --repo <path> to select the one that contains the pull request.
LLM / MCP Usage
Apex has two MCP transports:
- Hosted Streamable HTTP at
https://ai.cantina.xyz/mcp, authenticated with an organization service key, for production agents that do not need the caller's filesystem. - The
apex-mcpstdio server shipped by this package, authenticated with device login, for repository-local and interactive agent workflows.
See Hosted HTTPS MCP for the production URL and Bearer-token configuration. The rest of this section configures the local stdio server.
If Apex is installed globally, prefer:
apex setupThat registers Apex for installed Codex CLI, Claude Code, and GitHub Copilot CLI clients automatically. Codex and Claude registrations also set APEX_MCP_CLIENT and APEX_CLIENT_INTEGRATION so Apex can distinguish agent-driven MCP usage from direct CLI usage.
If you want to wire clients manually instead, Apex ships a stable apex-mcp binary. For Codex:
codex mcp add apex \
--env APEX_MCP_CLIENT=codex \
--env APEX_CLIENT_INTEGRATION=codex \
-- apex-mcpFor Claude Code:
claude mcp add apex \
--scope user \
-e APEX_MCP_CLIENT=claude \
-e APEX_CLIENT_INTEGRATION=claude \
-- apex-mcpapex setup claude uses Claude's name-first stdio command syntax and checks
whether the installed Claude CLI supports --scope user. If a Claude build
omits that option or advertises it but rejects it at runtime, setup safely
merges the same user-level mcpServers.apex entry into ~/.claude.json
without replacing other settings or servers.
For GitHub Copilot CLI:
copilot mcp add apex --tools "*" -- apex-mcpThe command after -- selects the local stdio transport; no version-specific transport flag is needed.
For any other MCP client, configure it to launch:
{
"mcpServers": {
"apex": {
"command": "apex-mcp",
"env": {
"APEX_MCP_CLIENT": "custom-mcp-client",
"APEX_CLIENT_INTEGRATION": "custom-mcp-client"
}
}
}
}From a local checkout during development, prefer the repo-local binary so the MCP stream stays clean:
{
"mcpServers": {
"apex": {
"command": "/path/to/apex-cli/bin/apex-mcp",
"env": {
"APEX_MCP_CLIENT": "local-dev",
"APEX_CLIENT_INTEGRATION": "local-dev"
}
}
}
}If you need to launch through pnpm, use --silent:
{
"mcpServers": {
"apex": {
"command": "pnpm",
"args": ["--silent", "mcp"],
"cwd": "/path/to/apex-cli",
"env": {
"APEX_MCP_CLIENT": "local-dev",
"APEX_CLIENT_INTEGRATION": "local-dev"
}
}
}
}Do not point an MCP client at plain pnpm mcp. pnpm writes its script banner to stdout before the protocol stream, which can break the initialize handshake.
The local stdio MCP server exposes Apex-specific tools for:
- auth status and device login
- local guest-session deadlines through
apex-trial-status(never the code or claim token) - doctor, credits, and provider connection URLs
- workspace inspection and workspace binding
- scan start, status, cancellation, findings, and findings export
- cross-scan workspace findings through
apex-workspace-findings, including direct workspace selection, first-class open state, web UI lifecycle fields, and server-side filters - Lite scan start by calling
apex-scanwithmode: "lite" - PR scan start by calling
apex-scanwithmode: "pr"andpullRequests - finding comments and valid/invalid feedback with
apex-finding-commentandapex-finding-feedback - Fix PR and current-repository fix review scans with
apex-finding-fix-review, optionally afterapex-finding-feedback
Neither MCP surface exposes trial redemption, trial claim, or service-key creation, listing, or revocation as tools. When a user supplies a Cantina trial code, run apex redeem <code> in a terminal instead of starting device login or putting the code in an MCP call. Production MCP clients should connect to https://ai.cantina.xyz/mcp; HTTP applications can use the hosted Apex REST API directly. Do not launch the local stdio server as an HTTP adapter.
For repository-scoped operations, pass cwd explicitly so the server can resolve the right .apex/workspace.json binding and repository roots.
Use apex-workspace-findings when an agent needs the same cross-scan finding
set as the workspace browser. Pass company, workspaceRef, and
findingState: "open" to select any accessible workspace without changing the
local binding and return only findings that still need review:
{
"company": "apex-internal",
"workspaceRef": "BEDR9",
"findingState": "open"
}Open state excludes fixed, invalid, dismissed, and duplicate findings. It is a
first-class selection, not status:open; actual finding status values are
proposed, partially_valid, valid, invalid, and duplicate. The
response includes status, validity, reviewState, duplicate metadata,
repository, and source file fields used by the web UI. Supported filter facets
are severity, scan, repo, review, impact, likelihood, status,
validation, visibility, duplicate, and source. Repeated filters in one
facet are ORed; filters across different facets are ANDed, and a leading !
negates a filter.
For Codex-style clients, the packaged skill can be installed with apex setup codex. For GitHub Copilot CLI, the same skill is installed into ~/.copilot/skills/apex-cli with apex setup copilot. The repo-local source lives at skills/apex-cli/SKILL.md.
For Claude Code, the packaged project skill can be installed into the current repository with apex setup claude. The repo-local source lives at .claude/skills/apex-cli/SKILL.md. Anthropic documents project skills as filesystem directories under .claude/skills/<name>/SKILL.md, and the Claude Agent SDK uses the same location when the Skill tool is enabled.
Usage Telemetry
Apex CLI emits first-party, privacy-preserving usage telemetry so Cantina can understand how people use the direct CLI, the interactive shell, and MCP tools in Codex, Claude, GitHub Copilot CLI, or other clients.
Telemetry is enabled by default and can be disabled locally:
apex telemetry status
apex telemetry disable
apex telemetry enableEnvironment opt-outs override local config:
APEX_TELEMETRY_DISABLED=1 apex scan
# also honored: APEX_DISABLE_TELEMETRY=1 or DO_NOT_TRACK=1Telemetry records lifecycle events such as command/tool start and completion, duration, success/failure category, CLI version, Node/platform basics, anonymous install/session IDs, and sanitized command metadata. It also adds attribution headers to Apex API requests, including surface (cli, interactive_shell, or mcp), client integration, invocation ID, command/tool name, and CLI version.
Telemetry does not send raw cwd paths, repository URLs, finding IDs, scan IDs, PR URLs, comments, file paths, trial codes, claim tokens, onboarding fingerprints, bearer tokens, or raw flag values. Sensitive inputs are reduced to booleans, counts, enum values, or length buckets.
Telemetry event posts do not include bearer tokens. The telemetry endpoint is POST /api/cli/v1/telemetry/events with a batch payload:
{
"events": [
{
"schemaVersion": 1,
"event": "apex.invocation.completed",
"cliVersion": "0.1.28",
"invocation": {
"surface": "mcp",
"command": "apex-scan",
"mcpTool": "apex-scan",
"metadata": {
"mode": "pr",
"pullRequestCount": 1,
"cwdProvided": true
}
},
"client": {
"integration": "codex"
},
"outcome": {
"success": true,
"durationMs": 1234
}
}
]
}Plugin And Marketplace Packaging
The npm package also includes marketplace-ready plugin artifacts:
.codex-plugin/plugin.jsonand.mcp.codex.jsonfor Codex plugin installs.claude-plugin/plugin.jsonand.mcp.claude.jsonfor Claude Code plugin installs.claude-plugin/marketplace.jsonfor a Claude marketplace entry backed by the public npm package
These plugin installs launch the pinned npm package with npx -y -p @cantinasecurity/[email protected] apex-mcp, so users do not need to install apex globally before enabling the plugin.
The repository also includes .agents/plugins/marketplace.json for local Codex marketplace testing from a checkout.
For local Claude validation:
claude plugin validate .
claude plugin marketplace add ./ --scope local
claude plugin install apex-cli@cantina-tools --scope localFor local Codex validation, add this repo as a local marketplace, then install apex-cli from the Cantina Tools marketplace in the Codex plugin directory:
codex plugin marketplace add ./See MARKETPLACE.md for the official Claude, Anthropic Connectors Directory, and OpenAI/Codex submission checklist. The local stdio MCP server is plugin-ready, but remote marketplace submissions still require the external review steps documented there.
Development Notes
The CLI uses the Apex /api/cli/v2/** local-source routes for scan planning and snapshot uploads, with legacy /api/cli/v1/** routes still used for provider-backed flows such as audit scans. Local state is stored under:
~/.config/apex/config.json~/.config/apex/credentials.json.apex/workspace.json
When starting a non-PR scan, any active workspace scan (including a PR scan) requires confirmation. Scripted usage can opt in explicitly with --force. Starting a PR scan skips that client preflight and may run alongside active workspace scans without --force, matching Bedrock's one-directional scan concurrency contract. Active-looking workspace scan rows are checked against the scan progress endpoint before the CLI treats them as blockers, so stale list entries do not hide terminal states such as cancelled.
To move between existing Apex workspaces from the CLI:
- Run
apex workspacesto list the workspaces available to your active company. - Run
apex workspace use <workspace-name|workspace-prefix|workspace-id>to bind the current directory. - If the workspace name contains spaces, quote it, for example
apex workspace use "Core Platform". - Use
apex scans,apex status --scan <scan-id>,apex findings, andapex export findingsagainst that binding. - Use
apex findings --workspace --company <handle> --workspace-ref <ref> --finding-state openfor the workspace browser's cross-scan findings that still need review, without changing the local binding.
