cloud-mcp
Enables running DigitalOcean CLI (doctl) commands, allowing management of DigitalOcean resources like droplets, databases, and more.
Integrates with HashiCorp Vault as an external secrets vault for securely storing and retrieving provider credentials and configuration.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cloud-mcplist AWS S3 buckets in my account"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cloud-mcp
A Node.js skeleton for wrapping multiple cloud CLIs behind one command surface.
What this gives you
Unified CLI entrypoint (
cloud-wrap)Provider pass-through commands for AWS, GCP, Azure, OCI, Alibaba, DigitalOcean, IBM Cloud, Tencent Cloud, and Huawei Cloud
Config file support to override command paths and inject environment variables
Vault abstraction for storing provider attributes with optional external replacement
MCP stdio server that registers provider tools and command runners
Structured logging and safe command execution with inherited stdio
Related MCP server: mcp_server_for_claudes_toolbox
Quick start
npm install
npm run bootstrap:clis
npm start -- list
npm start -- aws sts get-caller-identity
npm start -- oci iam region list
npm start -- alibaba ecs DescribeInstances
npm run mcpRepository-local CLI layout
This project can keep provider CLI entrypoints under mcp/<provider>/bin.
mcp/aws/bin/awsmcp/gcp/bin/gcloudmcp/azure/bin/azmcp/oci/bin/ocimcp/alibaba/bin/aliyunmcp/digitalocean/bin/doctlmcp/ibmcloud/bin/ibmcloudmcp/tencent/bin/tcclimcp/huawei/bin/hcloud
Run the bootstrap command to create links from your installed CLIs into this structure:
npm run bootstrap:clisOr pull and install all CLIs directly into the structure:
npm run install:clisThis installer covers AWS, GCP, Azure, OCI, Alibaba, DigitalOcean, IBM Cloud, and Tencent Cloud directly. Huawei Cloud is wired through the same provider interface, but the public huaweicloudcli Python package referenced by older installer versions is not available; set HUAWEI_CLI_BIN to a supported hcloud-compatible binary to enable Huawei command execution.
At runtime, provider resolution order is:
mcp/<provider>/bin/<cli>when present<PROVIDER>_CLI_BINenvironment overrideCLI from
PATH
If neither HUAWEI_CLI_BIN nor hcloud on PATH is available during npm run install:clis, a placeholder mcp/huawei/bin/hcloud is created that fails with an explicit setup message instead of breaking the image build.
Shared command limits live in mcp/cloud-command-limits.json.
Current repository default (mcp/cloud-command-limits.json) is permissive for all providers and intentionally includes CLI-style aliases for two sections:
{
"alibaba.*": [],
"aws.*": [],
"az.*": [],
"digitalocean.*": [],
"gcloud.*": [],
"huawei.*": [],
"ibmcloud.*": [],
"oci.*": [],
"tencent.*": []
}At load time this is normalized to canonical provider sections, so az.* becomes azure.* and gcloud.* becomes gcp.* in the effective runtime policy.
External command-limit loading:
CLOUD_COMMAND_LIMITS_SOURCE(optional): load command limits from an external source at startup.Supported values: file path,
file://URL,http://URL,https://URL.
CLOUD_COMMAND_LIMITS_REFRESH_INTERVAL_SECONDS(optional): whenCLOUD_COMMAND_LIMITS_SOURCEis set and this value is> 0, command limits are reloaded on that interval.If refresh fails, the last successfully loaded limits remain active.
PostgreSQL-backed command limits:
Command limits are persisted in PostgreSQL table
cloud_mcp.command_limits.Runtime command validation reads limits from the database before each provider command execution.
On startup, limits are loaded from
mcp/cloud-command-limits.json(orCLOUD_COMMAND_LIMITS_SOURCE) and synced into PostgreSQL.When refresh is enabled, each refresh cycle updates PostgreSQL records from the external source.
Database environment variables:
COMMAND_LIMITS_DATABASE_URL(preferred), orDATABASE_URLCOMMAND_LIMITS_LOCAL_POSTGRES_ENABLED(optional): whentrue|1|yesand no external DB URL is set, auto-uses local postgres URL.COMMAND_LIMITS_LOCAL_POSTGRES_PORT(required when local postgres auto-mode is enabled): local postgres port used to build the DB URL.
If neither database variable is set, command limits run in in-memory mode.
Database resolution order:
Use
COMMAND_LIMITS_DATABASE_URLwhen set.Else use
DATABASE_URLwhen set.Else if
COMMAND_LIMITS_LOCAL_POSTGRES_ENABLED=true|1|yes, requireCOMMAND_LIMITS_LOCAL_POSTGRES_PORTand usepostgres://cloud_mcp:cloud_mcp@127.0.0.1:<port>/cloud_mcp.Else run in-memory mode.
Start local PostgreSQL from repository assets:
export COMMAND_LIMITS_LOCAL_POSTGRES_PORT=5432
docker compose -f docker-compose.postgres.yml up -d
export COMMAND_LIMITS_DATABASE_URL="postgres://cloud_mcp:cloud_mcp@127.0.0.1:5432/cloud_mcp"Standalone migration for existing databases:
psql "$COMMAND_LIMITS_DATABASE_URL" -f db/migrations/002_command_limits_namespace_migration.sqlThis migration creates cloud_mcp.command_limits, copies legacy rows from public.command_limits when present, and ensures default provider-prefix records exist.
Enforced sections are keyed by provider prefix:
aws.*,gcp.*,azure.*,oci.*,alibaba.*,digitalocean.*,ibmcloud.*,tencent.*,huawei.*If a section is an empty array, all commands for that provider are allowed
If a section contains entries, only matching prefixes are allowed
Entries may be written as full prefixes like
aws.s3or shorthand likes3within theaws.*section
Prefix naming note:
Runtime enforcement uses provider names (
aws,gcp,azure,oci,alibaba,digitalocean,ibmcloud,tencent,huawei), not binary names.CLI-style aliases are supported and normalized during load:
gcloud.*maps togcp.*az.*maps toazure.*aliyun.*maps toalibaba.*doctl.*maps todigitalocean.*tccli.*maps totencent.*hcloud.*maps tohuawei.*
If both canonical and alias keys are provided for the same provider, canonical keys win (
gcp.*overgcloud.*,azure.*overaz.*,alibaba.*overaliyun.*,digitalocean.*overdoctl.*,tencent.*overtccli.*,huawei.*overhcloud.*).Recommended mapping is:
aws.*forawsgcp.*forgcloudazure.*forazoci.*forocialibaba.*foraliyundigitalocean.*fordoctlibmcloud.*foribmcloudtencent.*fortcclihuawei.*forhcloud
How to fill out the file:
Allow everything for every cloud:
{
"alibaba.*": [],
"aws.*": [],
"digitalocean.*": [],
"gcp.*": [],
"azure.*": [],
"oci.*": [],
"ibmcloud.*": [],
"tencent.*": [],
"huawei.*": []
}Restrict AWS and GCP, leave Azure and OCI open:
{
"alibaba.*": ["ecs"],
"aws.*": ["s3", "sts.get-caller-identity"],
"gcp.*": ["projects", "compute.instances.list"],
"azure.*": [],
"oci.*": [],
"digitalocean.*": ["compute"],
"ibmcloud.*": [],
"tencent.*": ["cvm"],
"huawei.*": ["ecs"]
}Use full provider-prefixed entries explicitly:
{
"aws.*": ["aws.s3", "aws.sts.get-caller-identity"],
"gcp.*": ["projects", "compute.instances.list"],
"azure.*": [],
"oci.*": ["oci.iam"]
}Lock each provider to a narrow subset:
{
"aws.*": ["ec2.describe-instances", "s3.ls"],
"gcp.*": ["projects.list"],
"azure.*": ["vm", "account.show"],
"oci.*": ["iam.region.list"]
}What the entries mean:
"s3"insideaws.*means any AWS command starting withaws.s3..."sts.get-caller-identity"insideaws.*means onlyaws sts get-caller-identity"projects"insidegcp.*means any GCP command starting withgcp.projects..."oci.iam"insideoci.*means any OCI command starting withoci.iam...
With this file:
aws s3 lsis allowedaws ec2 describe-instancesis deniedall Azure commands are allowed
gcloud projects listis allowedoci iam region listis allowed
Usage
Generic form
npm start -- run <provider> [args...]Examples:
npm start -- run aws s3 ls
npm start -- run gcp projects list
npm start -- run azure account show
npm start -- run oci iam region list
npm start -- run digitalocean compute droplet listProvider shorthands
npm start -- aws s3 ls
npm start -- gcp projects list
npm start -- azure account show
npm start -- oci iam region list
npm start -- tencent cvm DescribeInstancesMCP server
Start the MCP server with:
npm run mcp -- --config cloud-wrap.config.jsonIt registers these tools:
list_providersget_providerset_providerrun_providerrun_awsrun_gcprun_azurerun_ocirun_alibabarun_digitaloceanrun_ibmcloudrun_tencentrun_huaweiget_command_limitsset_command_limit_sectionreplace_command_limitspush_command_limits
Command-limit MCP management:
get_command_limits: reads effective command limits from database.set_command_limit_section: updates one provider section in database, then force-pushes to JSON target.replace_command_limits: replaces all sections in database, then force-pushes to JSON target.push_command_limits: force-pushes current DB limits to JSON target without modifying DB.
Force-push target:
pushTarget=internal: writes to localmcp/cloud-command-limits.json(or configured internal path).pushTarget=external: writes toCLOUD_COMMAND_LIMITS_SOURCE.pushTarget=auto: uses external source when configured, otherwise internal file.
Provider vault authorization:
Set
MCP_PROVIDER_AUTH_KEYto store an authorization key in vault at startup.When configured,
get_providerandset_providerrequireauthorizationKeyin the request input.When configured,
set_command_limit_section,replace_command_limits, andpush_command_limitsalso requireauthorizationKey.Requests with missing or invalid keys are rejected.
Container note
This repository no longer ships a first-party Dockerfile, so it does not provide a built-in container image build path.
If your deployment requires containers, provide your own image definition around the Node entrypoints (node src/mcp.js for MCP mode, node src/index.js for CLI mode) and any cloud CLIs you want available in that runtime.
A sample container definition is available at docker/Containerfile.sample and can be used with either Docker or Podman:
docker build -f docker/Containerfile.sample -t cloud-mcp:local .
podman build -f docker/Containerfile.sample -t cloud-mcp:local .Kubernetes (Helm) sample
A sample Helm chart is available at helm/cloud-mcp.
Build and push an image (Docker or Podman):
docker build -f docker/Containerfile.sample -t ghcr.io/your-org/cloud-mcp:latest .
docker push ghcr.io/your-org/cloud-mcp:latestCopy chart values and edit for your environment:
cp helm/cloud-mcp/values.yaml helm/cloud-mcp/values.local.yamlSet at minimum:
image.repositoryimage.tagenv.VAULT_ADDRsecrets.data.VAULT_TOKENenv.COMMAND_LIMITS_DATABASE_URL(or local-postgres toggle values)
Install or upgrade:
helm upgrade --install cloud-mcp ./helm/cloud-mcp -f helm/cloud-mcp/values.local.yamlVerify:
kubectl rollout status deployment/cloud-mcp-cloud-mcp
kubectl logs deployment/cloud-mcp-cloud-mcp --tail=200Notes:
The chart mounts
cloud-wrap.config.jsonfrom a ConfigMap at/etc/cloud-mcp/cloud-wrap.config.json.VAULT_TOKENandMCP_PROVIDER_AUTH_KEYare provided by Kubernetes Secret (secrets.data).Default container args run MCP mode (
mcp --config /etc/cloud-mcp/cloud-wrap.config.json).
Configuration
Create cloud-wrap.config.json using cloud-wrap.config.example.json as a template.
{
"vault": {
"module": "./external-vault.js",
"options": {}
},
"providers": {
"aws": {
"command": "aws",
"env": {
"AWS_PROFILE": "default"
},
"defaultProfile": "default",
"profileSupport": {
"mode": "env",
"envVar": "AWS_PROFILE"
},
"profiles": {
"default": {
"env": {
"AWS_PROFILE": "default"
},
"users": []
}
}
}
}
}If vault.module is present, the runtime will try to load that module first. The module should expose either createVault, a default factory, or a vault object with the same get/set/snapshot methods as the built-in service. If loading fails, the local in-memory vault is used.
This repo also includes a built-in external HashiCorp Vault adapter at src/core/hashicorpVault.js, mirrored after the akoya-mcp external vault setup. It is auto-selected when either:
VAULT_PROVIDER=externalboth
VAULT_ADDRandVAULT_TOKENare set
Fail-closed behavior: when VAULT_PROVIDER=external and both VAULT_ADDR and VAULT_TOKEN are set, startup fails if the external vault module cannot be loaded or initialized. In this explicit external mode, it does not fall back to local in-memory vault.
CLOUD_WRAP_VAULT_MODULE still takes precedence over all auto-selection logic.
For external vault integrations, these environment variables are forwarded into the external vault options object when set:
VAULT_PROVIDERVAULT_ADDRVAULT_TOKENVAULT_NAMESPACEVAULT_KV_MOUNTVAULT_KV_VERSIONVAULT_SECRET_PATHCOMMAND_LIMITS_LOCAL_POSTGRES_ENABLEDCOMMAND_LIMITS_LOCAL_POSTGRES_PORT
Required vault key contract:
Required environment variables for explicit external mode:
VAULT_PROVIDER=externalVAULT_ADDRVAULT_TOKEN
Required secret key at each provider path:
key name:
providerrequired object fields:
command(string),env(object)optional profile fields:
defaultProfile(string),profiles(map),profileSupport(mode=arg|env, withflagorenvVar)optional per-profile access field:
profiles.<name>.users(string array)
Provider authorization key (when enabled):
set
MCP_PROVIDER_AUTH_KEYto seed vault pathmcp.authorization.providerKeyget_providerandset_providerrequests must includeauthorizationKeymatching that value
When using the built-in external adapter, VAULT_SECRET_PATH is treated as a base path and each cloud CLI provider is stored separately:
${VAULT_SECRET_PATH}/aws${VAULT_SECRET_PATH}/gcp${VAULT_SECRET_PATH}/azure${VAULT_SECRET_PATH}/oci${VAULT_SECRET_PATH}/alibaba${VAULT_SECRET_PATH}/digitalocean${VAULT_SECRET_PATH}/ibmcloud${VAULT_SECRET_PATH}/tencent${VAULT_SECRET_PATH}/huawei
Each provider secret stores one object at key provider containing command, env, and optional profile fields.
Multi-profile provider behavior:
run_providerandrun_<provider>accept optionalprofile.run_providerandrun_<provider>accept optionaluserfor profile access checks.If
profileis provided, runtime appliesprofileSupportto inject profile context via args or env.profiles.<name>.argsandprofiles.<name>.envare merged into execution.profiles.<name>.userscontrols profile access:empty or missing array means profile is available to all users
non-empty array restricts profile use to those users
If
profileis omitted anddefaultProfileis configured, that profile is used.
CLOUD_WRAP_VAULT_MODULE can also be used to override vault.module from config.
For a ready-made external profile, use cloud-wrap.config.external-vault.example.json.
Then run:
npm start -- --config cloud-wrap.config.json aws sts get-caller-identityExtend with additional providers
Add a provider in your config file:
{
"providers": {
"do": {
"command": "doctl",
"env": {
"DIGITALOCEAN_ACCESS_TOKEN": "<token>"
}
}
}
}Then call:
npm start -- run do account getProject structure
src/
index.js # entry point
mcp.js # MCP stdio entry point
program.js # command definitions
core/
context.js # runtime context creation
execute.js # provider CLI spawning
mcp.js # MCP tool registration and server startup
config/
providers.js # built-in provider defaults
loadConfig.js # config loading and validation
utils/
logger.js # pino logger setupThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/LesterAJohn/cloud-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server