Add corgea mcp install for agent MCP configs - #163
Conversation
Install (or reinstall) the Corgea MCP server into an agent's JSON config using the URL and token already stored by `corgea login`. Re-running removes any existing Corgea entry first so the endpoint and token stay current. Unauthenticated runs fail through the same login gate as other commands. Co-authored-by: Ibrahim Rahhal <ibrahim.rahhal3636@gmail.com>
CI under cargo-llvm-cov failed save_images_separates_references_differing_only_in_case with "Text file busy" when execing a stub script that had just been written in place. Write the stub via fsync+rename, wait until it is executable, and give each test a unique temp dir. Co-authored-by: Ibrahim Rahhal <ibrahim.rahhal3636@gmail.com>
New `corgea mcp install` command is a minor SemVer bump. Cargo.toml is the release source of truth; keep Cargo.lock in sync. Co-authored-by: Ibrahim Rahhal <ibrahim.rahhal3636@gmail.com>
This reverts commit 6214eed.
| } else { | ||
| // Cursor interpolates ${env:NAME} from its own process environment, | ||
| // which a Dock/Start-menu launch usually lacks. Write the token. | ||
| args.push(format!("CORGEA-TOKEN:{token}")); |
There was a problem hiding this comment.
high: Project installation writes credentials into repository files
Project scope writes the raw Corgea token into files such as .cursor/mcp.json and .vscode/mcp.json, which are commonly committed. Printing a warning only after writing the secret does not prevent accidental disclosure. Project installs should use supported environment-variable or secret mechanisms, or reject project scope where secure indirection is unavailable.
Proof or reproduction:
corgea mcp install --agent cursor --scope project
git add .cursor/mcp.json
git diff --cached
# The diff contains CORGEA-TOKEN:<raw token> because the entry is built with format!("CORGEA-TOKEN:{token}").
| } | ||
|
|
||
| fn mcp_remote_entry(url: &str, token: &str, http_only: bool, use_env_block: bool) -> Value { | ||
| let mut args = vec!["-y".to_string(), "mcp-remote".to_string(), url.to_string()]; |
There was a problem hiding this comment.
high: Installer executes an unpinned npm package with credential access
Cursor, Windsurf, and Claude Desktop entries run npx -y mcp-remote without a version. Every launch can therefore download and execute whichever release currently owns the npm tag, while exposing the Corgea token through arguments or environment variables. Pin a reviewed version or ship a controlled transport implementation.
Proof or reproduction:
The generated command is equivalent to:
npx -y mcp-remote <url> --header CORGEA-TOKEN:<token>
There is no `mcp-remote@<version>` constraint.
|
|
||
| pub fn looks_like_corgea_mcp_url(value: &str) -> bool { | ||
| let lower = value.to_ascii_lowercase(); | ||
| lower.contains("corgea.") && lower.contains("/mcp") |
There was a problem hiding this comment.
high: Loose URL matching deletes unrelated MCP servers
looks_like_corgea_mcp_url uses substring checks instead of parsing and validating the hostname. Consequently, reinstalling Corgea removes unrelated entries whose URLs merely contain corgea. and /mcp. Match an explicit trusted Corgea hostname or another unambiguous identifier.
Proof or reproduction:
let existing = r#"{"mcpServers":{"unrelated":{"url":"https://notcorgea.app/mcp"}}}"#;
let (out, _) = upsert_corgea(Agent::Cursor, existing, "https://www.corgea.app/mcp", "tok").unwrap();
let value: Value = serde_json::from_str(&out).unwrap();
assert!(value["mcpServers"].get("unrelated").is_some()); // fails: entry was deleted
| "httpUrl": url, | ||
| "headers": token_header(token) | ||
| }), | ||
| Agent::Continue => json!({ |
There was a problem hiding this comment.
high: Continue installation creates a context provider instead of an MCP server
The Continue branch inserts an arbitrary provider named corgea under contextProviders. Continue does not interpret that object as an MCP server; MCP configuration belongs in its MCP-server configuration structure. Thus the advertised Continue installation succeeds but does not register a usable server.
Proof or reproduction:
let (out, _) = upsert_corgea(Agent::Continue, "{}", "https://www.corgea.app/mcp", "tok").unwrap();
let value: Value = serde_json::from_str(&out).unwrap();
assert!(value.get("mcpServers").is_some()); // fails
assert!(value["contextProviders"][0]["name"] == "corgea"); // confirms the wrong configuration type
There was a problem hiding this comment.
Automated review risk: 4/5.
The installer risks credential disclosure, executes an unpinned package, can delete unrelated MCP entries, and generates an invalid Continue configuration.
Critical or high-priority changes must be addressed.
Automatic approval was not submitted: checks failed: rust-tests.
Bring in the merged ETXTBSY image-test fix (#164) so this PR's CI can pass without any further MCP-branch changes. Co-authored-by: Ibrahim Rahhal <ibrahim.rahhal3636@gmail.com>
Adds
corgea mcp install --agent <name>so a logged-in CLI can write the Corgea MCP server into an agent's JSON config using the URL and token already stored bycorgea login.Version bumped 1.11.1 → 1.12.0 (minor: new command).
Cargo.tomlis the release source of truth.Behavior
scan/skill/ls. An empty or missing token exits with the existing "No token set" message.mcp-remotewith--transport http-onlyand the token in the header (Cursor does not interpolate${env:NAME}from the serverenvblock).--agent claude):mcp-remoteplus anenvblock, matching the docs."type": "http") withurl+CORGEA-TOKENheader.corgeakey, or any server whose URL still points at a*.corgea.*/mcpendpoint), that entry is removed and rewritten so a reinstall refreshes URL and token. Neighboring servers and unrelated keys are left intact.--scope user(default) orproject;--dirwrites a custom path;--set-defaultpersists the agent likecorgea skill install.Tests
CORGEA_URL/CORGEA_TOKEN, reinstall refresh, and--agent claude.This branch is now rebased/merged with
main, including the #164 ETXTBSY image-test fix. No further MCP-branch changes.