Files
cline/apps/cli
4829f08b3f fix(vscode): reliable MCP OAuth on the SDK extension (ENG-2108, CLINE-2304) (#11529)
* fix(vscode): store MCP OAuth in shared settings file like the CLI (ENG-2108)

VSCode stored MCP OAuth tokens in a single mcpOAuthSecrets secrets blob
keyed by sha256(name:url), while the CLI/SDK store per-server oauth state in
cline_mcp_settings.json. The two never interoperated (CLI auth was invisible to
VSCode), and VSCode's read-whole-blob/write-whole-blob through StateManager's
non-refreshing cache meant concurrent windows clobbered each other's tokens.

- Store MCP OAuth state in the shared settings file in @cline/core's format.
- Reads are fresh from disk; writes are scoped read-modify-write of one
  server's oauth key via updateMcpServerOAuthState (now atomic temp+rename).
- Replace the vscode:// callback flow with HTTP-based token collection via
  authorizeMcpServerOAuth (same local loopback flow the CLI uses).
- Reconnect an unauthenticated server when its tokens appear (e.g. CLI auth).
- One-time migration of legacy mcpOAuthSecrets tokens into the shared file.
- Remove McpOAuthRedirectResolver, mcpOAuthFlow, completeOAuth, and the
  mcp-auth URI callback route.

* feat(vscode): add --instances/--random-port to MCP OAuth test server

Lets you start several independent test servers, each on its own OS-assigned
random port, so you can add multiple streamableHttp MCP servers to Cline at
once and exercise concurrent OAuth flows. baseUrl now reflects the actually
bound port so discovery metadata and redirect URIs stay correct under random
ports.

* fix(vscode): stop MCP OAuth handshake writes from livelocking the settings watcher (ENG-2108)

Now that codeVerifier/clientInformation live in the shared settings file, the
MCP SDK's per-connect-attempt saveCodeVerifier() writes were tripping the
settings watcher, which re-entered updateServerConnections -> connectToServer
-> another write, looping forever. It was especially bad with two+
unauthenticated servers, where each server's verifier churn re-triggered the
other (visible as a flickering, ever-changing codeVerifier nonce).

The watcher now compares a connection-relevant fingerprint (full per-server
config minus the oauth block, plus a boolean for whether an access token
exists) and skips writes that only churn OAuth-handshake fields. A token
appearing/disappearing still changes the fingerprint, so CLI/other-window
authorization continues to trigger a reconnect via serverGainedOAuthTokens.

* feat(vscode): print paste-ready MCP settings fragment from OAuth test server

On startup the test server now emits an mcpServers JSON fragment (nested
transport shape, matching cline_mcp_settings.json) alongside the banner, so you
can paste it straight into the settings file instead of hand-writing it. With
--instances the entries get distinct names (oauth-test-1, ...), each carrying
its actual bound port.

* fix(vscode): atomic MCP settings writes + fingerprint gate; drop timer guards (CLINE-2097)

Deleting one MCP server could empty the whole list. Root cause: settings
writes were non-atomic (fs.writeFile), so chokidar (and any other process)
could read a transient empty/torn file mid-write and reconcile to zero servers.
The previous fix only masked this with a per-process isUpdatingClineSettings
boolean cleared on a 300ms timer — it did nothing for the CLI or other windows
and was racy.

Replace both timer guards (isUpdatingClineSettings, isUpdatingFromRemoteConfig)
with two deterministic, process-agnostic mechanisms:

- writeSettingsFile(): atomic temp-file + rename for every settings write, so
  any reader always sees a complete file. Holds for any number of concurrent
  writers (CLI, multiple windows, SDK OAuth handshake).
- content fingerprint: the watcher reconciles only when the connection-relevant
  view changed. writeSettingsFile pre-seeds the fingerprint so our own write is
  a no-op, while a genuine change from any other process is still processed.
  Because reconcile is idempotent and reads are never torn, a missed
  suppression is at worst a redundant reconnect, never data loss.

All RPC writers (toggle disabled, autoApprove x2, timeout, add, delete) and the
remote-config sync now go through writeSettingsFile. Removes all setTimeout(.,
300) flag juggling.

* feat(vscode): add a non-guessable 'frozzle' tool to the MCP OAuth test server

The MCP OAuth test server now serves tools/list + tools/call exposing a
'frozzle' tool whose output cannot be derived without calling it (reverse the
string and swap each letter's case, wrapped in guillemets). This gives an eval
a reliable end-to-end signal that the OAuth-authenticated MCP round-trip really
happened: a correct 'frozzle <text>' answer can't be hallucinated. The
transform is easy to verify at a glance and invertible. Adds frozzle.test.ts.

* fix(sdk): drop lingering OAuth callback sockets on close so deny->approve re-auth works (ENG-2108)

The local OAuth callback server's close() called Server.close(), which only
stops accepting new connections and lets existing keep-alive sockets linger.
The browser / global-fetch connection pool keeps such a socket to the fixed
callback port (1456) alive. So after the user denied an MCP OAuth request and
retried, the retry's approve callback could be delivered over the pooled socket
to the FIRST (already-settled) server. That server's settle() was a no-op, so
waitForCallback() never resolved, finishAuth()/token exchange never ran, and no
token was saved — the server stayed unauthenticated (the deny->approve repro).

Call server.closeAllConnections() in close() so no pooled socket outlives the
server. Adds a regression test driving a keep-alive agent across close().

* fix(vscode): actually reconnect MCP server when toggled back on (ENG-2108)

toggleServerDisabledRPC only flipped the in-memory disabled flag and set status
to 'connecting', but never rebuilt the connection. A disabled server's
connection has no live transport/client, so re-enabling left it stuck on the
yellow 'connecting' indicator forever and never re-advertised its tools to the
agent.

Tear down and rebuild the connection through deleteConnection + connectToServer
(which opens a real transport when enabled, or a disconnected stub when
disabled), then notifyWebviewOfServerChanges so the SDK session's tool list is
refreshed. OAuth state is preserved (deleteConnection doesn't clear it). Adds
McpHub.toggleServerDisabledRPC.test.ts.

* fix(vscode): reload MCP tools silently without chat spam (ENG-2108)

Restarting the SDK session to pick up MCP tool changes appended visible chat
messages ('MCP tools changed - reloading...' and 'MCP tools reloaded
successfully...') plus a completion_result banner. Toggling several servers
piled up many of these. Tool reloading should be transparent.

Emit only the session status transitions (running -> idle) via
emitSessionEvents([], ...) instead of appendAndEmit, so no chat messages or
completion banner are shown. Genuine reload failures still surface an error
message. Updates sdk-mcp-coordinator.test.ts accordingly.

* docs(mcp): clean up comments to describe current behavior

Revise comments across the MCP OAuth and settings code to document the code as
it stands, dropping references to prior implementations, task IDs, and
before/after narration. Also reflow the auth-server regression test to the
repository's formatter. No behavior change.

* fix(vscode): atomic fallback write in remote MCP sync; document sync OAuth I/O

Make the no-McpHub branch of syncRemoteMcpServersToSettings write via an
atomic temp-file + rename so a concurrent reader never observes a torn or
empty settings file, matching every other settings write.

Document why the OAuth state read-modify-write in McpOAuthManager is
synchronous: it serializes this process's shared-file updates without a
Promise queue, which we prefer over async I/O for reliability of the
cross-process settings file.

* fix(mcp): serialize settings read-modify-writes

* docs(vscode): clarify MCP settings create race

* fix(vscode): create MCP settings atomically

* fix(cli): keep clearing missing MCP OAuth state a no-op

* fix(vscode): avoid yielding while holding MCP settings lock (#11596)

* fix(mcp): async lock acquisition for VSCode MCP settings/OAuth writes

Add updateMcpSettingsFile/updateMcpServerOAuthStateAsync to @cline/core that
yield the event loop while acquiring the cross-process settings lock instead of
blocking it with Atomics.wait. The critical section stays synchronous and the
mutator stays pure, so the lock is never held across an await and serialization
is preserved without an in-process queue.

Route the VSCode extension host's OAuth state writes (McpOAuthManager) through
the async variant so a connection-time OAuth callback can no longer freeze the
extension host event loop or deadlock against an in-flight updateMcpSettingsFile
whose lock-releasing continuation needs the loop.

Unify the sync and async acquisition paths on a shared reentrancy guard
(activeLocks) so a nested settings update on the same file fails fast instead of
self-deadlocking.

Tests: contended async serialization asserting zero Atomics.wait calls, async
stale-lock reclaim, reentrancy fail-fast, and uncontended run+release.

* fix(mcp): bootstrap missing settings file inside the lock; tidy docs

Creating the MCP settings file now happens in one place: the locked
read-modify-write helpers. A missing file reads as an empty settings object, so
the first write to a fresh path (e.g. a fresh-install `cline mcp add`) creates
it inside the lock instead of throwing ENOENT. The SDK (updateMcpSettingsFile /
updateMcpSettingsFileSync) and the VSCode lock helper share this contract, so
callers no longer need to pre-create the file. Add regression tests for the
SDK, the CLI wizard addServer(), and the VSCode helper on a missing path.

Also flag the synchronous SDK entry points (updateMcpSettingsFileSync,
updateMcpServerOAuthState) as preferring their async siblings, with a TODO to
delete them once all callers migrate, and tighten the lock-helper doc comments
to describe current behavior.

* fix(vscode): finish npm->bun migration in dev tooling, tasks, and docs

The npm->bun migration (#11632) updated package scripts, .vscodeignore and .vscode-test.mjs but left a trail of npm/npx/node invocations in editor configs, dev scripts, and docs. Following the breadcrumbs from 'npm run protos':

- .vscode/launch.json: standalone-core debug uses 'bun <file>.ts' (was npx tsx); Open Storybook uses 'bun run' (was npm run).
- .vscode/tasks.json: all task commands use 'bun run' (was npm run).
- scripts/run-extension-host.sh and .claude/hooks/claude-code-for-web-setup.sh: 'bun run' (was npm run).
- debug-harness/server.ts: shebang 'bun'; build steps use 'bun run protos', 'bun esbuild.mjs', 'bunx vite build' (were npm/node/npx).
- dev script shebangs (test-hostbridge-server, test-standalone-core-api-server, testing-platform-orchestrator, interactive-playwright): '#!/usr/bin/env bun' (was npx tsx).
- WebviewProvider HMR hint, e2e README, copilot-instructions, PR template, mcp-oauth-test-server docs, generate-state-proto message, tsconfig.test comment, state-keys test comment: bun.

Left untouched (correct per .clinerules/bun-and-node): Node-runtime invocations (node build.mjs), prebuild-install --target=<node>, vsce, 'npm install -g cline' (user CLI install), and App.stories.tsx mock chat fixtures.

---------

Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Co-authored-by: Cline Agent <cline-agent@users.noreply.github.com>
2026-06-24 14:11:34 +09:00
..
2026-06-03 01:49:57 +02:00
2026-06-03 01:49:57 +02:00
2026-06-03 01:49:57 +02:00
2026-06-20 00:30:51 -07:00
2026-06-20 00:30:51 -07:00
2026-06-03 01:49:57 +02:00

Cline CLI

Run Cline in your terminal. Interactive chat for paired sessions, or fully headless for CI/CD and scripting. The CLI shares its agent core with the Cline VS Code extension, JetBrains plugin, and SDK, so plan/act modes, MCP servers, checkpoints, rules, skills, and provider configuration all behave the same across surfaces.

Install

npm install -g cline

For nightly builds:

npm install -g cline@nightly

Platform binaries are published for macOS, Linux, and Windows on arm64 and x64. The cline package resolves the correct binary for your platform via optional dependencies, so no Node, Bun, or Zig runtime is required at install time.

Quick start

Run interactively:

cline

Run a single prompt:

cline "Audit this package and propose fixes"

Pipe input:

cat file.txt | cline "Summarize this"

See cline --help for the full flag reference.

Use any provider

Cline supports the same providers as the VS Code extension. You can sign in to Cline directly, use your ChatGPT Subscription through openai-codex, or bring an API key from Anthropic, OpenAI, Google Gemini, OpenRouter, AWS Bedrock, GCP Vertex, Cerebras, Groq, and any OpenAI-compatible endpoint.

cline auth                              # interactive sign-in
cline auth cline                        # OAuth sign-in
cline auth --provider anthropic --apikey sk-... --modelid claude-sonnet-4-6

cline auth without a provider opens the interactive auth setup TUI with the same options as the old CLI flow (Sign in with Cline, Sign in with ChatGPT Subscription, Sign in with OCA, or use your own API key).

OAuth-supported providers (cline, openai-codex, oca) do not auto-launch a browser on normal startup. Authenticate explicitly first with cline auth <provider>. For non-interactive runs, if an OAuth provider is selected and no saved credentials are available, cline fails fast with an authentication message instead of launching a hidden browser flow.

Modes

Cline CLI runs in a few different shapes depending on what you need:

  • Interactive TUI: cline or cline -i opens a full terminal UI with plan/act toggle, slash commands, file mentions, and live tool approvals
  • One-shot: cline "your prompt" runs a single turn and exits
  • JSON: cline --json "..." streams NDJSON events for piping into other tools
  • Yolo: cline --yolo "..." skips approval prompts and exits when the turn finishes
  • Zen: cline --zen "..." fires the task to the background hub daemon and exits immediately (see below)

Headless mode for CI/CD

Run Cline with zero interaction for scripting and automation. Pipe input, get JSON output, chain commands, integrate into CI/CD pipelines.

# One-shot prompt, auto-approve all tools
cline --yolo "Run tests and fix any failures"

# Pipe a diff in for review
git diff origin/main | cline "Review these changes for issues"

# NDJSON output for downstream tooling
cline --json "List all TODO comments" | jq -r 'select(.type == "agent_event" and .event.text) | .event.text'

Features

  • Streaming TUI built on OpenTUI with markdown rendering, syntax-highlighted diffs, scrollable chat, and mouse support
  • Plan/Act mode toggle for switching between planning and execution
  • Native MCP support for connecting custom tools
  • Checkpoints with /undo to rewind workspace state
  • Sub-agent spawning and agent teams for parallel work
  • OAuth login for Cline, ChatGPT Subscription (openai-codex), and OCA
  • Configurable thinking budgets per run
  • Cron and event-driven schedules for recurring agent work
  • Chat connectors for Telegram, Google Chat, and WhatsApp

Usage

# Start Cline CLI without a prompt to enter interactive mode
cline

# Single prompt (one-shot) - includes tools, spawn, and teams
cline "Audit this package and propose fixes"

# Interactive mode with a starting prompt
cline -i "Let's work on this together. First, analyze the current state."

# With a custom system prompt
cline -i -s "You are a pirate" "Tell me about the sea"

# Require approval before each tool call
cline --auto-approve false "Inspect and modify this repository"

# Explicit yolo: enables submit_and_exit and disables spawn/team tools by default
cline --yolo --retries 5 "Refactor this package"

# Override consecutive internal mistake (retry) limit (default: 3)
cline --retries 5 "Fix failing tests"

# Team workflow with persistent name
cline --team-name my-team "Plan, implement, and verify release checklist"
cline --team-name my-team "Continue yesterday's team workflow"

# Show verbose run stats (elapsed time, tokens, estimated cost when available)
cline -v "Explain quantum computing"

# Use a specific provider, model, and access token for a single prompt
cline -P openrouter -m google/gemini-3-pro -k sk-... "Set up a storybook"

# Use a different model with the last used provider
cline -m anthropic/claude-opus-4-6 "Explain string theory"

# Stream structured NDJSON output
cline --json "Summarize this repository"

# Quick provider setup
cline auth --provider anthropic --apikey sk-... --modelid claude-sonnet-4-6
cline auth --provider openai-native --apikey sk-... --modelid gpt-5 --baseurl https://api.example.com/v1

MCP servers

Manage MCP servers with the interactive wizard:

cline mcp
cline config mcp

Open the add-server wizard with the name, transport, and command or URL already filled in with cline mcp install (cline mcp add also works). Stdio servers use everything after -- as the command and arguments:

cline mcp install fs -- npx -y @modelcontextprotocol/server-filesystem /tmp

Remote HTTP and SSE servers take a name, transport, and URL. The wizard still asks for auth details before saving:

cline mcp install ctx7 --transport http https://mcp.context7.com/mcp
cline mcp install events --transport sse https://example.com/sse

Because this command opens the wizard, it requires a TTY.

Connectors

Bridge a chat surface into RPC-backed Cline sessions. Each conversation thread maps to a session with full context. Supported platforms: Telegram, Slack, Google Chat, WhatsApp, and Linear.

# Telegram (polling mode)
cline connect telegram -k 123456:ABCDEF...

# Slack (webhook mode)
cline connect slack --bot-token $SLACK_BOT_TOKEN --signing-secret $SLACK_SIGNING_SECRET --base-url https://your-domain.com

# Slack (socket mode)
cline connect slack --bot-token $SLACK_BOT_TOKEN --app-token $SLACK_APP_TOKEN

# Google Chat (webhook mode)
cline connect gchat --base-url https://your-domain.com

# WhatsApp (webhook mode)
cline connect whatsapp --base-url https://your-domain.com

# Linear (webhook mode)
cline connect linear --api-key $LINEAR_API_KEY --base-url https://your-domain.com

# Stop connector bridges and delete their sessions
cline connect --stop
cline connect --stop telegram

In chat surfaces, connector slash commands include /help, /start, /new, /clear, /whereami, /tools, /yolo, /cwd <path>, /schedule, /abort, and /exit. Run cline connect <adapter> --help to see the full flag list for any adapter.

Schedules

Schedule agents on cron-like intervals or external events.

cline schedule create "Daily code review" \
  --cron "0 9 * * MON-FRI" \
  --prompt "Review PRs opened yesterday and summarize issues." \
  --workspace /path/to/repo \
  --provider cline \
  --model openai/gpt-5.3-codex \
  --timeout 3600 \
  --tags automation,review

cline schedule list
cline schedule get <schedule-id>
cline schedule trigger <schedule-id>
cline schedule history <schedule-id> --limit 20
cline schedule export <schedule-id> > daily-review.yaml
cline schedule import ./daily-review.yaml

Schedules can route results back to chat surfaces with --delivery-adapter, --delivery-bot, and --delivery-thread.

Options

Flag Description
-s, --system <prompt> Override the system prompt
-P, --provider <id> Provider id (default: cline)
-m, --model <id> Model id (default: anthropic/claude-sonnet-4.6)
-k, --key <api-key> API key override for this run
-p, --plan Run in plan mode (default is act mode)
-i, --tui Interactive TUI multi-turn mode
-t, --timeout <seconds> Optional run timeout in seconds
-c, --cwd <path> Working directory for tools
--config <path> Configuration directory (used for CLI home resolution)
--hooks-dir <path> Additional hooks directory hint for runtime hook injection
--acp ACP (Agent Client Protocol) mode
--thinking [none|low|medium|high|xhigh] Model thinking level when supported. Defaults to medium when the flag is provided without a level; thinking is off when the flag is omitted.
--compaction <agentic|basic|off> Context compaction mode. Defaults to basic; use agentic for LLM compaction or off to disable.
--retries <count> Maximum consecutive mistakes (retries) before halting (default: 3)
--json Output NDJSON instead of styled text
--data-dir <path> Use isolated local state at <path> instead of ~/.cline (enables sandbox mode automatically)
--auto-approve [true|false] Set tool auto-approval for all tools
--kanban Run the external kanban app
-y, --yolo Skip tool approval prompts, enable submit_and_exit, and disable spawn/team tools by default
-z, --zen Dispatch the task to the background hub and exit the CLI immediately
--team-name <name> Override the runtime team state name
-h, --help Show help and exit
-v, --verbose Show verbose runtime diagnostics
-V, --version Show version and exit

--json is non-interactive and requires either a prompt argument or piped stdin. --key takes precedence over environment variables.

Top-level commands

  • cline config - Open the interactive config view
  • cline history|h [options] - List session history or manage saved sessions
  • cline version - Show CLI version
  • cline update [options] - Check for CLI and kanban updates
  • cline auth <provider> - Authenticate or seed provider credentials
  • cline connect <adapter> - Run a chat connector bridge (telegram, gchat, whatsapp)
  • cline connect --stop [adapter] - Stop connector bridge processes and their sessions
  • cline schedule <command> - Create and manage scheduled runs
  • cline doctor - Inspect local CLI health and stale processes
  • cline doctor fix - Kill stale local RPC listeners and old CLI processes
  • cline doctor log - Open the CLI runtime log file
  • cline hook - Handle a hook payload from stdin
  • cline hub - Manage the local hub daemon
  • cline kanban - Run the external kanban app, installing it first when needed

Zen mode

--zen (alias -z) runs a task in the background hub daemon and exits the CLI immediately. It is intended for long-running tasks you want to fire off and walk away from.

cline --zen "Refactor the authentication module and add unit tests"

Behavior:

  • The CLI starts (or reuses) the local hub daemon, submits the task, then exits. It does not stream output or stay attached to the session.
  • Because there is no human in the loop once the CLI exits, zen sessions run with full tool auto-approval (same semantics as --yolo). spawn/team tools are disabled by default for safety, consistent with yolo-mode defaults.
  • If the Cline menubar app is running, it subscribes to hub ui.notify events and will surface a system notification when the task completes.
  • If the menubar app is not running, there is no live UI for the task. Use cline history later to find the session and inspect the result.
  • --zen is incompatible with --data-dir (the implicit sandbox requires a local backend that exits with the CLI) and with --tui (there is no terminal UI to render into).

Tool approval

Tool calls are auto-approved by default. Use --auto-approve false to require review before tool execution.

cline --auto-approve false "Inspect and modify this repository"

When approval is required, the CLI prompts in TTY mode:

Approve tool "<tool_name>" with input <preview>? [y/N]
  • Enter y or yes to approve.
  • Enter anything else (or press Enter) to reject.
  • If stdin/stdout is not a TTY, required-approval calls are denied in terminal mode.

Desktop-integrated approval mode is also supported via env wiring (CLINE_TOOL_APPROVAL_MODE=desktop and CLINE_TOOL_APPROVAL_DIR=<path>). In desktop mode, CLI writes a request JSON file and waits for a matching decision JSON file.

Environment variables

  • ANTHROPIC_API_KEY - API key for Anthropic
  • CLINE_API_KEY - API key for Cline (when using -P cline)
  • OPENAI_API_KEY - API key for OpenAI (when using -P openai)
  • OPENROUTER_API_KEY - API key for OpenRouter (when using -P openrouter)
  • AI_GATEWAY_API_KEY - API key for Vercel AI Gateway (when using -P vercel-ai-gateway)
  • V0_API_KEY - API key for v0 (when using -P v0)
  • CLINE_DATA_DIR - Base data directory for sessions/settings/teams/hooks
  • CLINE_SANDBOX - Set to 1 to force sandbox mode
  • CLINE_SANDBOX_DATA_DIR - Override sandbox state directory
  • CLINE_TEAM_DATA_DIR - Override team persistence directory
  • CLINE_BUILD_ENV - Runtime build mode for SDK-owned subprocess launches
  • CLINE_DEBUG_HOST - Host for development inspector listeners (default 127.0.0.1)
  • CLINE_DEBUG_PORT_BASE - Base inspector port for development child processes
  • CLINE_TOOL_APPROVAL_MODE - Approval mode (desktop uses file IPC; unset uses terminal prompt)
  • CLINE_TOOL_APPROVAL_DIR - Directory for desktop approval request/decision files
  • CLINE_LOG_ENABLED - Set to 0/false to disable runtime file logging
  • CLINE_LOG_LEVEL - Runtime log level (trace|debug|info|warn|error|fatal|silent, default info)
  • CLINE_LOG_PATH - Runtime log file path (default <CLINE_DATA_DIR>/logs/cline.log)
  • CLINE_LOG_NAME - Logger name embedded in runtime log records

--key takes precedence over environment variables.

Contributing

See DEVELOPMENT.md for local development setup, monorepo structure, and TUI architecture. See DISTRIBUTION.md for how the CLI is packaged and distributed.

License

Apache 2.0 © Cline Bot Inc.