From ae52c802e417a149304a3612711f33d4c52990c7 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 8 Nov 2026 21:47:33 -0800 Subject: [PATCH] Plug-ins: test that mcp --headless needs the start-up flag for grants plugin_grants_need_the_start_up_flag now drives `vectorcraft-cli mcp --headless` over stdio. plugin.install with grant is refused without --allow-plugin-grants and accepted with it. --- apps/vectorcraft-cli/tests/it/cli.rs | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/vectorcraft-cli/tests/it/cli.rs b/apps/vectorcraft-cli/tests/it/cli.rs index e7853700f..d6295e2ba 100644 --- a/apps/vectorcraft-cli/tests/it/cli.rs +++ b/apps/vectorcraft-cli/tests/it/cli.rs @@ -19,7 +19,7 @@ fn empty_dir(dir: std::path::PathBuf) -> std::path::PathBuf { dir } -/// `run` refuses `plugin.install`'s `grant` unless the process was started with +/// `run` and `mcp --headless` refuse `plugin.install`'s `grant` unless the process was started with /// `--allow-plugin-grants`, which `mcp` won't take with `--connect`. #[test] fn plugin_grants_need_the_start_up_flag() { @@ -37,6 +37,39 @@ fn plugin_grants_need_the_start_up_flag() { let out = run(&["--allow-plugin-grants"]); assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr)); + let mcp_config = empty_dir(std::env::temp_dir().join(format!("vectorcraft-cli-test-mcp-grants-{}", std::process::id()))); + let mcp_install = |extra: &[&str]| -> Value { + let mut child = Command::new(BIN) + .env("VECTORCRAFT_CONFIG_DIR", &mcp_config) + .args(["mcp", "--headless"]) + .args(extra) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn() + .unwrap(); + { + let mut stdin = child.stdin.take().unwrap(); + let params = json!({"dataBase64": module, "grant": ["doc.read"]}); + for m in [ + json!({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}), + json!({"jsonrpc":"2.0","method":"notifications/initialized"}), + json!({"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_command","arguments":{"command":"plugin.install","params":params}}}), + ] { + writeln!(stdin, "{m}").unwrap(); + } + } + let out = child.wait_with_output().unwrap(); + assert!(out.status.success()); + let replies: Vec = String::from_utf8(out.stdout).unwrap().lines().map(|l| serde_json::from_str(l).unwrap()).collect(); + replies.into_iter().find(|r| r["id"] == 2).unwrap()["result"].take() + }; + let refused = mcp_install(&[]); + assert_eq!(refused["isError"], true, "without the flag: {refused}"); + assert!(refused["content"][0]["text"].as_str().unwrap().contains("--allow-plugin-grants"), "{refused}"); + let accepted = mcp_install(&["--allow-plugin-grants"]); + assert_eq!(accepted["isError"], false, "with the flag: {accepted}"); + let out = Command::new(BIN).args(["mcp", "--allow-plugin-grants", "--connect", "127.0.0.1:1"]).output().unwrap(); assert!(!out.status.success()); assert!(String::from_utf8_lossy(&out.stderr).contains("--allow-plugin-grants applies to the headless server"));