google-cloud-observability-mcp
v0.2.2
Published
Model Context Protocol server for Google Cloud observability services (Logging, Monitoring, Trace, Spanner)
Maintainers
Readme
Google Cloud Observability MCP Server
A Model Context Protocol (MCP) server for Google Cloud services including Logging, Spanner, Monitoring, and Cloud Trace.
This is a modified fork of krzko/google-cloud-mcp (Apache License 2.0), published under a new package name to fix a set of bugs found while actually using the query tools against production data:
query-metricscrashing withInvalid time valuewhenever a query returned real data (a protobuf timestamp was passed straight tonew Date())- the aggregation aligner being hardcoded to
ALIGN_MEAN, which Cloud Monitoring rejects for CUMULATIVE/DELTA metrics (e.g. restart counts, request counts)list-tracesandnatural-language-trace-querycrashing on the sameInvalid time valueerror, caused by assuming Cloud Trace v2 response fields that don't exist on the v1 API this server actually calls- log entries always rendering as
No timestamp | DEFAULT | unknownbecause fields were read from the wrong place on the log entry objectnatural-language-metrics-queryonly working when the query contained a literalmetric.type="...", with no fallback for plain-English phrasinglist-metric-typestiming out on anything but a narrow filter, with no cap on how much it would try to scanSee the LICENSE file for full attribution to the original project.
Quick Start (npx)
No clone, no build — the easiest way to run this server is via npx, the same way most MCP servers are installed.
Set up a least-privilege service account for it to use — see Least-Privilege IAM Setup below, or reuse an existing key if you already have one scoped appropriately.
Add it to your MCP client's config. For Claude Desktop, Cursor, or any client that uses an
mcpServersblock:{ "mcpServers": { "google-cloud-observability": { "command": "npx", "args": ["-y", "google-cloud-observability-mcp@latest"], "env": { "GOOGLE_APPLICATION_CREDENTIALS": "/absolute/path/to/your/key.json", "GOOGLE_CLOUD_PROJECT": "your-project-id" } } } }Use an absolute path to the key file on the machine actually running the client —
npxruns the server as a local child process, not a shared remote one.Restart your client.
npx -ydownloads and caches the latest published version automatically; there's nothing else to install or update manually.
Features
- Google Cloud Logging: Query logs, list log entries, and search across different log sources
- Google Cloud Spanner: Execute queries, list databases and instances, get schema information
- Google Cloud Monitoring: Query metrics, list metric descriptors, get monitoring data
- Google Cloud Trace: Retrieve trace data and analyze distributed system performance
- Resource Discovery: Automatically discover and list available Google Cloud resources
- Project Management: Tools for managing Google Cloud project settings
Transport Support
This server supports two transport modes:
1. Stdio Transport (Default)
The traditional MCP stdio transport for use with MCP clients like Claude Desktop.
2. HTTP Transport (New!)
A web-based HTTP transport implementing the MCP Streamable HTTP specification.
Manual Installation (from source)
Only needed if you're developing the server itself, or want to run a version that isn't published to npm yet — otherwise prefer Quick Start above.
# Clone the repository
git clone <repository-url>
cd google-cloud-mcp
# Install dependencies
pnpm install
# Build the project
pnpm buildDocker
Build the image
docker build -t google-logging-mcp .Run the container
For the stdio transport (used interactively by MCP clients), run it attached:
docker run -i --rm \
-e GOOGLE_APPLICATION_CREDENTIALS=/secrets/key.json \
-v /path/to/service-account-key.json:/secrets/key.json:ro \
google-logging-mcpFor the HTTP transport running as a long-lived background service that comes back up automatically after a reboot or crash, add --restart=always:
docker run -d \
--name google-logging-mcp \
--restart=always \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e MCP_HTTP_HOST=0.0.0.0 \
-e GOOGLE_APPLICATION_CREDENTIALS=/secrets/key.json \
-v /path/to/service-account-key.json:/secrets/key.json:ro \
google-logging-mcpMCP_HTTP_HOST=0.0.0.0 is required here — the server binds to 127.0.0.1 by default, which is unreachable from outside the container even with -p published.
--restart=always tells the Docker daemon to restart the container whenever it stops, including after the host reboots — as long as Docker itself is set to start on boot (this is the default on Docker Desktop and most Docker Engine installs). To apply the policy to a container that's already running, use:
docker update --restart=always google-logging-mcpTo stop auto-restart and remove the container:
docker rm -f google-logging-mcpAdding This MCP to Claude Desktop
Via npx (recommended)
This is the Quick Start config repeated for convenience — no Docker, no shared server, each user runs their own local instance with their own credentials.
Set up a service account per Least-Privilege IAM Setup and note the path to its key file.
Open Claude Desktop's config file:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Windows:
Add an entry under
mcpServers:{ "mcpServers": { "google-cloud-observability": { "command": "npx", "args": ["-y", "google-cloud-observability-mcp@latest"], "env": { "GOOGLE_APPLICATION_CREDENTIALS": "/absolute/path/to/your/key.json", "GOOGLE_CLOUD_PROJECT": "your-project-id" } } } }Fully quit and reopen Claude Desktop — the config is only read at launch, closing the window isn't enough. The first launch takes a few extra seconds while
npxdownloads the package.
Via Docker HTTP server (shared/always-on alternative)
Use this instead if you want one centrally-hosted server shared by a whole team, rather than everyone running their own local instance. Claude Desktop's config file only launches local stdio processes under mcpServers — it does not speak the Streamable HTTP transport directly, even though the field names (url, type: "http") exist in other MCP clients like Claude Code. To connect Claude Desktop to the HTTP server running in Docker, bridge it with mcp-remote, a small stdio↔HTTP proxy run on demand via npx.
Make sure the container is running with the HTTP transport (see Docker above):
docker run -d \ --name google-logging-mcp \ --restart=always \ -p 3000:3000 \ -e MCP_TRANSPORT=http \ -e MCP_HTTP_HOST=0.0.0.0 \ -e GOOGLE_APPLICATION_CREDENTIALS=/secrets/key.json \ -v /path/to/service-account-key.json:/secrets/key.json:ro \ google-logging-mcpOpen Claude Desktop's config file (paths above) and add an entry under
mcpServers:{ "mcpServers": { "google-logging": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:3000/mcp", "--transport", "http-only" ] } } }Fully quit and reopen Claude Desktop.
Notes:
- The first launch takes a few extra seconds while
npxdownloadsmcp-remote. - If Claude Desktop runs on a different machine than the Docker host, replace
localhostwith that host's reachable IP or hostname, and make sure port 3000 is open to it. - The server has no client-side auth — anything that can reach the port can call these tools using the container's mounted credentials. Don't expose port 3000 beyond a trusted network.
Adding This MCP to Cursor
Via npx (recommended)
Cursor supports the same command/args/env stdio config as Claude Desktop.
Set up a service account per Least-Privilege IAM Setup and note the path to its key file.
Open or create Cursor's config file:
- Project-scoped:
.cursor/mcp.jsonin the repo you want it available in - Global (all projects):
~/.cursor/mcp.json
- Project-scoped:
Add an entry under
mcpServers:{ "mcpServers": { "google-cloud-observability": { "command": "npx", "args": ["-y", "google-cloud-observability-mcp@latest"], "env": { "GOOGLE_APPLICATION_CREDENTIALS": "/absolute/path/to/your/key.json", "GOOGLE_CLOUD_PROJECT": "your-project-id" } } } }In Cursor, open Settings → MCP and confirm
google-cloud-observabilityshows as connected.
Via Docker HTTP server (shared/always-on alternative)
Use this instead if you want one centrally-hosted server shared by a whole team. Unlike Claude Desktop, Cursor's MCP client natively supports the Streamable HTTP transport via a url field — no mcp-remote bridge required.
Make sure the container is running with the HTTP transport (see Docker above).
Open or create Cursor's config file (paths above) and add an entry under
mcpServers:{ "mcpServers": { "google-logging": { "url": "http://localhost:3000/mcp" } } }In Cursor, open Settings → MCP and confirm
google-loggingshows as connected. Cursor reconnects automatically if the container restarts, so no reload should be needed after that.
Notes:
- If Cursor runs on a different machine than the Docker host, replace
localhostwith that host's reachable IP or hostname. - Same caveat as above: the server has no client-side auth, so keep port 3000 restricted to a trusted network.
Configuration
Environment Variables
GOOGLE_APPLICATION_CREDENTIALS: Path to your Google Cloud service account key fileGOOGLE_CLOUD_PROJECT: Your default Google Cloud project IDGOOGLE_CLIENT_EMAIL: Service account email (alternative to credentials file)GOOGLE_PRIVATE_KEY: Service account private key (alternative to credentials file)LAZY_AUTH: Set to 'false' to initialize auth immediately (default: 'true')DEBUG: Set to 'true' for debug loggingMCP_TRANSPORT: Transport type - 'stdio' (default) or 'http'MCP_HTTP_PORT: Port for HTTP transport (default: 3000)MCP_HTTP_HOST: Bind address for HTTP transport (default: '127.0.0.1'). Set to '0.0.0.0' when running in Docker so the port mapping can reach it — the server's Origin-header check still blocks non-local browser origins.
Google Cloud Authentication
You can authenticate in several ways:
Service Account Key File (Recommended):
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.jsonEnvironment Variables:
export GOOGLE_CLIENT_EMAIL=your-service-account@project.iam.gserviceaccount.com export GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"Application Default Credentials: If running on Google Cloud, ADC will be used automatically.
Least-Privilege IAM Setup
Don't reuse a broad/owner-level service account for this server — every tool it exposes is read-only, so a dedicated service account with exactly these roles is all it ever needs:
| Role | Why |
|------|-----|
| roles/logging.viewer | query-logs, logs-time-range, find-traces-from-logs, and the gcp-logs:// resources |
| roles/monitoring.viewer | query-metrics, list-metric-types, natural-language-metrics-query, and the gcp-monitoring:// resources — includes monitoring.timeSeries.list, which is sufficient for all metrics tools in this server |
| roles/cloudtrace.user | get-trace, list-traces, natural-language-trace-query, and the gcp-trace:// resources |
| roles/spanner.viewer | list-spanner-instances, list-spanner-databases (metadata only, no query access) |
| roles/spanner.databaseReader | execute-spanner-query, list-spanner-tables, spanner-query-count, schema resources — actual data reads |
Create the service account and grant these roles:
PROJECT_ID="your-project-id"
SA_NAME="mcp-observability-readonly"
SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create "$SA_NAME" \
--project="$PROJECT_ID" \
--display-name="Google Cloud Observability MCP (read-only)"
for ROLE in roles/logging.viewer roles/monitoring.viewer roles/cloudtrace.user roles/spanner.viewer roles/spanner.databaseReader; do
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:${SA_EMAIL}" \
--role="$ROLE"
done
gcloud iam service-accounts keys create key.json \
--iam-account="$SA_EMAIL"spanner.databaseReader grants read access project-wide by default. If you only need specific databases reachable, scope it there instead of at the project level:
gcloud spanner databases add-iam-policy-binding DATABASE_ID \
--instance=INSTANCE_ID \
--project="$PROJECT_ID" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/spanner.databaseReader"If you don't use Spanner at all, skip both Spanner roles entirely — the corresponding tools will just fail with a clear permission error instead of succeeding, and nothing else depends on them.
Point GOOGLE_APPLICATION_CREDENTIALS at the resulting key.json in whichever config you're using (npx, Docker, or a local build).
Usage
Using Stdio Transport (Default)
# Start with stdio transport
pnpm start
# Or explicitly specify stdio
MCP_TRANSPORT=stdio pnpm startUsing HTTP Transport
# Start with HTTP transport
MCP_TRANSPORT=http pnpm start
# Or with custom port
MCP_TRANSPORT=http MCP_HTTP_PORT=8080 pnpm startWhen using HTTP transport, the server will be available at:
- MCP Endpoint:
http://127.0.0.1:3000/mcp - Health Check:
http://127.0.0.1:3000/health
HTTP Transport Features
The HTTP transport implements the MCP Streamable HTTP specification with:
- Session Management: Automatic session ID assignment and tracking
- Server-Sent Events (SSE): For real-time communication and server-initiated messages
- Request/Response Handling: Proper JSON-RPC 2.0 message handling
- Security: Origin validation to prevent DNS rebinding attacks
- CORS Support: Cross-origin requests support for web applications
- Connection Management: Automatic cleanup of stale connections
HTTP Transport Usage Examples
Initialize Connection
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}'The response will include a Mcp-Session-Id header that should be used in subsequent requests.
Make Requests with Session
curl -X POST http://127.0.0.1:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Mcp-Session-Id: <session-id>" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'Server-Sent Events Stream
curl -X GET http://127.0.0.1:3000/mcp \
-H "Accept: text/event-stream" \
-H "Mcp-Session-Id: <session-id>"Available Tools
Logging Tools
gcp-logging-query: Query Google Cloud Logsgcp-logging-list-entries: List log entries with filters
Spanner Tools
gcp-spanner-execute-query: Execute SQL queries on Spanner databasesgcp-spanner-list-databases: List Spanner databasesgcp-spanner-list-instances: List Spanner instancesgcp-spanner-get-schema: Get database schema informationgcp-spanner-query-count: Get query execution metrics
Monitoring Tools
gcp-monitoring-query: Query monitoring metricsgcp-monitoring-list-metrics: List available metric descriptorsgcp-monitoring-get-resource-metrics: Get metrics for specific resources
Trace Tools
get-trace: Retrieve trace data by trace IDsearch-traces: Search for traces with filtersget-trace-summary: Get summary statistics for traces
Project Tools
gcp-get-project-info: Get current project informationgcp-list-enabled-services: List enabled APIs and services
Available Resources
Logging Resources
gcp://logging/logs/{logName}: Individual log resourcesgcp://logging/entries: Recent log entries
Spanner Resources
gcp://spanner/instances: List of Spanner instancesgcp://spanner/databases/{instanceId}: Databases in an instancegcp://spanner/schema/{instanceId}/{databaseId}: Database schema
Monitoring Resources
gcp://monitoring/metrics: Available monitoring metricsgcp://monitoring/resources: Monitored resource types
Trace Resources
gcp://trace/traces: Recent trace data
Available Prompts
analyze-logs: Analyze log patterns and errorsquery-optimization: Optimize Spanner queriestroubleshoot-performance: Troubleshoot application performance issuessecurity-analysis: Analyze security-related logs and traces
Development
# Install dependencies
pnpm install
# Run in development mode with stdio transport
pnpm dev
# Run in development mode with HTTP transport
MCP_TRANSPORT=http pnpm dev
# Build the project
pnpm build
# Run tests
pnpm test
# Lint the code
pnpm lint
# Format the code
pnpm formatTroubleshooting
Authentication Issues
Check your credentials:
gcloud auth application-default loginVerify service account permissions:
- Logging Viewer
- Spanner Database User
- Monitoring Viewer
- Cloud Trace User
Test authentication:
DEBUG=true pnpm start
HTTP Transport Issues
Port conflicts: If port 3000 is in use, specify a different port:
MCP_HTTP_PORT=8080 MCP_TRANSPORT=http pnpm startCORS issues: The server only accepts requests from localhost, 127.0.0.1, and .local domains for security.
Session management: Make sure to include the
Mcp-Session-Idheader in requests after initialization.
Performance Issues
Enable lazy authentication:
LAZY_AUTH=true pnpm startReduce logging verbosity: Remove
DEBUG=truefrom production environments.
Security Considerations
HTTP Transport Security
- The server binds only to
127.0.0.1(localhost) by default - Origin header validation prevents DNS rebinding attacks
- Sessions are automatically cleaned up
- Request timeouts prevent resource exhaustion
Google Cloud Security
- Use service accounts with minimal required permissions
- Regularly rotate service account keys
- Monitor access logs for unusual activity
- Use VPC-native clusters when possible
License
Apache License 2.0 - see LICENSE for full terms. This is a modified fork of krzko/google-cloud-mcp (Copyright 2025 Krzysztof Kowalski), also Apache-2.0 licensed.
