| Surface | What it is | Use it when |
|---|---|---|
| HTTP API | The clone’s HTTP API at the endpoint spin printed. For Slack this is the real Slack Web API — RPC methods, the {ok} envelope, opaque bearer tokens. | Your agent already speaks the product’s API, or you want full control. The default, fully-wired path. |
| MCP server | A Model Context Protocol server that exposes the clone as a set of tools. | Your agent is an MCP client (Claude Desktop, an SDK agent) and you want tool-shaped access. |
slack-a1b2,
and port 3001 — substitute your own clone id and endpoint.
Option A — the Slack Web API
spin hands you a base URL and two ready-to-use tokens:
POST /api/chat.postMessage), args in the JSON body, and the
{ "ok": true, … } envelope. The clone expects real auth — you have two ways in.
Fastest — the provisioned bot token
Everyspin slack auto-provisions a default workspace, admin user, and app, then
prints a bot token (xoxb-…) and a user token (xoxp-…). No signup or
login; send one as a bearer token. Reprint them any time with
asym tokens <id>.
is_bot: true);
a user token acts as the admin. App-token scopes are enforced — a method
whose scope the token lacks returns { "ok": false, "error": "missing_scope" } at
HTTP 200, like every Slack-method error (the clone never returns 4xx/5xx on a
method route — the one non-200 is 429 ratelimited).
See Apps and tokens.
Per-user — JWT login
When you want to act as a specific seeded human (e.g. to test multi-user flows), log in for a JWT instead. JWT/web-UI identities are exempt from scope enforcement, and the access token is used exactly like the bearer token above.Authenticate
Log in as a seeded user (or sign up your own) to get an access token. The
(
acme-corp fixture creates six users who all share the password
password123 — dana@acme.test is one:/api/auth/* is a clone-operation, so it keeps a plain REST shape rather
than the { ok } envelope.)Act
Now your agent drives the Web API like any client — list channels, then post
a message. Take a channel id from
conversations.list (the clone uses internal
UUID ids — a known cosmetic deviation from Slack’s C… that doesn’t change call
signatures), and chat.postMessage takes its args in the body:Option B — the MCP server
The Slack template ships an MCP server (apps/slack-clone/mcp-server) that
exposes the clone as the reference Slack MCP tools — handy for MCP-native agents
that prefer tools over raw HTTP. It speaks stdio, connects to the clone’s Postgres
database, and is bound to a single app token so every tool acts strictly as
that identity, inside that workspace, limited to that token’s scopes.
The tools it exposes (verbatim names from the
reference Slack MCP server):
| Tool | Does |
|---|---|
slack_list_channels | List channels in the workspace. |
slack_post_message | Post a message to a channel. |
slack_reply_to_thread | Reply in a thread. |
slack_add_reaction | React to a message. |
slack_get_channel_history | Read a channel’s recent messages. |
slack_get_thread_replies | Read a thread’s replies. |
slack_get_users | List workspace users. |
slack_get_user_profile | Look up one user’s profile. |
slack_auth_test, slack_search_messages,
slack_open_dm.
Wire it up
The MCP server needs two things: aDATABASE_URL pointing at the clone’s
database, and a SLACK_MCP_TOKEN — the bot (xoxb-…) or user (xoxp-…) token
from spin that fixes its identity. The clone’s database is named after its id
(slack-a1b2 → clone_slack_a1b2) inside the shared Postgres.
Build the server once, then run it with both env vars set on the shared network:
Register it with an MCP client
Point your MCP client at the built server over stdio. For a Claude Desktop-style config:slack_post_message, slack_list_channels, and the rest as
tools — each operating on the clone’s real data, gated by the bound token’s scopes.
Score the run
However your agent connected, its work is now rows in the clone’s database. Read them back to grade the run — see Inspect what happened and thequery reference:
asym reset slack-a1b2 returns the clone to its seeded
starting state for the next run.
Where to go next
Seeding
Give your agent a known starting state — fixtures vs AI data.
Slack template
The clone’s API shape, schema, and fidelity to real Slack.
query reference
Read the clone’s database to score what your agent did.
Lifecycle commands
Reset, stop, start, and destroy between trials.