Multi-Cloud MCP Server
Provides tools to inspect and query Google Cloud Platform (GCP) infrastructure, including BigQuery datasets and tables, Cloud Build logs, and Cloud Run services, revisions, and logs.
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., "@Multi-Cloud MCP Servercheck the latest Cloud Build status in the prod environment"
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.
Multi-Cloud MCP Server
A local Model Context Protocol server that gives an LLM client (Claude Desktop, VS Code, Claude Code, etc.) tools to inspect and query your own GCP and AWS infrastructure: data warehouses, CI build systems, container/serverless runtimes, and their logs. You point it at your own project(s) and account(s) through a short interactive setup wizard. Nothing is hardcoded to any specific company, project, or account.
Table of contents
Related MCP server: BigQuery MCP Server
Quickstart
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python3 setup_wizard.py # interactive: configure your GCP and/or AWS environments
python3 server.py # runs the MCP server over stdioPoint your MCP client at server.py as the command to run (with the same .venv interpreter). For example, in a VS Code mcp.json or Claude Desktop config, the command is the absolute path to .venv/bin/python3 and the argument is the absolute path to server.py.
How it works
.env (written by setup_wizard.py)
|
v
config.py (parses .env into GCPEnvironment / AWSEnvironment objects)
|
v
server.py (registers tools for whichever providers have at least
| one configured environment, then serves over stdio)
-------------+-------------
| |
providers/gcp/ providers/aws/
one file per GCP service one file per AWS service
(bigquery, cloudbuild, (athena, codebuild, ecs,
cloudrun) lambda, s3, identity)Every tool function takes an optional env= argument naming which configured environment to act against (for example env="prod"). If you omit it, the tool falls back to whichever environment the wizard set as the default for that provider. Call the always-available list_environments tool to see what is currently configured and which environment is the default for each provider.
File by file
server.py: the entry point. At import time it readsconfig.CONFIGand registers only the tool modules for providers that actually have a configured environment (a GCP-only setup never exposes AWS tools, and vice versa). It also defines one provider-agnostic tool,list_environments, directly. If neither provider is configured it prints a message to stderr and exits with status 1, rather than hanging waiting for input, because the stdio transport is reserved for MCP protocol traffic once an MCP client has launched it.config.py: the configuration model. DefinesGCPEnvironmentandAWSEnvironmentdataclasses, anAppConfigregistry keyed by environment name,load_config(path)to parse a.envfile into anAppConfig,render_env_file(cfg)andsave_config(cfg, path)to write one back out, and aslug(name)helper that turns an arbitrary environment name into the uppercase, underscore-separated form used in.envkey names (so"client-a-prod"becomes the key prefixCLIENT_A_PROD).AppConfig.resolve_gcp(env)/resolve_aws(env)are what every tool calls to turn anenv=argument (orNone) into a concrete environment object, raising aValueErrorthat lists what is actually configured if the name does not exist.setup_wizard.py: the interactive onboarding flow. Run it any time, it loads whatever.envalready exists, lets you add, remove, or change the default environment for either provider through a numbered menu, verifies each new environment's credentials as you add it (a live BigQuery/STS call, non-fatal for GCP, prompts to save-anyway for AWS on failure), and rewrites.envfrom scratch on save.live_check.py: a standalone smoke test you can run any time against your real.envto confirm a configured environment's credentials still work, without needing the full pytest suite or any specific cloud resources to exist. See Testing below.providers/errors.py: a single decorator,friendly_errors, applied to every tool function. It catchesValueError(an unknown environment name, a missing key file) and any other exception (an expired credential, an API failure) and turns it into a plain string starting with"Error: ..."or"Error calling <tool>: ...", so a bad call comes back as readable text instead of a stack trace.providers/gcp/auth.py: resolves GCP credentials for aGCPEnvironment, either via Application Default Credentials (google.auth.default()) or a service-account JSON key file, and exposesget_access_token()for the one tool module that talks to a GCP REST API directly instead of through a client library.providers/gcp/bigquery_tools.py:bq_list_datasets,bq_list_tables,bq_describe_table,bq_query,bq_preview_table. Thin wrappers around thegoogle-cloud-bigqueryclient.providers/gcp/cloudbuild_tools.py:cloudbuild_list_builds,cloudbuild_get_logs,cloudbuild_describe_build. There is no official Cloud Build Python client used here; it calls the REST API directly with a bearer token fromauth.py, and fetches full build logs straight from the build's GCS logs bucket.providers/gcp/cloudrun_tools.py:cloudrun_list_services,cloudrun_describe_service,cloudrun_list_revisions,cloudrun_get_logs,cloudrun_get_error_logs. Usesgoogle-cloud-runfor service/revision metadata andgoogle-cloud-loggingfor log retrieval, filtered byseverity>=ERRORfor the error-only variant.providers/aws/auth.py: resolves aboto3.Sessionfor anAWSEnvironment, either via a named profile (or the default credential chain) or explicit static keys, plusverify_credentials()(a thinsts:GetCallerIdentitywrapper used by both the wizard and theaws_whoamitool).providers/aws/logs_helpers.py: one sharedfetch_log_events()function used by bothecs_tools.pyandlambda_tools.py, since both need the same "fetch recent CloudWatch Logs, optionally error-filtered" behavior. The error filter is a CloudWatch Logs filter pattern (?ERROR ?Error ?CRITICAL ?FATAL ?Exception ?Traceback), since CloudWatch has no built-in structured severity field the way GCP's logging API does.providers/aws/athena_tools.py:athena_list_databases,athena_list_tables,athena_describe_table,athena_query,athena_preview_table. This is the closest AWS equivalent to BigQuery: a serverless SQL engine over the Glue Data Catalog. Unlike BigQuery, a query is asynchronous (start, then poll for completion, then fetch results), soathena_querypolls every second for up to 30 seconds before giving up.providers/aws/codebuild_tools.py:codebuild_list_projects,codebuild_list_builds,codebuild_get_logs,codebuild_describe_build. The CodeBuild equivalent of the Cloud Build tools.providers/aws/ecs_tools.py:ecs_list_clusters,ecs_list_services,ecs_describe_service,ecs_list_tasks,ecs_get_logs,ecs_get_error_logs. Covers the container half of what Cloud Run does in one service on GCP; the log tools resolve the right CloudWatch log group automatically from the service's task definition.providers/aws/lambda_tools.py:lambda_list_functions,lambda_describe_function,lambda_list_versions,lambda_get_logs,lambda_get_error_logs. Covers the serverless-function half of Cloud Run's niche. A function's log group is always/aws/lambda/<function_name>, so no extra lookup is needed before fetching logs.providers/aws/s3_tools.py:s3_list_buckets,s3_list_objects. Bonus coverage beyond the GCP tool set's shape.providers/aws/identity_tools.py:aws_whoami. Bonus coverage: confirms which AWS account and identity a named environment actually resolves to, useful once you have several environments configured.
Configuring environments
An "environment" is a named GCP project or AWS account/region you want the server able to talk to. You can configure any number of them under any names you like: dev, prod, client-a-prod, whatever makes sense to you. Run the wizard to add one:
$ python3 setup_wizard.py
=== Multi-Cloud MCP Setup Wizard ===
Loaded 0 GCP environment(s): (none)
Loaded 0 AWS environment(s): (none)
Main menu:
1) Add a cloud environment
2) Remove an environment
3) Set default environment for a provider
4) Save and exit
5) Exit without saving
Choose [1-5]: 1
Provider?
1) gcp
2) aws
Choose [1-2]: 1
--- Add GCP environment ---
Environment name (e.g. 'dev', 'prod', 'client-a-prod'): prod
GCP project ID: my-real-project-id
Region [us-central1]:
Auth method:
1) Application Default Credentials (gcloud auth application-default login)
2) Service account JSON key file
Choose [1-2]: 1
Verifying...
Auth OK.
BigQuery smoke test OK.
Added GCP environment 'prod'.Re-run the wizard any time to add another environment, remove one, or change which one is the default. It always reloads whatever .env already exists first, so nothing you have already configured is lost.
GCP auth modes
Chosen per environment, in the wizard:
Application Default Credentials (ADC): run
gcloud auth application-default loginonce beforehand, or rely on the default service account if this is running inside GCP itself.Service account JSON key file: point the wizard at a downloaded key file. Useful if you do not have
gcloudinstalled at all. The path is stored in.envasGCP_ENV_<NAME>_CREDENTIALS_PATH.
AWS auth modes
Also chosen per environment, in the wizard:
Named profile (recommended): set one up first with
aws configureoraws configure sso. No secrets are ever written to.env, only the profile name.Access key and secret: pasted directly into
.envfor an environment with no AWS CLI configured at all..envis git-ignored and the wizard sets its file permissions to600, but a profile is still the safer choice when you have one available.
Tool catalog with examples
Every tool below also accepts an optional env argument; it is omitted from the example calls where the default environment is being used.
BigQuery (GCP)
bq_list_datasets()
→ Project: my-real-project-id
part_catalog
analytics
bq_query(sql="SELECT id, name FROM `my-real-project-id.part_catalog.part_level` LIMIT 2")
→ [
{"id": "A100", "name": "Bearing"},
{"id": "A101", "name": "Gasket"}
]Cloud Build (GCP)
cloudbuild_list_builds(branch="main", limit=5)
→ [
{"id": "8f2e...", "status": "SUCCESS", "branch": "main",
"createTime": "2026-09-01T10:02:00Z", "finishTime": "2026-09-01T10:06:00Z",
"logUrl": "https://console.cloud.google.com/cloud-build/builds/8f2e..."}
]Cloud Run (GCP)
cloudrun_get_error_logs(service_name="my-service", limit=20)
→ [
{"timestamp": "2026-09-01T10:05:12Z", "severity": "ERROR",
"message": "connection refused: upstream timeout"}
]Athena (AWS, BigQuery equivalent)
athena_query(sql="SELECT id, amount FROM salesdb.orders LIMIT 2")
→ [
{"id": "1", "amount": "9.99"},
{"id": "2", "amount": "14.50"}
]CodeBuild (AWS, Cloud Build equivalent)
codebuild_describe_build(build_id="my-project:abcd-1234")
→ {
"id": "my-project:abcd-1234", "status": "SUCCEEDED",
"startTime": "2026-09-01 10:00:00+00:00", "endTime": "2026-09-01 10:04:12+00:00",
"sourceVersion": "main",
"phases": [{"phaseType": "BUILD", "phaseStatus": "SUCCEEDED", "durationInSeconds": 42}]
}ECS / Fargate (AWS, Cloud Run container half)
ecs_get_error_logs(cluster="my-cluster", service_name="my-service")
→ [
{"timestamp": 1767283512000, "logStream": "ecs/app/abc123",
"message": "ERROR something broke"}
]Lambda (AWS, Cloud Run serverless half)
lambda_describe_function(function_name="my-function")
→ {
"name": "my-function", "runtime": "python3.12", "memorySize": 256, "timeout": 30,
"handler": "lambda_function.handler", "role": "arn:aws:iam::123456789012:role/lambda-role",
"lastModified": "2026-09-01T10:00:00.000+0000", "envVars": ["STAGE", "LOG_LEVEL"]
}S3 (AWS, bonus)
s3_list_objects(bucket="my-bucket", prefix="logs/2026/09/", limit=5)
→ [
{"key": "logs/2026/09/01.json", "size": 4021, "lastModified": "2026-09-01 00:05:00+00:00"}
]Identity (AWS, bonus)
aws_whoami()
→ Environment: prod
Account: 123456789012
ARN: arn:aws:iam::123456789012:role/my-role
Region: us-east-1Always available
list_environments()
→ GCP environments:
dev (default) - project: my-dev-project, region: us-central1
prod - project: my-real-project-id, region: us-central1
AWS environments:
staging (default) - region: us-east-1Extending with a new service
Every tool module follows the same shape: a register(mcp) function that defines its @mcp.tool()-decorated functions as closures, each wrapped with @friendly_errors, each resolving its environment through CONFIG.resolve_gcp(env) or CONFIG.resolve_aws(env). To add a new service:
Create
providers/gcp/<service>_tools.pyorproviders/aws/<service>_tools.pyfollowing that shape.Add it to the relevant import list and registration loop in
server.py.Write a test file under
tests/gcp/ortests/aws/using thegcp_config/aws_configfixtures described below.
Never hardcode a project ID, account ID, or region anywhere. Everything should flow through the resolved environment object.
Testing
The test suite mocks every cloud call, so it runs with no real GCP or AWS credentials and makes no real network calls (aside from AWS tests, which run entirely against moto's in-memory AWS simulation, still fully offline).
pip install -r requirements-dev.txt
python3 -m pytest tests/ -vtests/conftest.py provides two fixtures used throughout: gcp_config(module) and aws_config(module), which each monkeypatch a tool module's CONFIG to a fake, single-environment AppConfig. AWS tests wrap their body in moto's @mock_aws decorator and use fake static keys, so the real providers/aws/auth.py code path runs end to end against moto's simulated AWS rather than mocking authentication away. GCP has no equivalent in-memory emulator, so GCP tests mock at the client-class boundary instead (bigquery.Client, run_v2.ServicesClient, and so on).
tests/test_server.py and tests/test_setup_wizard.py run the real scripts as subprocesses in an isolated temporary working directory, since both have import-time or interactive side effects that are not safe to exercise by importing them directly inside the test process.
Live smoke test
The mocked suite proves the code is correct in isolation, but it can't catch things like a mistyped project ID, an API that isn't enabled, or an expired credential. live_check.py covers that gap: it reads your real .env and makes one real, read-only call per configured environment (an actual credential fetch plus a lightweight BigQuery call for GCP, an actual sts:GetCallerIdentity for AWS), so it exercises the exact same auth code path the real tools use, without needing you to have any specific resources (datasets, buckets, functions) already set up.
python3 live_check.py # check every configured environment
python3 live_check.py --env prod # check only one environment by name
python3 live_check.py --provider aws # check only one providerThis was run against a real GCP project and a real AWS account during development: BigQuery, S3, Lambda, ECS, CodeBuild, and Athena all round-tripped successfully end to end (each reporting empty results, since those particular resources had nothing in them yet), and Cloud Run / Cloud Build correctly surfaced real "API not enabled" errors as clean text through friendly_errors instead of a raw traceback, confirming the error-handling path works against real failures too, not just mocked ones.
Troubleshooting
"No cloud providers configured" on startup: run
python3 setup_wizard.py."Unknown GCP/AWS environment '...'": the error message lists what is actually configured; use one of those names, or add a new one with the wizard.
GCP ADC issues:
gcloud auth application-default login.AWS profile issues:
aws sts get-caller-identity --profile <name>to test outside the wizard.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This 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.
Related MCP Connectors
Unified API to query AWS, GCP, Azure and generate Terraform/CLI execution kits for AI agents.
Your AI Agent's Infrastructure Layer. Connect Claude, Copilot, Codex, or ChatGPT to 200+ managed open source services. Start databases, pipelines, and applications through natural language.
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides AI agents with natural language control over AWS, Azure, GCP, and Alibaba Cloud infrastructure through dynamic API discovery and execution. Supports 51,900+ cloud operations and includes OpenTofu integration for complete infrastructure lifecycle management.3MIT
- AlicenseNot gradedqualityCmaintenanceEnables LLMs to explore BigQuery datasets and tables, run safe read-only queries, and optionally perform vector search using BigQuery embeddings.9MIT

Synlake MCP Serverofficial
AlicenseAqualityDmaintenanceEnables AI agents to discover, evaluate, and provision cloud infrastructure across AWS, GCP, and Azure with cross-cloud normalization, cost comparisons, and deployable execution kits.517MIT- FlicenseNot gradedqualityDmaintenanceProvides 30+ read-only tools for querying Google Cloud Platform infrastructure, designed for AI assistants and Terraform workflows.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/anandapurva55/multi-cloud-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server