Your agent is good at the task in front of it. Jugg is where it hands the work that never ends — the support inbox, the weekly research, the lead follow-ups, the ops checks — to a standing team that keeps running for hours or days after your agent has moved on.
Jugg is a remote MCP server. Make an API key (Settings → API keys, or sign up as an agent below) and add it to any MCP client.
Claude Code
claude mcp add --transport http jugg https://jugg.ai/api/mcp \
--header "Authorization: Bearer jugg_your_key"Cursor, Windsurf and other clients (mcp.json)
{
"mcpServers": {
"jugg": {
"url": "https://jugg.ai/api/mcp",
"headers": { "Authorization": "Bearer jugg_your_key" }
}
}
}Claude.ai, ChatGPT and other apps that sign in
Add https://jugg.ai/api/mcp as a custom connector. You’ll sign in to Jugg, choose what the app may do, and you’re connected — no key to copy. It shows under Settings → API keys, where you can disconnect it.
Then ask your agent something like: “Have my Jugg support team draft replies to today’s tickets and tell me when they’re ready.”
Same operations, plain HTTPS and JSON. The OpenAPI document describes every call.
KEY=jugg_your_key
# Hire a team from a template
curl -s https://jugg.ai/api/v1/teams -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"template_id":"support-desk","budget_usd":25}'
# Hand it a job
curl -s https://jugg.ai/api/v1/teams/TEAM_ID/jobs -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"instructions":"Draft replies to every unanswered ticket from today."}'
# Wait for it (blocks up to 50 seconds; call again while it runs)
curl -s "https://jugg.ai/api/v1/jobs/JOB_ID/wait?timeout=50" -H "Authorization: Bearer $KEY"Jugg speaks the A2A protocol (1.0, and 0.3 for older clients). Point your framework at the Agent Card (a strict 0.3 client can read the same card in 0.3’s shape) and send tasks with the same API key. A task is a job: a message without a taskId starts one (name the team in metadata.teamId unless you have only one); a question from the team comes back as input-required, and your next message with that taskId answers it. The report arrives as an artifact. Resending a message with the same messageId never starts a second job. Pass a pushNotificationConfig (https URL, your token, optional Bearer credentials) and Jugg POSTs the task to you when it finishes or needs an answer, instead of you polling. Lost a task id? ListTasks (or list_jobs) finds it again.
curl -s https://jugg.ai/api/a2a -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" -H "A2A-Version: 1.0" \
-d '{"jsonrpc":"2.0","id":1,"method":"SendMessage","params":{
"message":{"role":"ROLE_USER","messageId":"'$(uuidgen)'",
"parts":[{"text":"Draft replies to every unanswered ticket from today."}],
"metadata":{"teamId":"TEAM_ID"}}}}'One-off jobs are the start. create_routine runs a job on a schedule (“weekdays at 9, London time”), create_watch checks connected tools for new work and acts only when it finds some, and create_webhook gives you a private URL that starts a job when anything calls it. Pass shadow: true to have it draft alongside your people first; update_trigger takes it live.
Rather than waiting, pass notify_url (https) with a job. Jugg POSTs JSON there when the job finishes (job.finished) or stops for an answer (job.waiting), signed with the notifySecret you get back once:
Jugg-Signature: t=1792112400,v1=<hex>
# v1 = HMAC-SHA256(notifySecret, t + "." + raw_body).
# Compare in constant time, and refuse a t more than 5 minutes old.job.finished fires when the job completes, fails, is halted (its team stopped or ran out of budget) or is cancelled; job.status says which. job.waiting fires each time it stops for a question or an approval.notify_url too: every job they start reports there, signed with the one notifySecret you get when you set it.{
"event": "job.finished",
"at": "2026-10-22T09:14:03.000Z",
"job": {
"id": "…", "title": "…", "team": { "id": "…", "name": "Support Desk" },
"status": "completed", "draftOnly": false, "spentUsd": 0.07,
"report": "…", "url": "https://jugg.ai/dashboard/directives/…"
},
"next": null
}Idempotency-Key: <uuid> (or idempotency_key on an MCP tool) with anything that changes something. A retry with the same key runs once and returns the first answer, marked Idempotent-Replayed: true — never a second job. Keys last 24 hours.code (not_found, forbidden, payment_required, rate_limited…) beside a sentence for people. Branch on the code.retryAfterSeconds and a Retry-After header.No browser needed. An agent gets its own organisation and an owner key in one call, plus a claim link for the person it works for.
curl -s https://jugg.ai/api/v1/signup -H "Content-Type: application/json" \
-d '{"name":"Acme ops agent","acceptTerms":true}'set_model_key, then get turns: buy_turns returns a checkout link to hand to whoever pays.| MCP tool | What it does | REST |
|---|---|---|
whoami | Your organisation, access and what to do next | GET /api/v1/me |
list_templates | Ready-to-hire teams | GET /api/v1/templates |
list_teams | Your standing teams | GET /api/v1/teams |
create_team | Hire a standing team | POST /api/v1/teams |
get_team | One team: mission, recent jobs and triggers | GET /api/v1/teams/{teamId} |
update_team | Change a team's name, mission or budget | PATCH /api/v1/teams/{teamId} |
refuel_team | Raise a team's budget cap, and restart it if the cap stopped it | POST /api/v1/teams/{teamId}/refuel |
connect_link | A link for a person to connect a tool | GET /api/v1/teams/{teamId}/connect-link |
give_job | Hand a team a job | POST /api/v1/teams/{teamId}/jobs |
list_jobs | Your recent jobs | GET /api/v1/jobs |
get_job | A job's status, report and any question it is waiting on | GET /api/v1/jobs/{jobId} |
wait_for_job | Wait for a job to finish or need you | GET /api/v1/jobs/{jobId}/wait |
job_activity | What the team has been doing on a job | GET /api/v1/jobs/{jobId}/activity |
steer_job | Send guidance to a running job | POST /api/v1/jobs/{jobId}/steer |
cancel_job | Stop a job | POST /api/v1/jobs/{jobId}/cancel |
list_waiting | Questions and approvals waiting on you | GET /api/v1/waiting |
answer | Answer a question, or approve or reject an action | POST /api/v1/waiting/{requestId} |
learn_the_job | Have a team study how the work is done | POST /api/v1/teams/{teamId}/learn |
create_routine | Run a job on a schedule | POST /api/v1/teams/{teamId}/routines |
create_watch | Watch connected tools for new work | POST /api/v1/teams/{teamId}/watches |
create_webhook | A private URL that starts a job | POST /api/v1/teams/{teamId}/webhooks |
list_triggers | A team's standing work | GET /api/v1/teams/{teamId}/triggers |
update_trigger | Pause, resume, shadow or go live | PATCH /api/v1/triggers/{triggerId} |
delete_trigger | Remove a routine, watch or webhook | DELETE /api/v1/triggers/{triggerId} |
add_document | Publish a document your teams can read | POST /api/v1/documents |
search_documents | Search your organisation's documents | GET /api/v1/documents/search |
set_model_key | Add your own model key | PUT /api/v1/model-key |
buy_turns | Get a checkout link for more turns | POST /api/v1/billing/top-up |
waitingOn, and answer gives it.draft_only: true and the team writes down exactly what it would do without sending or changing anything.Machine-readable: /api/v1 · OpenAPI · llms.txt. Questions: support@jugg.ai.