# Your MCP server starts the job. Now it can tell the agent it's done.

**No status tool to poll, no timeout to tune. One `emit` when the job finishes.**

A background job, such as a render, a crawl, a build or a training run, finishes long after the tool call that started it returns. Your server knows the moment it's done. The agent that asked doesn't, and in most agents nothing tells it.

With Wakeshift, the tool that starts the job also subscribes the conversation. When the job finishes, your server calls `emit`, and that conversation picks up where it left off, in Claude Code, Codex, Cursor, Copilot CLI or whichever agent your user runs. Your user can start the job and walk away.

[Try it in two minutes](https://try.wakeshift.ai), no sign-up · [Read the quickstart](https://wakeshift.ai/docs/quickstart)

## What happens today

There are three usual answers, and each one breaks somewhere.

- **Block until it's done.** That works until a timeout. Cloudflare's edge closes a request after 100 seconds, and MCP clients have limits of their own.
- **Return a job ID and a status tool.** The agent checks, says "still running," and ends its turn, so the user ends up doing the waiting. Or it keeps checking, and every check is a model turn that rereads the conversation. Developers have reported about 400M tokens in one night of Claude Code's `/loop` ([claude-code#106522](https://github.com/anthropics/claude-code/issues/106522)), and 474 timer wakes in Cursor, 99% of which found nothing ([Cursor forum](https://forum.cursor.com/t/172963)).
- **Hope the user comes back.** One developer's overnight job finished, but the follow-up the agent had promised never ran, "because nothing woke the main session" ([claude-code#104807](https://github.com/anthropics/claude-code/issues/104807)).

MCP's progress notifications don't help either: they travel inside a tool call that's still open, and stop when it returns.

## How it works

On the MCP server you already run, the tool that starts the job subscribes the conversation that called it:

```ts
const crawlFinished = wake.defineEvent("crawl.finished", {
  description: "A site crawl finished",
  args: z.object({ crawl: z.string() }),
  payload: z.object({ status: z.string(), pages: z.number() }),
  text: (r, { crawl }) => `Crawl ${crawl} ${r.status}: ${r.pages} pages`,
})

const attached = wake.attach(server)

server.registerTool(
  "start_crawl",
  { description: "Crawl a site", inputSchema: attached.inputs(z.object({ url: z.string() })) },
  attached.events("start_crawl", { subscribes: [crawlFinished] }, async ({ url }, call) => {
    const crawl = await startCrawl(url)
    await call.subscribe(crawlFinished, { crawl })
    return `Crawl ${crawl} started. You'll hear back when it finishes.`
  }),
)
```

When the job ends, wherever your backend learns it (the code that finishes the job, a queue consumer, or a webhook handler you already have):

```ts
await crawlFinished.emit({ crawl }, { status: "done", pages: 1834 })
```

The agent wakes with "Crawl c81f done: 1834 pages", marked as coming from your app, and carries on: it reads the results with your tools, or tells the user. The SDKs are open source, for [TypeScript](https://wakeshift.ai/docs/sdk), [Python](https://wakeshift.ai/docs/python) and [Go](https://wakeshift.ai/docs/go), and any other language can use the [HTTP API](https://wakeshift.ai/docs/other-languages).

## What your user sees

They ask for the crawl, and the agent says it'll pick it up when it's done. They go to lunch. When the crawl finishes, the agent wakes, in most agents within seconds, and continues the work they started together. If they closed the agent, what arrived is held until the conversation reconnects ([what each agent needs after a restart](https://wakeshift.ai/docs/agents#trust-steps)).

- **The first time,** some agents ask once: Codex needs a one-time install, and Cursor asks before it starts a background command. [Agents](https://wakeshift.ai/docs/agents) lists what each one asks.
- **In Claude Code,** nothing needs installing. The agent asks once how to notify the user: in this session, with nothing installed; in every session, through Wakeshift's plugin, after which nothing more is approved; or not at all. For this session only, manual permission mode asks again each time Claude Code restarts its background monitor, every 25 minutes, so while the user is away, wakes wait on that approval. If your app turns on the [wait tool](https://wakeshift.ai/docs/agents#the-wait-tool-for-claude-code) (it's off by default), Claude Code in the terminal, on accounts with MCP tasks, waits with it instead: one approval if the user chooses "don't ask again", and the wait carries on through `/compact`, closing and `claude --continue`. It costs a request held open to your server, renewed about three times a minute, for each waiting conversation. With it off, nothing holds requests open to your server.
- **A subscription lasts** until the agent or your tool ends it, and expires after 30 days (or the `ttl` you set) without a delivery or a fresh subscribe.

## When you don't need this

- **Jobs under a minute or two.** A blocking call, or a couple of checks, is fine.
- **Users only in Claude Code's terminal, on accounts with MCP tasks.** There, a server that speaks MCP tasks on protocol 2026-07-28 can have Claude Code follow the job for it. Wakeshift's wait tool uses the same path, and Wakeshift covers the other agents.
- **Users only in ChatGPT's Work chats or dots.** They subscribe to MCP Events themselves, and a free toolkit is enough ([hosted MCP Events](https://wakeshift.ai/mcp-events)).

## Next

- [Quickstart](https://wakeshift.ai/docs/quickstart): offer an event from your MCP server and wake Claude Code with it.
- [One MCP server, every agent](https://wakeshift.ai/claude-code-codex-cursor): which agents wake, and what each asks of your user.
- [Pricing](https://wakeshift.ai/pricing): free for 50,000 deliveries a month. The people who use your app never pay.
