The canonical standalone MCP/API Skill is calle 1.0.2. Verify its
loaded name and version after host reload, not just its directory on disk.
Plugin-owned calle entries have separate lifecycles; identify the intended
standalone or plugin entry when the host exposes overlapping names.
The legacy CLI compatibility entry is calle-cli; its executable remains
calle, and authentication and recovery state stay on the original CLI path.
Users retaining the old standalone CLI workflow should follow the
explicit migration steps. Do not fix a
name mismatch by logging out, deleting credentials or recreating a pending call.
The temporary callev2 testing source is retired, and migration of its installed
copies is outside this release's scope. Same-name update checks do not authorize
switching Skill identity or publisher. An unavailable source means unknown
update status.
Use this guide when CALL-E installation, authentication, or tool verification fails in a local agent environment.
A request works in your terminal but fails in the Cursor agent shell with
CONNECT tunnel failed, response 403. The CALL-E CLI may also report
fetch failed.
In Cursor 3.21.16, the setting is under Settings → Agents → Execution and Approvals → Run Mode. Keep Auto-Review (with Sandbox) enabled while checking network access. Run this in the agent shell:
printf "CURSOR_SANDBOX=%s\n" "$CURSOR_SANDBOX"
curl -sS --connect-timeout 10 --max-time 20 -o /dev/null -w "HTTP %{http_code}\n" https://seleven-mcp-sg.airudder.com/On macOS, CURSOR_SANDBOX=seatbelt identifies the sandbox. If curl reports a
CONNECT 403 there but reaches the same host in your terminal, check the sandbox's
domain policy. A generic fetch failed alone does not identify the cause.
Using your editor, add the CALL-E host to the workspace's
.cursor/sandbox.json. If the file already exists, merge the entry into its
networkPolicy.allow list without replacing other settings:
{
"networkPolicy": {
"default": "deny",
"allow": ["seleven-mcp-sg.airudder.com"]
}
}This keeps the sandbox enabled. Existing deny rules and organization policies can still block the host; see Cursor's sandbox configuration reference. Retry the curl check. An HTTP 404 from this root URL still confirms that HTTPS reached the server; it does not verify authentication.
If curl connects but the Node CLI still reports fetch failed, Node may not be
using the sandbox's proxy. Follow
CLI entry point selection
to prepare the trusted launcher and a tools-request.json with this argv:
["mcp", "tools"]With an existing CALL-E login, run:
NODE_USE_ENV_PROXY=1 node run-agent-command.mjs tools-request.jsonThis asks Node to use the proxy environment supplied by the sandbox. Keep TLS
certificate verification enabled. The environment variable requires a Node
version that supports it; see the
Node reference.
A successful response has ok: true and lists plan_call, run_call, and
get_call_run among its tools.
These steps were tested on macOS with Cursor 3.21.16, Node 26.8.2, and CALL-E CLI
0.5.2, using an existing login. The domain entry resolved curl's CONNECT 403;
NODE_USE_ENV_PROXY=1 also resolved the CLI's fetch failed. This check does not
cover a fresh OAuth login or skill installation.
For Python applications, invoke the existing CLI launcher with a trusted Node
executable and pass arguments as JSON through stdin. This avoids Windows
command-name lookup and shell parsing of argument values. The launcher verifies
that the selected package is @call-e/cli before running it.
Follow CLI entry point selection
to select a trusted installation. Replace the two paths below with your absolute
Node executable and @call-e/cli package paths:
import json
import subprocess
from pathlib import Path
node = Path(r"C:\Program Files\nodejs\node.exe")
package_dir = Path(r"C:\trusted\node_modules\@call-e\cli")
launcher = package_dir / "scripts" / "run-agent-command.mjs"
request = {"package_dir": str(package_dir), "argv": ["--help"]}
subprocess.run(
[str(node), str(launcher)],
input=json.dumps(request),
text=True,
shell=False,
check=True,
)This help check requires no login and makes no calls. Use the same invocation
on macOS or Linux with the corresponding absolute paths. For other commands,
change argv; see the CLI reference for integration attribution and returned
argument arrays.
Why does calle work in my terminal but fail from Python?
Python's subprocess.run(["calle", "--help"]) can raise
FileNotFoundError: [WinError 2] on Windows. npm provides a calle.cmd wrapper,
while a direct process launch does not resolve the bare name like a shell does.
The CLI has not started when this error occurs.
Can I use calle.cmd or cmd /c instead?
The reported Windows test confirmed that calle.cmd --help displayed help when
called from Python, and the reporter used cmd /c for a status query. Those
results do not verify arbitrary arguments. For application integrations, use
the recommended launcher: command scripts can reinterpret quotes, special
characters, and multiline text. Adding shell=True is not needed.
Where do I find the paths?
In PowerShell, Get-Command node.exe shows the Node executable. For a global
npm installation, npm root -g gives the package root; append @call-e/cli to
that directory. For a local installation, select the trusted application's
node_modules/@call-e/cli directory. Configure these paths once instead of
running discovery commands before every invocation.
How do I pass spaces, quotes, or multiline text?
Keep each argument as one string in argv, including an entire multiline value
as one element. Let json.dumps serialize the request. Do not add shell quotes
to individual arguments, concatenate a command string, or use shell=True.
What if the launcher rejects the package or entry point?
Check that package_dir names the @call-e/cli directory, not its parent
node_modules directory or the older @call-e/calle SDK. If the launcher reports
that command-help checks failed, update the trusted CLI installation as directed
by the CLI reference before authenticating.
A Node integration on Windows may abort while its host process exits with this libuv assertion:
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c, line 94
This has been observed when the same long-running Node process starts CALL-E
with asynchronous spawn() handles and also uses a synchronous child process,
such as execSync("npm root -g"), to discover the CLI entry point.
A separate shell-launch symptom can occur when a multiline --goal is sent
through cmd /c: cmd.exe may split or reinterpret the arguments before the
CLI receives them, sometimes surfacing as Unknown option: --to-phone.
In the reported configuration, the assertion came from Node/libuv teardown in the embedding process after synchronous and asynchronous child-process paths were mixed. It is not evidence that the CALL-E CLI rejected the request or failed internally. The same assertion can have other causes, so apply this guidance when the host matches the child-process pattern above.
The multiline failure is related but distinct: a command shell parses the command string before CALL-E sees it, so newlines and quoting may change the argument boundaries.
Keep the embedded CLI launch asynchronous and shell-free from discovery through process exit:
- Install
@call-e/clias a dependency of the embedding application and resolve its published JavaScript entry point during application startup. - Start that entry point with the current Node executable and asynchronous
spawn(). - Pass every CLI token as a separate array element, including the complete multiline goal as one element.
- Set
shell: falseand wait for the child process to close before tearing down the host.
import { spawn } from "node:child_process";
import { once } from "node:events";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const cliEntry = require.resolve("@call-e/cli/bin/calle.js");
export async function planCall({ phone, goal }) {
const child = spawn(
process.execPath,
[
cliEntry,
"call",
"plan",
"--to-phone",
phone,
"--goal",
goal,
],
{
shell: false,
stdio: "inherit",
windowsHide: true,
},
);
const [exitCode] = await once(child, "close");
if (exitCode !== 0) {
throw new Error(`calle call plan exited with code ${exitCode}`);
}
}Do not route this integration path through cmd /c, a PowerShell command
string, or a package-manager command shim. Do not run
execSync("npm root -g") while the host still owns live asynchronous child
handles. If a global CLI install is unavoidable, resolve its absolute entry
path outside the long-running host, inject it as application configuration, and
validate it before starting concurrent child work.
First use the same launch pattern with call plan --help; this verifies the
shell-free child path and normal process exit without a network request. Then
use calle call plan with a multiline goal; planning does not place a call.
Confirm that the integration no longer reports shell argument-parsing errors
and that the child and host processes exit normally. If the assertion remains
in an integration that does not match the pattern above, investigate that
host's other child handles and teardown paths separately.
calle call plan exits with this error while authentication and MCP tool
discovery still work:
MCP request timed out for tools/call
The plan_call request took longer than the CLI's effective request timeout.
Current CLI releases allow 150 seconds for plan_call by default while keeping
the shared 15-second default for other MCP requests. Older CLI releases used
the shared 15-second timeout for planning too. An explicit
--timeout-seconds value overrides either default.
This is a client-side timeout, not an authentication error. Planning does not place a call, so it is safe to retry after adjusting the timeout.
Check the defaults reported by the installed CLI:
["call", "plan", "--help"]If the command used an explicit timeout shorter than planning needs, remove the flag to use the current planning default or retry with a longer value:
["call", "plan", "--to-phone", "+15551234567", "--goal", "Confirm the appointment", "--timeout-seconds", "300"]If help reports only the 15-second shared default for planning, update the CLI and retry:
npm install -g @call-e/cliSee the CLI reference for the canonical timeout defaults and option behavior.
A successful retry prints the planned call payload as JSON. Review the plan and continue through the normal confirmation flow; do not treat a successful plan as evidence that a call has already started.