agents · public sandbox

Agent quickstart: Create a sandbox family workspace

A public, unauthenticated MCP endpoint for evaluator agents. Call one tool to spin up a sandbox family care workspace — no OAuth, no API key, no invites sent. When the human is ready, they sign in with the same email to claim the workspace and unlock the authenticated MCP surface.

What this is

POST https://app.joinsandwich.com/api/mcp/public is an unauthenticated MCP-style entrypoint for evaluator agents that have not signed a human in yet. It exposes one tool — start_family_care_workspace — that creates a sandbox family care workspace so an agent can demonstrate Sandwich end-to-end without an OAuth dance. The endpoint is distinct from the authenticated /api/mcp surface, which is the right place for real workspace operations once the user has claimed their sandbox.

Sandbox only. Every workspace created here is tagged sandbox: true and stamped to a synthetic anonymous-mcp owner uid. No invite emails are sent. No confirmation email is sent. Nothing leaves the platform until a human signs in and claims it.

When agents should use it

  • You are an evaluator/demo agent showing what Sandwich does, and the human in the loop has not signed in yet.
  • You want to give the user a tangible result (a real Family Inbox address, a real workspace they can later claim) without first sending them through OAuth.
  • You are integration-testing or building an agent connector and want a no-auth code path you can hit from CI or a sandbox MCP client.

Do not use this endpoint to do real care work. The moment the user wants real invites, persistent private care data, calendar/email integrations, or inbox management, hand them off to the claim flow and switch to the authenticated MCP.

Endpoint

One endpoint, one transport, no headers required beyond Content-Type:

public MCP endpointhttp
POST /api/mcp/public HTTP/1.1
Host: app.joinsandwich.com
Content-Type: application/json

A plain GET on the same URL returns a capability descriptor (name, transport, protocol version, advertised tools, rate-limit note) — useful for liveness checks and tool discovery without a JSON-RPC handshake.

Supported JSON-RPC methods: initialize, tools/list, tools/call, ping. The protocol version is 2025-03-26.

Discover tools — tools/list

tools/listbash
curl -s https://app.joinsandwich.com/api/mcp/public \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

The response advertises one tool today:

start_family_care_workspace
Creates a sandbox family care workspace. Allocates a real Family Inbox address and a loved-one record, both tagged sandbox: true. Never sends invite emails — family/sibling addresses come back as inviteDrafts so the agent can show the user what would be sent.

Call the tool — tools/call

sandbox: true is required. Names are required; everything else is optional. Emails are validated and de-duplicated (max 8 family invites). Keep the body under 64 KB.

tools/call — start_family_care_workspacebash
curl -s https://app.joinsandwich.com/api/mcp/public \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "start_family_care_workspace",
      "arguments": {
        "lovedOneFirstName": "Ada",
        "lovedOneLastName": "Lovelace",
        "familyName": "The Lovelace Family (demo)",
        "primaryCaregiverEmail": "demo+caregiver@example.com",
        "careContext": "Lives independently. Adult kids coordinate weekly check-ins.",
        "familyMemberEmails": [
          "demo+sister@example.com",
          "demo+brother@example.com"
        ],
        "sandbox": true
      }
    }
  }'

Argument reference

lovedOneFirstName · required
First name of the care recipient. 1–60 chars.
lovedOneLastName · required
Last name of the care recipient. 1–60 chars.
sandbox · required
Must be true. The endpoint rejects anything else.
familyName
Workspace display name. Defaults to "The <lastName> Family (sandbox)". Up to 120 chars.
primaryCaregiverEmail
Email of the primary caregiver. Optional but strongly recommended — it is the email the human must sign in with to claim the sandbox.
careContext
Free-text care context (up to 2000 chars). Stored on the workspace; not echoed in internal notifications. Keep sensitive medical/financial detail out — see safety.
familyMemberEmails
Up to 8 sibling/family emails. Returned as inviteDrafts. Nothing is emailed from this endpoint.

Response fields

On success, the tool returns two content blocks: a human-readable summary (type: "text") and a JSON-encoded SandboxWorkspaceResult as the second text block. Agents should parse the second block.

SandboxWorkspaceResult (parsed)json
{
  "workspaceId": "fam_01HXYZ…",
  "lovedOneId": "lo_01HXYZ…",
  "inboxAddress": "lovelace-ada-7f3a@inbox.joinsandwich.com",
  "familyName": "The Lovelace Family (demo)",
  "inviteDrafts": [
    { "email": "demo+sister@example.com",
      "role": "caregiver",
      "status": "draft",
      "note": "Not sent — sandbox endpoint never emails." }
  ],
  "sandbox": true,
  "primaryCaregiverEmail": "demo+caregiver@example.com"
}
workspaceId
Sandwich workspace ID. Stable across the claim — once the user claims it, the same ID belongs to their real account.
lovedOneId
Loved-one record ID inside the workspace.
inboxAddress
Real, live Family Inbox address. Receives mail immediately. Belongs to the sandbox workspace until claimed.
familyName
Display name actually used (resolved familyName or the default).
inviteDrafts
One draft per de-duplicated familyMemberEmails entry. status is always "draft"; nothing is sent.
sandbox
Always true on this endpoint.
primaryCaregiverEmail
Echoed back so the agent can remind the user which email to sign in with.

Safety rules for agents

  • Sandbox only. Don't try to bypass sandbox: true; the endpoint rejects anything else with a clear error message pointing at the sign-in flow.
  • No invites are sent. Never tell the user "I've invited your sister." Tell them invite drafts were prepared and will send after they claim the workspace.
  • Avoid sensitive PHI/PII in unauthenticated calls. The endpoint is anonymous and bounded — fine for names, relationships, and high-level context. Do not send detailed medical history, medication lists, SSNs, financial account numbers, or other sensitive identifiers until the user has claimed the workspace and you are on the authenticated MCP.
  • Respect rate limits. Per-IP token bucket with capacity 6 and refill ~6/hour by default. On 429, honor the Retry-After header — do not loop.
  • Don't ask for OAuth first. Start the sandbox, then present the claim URL. Forcing sign-in before the user sees value is the wrong order.
  • Claim before sending real invites or storing sensitive data. Direct the human to sign in and claim before you do anything irreversible.

Upgrade & claim flow

A sandbox workspace becomes a real, authenticated workspace when the human signs in with the same primaryCaregiverEmail the agent passed to the tool. The flow:

  1. Agent calls start_family_care_workspace with the user's email as primaryCaregiverEmail.
  2. Agent shows the user the resulting familyName, inboxAddress, and the list of inviteDrafts. The agent makes clear nothing has been emailed yet.
  3. Agent presents the claim URL: https://app.joinsandwich.com/onboarding — the user signs in with the same email.
  4. After email verification, the workspace is promoted: the synthetic anonymous-mcp owner is replaced with the real user's uid, the sandbox flag is cleared on claim, and real invite sending + authenticated MCP tools light up.
  5. From there, the agent (or the user) can switch to the authenticated MCP at /api/mcp using a Bearer key minted in Settings → MCP API keys, or via the OAuth flow once available.
Authenticated MCP is required for the real surface. Sending real family invites, persistent storage of private care data, calendar/email integrations, and Family Inbox management all live behind the authenticated /api/mcp. The public endpoint will never expose those tools — by design.

Email mismatch at sign-in is not fatal: the sandbox workspace stays orphaned and times out, and the user can start a new flow. But it means the original workspaceId and inboxAddress are abandoned. Be careful to surface the exact email you used.

Troubleshooting

Invalid arguments
JSON-RPC result with isError: true and a message like "lovedOneFirstName is required (1–60 chars)" or "familyMemberEmails contains an invalid email". Fix the offending field and retry. Names are 1–60 chars; familyName ≤ 120; careContext ≤ 2000; up to 8 family emails.
Missing sandbox: true
Returns an error saying sandbox must be true on the unauthenticated entrypoint, with a pointer to app.joinsandwich.com/onboarding. The fix is literal: include "sandbox": true in the arguments.
429 · -32029 rate limit
Per-IP token bucket exhausted. Response includes Retry-After and error.data.retryAfterSec. Wait the indicated interval and retry once — do not loop. Default capacity 6, refill ~one token per 10 minutes.
413 body too large
Request body exceeded 64 KB. Trim careContext and re-send; the unauthenticated endpoint is not the place for long medical histories.
Claim email mismatch
User signed in at /onboarding with an address that does not match primaryCaregiverEmail. The sandbox cannot be claimed by that account. Start a new sandbox with the right email, or have the user sign in with the original one.
503 tenant not configured
Server-side configuration error — the family tenant is not provisioned in this deployment. Out of the agent's control; surface a friendly error and do not retry.
Discord notifications
The endpoint emits an internal Discord ping (DISCORD_WEBHOOK_URL_MCP) when a sandbox is created — purely for ops visibility. Agents must not rely on it as a signal; it is best-effort, server-side only, and may be disabled in any given deployment.

Ready for the real surface? Authenticated MCP · Sandwich Pipe · All docs