The MCP server that auths itself: per-token scoping for agent fleets
Published: April 22, 2026
When v1.0 of SwiftyClip shipped, the MCP server was deliberately single-user. If an agent could spawn swiftyclip mcp, it got all nine tools. That was the right call for launch — most SwiftyClip users are solo creators, and adding auth before adding utility is a great way to ship nothing.
Two weeks in, the picture changed. We started seeing Claude Code sessions where the primary agent spawns sub-agents for specific subtasks. A scoring sub-agent, a rendering sub-agent, a scheduling sub-agent. Suddenly the question "which tools does this particular agent session need?" isn't rhetorical.
v1.0.4 ships two things that together solve this: per-token MCP auth, and the clip.createToken tool.
Per-token authentication (MCPAuthStore)
Every token now carries:
id: UUID— stable, revocable.displayName: String— free-form label.token: String— 32 hex chars.allowedTools: Set<String>— allowlist. If empty: no tools. If the set contains a tool name: that tool is callable.createdAt,lastUsedAt
The backwards-compat story: if no tokens are registered, everything works like v1.0. Single-user, full access. The moment you register your first token, the gate drops and every request must include params.auth.token.
That's a deliberate choice. We'd rather the zero-config posture stay friendly for solo creators than force every new user through a "generate a token" dance.
clip.createToken: the 12th tool
The new tool:
clip.createToken { displayName, allowedTools[] } → { id, token, allowedTools }Why expose it over MCP instead of making it CLI-only? Because multi-agent workflows want to provision their own children. A planning agent needs to give a rendering worker a token that can only call clip.render and nothing else. Without clip.createToken, that's either a human-in-the-loop step or a trusted shared secret — both of which defeat the security goal.
With clip.createToken, the flow becomes:
- User generates a top-level token with allowlist = [*].
- Top-level agent uses that token, then mints a sub-token per worker with the minimum allowed tools.
- When the workflow ends, the top-level agent calls
clip.revokeTokenon each child. (Coming in v1.0.5 — today we rely on manual revoke via CLI or Settings.)
Three attack surfaces we're explicitly not protecting
Honest posture time. Per-token MCP auth doesn't solve:
- Local filesystem access. If an agent has a token that can call
clip.ingest, it can point at any path the user has read access to. We don't sandbox paths. The App Sandbox protects against kernel- level escape; it does not protect user-visible files from your own agent. - Token exfiltration by a compromised agent. If a malicious prompt extracts your token and ships it somewhere, rotate in Settings. We don't implement rate- limiting per token in v1.0.4 (it's on the list).
- Cross-process spoofing. Any process on your Mac with access to UserDefaults can read the tokens. This is the macOS security model; we don't fight it. For true multi-user hardening, use separate user accounts.
How it's built
The implementation is small: MCPToken is a Sendable struct, MCPAuthStore is an actor that persists tokens through the existing PreferencesStore, and MCPServer validates every tools/call before dispatching to the bridge. Under 200 lines of Swift end-to-end.
Swift 6 strict concurrency caught three bugs during implementation: a non-Sendable UserDefaults crossing actor boundaries (fixed by adding a suite-name init), a silent mutation from a concurrent test (fixed by making register a single method that handles upsert), and a sneaky Date roundtrip comparison that broke under JSON encoding precision (fixed by comparing individual fields, not structs). Three bugs that would have been runtime traps in a loose- concurrency codebase.
What ships next
clip.revokeToken— round-trip token management from within an agent session.- Per-token rate limits (requests/minute by tool).
- Audit log — Settings → Agents shows which tokens have called which tools, when.
- Time-bound tokens — "this token expires in 1 hour."
For now, all 12 tools + the auth plumbing are live in v1.0.4. Full tool reference: /docs/mcp. Integration guides: Claude Code, Cursor, Codex, OpenClaw.