# InstaNode Dev Mcp

> Provision Postgres databases + webhooks from AI coding agents in one HTTP call.

- **Type:** MCP server
- **Install:** `agentstack add mcp-instanode-dev-mcp`
- **Verified:** Pending review
- **Seller:** [InstaNode-dev](https://agentstack.voostack.com/s/instanode-dev)
- **Installs:** 0
- **Latest version:** 0.7.2
- **License:** MIT
- **Upstream author:** [InstaNode-dev](https://github.com/InstaNode-dev)
- **Source:** https://github.com/InstaNode-dev/mcp
- **Website:** https://instanode.dev

## Install

```sh
agentstack add mcp-instanode-dev-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# instanode-mcp

MCP server for [instanode.dev](https://instanode.dev). Lets AI coding agents
(Claude Code, Cursor, Windsurf, Continue, etc.) provision the full bundle of
ephemeral developer infrastructure over HTTPS — no Docker, no signup required
for the free anonymous tier.

One tool call per resource type, each returning a drop-in connection string:

- **Postgres** (`create_postgres`) → `postgres://...` with pgvector pre-installed
- **Redis** (`create_cache`) → `redis://...` with ACL-scoped user + namespace
- **MongoDB** (`create_nosql`) → `mongodb://...` with role scoped to the DB
- **NATS JetStream** (`create_queue`) → `nats://...` with scoped subject namespace
- **S3-compatible storage** (`create_storage`) → endpoint + keys + prefix
  (backed by DigitalOcean Spaces)
- **Webhook receiver** (`create_webhook`) → public URL that stores every
  inbound request
- **Container deployment** (`create_deploy`) → upload a base64 gzip tarball
  (Dockerfile + source), get back a public URL in ~30s. Bind any of the
  resources above by passing their tokens as `resource_bindings` — the API
  resolves tokens to connection URLs server-side.
- **Multi-service stack** (`create_stack`) → declare 1..N services in an
  `instant.yaml` manifest, ship them as a bundle in a single MCP call. Anonymous
  callers get a 6h-TTL stack with a live URL on
  `*.deployment.instanode.dev` — no card required. Cross-service refs
  (`service://`) resolve cluster-internally at deploy time. Poll
  status with `get_stack`.

Every anonymous resource auto-expires in 24h. The provision response carries
a `note` and `upgrade` field — the MCP server surfaces both verbatim so the
agent can show the user the exact CTA + claim URL needed to keep the
resource permanently. Run `claim_resource` on the returned `upgrade_jwt` to
get the dashboard claim URL.

## Install

### Claude Code

```bash
claude mcp add instanode -- npx -y instanode-mcp@latest
```

To authenticate (unlock paid-tier limits and the account-management tools):

```bash
claude mcp add instanode \
  --env INSTANODE_TOKEN= \
  -- npx -y instanode-mcp@latest
```

### Cursor

Add to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):

```json
{
  "mcpServers": {
    "instanode": {
      "command": "npx",
      "args": ["-y", "instanode-mcp@latest"],
      "env": {
        "INSTANODE_TOKEN": ""
      }
    }
  }
}
```

### Windsurf

Add to `~/.codeium/windsurf/mcp_config.json`:

```json
{
  "mcpServers": {
    "instanode": {
      "command": "npx",
      "args": ["-y", "instanode-mcp@latest"],
      "env": {
        "INSTANODE_TOKEN": ""
      }
    }
  }
}
```

### Continue.dev

Add to your `~/.continue/config.yaml`:

```yaml
mcpServers:
  - name: instanode
    command: npx
    args: ["-y", "instanode-mcp@latest"]
    env:
      INSTANODE_TOKEN: ""
```

For a drop-in `CLAUDE.md` / `.cursorrules` that tells the agent exactly when
to reach for this MCP, see .

## Environment

| Variable                  | Required | Default                       | Purpose                                                                                                                                                                                  |
|---------------------------|----------|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `INSTANODE_TOKEN`         | No       | —                             | Bearer JWT minted at . Required for `list_resources`, `claim_token`, `delete_resource`, `get_api_token`, and all deploy tools (`create_deploy`, `list_deployments`, `get_deployment`, `redeploy`, `delete_deployment`). Unlocks paid-tier limits on every `create_*`. |
| `INSTANODE_API_URL`       | No       | `https://api.instanode.dev`   | Override the API base URL. Only set this for local development against a k3s cluster.                                                                                                    |
| `INSTANODE_DASHBOARD_URL` | No       | `https://instanode.dev`       | Override the dashboard host that `claim_resource` builds claim URLs against. Only set this for staging.                                                                                  |

## Tools

| Tool              | Description                                                                                                                                                       |
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `create_postgres` | `POST /db/new` — Provision a Postgres database (pgvector included). Returns `connection_url` + the `note`/`upgrade` claim URL. `name` required.                   |
| `create_vector`   | `POST /vector/new` — Provision a pgvector-enabled Postgres database (embedding store). Returns `connection_url` + `extension`/`dimensions` + `note`/`upgrade`. `name` required; optional `dimensions` is a documentation hint. |
| `create_cache`    | `POST /cache/new` — Provision a Redis cache (ACL-scoped user + namespace). Returns `connection_url` + `note`/`upgrade`. `name` required.                          |
| `create_nosql`    | `POST /nosql/new` — Provision a MongoDB database (per-resource user + DB-scoped role). Returns `connection_url` + `note`/`upgrade`. `name` required.              |
| `create_queue`    | `POST /queue/new` — Provision a NATS JetStream queue (scoped subject namespace). Returns `connection_url` + `note`/`upgrade`. `name` required.                    |
| `create_storage`  | `POST /storage/new` — Provision an S3-compatible bucket prefix (DigitalOcean Spaces). Returns endpoint, access keys, prefix + `note`/`upgrade`. `name` required.  |
| `create_webhook`  | `POST /webhook/new` — Provision an inbound webhook receiver URL. Returns `receive_url` + `note`/`upgrade`. `name` required.                                       |
| `create_deploy`   | `POST /deploy/new` — Upload a base64 gzip tarball (with Dockerfile) and deploy a container. Returns `deploy_id`, `status`, `url`, `build_logs_url`. `name` required. Pass `redeploy: true` (with the SAME `name`) to update an existing deployment IN PLACE (same app_id + URL). Requires `INSTANODE_TOKEN`. |
| `create_stack`    | `POST /stacks/new` — Multi-service bundle. Upload an `instant.yaml` manifest plus one base64 gzip tarball per service; returns `stack_id`, per-service URLs, and the 6h-TTL claim block on the anonymous tier. **Anonymous-friendly** (the wedge). `name`, `manifest`, `service_tarballs` required. |
| `get_stack`       | `GET /stacks/{stack_id}` — Poll a stack's per-service status + URLs. Anonymous-friendly. `stack_id` required.                                                     |
| `list_deployments`| `GET /api/v1/deployments` — List all deployments on the caller's team. Requires `INSTANODE_TOKEN`.                                                                |
| `get_deployment`  | `GET /api/v1/deployments/:id` — Fetch one deployment (poll until `status="running"`). Requires `INSTANODE_TOKEN`.                                                 |
| `get_deployment_events` | `GET /api/v1/deployments/:id/events` — Read the failure-timeline autopsy for a deployment (`kind`/`reason`/`exit_code`/`event`/`last_lines`/`hint`/`created_at`, newest first) so an agent can self-correct a broken Dockerfile. Optional `limit`. Requires `INSTANODE_TOKEN`. |
| `redeploy`        | `POST /deploy/:id/redeploy` — Push updated code to an existing deployment BY ID. Same URL, new build. Requires `tarball_base64` (same shape as `create_deploy`) — the api never reuses the original tarball. For the more common "update by name" path prefer `create_deploy({ name, redeploy: true, tarball_base64 })`. Requires `INSTANODE_TOKEN`. |
| `delete_deployment` | `DELETE /deploy/:id` — Tear down a running deployment. Irreversible. Requires `INSTANODE_TOKEN`.                                                                |
| `claim_resource`  | Helper — turn an `upgrade_jwt` from any `create_*` response into the dashboard claim URL the user should click. No API call. No auth required.                    |
| `claim_token`     | `POST /claim` — Programmatic claim: attach an anonymous resource to the authenticated account using its `upgrade_jwt` + `email`. No auth required.                |
| `list_resources`  | `GET /api/v1/resources` — List resources on the caller's account. Requires `INSTANODE_TOKEN`.                                                                     |
| `delete_resource` | `DELETE /api/v1/resources/{token}` — Hard-delete a resource you own. Paid tier only. Requires `INSTANODE_TOKEN`.                                                  |
| `get_api_token`   | `POST /api/v1/auth/api-keys` — Mint a fresh bearer Personal Access Token (PAT). Requires an existing user-session `INSTANODE_TOKEN` (PATs cannot mint other PATs — the API returns 403 in that case). |
| `get_capabilities`| `GET /api/v1/capabilities` — Read the live per-tier capability matrix (storage / connection / resource-count / deployment caps, pricing, backup + RPO/RTO promises) in upgrade order so an agent can plan a provision before a call `402`s. **Auth optional** (public discovery surface). |
| `set_vault_key`   | `PUT /api/v1/vault/{env}/{key}` — Write a secret to the team vault (always a new version). Reference it from a deploy as `vault://{env}/{key}` in `env_vars`; the API decrypts it at deploy time. Vault is paid (Hobby+ = 20 entries, Pro/Team = unlimited; Hobby/Pro restrict env to `production`). Requires `INSTANODE_TOKEN`. |
| `rotate_vault_key`| `POST /api/v1/vault/{env}/{key}/rotate` — Rotate a vault secret's value (new version, recorded under a distinct audit action). Redeploy referencing apps to apply. Requires `INSTANODE_TOKEN`. |
| `update_deploy_env` | `PATCH /deploy/{id}/env` — Merge env vars into an existing deployment (incoming wins; values may be `vault://env/KEY` refs). Returns the merged map with secrets redacted. Redeploy to apply. Requires `INSTANODE_TOKEN`. |
| `update_stack_env`| `PATCH /stacks/{slug}/env` — Merge env vars into an existing stack (row-locked; an empty-string value deletes a key). Redeploy the stack to apply. Requires `INSTANODE_TOKEN`. |
| `presign_storage` | `POST /storage/{token}/presign` — Mint a short-lived (≤1h) presigned S3 URL (`GET`/`PUT`/`HEAD`) scoped to a storage prefix. Auth is the storage token in the path — works for anonymous-tier storage. `DELETE` is not offered (a leaked URL must not wipe a prefix). |
| `pause_resource`  | `POST /api/v1/resources/{id}/pause` — Suspend a resource without deleting it (storage + connection URL preserved; new connections refused). **Pro tier or higher.** Requires `INSTANODE_TOKEN`. |
| `resume_resource` | `POST /api/v1/resources/{id}/resume` — Un-pause a resource (same connection URL keeps working). **Pro tier or higher.** Requires `INSTANODE_TOKEN`. |
| `rotate_credentials` | `POST /api/v1/resources/{id}/rotate-credentials` — Rotate a resource's password; returns the NEW `connection_url` in plaintext (host + DB unchanged). Locks out a leaked old URL. Requires `INSTANODE_TOKEN`. |
| `wake_deployment` | `POST /deploy/{id}/wake` — Explicitly wake a scaled-to-zero deployment (scales to 1 replica; cold-start before serving). Flag-gated on the platform: returns 501 `scale_to_zero_disabled` when the feature is off. Requires `INSTANODE_TOKEN`. |

### Container deployment (`create_deploy`)

Deploying is a single multipart/form-data POST with a base64-encoded gzip
tarball of the project (Dockerfile + source). The MCP tool handles the
encoding plumbing; the agent's job is just to construct the tarball.

**Building the tarball (any language):**

```python
import base64, subprocess
tar = subprocess.check_output(["tar", "czf", "-", "-C", project_dir, "."])
tarball_base64 = base64.b64encode(tar).decode()
```

```js
import { execFileSync } from "node:child_process";
const tar = execFileSync("tar", ["czf", "-", "-C", projectDir, "."]);
const tarball_base64 = tar.toString("base64");
```

Cap: 50 MB after decode. Honor `.dockerignore` — only ship what
`docker build` needs. The `name` field is required (1–64 chars,
letters/numbers/spaces/dashes) — it's the human-readable label shown
on the dashboard.

**Binding provisioned resources:**

Provision the resources first with `create_postgres` / `create_cache` / etc.
to get their tokens (UUIDs), then pass the tokens as `resource_bindings`:

```json
{
  "tarball_base64": "...",
  "name": "my-app",
  "port": 8080,
  "resource_bindings": {
    "DATABASE_URL": "",
    "REDIS_URL":    ""
  }
}
```

The agent passes **resource tokens** (not connection URLs); the API
resolves each token to its connection URL server-side at deploy time. The
MCP server never pre-resolves tokens — pre-resolving would round-trip every
binding through `GET /credentials` and embed raw secrets into the tool
params, which the agent host may log.

**Polling:**

`create_deploy` returns `status="building"` immediately. Poll
`get_deployment({ id: deploy_id })` every few seconds until status flips to
`"running"` (typical: ~30s). At that point the `url` field is the live URL.

### Updating an existing deployment (same URL, new build)

To ship v2 of an app you already deployed without changing the URL or
`app_id`, call `create_deploy` again with the **same `name`** plus
`redeploy: true`:

```json
{
  "tarball_base64": "...",
  "name": "my-app",
  "redeploy": true
}
```

The api finds the existing deployment by `(team_id, name)` and updates it
in place — same `app_id`, same `*.deployment.instanode.dev` URL, status
flips back to `building` while the new image rolls out.

Without `redeploy: true`, calling `create_deploy` with a name you've used
before mints a **new** `app_id` and a **new** URL (the legacy behaviour).
This is the trap that caused the AGENT-UX issue where agents ended up
with two live deployments + two URLs for the same app.

The standalone `redeploy` tool (by `id`, not `name`) still works and also
requires a `tarball_base64` — the api never reuses the original tarball.
Prefer the `create_deploy({ name, redeploy: true })` path when you have
the name; use `redeploy({ id, tarball_base64 })` when you only have the
deploy id.

### Private deploys

Set `private: true` and pass `allowed_ips` to restrict access to specific IPs
or CIDR blocks at the Ingress. Useful when the agent is asked to deploy a
CRM, internal dashboard, or staging app that should only be reachable by the
user.

**Pro tier or higher required.** Hobby callers will see HTTP 402 with an
`agent_action` field — the MCP server surfaces the upgrade URL so the agent
can prompt the user to upgrade.

**Example prompt** (paste into Claude Code):

> "Deploy my CRM as a private app, only accessible from 1.2.3.4 and my office
> subnet 10.0.0.0/8"

The agent will then call:

```json
{
  "tarball_base64": "...",
  "name": "my-crm",
  "private": true,
  "allowed_ips": ["1.2.3.4", "10.0.0.0/8"]
}
```

`get_deployment` and `list_deployments` surface `private` + `allowed_ips`
back to the agent so it can confirm the policy to the user. To turn a
private deploy public, redeploy without the flags.

### How anonymous → claimed works

Every `create_*` tool returns three fields the agent should treat as
load-bearing:

- `token` — the resource UUID (used for `claim_token` and `delete_resource`).
- `note` — a one-sentence human-readable CTA, already mentions the upgrade URL.
- `upgrade` — the full claim URL (`https://instanode.dev/start?t=`). The
  user clicks it, signs in with GitHub/Google or a magic link, and the
  resource is attached to their account.

`upgrade_jwt` is also returned for callers that want to build their own UI
around the claim flow. The `claim_resource` tool accepts that JWT and
returns the same dashboard URL — useful if the

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [InstaNode-dev](https://github.com/InstaNode-dev)
- **Source:** [InstaNode-dev/mcp](https://github.com/InstaNode-dev/mcp)
- **License:** MIT
- **Homepage:** https://instanode.dev

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Versions

- **0.7.2** — security scan: pending review — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-instanode-dev-mcp
- Seller: https://agentstack.voostack.com/s/instanode-dev
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
