Tenant isolation
Every endpoint gets its own Postgres database. Not row-level security on a shared table — actual physical separation.
Why per-tenant databases
Multi-tenant SaaS usually puts every customer's data in one big shared schema and relies
on row-level security to enforce boundaries. That works until a misconfigured policy or
a single missed WHERE tenant_id = ? leaks one customer's data to another.
We didn't want that risk for AI agents executing dynamically-generated queries.
Instead, ShipMCP creates a dedicated Neon Postgres project per endpoint. Different connection string, different storage, different compute. There is no path through the application that could ever read another tenant's rows, because the connection itself doesn't know about them.
What's isolated
| Resource | Per-tenant? |
|---|---|
| Postgres database (tables, indexes, data) | Yes |
| Connection string + credentials | Yes |
| Storage quota + billing | Yes |
| API tokens (one set per endpoint) | Yes |
| Rate-limit counters | Yes (Cloudflare Durable Object keyed by endpoint) |
| llms.txt + tool manifest | Yes (regenerated per endpoint) |
| Edge worker code | Shared (same Cloudflare Worker handles all endpoints) |
The auth boundary
Every MCP request includes Authorization: Bearer smcp_…. The edge worker
hashes the token, looks it up against the endpoint's authorized set, and either accepts
or rejects with 401. Token-to-endpoint binding happens at issue time —
there's no global "user" abstraction at the data plane. A token for endpoint A literally
cannot be used to query endpoint B.
See API tokens & magic links for the issuance and rotation flow.
Rate limiting
Each endpoint gets its own rate-limit counter, enforced via a Cloudflare Durable Object.
The default budget is your plan's monthly call quota (1k on Free, unlimited on Pro and
Scale) plus a per-second burst ceiling to prevent runaway agents. Hitting the limit
returns 429 Too Many Requests with a Retry-After header.
Account deletion
When a tenant deletes their account, the dashboard removes D1 rows synchronously and
dispatches a DeleteAccountJob to the ingest worker. That job tears down
every Neon project owned by the tenant via the Neon API. Once the job acknowledges,
no copy of your data remains on our infrastructure.
Heads up: per-tenant databases mean per-tenant cold-start risk. We use Hyperdrive connection pooling at the edge to amortize this — first query in 30 seconds may add ~200 ms; subsequent queries in the same connection window are sub-100 ms.
Compliance
Scale-tier customers get SOC 2 and HIPAA compliance documentation on request. Email matt@mrdula.solutions with your use case.