Skip to content

Ephemeral containers and claim

Your agent can connect a user who has no Wire account. They get a fully working ephemeral container with a 7-day lifetime: same tools, same MCP endpoint, no signup. When they’re ready to keep it, the SDK upgrades the container to permanent without the user ever leaving your agent.

This is the no-account onboarding flow: connect first, let the user try things, prompt to claim before the container expires.

Two surfaces tell you:

  • connection.expiresAt is non-null on an ephemeral connection and tells you when the container lapses.
  • getStatus(apiKey) returns container.isEphemeral and container.ephemeralExpiresAt, so you can check at any time and decide when to prompt.
const claimed = await client.claim(connection.apiKey, {
onUserPrompt: ({ url }) => {
myUi.show(`Sign up to keep your container: ${url}`);
},
});
// claimed.expiresAt === null, the container is permanent

claim() mints a single-use claim link, hands it to your onUserPrompt handler (or prints it and opens the OS browser if you don’t pass one), and resolves once the user finishes signing up. All their data, the MCP URL, and the apiKey stay exactly the same.

Semantics worth knowing:

  • Calling claim() on an already-claimed container resolves immediately with the current snapshot. It’s safe to call twice.
  • If the user doesn’t finish within five minutes (configurable via timeoutMs), claim() throws CLAIM_TIMEOUT. The link itself stays valid for 30 minutes, so the user can still finish in the browser, and a later getStatus() will show the container as permanent.

Turn-based agents shouldn’t hold a promise open while a user signs up. Mint the link, show it, and detect completion on your own schedule:

const { url, expiresAt } = await client.getClaimUrl(connection.apiKey);
myUi.show(`Sign up to keep your container: ${url}`);
// Any later turn:
const status = await client.getStatus(connection.apiKey);
if (!status.container.isEphemeral) {
// claimed, celebrate accordingly
}

getClaimUrl() mints the link and nothing else. It throws ALREADY_CLAIMED if the container is already permanent, which doubles as a cheap “does this still need claiming” check.

ephemeralExpiresAt gives you the deadline. A pattern that works well: prompt once when meaningful data has accumulated (the user now has something to lose), then again as expiry approaches. Avoid prompting on first contact; the whole point of the flow is that the user experiences value before being asked to sign up.