This guide takes a new installation from an sctl binary to a working AI-tool connection. The AI client talks
to sctl mcp over stdio; sctl mcp talks to a separately running sctl serve; the ScriptCat extension connects
to that daemon and remains the authority for source disclosure and write approval.
AI client ── stdio MCP ──▶ sctl mcp ── local control API ──▶ sctl serve ── WebSocket ──▶ ScriptCat
The process model is described in architecture.md. This document owns only the end-user installation and setup workflow.
Install the latest release on macOS or Linux with one command:
curl -fsSL https://raw.githubusercontent.com/scriptscat/sctl/main/scripts/install.sh | shor on Windows PowerShell:
irm https://raw.githubusercontent.com/scriptscat/sctl/main/scripts/install.ps1 | iexThe installer downloads the hyphen-named release archive sctl-<version>-<os>-<arch>.<ext> for your platform,
verifies its sha256 against checksums.txt, installs sctl into ~/.local/bin (macOS/Linux) or
%LOCALAPPDATA%\sctl\bin (Windows), and prints a PATH hint when the install directory is not on it.
SCTL_VERSION pins a specific version; SCTL_INSTALL_DIR overrides the install directory.
To install manually instead, download the matching sctl-<version>-<os>-<arch>.<ext> archive from
GitHub Releases, extract it, and put the sctl executable on
PATH. If no published release is available, contributors can build sctl from source.
On macOS and Linux, make a downloaded binary executable if the unpacking tool discarded permissions:
chmod +x /absolute/path/to/sctlVerify the exact binary that the shell and MCP client will run:
command -v sctl
sctl versionA contributor's plain go build reports 0.0.0-dev; release builds inject their version, commit, and build
time through the release workflow.
The daemon, CLI commands, and MCP process must use the same data directory. It contains the long-term pairing key, the daemon's local control token, and logs. Pick an absolute path that belongs to the current user:
/absolute/path/to/sctl-data
Set SCTL_DATA_DIR for every process that runs sctl:
export SCTL_DATA_DIR=/absolute/path/to/sctl-data
sctl serve
sctl status
sctl mcpAn explicit --data-dir takes precedence over SCTL_DATA_DIR.
Do not put this directory in a repository or cloud-synchronized shared folder. The credential inventory and file permissions are owned by threat-model.md.
If neither --data-dir nor SCTL_DATA_DIR is set, sctl uses the platform's per-user application data directory.
The listener defaults to 127.0.0.1:8643. To use another address, pass the same
--listen-address <host:port> global flag to serve and every CLI or MCP process that connects to it.
Run the daemon in a terminal and leave it running:
sctl servesctl serve is the only process that owns the WebSocket connection to ScriptCat. CLI commands and sctl mcp
never start it automatically. For long-running use, configure the operating system's user service manager to
run this exact command; service-manager-specific installation is outside this guide.
Before enrollment, this command should reach the daemon and report that no extension is connected:
sctl statusIf it reports that the daemon is unreachable, fix that before configuring an MCP client.
-
Open ScriptCat's options page and enable External Access.
-
Keep
sctl serverunning. -
In another terminal, run:
sctl connect
-
Enter the displayed one-time code in ScriptCat's External Access enrollment dialog.
-
Verify the connection:
sctl status
The status output must say that the extension is connected. The one-time code is valid only for the enrollment window and must not be pasted into an AI conversation, issue, log, or MCP configuration. After enrollment, the extension and daemon use the persisted long-term pairing state; each AI client does not enroll separately.
Disabling External Access in ScriptCat revokes the extension side of this relationship. Run connect again if
you intentionally revoke it and later want to reconnect.
Use the MCP client's stdio-server configuration and point it at the exact sctl binary verified in step 1. The common configuration shape is:
{
"mcpServers": {
"scriptcat": {
"command": "/absolute/path/to/sctl",
"env": {
"SCTL_DATA_DIR": "/absolute/path/to/sctl-data"
},
"args": [
"mcp",
"--name",
"my-ai-client"
]
}
}
}Adapt the outer property name to the client, but keep command and args unchanged. Important details:
commandshould be an absolute executable path. GUI applications often have a smallerPATHthan a shell.SCTL_DATA_DIRmust resolve to the same absolute directory used bysctl serve.- Use an absolute data path. JSON configurations generally do not perform shell expansion for
~,$HOME, command substitutions, or quoted shell expressions. mcpstarts only the stdio MCP process. The daemon must already be running.--nameis an audit label, not an authorization boundary. Give each configured client a recognizable label.- Do not redirect stdout: it is reserved exclusively for MCP protocol frames. Diagnostics go to stderr and the
data directory's
logs/folder.
Restart or reload the AI client after changing its MCP configuration.
First verify the infrastructure independently of the AI client:
sctl status
sctl get -o jsonstatus must report a connected extension. get should return a JSON list; an empty list is a valid result.
Then open the AI client's MCP/tool view and confirm that ScriptCat tools are present. Ask it to list installed scripts. A successful call proves the full path:
AI client → sctl mcp → sctl serve → ScriptCat → JSON-RPC response
Reading script source can open a source-disclosure prompt in ScriptCat. Installing, editing, enabling, disabling, and deleting scripts block until the user approves or rejects the operation in the browser. This is expected behavior, not an MCP timeout; the security model is detailed in threat-model.md.
| Symptom | Check |
|---|---|
| MCP process exits immediately or reports that the daemon is unreachable | Start sctl serve first. Requester commands never auto-start it. |
| Control-channel authentication fails | Confirm that serve, CLI commands, and the MCP process resolve to the same absolute data directory; check both SCTL_DATA_DIR and any explicit --data-dir, then restart the MCP client. |
status says the extension is not connected |
Enable External Access in ScriptCat. If it has never been enrolled or was revoked, run connect and enter a new one-time code. |
| Tools do not appear in the AI client | Use the absolute sctl executable path, validate the client's JSON/TOML syntax, and reload the client. Check stderr and <data-dir>/logs/. |
| A read or write call appears to wait | Look for the ScriptCat disclosure or confirmation page. The operation intentionally blocks for the user's decision. |
| The MCP client reports malformed protocol output | Remove wrappers that print banners or diagnostics to stdout. Launch sctl directly; its MCP stdout is protocol-only. |
For daemon logs and lower-level evidence, follow verification.md. For protocol semantics, see protocol.md.
- Never send the one-time enrollment code,
pairing.key, orcontrol.tokento an AI model or another user. - Keep the data directory private to the current operating-system user.
- Treat
--nameonly as an audit label; it does not isolate one MCP client from another. - Review ScriptCat's browser confirmation page before approving writes or source disclosure.
- Remove an MCP server from the AI client's configuration when that client should no longer have access. Use ScriptCat's External Access switch when you intend to revoke the daemon connection itself.