mcpbeat

Neo4j Aura Provisioning Skill

neo4j-contrib/neo4j-aura-provisioning-skill

Provisions and manages Neo4j Aura instances via CLI (aura-cli v1.7+) or REST API. Use when creating, pausing, resuming, resizing, or deleting AuraDB Free/Professional/Business Critical/VDC instances; downloading credentials; scripting CI/CD pipelines; polling async status; or using the Terraform neo4j/neo4j-aura provider. Covers auth setup (client credentials OAuth2), credential lifecycle (download once — never recoverable), instance type selection, region codes, and Python provisioning scripts. Does NOT handle Cypher queries — use neo4j-cypher-skill. Does NOT cover Graph Data Science algorithms — use neo4j-gds-skill or neo4j-aura-graph-analytics-skill. Does NOT cover neo4j-admin/cypher-shell — use neo4j-cli-tools-skill.

6k tokens
context cost
the whole folder, loaded on every use
6
files
instructions only
0
copies elsewhere
how many repositories repackaged it
101
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/neo4j-contrib/neo4j-skills --skill neo4j-aura-provisioning-skill

What comes with it

9 848 bytes besides the instruction
README.md
references/aura-agent.md
references/aura-monitoring.md
references/aura-tiers.md
references/data-importer.md

What it tells the agent to use

found in the instruction text
Bash runs shell commands — read the instruction before connecting
WebFetch fetches pages from the network

The instruction itself

28 sections, as written by the author

When to Use

  • Creating an Aura instance (CLI, REST API, Python, Terraform)
  • Pausing, resuming, resizing, or deleting an instance
  • Downloading initial credentials from creation response
  • Polling instance status: creatingrunning
  • Setting up CI/CD provisioning or teardown pipelines
  • Choosing instance tier (Free vs Professional vs Business Critical vs VDC)

When NOT to Use

  • Cypher queries against running DBneo4j-cypher-skill
  • GDS algorithms on Auraneo4j-gds-skill (Pro with plugin) or neo4j-aura-graph-analytics-skill (serverless)
  • neo4j-admin / cypher-shellneo4j-cli-tools-skill
  • Application driver setup → use a language driver skill (python, javascript, java, go, dotnet)

Instance Tier Decision Table

| Tier | API type code | Memory | GDS | Replicas | Use when |

|---|---|---|---|---|---|

| AuraDB Free | free-db | 1 GB | ❌ | ❌ | Dev/demo; ≤200k nodes/400k rels |

| AuraDB Professional | professional-db | 2–64 GB | plugin available | ❌ | Production workloads |

| AuraDB Business Critical | business-critical | 4–384 GB | plugin available | ✅ | HA, multi-AZ, SLA |

| AuraDB VDC | enterprise-db | custom | ✅ | ✅ | Dedicated infra, compliance |

| AuraDS Professional | professional-ds | 2–64 GB | ✅ built-in | ❌ | Data science / GDS |

| AuraDS Enterprise | enterprise-ds | custom | ✅ | ✅ | Enterprise GDS |

AuraDB Free limits: 200k nodes, 400k rels; auto-pauses after 72 h inactivity; deleted if paused >30 days; no resize.


Auth Setup

CLI (aura-cli v1.7+)

Install (binary, not pip):

# macOS
curl -L https://github.com/neo4j/aura-cli/releases/latest/download/aura-cli-darwin-amd64.tar.gz | tar xz
sudo mv aura-cli /usr/local/bin/
aura-cli -v          # verify

Add credentials (from console.neo4j.io → Account Settings → API Credentials):

aura-cli credential add \
  --name "my-creds" \
  --client-id "$AURA_CLIENT_ID" \
  --client-secret "$AURA_CLIENT_SECRET"
aura-cli credential use --name "my-creds"

Verify:

aura-cli instance list --output table

REST API — Get Bearer Token

Token endpoint: POST https://api.neo4j.io/oauth/token

Token expires: 3600 s (1 h). On 403 → refresh token.

TOKEN=$(curl -s --request POST 'https://api.neo4j.io/oauth/token' \
  --user "${AURA_CLIENT_ID}:${AURA_CLIENT_SECRET}" \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  | jq -r '.access_token')
echo "Token: ${TOKEN:0:20}..."

Use in all subsequent calls: --header "Authorization: Bearer $TOKEN"


Step 1 — List Tenants (Projects)

CLI:

aura-cli tenants list --output table
# Copy TENANT_ID for create operations

REST:

curl -s https://api.neo4j.io/v1/tenants \
  -H "Authorization: Bearer $TOKEN" | jq '.data[] | {id, name}'

Step 2 — Create Instance

CRITICAL: Capture output immediately. Initial password shown ONCE — never retrievable again.

If lost: delete and recreate. Store aura-creds.json before doing anything else.

CLI

aura-cli instance create \
  --name "my-instance" \
  --cloud-provider gcp \
  --region europe-west1 \
  --type professional-db \
  --tenant-id "$TENANT_ID" \
  --output json | tee aura-creds.json

# Extract for .env
INSTANCE_ID=$(jq -r '.id' aura-creds.json)
PASSWORD=$(jq -r '.password' aura-creds.json)

REST API (full create)

RESPONSE=$(curl -s -X POST https://api.neo4j.io/v1/instances \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name":           "my-instance",
    "cloud_provider": "gcp",
    "region":         "europe-west1",
    "type":           "professional-db",
    "tenant_id":      "'"$TENANT_ID"'",
    "memory":         "4GB",
    "version":        "5"
  }')
echo "$RESPONSE" | tee aura-creds.json
INSTANCE_ID=$(echo "$RESPONSE" | jq -r '.data.id')
PASSWORD=$(echo "$RESPONSE"   | jq -r '.data.password')

Instance create request body fields:

| Field | Required | Values |

|---|---|---|

| name | ✅ | any string |

| cloud_provider | ✅ | gcp aws azure |

| region | ✅ | see region table |

| type | ✅ | see tier table |

| tenant_id | ✅ | from tenant list |

| memory | ✗ | 1GB 2GB 4GB 8GB384GB |

| version | ✗ | 5 (default) |


Step 3 — Poll Until RUNNING (CRITICAL — All Ops Are Async)

ALL lifecycle operations (create, pause, resume, resize) are async. Do NOT attempt connection or next operation until status = running (or paused for pause op).

poll_status() {
  local INSTANCE_ID=$1 TARGET=$2 MAX_WAIT=${3:-600}
  local ELAPSED=0 STATUS
  echo "Polling for status=$TARGET (max ${MAX_WAIT}s)..."
  while [ $ELAPSED -lt $MAX_WAIT ]; do
    STATUS=$(aura-cli instance get --instance-id "$INSTANCE_ID" --output json \
             | jq -r '.status' 2>/dev/null)
    echo "  [${ELAPSED}s] status=$STATUS"
    [ "$STATUS" = "$TARGET" ] && echo "Ready." && return 0
    [ "$STATUS" = "destroying" ] && echo "ERROR: instance is being destroyed" && return 1
    sleep 10; ELAPSED=$((ELAPSED + 10))
  done
  echo "TIMEOUT after ${MAX_WAIT}s — last status: $STATUS" && return 1
}

poll_status "$INSTANCE_ID" "running" 600

REST equivalent:

while true; do
  STATUS=$(curl -s "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
    -H "Authorization: Bearer $TOKEN" | jq -r '.data.status')
  [ "$STATUS" = "running" ] && break
  sleep 10
done

Status lifecycle:

creating → running → pausing → paused → resuming → running
                  ↘ destroying → (gone)

Step 4 — Write .env and Verify

CONNECTION_URI="neo4j+s://${INSTANCE_ID}.databases.neo4j.io"

cat > .env <<EOF
NEO4J_URI=${CONNECTION_URI}
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=${PASSWORD}
NEO4J_DATABASE=neo4j
AURA_INSTANCE_ID=${INSTANCE_ID}
EOF

# Ensure .env never committed
grep -q '^\.env$' .gitignore 2>/dev/null || echo '.env' >> .gitignore

# Verify connectivity
cypher-shell -a "$CONNECTION_URI" -u neo4j -p "$PASSWORD" "RETURN 'connected' AS status"

Step 5 — Lifecycle Operations

All operations require instance in the correct state. Wrong-state ops return 4xx error.

Pause

Required state: running

aura-cli instance pause --instance-id "$INSTANCE_ID"
poll_status "$INSTANCE_ID" "paused" 600

Resume

Required state: paused

aura-cli instance resume --instance-id "$INSTANCE_ID"
poll_status "$INSTANCE_ID" "running" 900   # resume can take longer

Resize (Professional+ only — NOT Free)

Required state: running; instance remains available during resize.

# REST only — CLI resize not available in v1.7
curl -s -X PATCH "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"memory": "8GB"}'
poll_status "$INSTANCE_ID" "running" 600
# Cannot reduce below current usage level

Delete

IRREVERSIBLE. Export snapshots first if data needed.

aura-cli instance delete --instance-id "$INSTANCE_ID"
# No poll needed — immediate

REST:

curl -s -X DELETE "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
  -H "Authorization: Bearer $TOKEN"

Python CI/CD Provisioning Script

import os, time, requests

CLIENT_ID     = os.environ["AURA_CLIENT_ID"]
CLIENT_SECRET = os.environ["AURA_CLIENT_SECRET"]
BASE          = "https://api.neo4j.io/v1"

def get_token() -> str:
    r = requests.post(
        "https://api.neo4j.io/oauth/token",
        auth=(CLIENT_ID, CLIENT_SECRET),
        data={"grant_type": "client_credentials"},
    )
    r.raise_for_status()
    return r.json()["access_token"]

def auth_headers(token: str) -> dict:
    return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

def create_instance(token: str, tenant_id: str, **kwargs) -> dict:
    payload = {"tenant_id": tenant_id, "version": "5", **kwargs}
    r = requests.post(f"{BASE}/instances", headers=auth_headers(token), json=payload)
    r.raise_for_status()
    return r.json()["data"]   # contains id, password, connection_url

def poll_status(token: str, instance_id: str, target: str, timeout: int = 600) -> None:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{BASE}/instances/{instance_id}", headers=auth_headers(token))
        r.raise_for_status()
        status = r.json()["data"]["status"]
        print(f"  status={status}")
        if status == target:
            return
        if status == "destroying":
            raise RuntimeError("Instance destroyed unexpectedly")
        time.sleep(10)
    raise TimeoutError(f"Instance {instance_id} did not reach '{target}' in {timeout}s")

# --- usage ---
token    = get_token()
instance = create_instance(
    token,
    tenant_id = os.environ["AURA_TENANT_ID"],
    name           = "ci-test-instance",
    cloud_provider = "aws",
    region         = "us-east-1",
    type           = "professional-db",
    memory         = "2GB",
)
# SAVE CREDENTIALS IMMEDIATELY — password never retrievable again
print(f"ID:       {instance['id']}")
print(f"URI:      neo4j+s://{instance['id']}.databases.neo4j.io")
print(f"Password: {instance['password']}")   # log to secure vault NOW

poll_status(token, instance["id"], "running", timeout=600)
print("Instance ready.")

Region Codes

AWS

| Region code | Location |

|---|---|

| us-east-1 | N. Virginia |

| us-east-2 | Ohio |

| us-west-2 | Oregon |

| eu-west-1 | Ireland |

| eu-west-3 | Paris |

| eu-central-1 | Frankfurt |

| ap-southeast-1 | Singapore |

| ap-southeast-2 | Sydney |

| ap-south-1 | Mumbai |

| sa-east-1 | São Paulo |

GCP

| Region code | Location |

|---|---|

| europe-west1 | Belgium |

| europe-west3 | Frankfurt |

| europe-west4 | Netherlands |

| us-central1 | Iowa |

| us-east1 | S. Carolina |

| us-east4 | N. Virginia |

| asia-east1 | Taiwan |

| asia-northeast1 | Tokyo |

| asia-southeast1 | Singapore |

| australia-southeast1 | Sydney |

Azure

| Region code | Location |

|---|---|

| eastus | E. US |

| eastus2 | E. US 2 |

| westeurope | Netherlands |

| northeurope | Ireland |

| uksouth | London |

| southeastasia | Singapore |

| brazilsouth | Brazil |

| koreacentral | Korea |

Enterprise tiers (Business Critical, VDC) add 20+ additional regions per provider. Check console for full list.

Free tier: GCP only; limited subset of regions.


Terraform Provider

terraform {
  required_providers {
    aura = {
      source  = "neo4j/neo4j-aura"
    }
  }
}

provider "aura" {
  client_id     = var.aura_client_id       # or AURA_CLIENT_ID env var
  client_secret = var.aura_client_secret   # or AURA_CLIENT_SECRET env var
}

resource "aura_instance" "db" {
  name           = "prod-db"
  type           = "professional-db"
  cloud_provider = "gcp"
  region         = "europe-west1"
  memory         = "4GB"
  tenant_id      = var.aura_tenant_id
}

output "neo4j_uri" {
  value     = "neo4j+s://${aura_instance.db.id}.databases.neo4j.io"
  sensitive = false
}
output "neo4j_password" {
  value     = aura_instance.db.password
  sensitive = true
}

After terraform apply: poll status before marking infra ready — Terraform resource creation returns when API call completes, not when DB is running.


Common Errors

| Error | Cause | Fix |

|---|---|---|

| 403 Forbidden after working | Token expired (1 h TTL) | Re-run get_token() |

| 409 Conflict on create | Name already exists in tenant | Change name or delete existing |

| 422 on pause | Instance not running | Check status; wait for ongoing op to finish |

| 422 on resume | Instance not paused | Check status |

| 422 on resize | Below current usage | Reduce data first; can't shrink below usage |

| Region not found | Tier doesn't support that region | Use Free tier on GCP only; Pro/BC on all 3 clouds |

| Credentials lost after create | Password only returned at create time | Delete + recreate — no reset exists |

| 429 Too Many Requests | Rate limit hit (25 req/min Free, 125 req/min Pro+) | Add time.sleep(2) between polling calls |

| instance list returns empty | Wrong credential active | aura-cli credential use --name <name> |


API Rate Limits

| Tier | Requests/minute |

|---|---|

| Free / Pro Trial (no billing) | 25 |

| Pro with billing, BC, VDC | 125 |

Poll interval: ≥10 s to stay within limits on Free; 5 s safe on Pro+.

On Retry-After header in 5xx response: wait that many seconds before retry.


Security Rules

  • Write initial credentials to .env; verify .env in .gitignore before proceeding
  • Never print PASSWORD in CI logs — write to secrets vault (AWS Secrets Manager, GitHub secret, Vault)
  • Use from_env() / os.environ — never hardcode credentials
  • If .env absent: python-dotenv load_dotenv() auto-loads; do NOT prompt user unless loading fails

WebFetch — Current Docs

| Need | URL |

|---|---|

| REST API spec (OpenAPI) | https://neo4j.com/docs/aura/platform/api/specification/ |

| CLI reference | https://neo4j.com/docs/aura/aura-cli/ |

| Region list | https://neo4j.com/docs/aura/managing-instances/regions/ |

| Auth details | https://neo4j.com/docs/aura/api/authentication/ |

| Instance actions | https://neo4j.com/docs/aura/managing-instances/instance-actions/ |


Checklist

  • [ ] .env created with URI/user/password; .env in .gitignore
  • [ ] Initial credentials saved to secure storage immediately after create
  • [ ] poll_status called after create — do NOT connect before status = running
  • [ ] poll_status called after pause/resume
  • [ ] Correct tier selected (Free for dev, Pro+ for production, BC for HA)
  • [ ] Region confirmed available for chosen tier and cloud provider
  • [ ] Tenant ID provided for all create/list operations (required in multi-tenant orgs)
  • [ ] Token refreshed if > 1 h old (or 403 received)
  • [ ] Delete confirmed by user — data loss is permanent, no recovery

How to use it

Copy the folder

Take neo4j-contrib/neo4j-aura-provisioning-skill from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.