feat: add non-interactive mode to mcp add command#53
Conversation
| .option("url", { type: "string", describe: "Server URL (for remote type)" }) | ||
| .option("command", { type: "string", describe: "Command to run (for local type)" }) | ||
| .option("header", { type: "array", string: true, describe: "HTTP headers as key=value (repeatable)" }) | ||
| .option("no-oauth", { type: "boolean", describe: "Disable OAuth" }) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
packages/opencode/src/cli/cmd/mcp.ts
Outdated
| // Try the other scope | ||
| const otherPath = await resolveConfigPath( | ||
| useGlobal ? Instance.worktree : Global.Path.config, | ||
| !useGlobal, | ||
| ) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
|
Addressing Sentry review comments:
|
| export async function list() { | ||
| return state().then((x) => Object.values(x)) | ||
| const full = state() | ||
| const resolved = await Promise.race([full, Promise.resolve(undefined)]) |
There was a problem hiding this comment.
Bug: Promise.race with Promise.resolve(undefined) causes Command.list() to always return only default commands, excluding custom ones from config, MCP, or skills.
Severity: HIGH
Suggested Fix
The Promise.race implementation is incorrect for its intended purpose. A different approach is needed, such as checking if the full promise is already resolved before the race, or using a timeout-based approach instead of racing against an immediately resolved promise.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/altimate-code/src/command/index.ts#L188
Potential issue: In `Command.list()` and `Command.get()`, the code uses
`Promise.race([full, Promise.resolve(undefined)])`. Because `Promise.resolve(undefined)`
creates an already-resolved promise, it always wins the race immediately. This causes
the `resolved` variable to always be `undefined`. As a result, `Command.list()` only
returns the three default commands (`init`, `discover`, `review`) and never includes MCP
prompts, skills, or user-configured commands. This breaks any UI feature, such as the
`/command` endpoint, that relies on listing all available commands. While
`Command.get()` has a fallback, its optimization path becomes dead code.
1cf8025 to
80f08d6
Compare
Add CLI flags (`--name`, `--type`, `--url`, `--command`, `--header`, `--no-oauth`, `--global`) to `mcp add` for scripted usage. When `--name` and `--type` are provided, the command skips all interactive prompts and writes the MCP config directly. This enables copy-paste onboarding commands from the Altimate web UI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Define `oauth` as a boolean (default `true`) so `--no-oauth` works via yargs' built-in prefix negation instead of a custom `no-oauth` option that conflicts with yargs' `--no-X` handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `altimate-code mcp remove <name>` (alias `rm`) to remove an MCP server from config. Supports `--global` flag; auto-searches the other scope if the server isn't found in the specified one. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
`mcp add` and `mcp remove` now auto-detect when `cwd` is not inside a git project and write to the global config instead of trying to create `/altimate-code.json`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80f08d6 to
7233f77
Compare
packages/opencode/src/cli/cmd/mcp.ts
Outdated
| // Try the other scope | ||
| const otherPath = await resolveConfigPath( | ||
| useGlobal ? Instance.worktree : Global.Path.config, | ||
| !useGlobal, | ||
| ) |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
- Update `ci.yml` TypeScript test `working-directory` from `packages/altimate-code` to `packages/opencode` (post-restructure) - Fix `mcp remove` fallback logic to avoid accessing filesystem root when not in a git repo — only try cross-scope fallback when `Instance.worktree` is valid (i.e., in a git repo) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e242f11 to
8b7ab63
Compare
- Validate server name is non-empty (reject whitespace-only)
- Use `trim().split(/\s+/).filter(Boolean)` for command parsing
instead of naive `split(" ")` that breaks on multiple spaces
- Add `URL.canParse()` validation for remote server URLs,
matching interactive mode's validation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…active feat: add non-interactive mode to mcp add command
Summary
mcp addcommand with flags:--name,--type,--url,--command,--header,--no-oauth,--globalmcp remove(aliasrm) command to remove MCP servers by name--no-oauthby using yargs built-in--no-negation instead of a custom option~)Test plan
altimate-code mcp add --name "test" --type remote --url "https://example.com/sse" --header "Authorization=Bearer token" --no-oauth --globaland verify config is writtenaltimate-code mcp remove test --globaland verify config entry is removedmcp addfrom a non-git directory (e.g.~) without--globaland verify it falls back to global configmcp removefor a server that doesn't exist and verify error message🤖 Generated with Claude Code