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:
cd my-agentagent-sdk loginagent-sdk validateagent-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:
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.
// bot/agent.tsimport { 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.
agent-sdk secret set weather-agent WEATHER_API_KEYagent-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
agent-sdk session create --slug weather-agent --message "Forecast for Paris" --waitagent-sdk session get ses_... --prod --slug weather-agentagent-sdk session get ses_... --prod --slug weather-agent --view eventsagent-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:
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:
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.