The CloudSpawn MCP (Model Context Protocol) server. Connects to Claude Desktop and exposes GCP infrastructure provisioning as conversational tools — deploy services, create databases, store secrets, and more, all through natural language.
┌─────────────────────────────────────────────────────────────────┐
│ Claude Desktop │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ MCP Client (stdin/stdout) │ │
│ └──────────────────────┬────────────────────────────────────┘ │
└─────────────────────────┼───────────────────────────────────────┘
│ MCP Protocol
┌─────────────────────────┼───────────────────────────────────────┐
│ cloud-spawn-be │ │
│ ┌──────────────────────▼────────────────────────────────────┐ │
│ │ MCP Server (index.ts) │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ Auth Middleware (withAuth) │ │ │
│ │ │ Validates API key → derives customer_id │ │ │
│ │ │ Rate limiting · Activity logging │ │ │
│ │ └──────────────┬───────────────────────────────────────┘ │ │
│ │ ┌──────────────▼───────────────────────────────────────┐ │ │
│ │ │ Tools (9 registered) │ │ │
│ │ │ deploy_service · deploy_static_site · create_db │ │ │
│ │ │ create_bucket · store_secret · get_service_url │ │ │
│ │ │ get_customer_status · teardown · register_customer │ │ │
│ │ └──────────────┬───────────────────────────────────────┘ │ │
│ └─────────────────┼────────────────────────────────────────┘ │
│ ┌─────────────────▼────────────────────────────────────────┐ │
│ │ GCP Clients (admin SA impersonation) │ │
│ │ Cloud Run · Cloud SQL · GCS · Secret Manager · LB │ │
│ └─────────────────┬────────────────────────────────────────┘ │
│ ┌─────────────────▼────────────────────────────────────────┐ │
│ │ Platform DB (cs_platform_mgmt on Cloud SQL) │ │
│ │ users · customers · api_keys · activity_log │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ GCP (cs-platform project) │
│ Cloud Run · Cloud SQL · GCS · Secret Manager · Global LB │
└─────────────────────────────────────────────────────────────────┘
Tool call with api_key
│
▼
┌───────────────┐ ┌──────────────────┐ ┌────────────────┐
│ Rate Limit │────▶│ Validate Key │────▶│ Set │
│ Check │ │ (SHA-256 hash, │ │ customer_id │
│ (10/5min │ │ timingSafeEqual)│ │ from auth │
│ → 15min lock)│ │ │ │ context │
└───────────────┘ └──────────────────┘ └───────┬────────┘
│
▼
┌────────────────┐
│ Execute Tool │
│ Handler │
└───────┬────────┘
│
▼
┌────────────────┐
│ Log Activity │
│ (async, │
│ non-blocking) │
└────────────────┘
All customer resources live in a single shared GCP project (cs-platform). Isolation is enforced through naming conventions, resource labels, and API key scoping:
cs-platform (shared project)
├── Cloud Run
│ └── {customerId}-{serviceName} labels: customer-id, managed-by
├── Cloud SQL (cs-platform-db instance)
│ ├── cs_{customerId}_{dbName} customer databases
│ └── cs_platform_mgmt platform management database
├── Cloud Storage
│ └── {projectId}-{customerId}-{slug} labels: customer-id, managed-by
├── Secret Manager
│ └── {customerId}_{secretName} labels: customer-id
└── Global HTTPS Load Balancer
├── cs-bs-{customerId}-{service} backend services (Cloud Run)
├── cs-be-{customerId}-{site} backend buckets (static sites)
└── URL Map routes {customer}-{name}.cloudspawn.app → backends
src/
├── index.ts # MCP server entry point (stdio transport)
├── config.ts # Environment variable loading
├── types/
│ └── index.ts # Shared TypeScript interfaces
├── gcp/
│ ├── client.ts # Admin SA impersonation setup
│ ├── cloud-run.ts # Cloud Run service CRUD + LB registration
│ ├── cloud-sql.ts # Database creation on shared instance
│ ├── storage.ts # GCS bucket management + file uploads
│ ├── secret-manager.ts # Secret storage + Cloud Run injection
│ ├── load-balancer.ts # Global HTTPS LB infrastructure
│ ├── platform-db.ts # Platform management DB (users, keys, etc.)
│ ├── projects.ts # GCP API enablement
│ └── teardown.ts # Resource cleanup orchestration
├── tools/
│ ├── deploy-service.ts # Deploy container to Cloud Run
│ ├── deploy-static-site.ts# Deploy HTML/CSS/JS to GCS + LB
│ ├── create-database.ts # Create PostgreSQL database
│ ├── create-bucket.ts # Create GCS bucket
│ ├── store-secret.ts # Store secret, optionally inject into service
│ ├── get-service-url.ts # Get Cloud Run + custom domain URL
│ ├── get-customer-status.ts# List all resources for a customer
│ ├── register-customer.ts # Register a new customer namespace
│ └── teardown-customer.ts # Destroy all customer resources
└── utils/
├── auth.ts # withAuth middleware for API key validation
├── errors.ts # Tool response helpers + GCP error mapping
└── logger.ts # Structured JSON logging to stderr
- Node.js 20+
- GCP project with Cloud SQL, Cloud Run, GCS, Secret Manager, and Load Balancing APIs enabled
- An admin service account with appropriate IAM roles
- Application Default Credentials configured (
gcloud auth application-default login)
npm installCreate a .env file:
# Required
CLOUDSPAWN_ORG_ID=123456789 # GCP organization ID
CLOUDSPAWN_BILLING_ACCOUNT_ID=AABBCC # GCP billing account ID
CLOUDSPAWN_ADMIN_SA=cs-admin@project.iam.gserviceaccount.com
CLOUDSPAWN_PLATFORM_PROJECT=cs-platform
CLOUDSPAWN_PLATFORM_DB_PASSWORD= # Password for cs_platform_admin DB user
# Optional (with defaults)
CLOUDSPAWN_REGION=us-central1
CLOUDSPAWN_DOMAIN=cloudspawn.appnpm run build # Compile TypeScript → build/
npm start # Run the MCP server (stdio transport)
npm run dev # Watch mode for developmentAdd to your Claude Desktop MCP config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"cloudspawn": {
"command": "node",
"args": ["/path/to/cloud-spawn-be/build/index.js"],
"env": {
"CLOUDSPAWN_ORG_ID": "...",
"CLOUDSPAWN_BILLING_ACCOUNT_ID": "...",
"CLOUDSPAWN_ADMIN_SA": "...",
"CLOUDSPAWN_PLATFORM_PROJECT": "...",
"CLOUDSPAWN_PLATFORM_DB_PASSWORD": "..."
}
}
}
}Every tool requires an api_key parameter. The API key determines which customer's resources the tool operates on — customer_id is derived from the key and cannot be overridden.
| Tool | Description |
|---|---|
register_customer |
Register a new customer namespace, optionally create initial DB |
deploy_service |
Deploy a container image to Cloud Run with custom domain |
deploy_static_site |
Deploy HTML/CSS/JS files to GCS with CDN + custom domain |
create_database |
Create a PostgreSQL database on the shared Cloud SQL instance |
create_bucket |
Create a GCS bucket for file storage |
store_secret |
Store a secret, optionally inject into a Cloud Run service |
get_service_url |
Get the URL for a deployed Cloud Run service |
get_customer_status |
List all resources (services, DBs, buckets, secrets) |
teardown_customer |
Irreversibly destroy all customer resources |
- API key scoping: Each key is bound to exactly one
customer_idvia FK.withAuthoverrides any user-suppliedcustomer_id. - Key storage: Only SHA-256 hashes are stored. Full key is returned once at creation.
- Timing attacks: Key validation uses
crypto.timingSafeEqualon the hash. - Rate limiting: 10 failed auth attempts in 5 minutes locks the source for 15 minutes.
- SQL injection: All queries use parameterized placeholders (
$1,$2). - Error messages: Generic "Invalid or missing API key" on failure — no information leakage.