Appearance
Deploy an Agent SDK project
Deploy a pushed Git ref as a stable service on Cursor-managed hosting, or self-host it when you need your own network or process controls.
Deploy from Git
Commit and push the ref you want to run, then deploy it:
bash
cd my-agent
agent-sdk login
agent-sdk validate
agent-sdk deployThe command waits until the agent is running and prints its URL. Open Deployed Agents to see the agent and manage it.
deploy builds the pushed ref, so uncommitted changes don't ship. Pass the source when the checkout is not the one you want:
text
agent-sdk deploy \
--repo https://github.com/acme/agents \
--ref main \
--path agents/weather \
--slug weather-agentConnect deployed peers
To call another agent your team deployed, add defineConnection({ agent: "weather-agent" }) to the caller and redeploy it. See Peer agents.
Privacy Mode
Managed hosting stores your repository and the agent's data, so it depends on your privacy setting:
| Privacy setting | Managed hosting |
|---|---|
| Privacy Mode | Available. Cursor stores deployment data the same way it does without Privacy Mode, and the agent's model requests get the same Privacy Mode handling as your other Cursor requests. |
| Privacy Mode (Legacy) | Not available. deploy, a hosted session, and an eval run all refuse. |
Switch to Privacy Mode, or ask a team admin when your team enforces the setting.
Add egress and secrets
Declare the hosts and secret names your code calls. agent-sdk info --dir . shows them combined with what mounted extensions add.
ts
// bot/agent.ts
import { defineAgent } from "@grok/agent-sdk";
export default defineAgent({
hosting: {
egressDomains: ["api.weather.example.com"],
secretNames: ["WEATHER_API_KEY"],
},
});After you deploy, set each value at the hidden prompt. The next task uses the new value without another deploy.
bash
agent-sdk secret set weather-agent WEATHER_API_KEY
agent-sdk secret list weather-agentCommit secret names, never values. Don't pass NAME=VALUE to secret set or use a name that starts with CURSOR_.
Hosted secrets arrive after your modules load, so read each one inside the handler, tool, or callback that needs it. Give an MCP connection a ${NAME} template instead.
SCM channels take each credential as a named secret, such as { secretName: "GITHUB_WEBHOOK_SECRET" }. The channel reads the environment variable with that name locally and the deployment secret on Cursor hosting. On Cursor hosting, Cursor rejects a badly signed delivery before it reaches your agent. validate fails on a literal or a getter.
Write each egress host as a lowercase hostname with no scheme or path, such as api.example.com, and add a port such as clickhouse.example.com:9440 only for raw TCP. agent-sdk deploy rejects any other form, and the error quotes that host.
Your team's egress policy limits which hosts you can list in hosting.egressDomains. If you list a host that the policy blocks, agent-sdk deploy fails and the error names that host. A deployment that is already running keeps the policy from its last successful deploy. Ask a team admin to add the host, or remove it and deploy again.
| Team egress mode | What agent-sdk deploy allows |
|---|---|
| No mode set | Every host in hosting.egressDomains. |
| Allow all network access | Every host in hosting.egressDomains. The bot stays limited to that list. |
| Defaults + team allowlist | The platform default list, plus the team list. |
| Team allowlist only | The team list. |
No team list can remove the platform base, which includes Cursor's API and the npm registry. agent-sdk deploy --json lists every allowed host under egress.effective.
A team entry *.example.com allows example.com, every subdomain, and narrower wildcards such as *.api.example.com. An agent entry *.example.com skips the apex, so list example.com too when the agent calls it.
A raw TCP host such as db.example.com:5432 needs a team CIDR:port entry that covers every public IPv4 address it resolves to. If your team restricts egress, a PlanetScale Postgres host (*.pg.psdb.cloud) needs a team CIDR:port entry for ports 5432 and 6432.
Use the hosted agent
Verify a hosted turn
bash
agent-sdk session create --slug weather-agent --message "Forecast for Paris" --wait
agent-sdk session get ses_... --prod --slug weather-agent
agent-sdk session get ses_... --prod --slug weather-agent --view events
agent-sdk logs --prod --slug weather-agentWithout --wait, the command returns before the session exists, so the output has no sessionId yet. A long turn can show running with no logs for several minutes. If the event count keeps going up, the turn is still working.
Send work to the deployment
Call a custom route on the stable alias URL with the alias token:
bash
curl -X POST "$AGENT_ALIAS_URL/v1/channels/tickets/ticket" \
-H "X-Agent-Alias-Token: $AGENT_ALIAS_TOKEN" \
-H 'content-type: application/json' \
-d '{"ticketId":"ENG-142","message":"CSV export returns 500"}'See Route responses for what the caller gets back. To confirm the work started, run agent-sdk session list --prod --slug weather-agent.
Protect the alias token
The first deploy prints the alias token once. If it leaks or you lose it, run agent-sdk deployment rotate-token weather-agent. Output from deployment --json can include access headers, so guard it the same way.
Use publicEndpoint() only for a webhook provider that can't send the token and whose signature the channel verifies.
Update the deployment
Push the new ref and deploy the same slug. Each redeploy replaces the watched repositories, so pass every --cursor-events-repo value again, or the deployment watches only its GitHub source repository. Run agent-sdk deployment get weather-agent to check a rollout.
Keep state across replacements
Sessions, ctx.host.kv, and ctx.host.files survive restarts and redeploys. Anything else the agent writes to disk can disappear.
Self-host securely
Run Agent SDK under Node 22.13 or newer, never Bun. One process can serve every agent under a directory:
bash
export CURSOR_API_KEY="<cursor-api-key>"
export AGENT_SDK_BEARER_TOKEN="$(openssl rand -hex 32)"
agent-sdk serve \
--dir /srv/agents \
--host 127.0.0.1 \
--port 3000 \
--state-root /var/lib/agent-sdk \
--bearer-token "$AGENT_SDK_BEARER_TOKEN"Before you expose the host:
- Put TLS or an authenticating proxy in front of the server.
- Keep
--bearer-tokenunless a proxy authenticates every caller. - Keep
--state-rooton a backed-up persistent volume outside the repository. - Turn on schedules in only one process per project.
In a container, use --host 0.0.0.0 behind an authenticating network boundary.