Stash for assistants
Connect Claude or any MCP client, and what a token lets it do.
An MCP server, so Claude and other assistants can work with a Stash account: see the projects in it, create one, and get the details needed to connect an application to its database.
If you have not got Stash running yet, start with Setting up Stash.
It is a local process. It runs on the customer's machine, holds their own API token, and talks to the Stash HTTP API. Nothing about it is privileged: every refusal comes from the same routes the dashboard uses, and revoking the token in the dashboard is the whole of the off switch.
Install it
- In Stash, open API tokens and create one. Leave read-only unticked if the assistant should be able to create projects. The token is shown once.
- Point your client at the server. For Claude Desktop, in
claude_desktop_config.json:
{
"mcpServers": {
"stash": {
"command": "node",
"args": ["/absolute/path/to/stash/apps/mcp/dist/main.js"],
"env": {
"STASH_TOKEN": "the token you just created",
"STASH_URL": "http://127.0.0.1:3010"
}
}
}
}
For Claude Code:
claude mcp add stash --env STASH_TOKEN=… --env STASH_URL=http://127.0.0.1:3010 -- node /absolute/path/to/stash/apps/mcp/dist/main.js
STASH_URL defaults to http://127.0.0.1:3010, which is where pnpm dev
serves the dashboard. Plain http is refused for anything that is not this
machine: the token is a bearer credential and sending one in the clear to
another host is not a thing to do by accident.
Build it first with pnpm build from the repository root. dist/main.js is
what a client runs.
What it can do
| Tool | What it is for |
|---|---|
list_projects |
Everything in the account, with each database's status. |
create_project |
Creates a project and starts building its Postgres. Provisions real infrastructure, and the account has a limit. |
get_project |
One project. Once its database is ready, the host, user, password and connection string. |
Three, not thirteen. Deploys, payments and email do not exist yet, and a tool for a surface that is not built is worse than no tool: a model reads the list as capabilities and will offer the customer something that cannot happen. Tools get added as the surfaces land.
What a read-only token cannot do
Two things, and both are deliberate:
- Create a project, because that provisions a database somebody pays for.
- Read connection details, because a Postgres connection string is not read-only by any reading of those words. It opens the database with the owner's role and can drop every table in it.
get_project still answers for a read-only token. It says why the
credential is missing, so an assistant can tell "not allowed" from "not ready
yet" and say the useful thing rather than guessing out loud.
If something is wrong
Diagnostics go to stderr, which clients show in their logs. Nothing is ever written to stdout, because stdout is the protocol: one stray line of anything else corrupts the JSON-RPC stream and the client disconnects with a parse error that names nothing.
- "STASH_TOKEN is not set": the client did not pass
env, or the token is blank. - "Stash did not accept this token": it was revoked, or it is from a different Stash. Check the API tokens screen.
- "Could not reach Stash": nothing answered at
STASH_URL. Ispnpm devrunning?
How it is tested
src/tools.test.tsdrives the tools through the SDK's ownClientover its in-memory transport, with Stash faked. Real protocol, real schema validation.smoke/mcp.spec.tslaunches this server as a subprocess exactly as a client does, holding a token created by clicking buttons in the dashboard, and checks that a project an assistant creates shows up on the screen a person looks at.
Found something wrong? Edit this page.