# Docker MCP Gateway Configuration - Google Sheets Server
## Status: ✅ FULLY RESOLVED AND WORKING
**Last Updated**: October 12, 2025
**Resolution**: Volume mount authentication working successfully with all 25 tools
---
## Executive Summary
The Google Sheets MCP server is now **fully functional** with Docker MCP Gateway. The initial implementation used Docker MCP secrets which were not being properly injected by the gateway. The solution was to switch to **volume mount** authentication, which directly mounts the credentials file into the container.
### Final Working Configuration
- ✅ All 25 Google Sheets tools loading correctly
- ✅ Authentication working with volume-mounted credentials
- ✅ Gateway successfully initializing in 1.5 seconds
- ✅ Tested and verified: `list_spreadsheets` and `list_sheets` working
---
## Problem: Docker MCP Secret Injection Failure
### What Was Wrong
**Initial Catalog Configuration (NOT WORKING)**:
```yaml
secrets:
- name: GOOGLE_APPLICATION_CREDENTIALS
env: GOOGLE_APPLICATION_CREDENTIALS
- name: SERVICE_ACCOUNT_EMAIL
env: SERVICE_ACCOUNT_EMAIL
- name: DRIVE_FOLDER_ID
env: DRIVE_FOLDER_ID
```
**The Issue**:
- Docker MCP Gateway was reading secrets from the secret store
- However, when launching containers, it passed environment variable **names** without **values**
- Container received: `-e GOOGLE_APPLICATION_CREDENTIALS` (empty)
- Should receive: `-e GOOGLE_APPLICATION_CREDENTIALS=/path/to/creds.json`
**Evidence from Gateway Logs**:
```
Running googlesheets-mcp-server:latest with [...-e GOOGLE_APPLICATION_CREDENTIALS -e SERVICE_ACCOUNT_EMAIL...]
Can't start googlesheets: failed to connect: calling "initialize": EOF
0 tools listed
```
The environment variables were empty in the container, causing authentication to fail.
---
## Solution: Volume Mount Authentication
### Working Catalog Configuration
**File**: `~/.docker/mcp/catalogs/custom.yaml`
```yaml
version: 2
name: custom
displayName: Custom MCP Servers
registry:
googlesheets:
description: "Bridge between MCP clients and Google Sheets API"
title: "Google Sheets"
type: server
dateAdded: "2025-10-11T00:00:00Z"
image: googlesheets-mcp-server:latest
tools:
- name: list_spreadsheets
- name: create_spreadsheet
- name: get_sheet_data
# ... all 25 tools listed ...
config:
- name: googlesheets
description: Configure Google Sheets API credentials
type: object
properties:
credentials_path:
type: string
description: Path to Google service account JSON file
required:
- credentials_path
volumes:
- /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json:/app/credentials.json:ro
env:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /app/credentials.json
metadata:
category: productivity
tags:
- google
- sheets
- spreadsheet
license: MIT
owner: local
```
**Key Changes**:
1. **Removed** `secrets` section entirely
2. **Added** `config` section to define `credentials_path` parameter
3. **Added** `volumes` section with **absolute path** to mount credentials
4. **Added** `env` section to set `GOOGLE_APPLICATION_CREDENTIALS` to the mounted file path
### Server Configuration
**File**: `~/.docker/mcp/config.yaml`
```yaml
servers:
googlesheets:
credentials_path: /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json
```
**Note**: This config file is used by the catalog template variable system, but since we use absolute paths in the volume mount, it's mainly for documentation purposes.
---
## Why This Solution Works
### Volume Mount Approach
1. **Direct File Access**: The credentials JSON file is mounted directly into the container at `/app/credentials.json`
2. **No Secret Injection Dependency**: Bypasses Docker MCP's secret injection mechanism entirely
3. **Standard Docker Pattern**: Uses standard Docker `-v` volume mounting
4. **Read-Only Mount**: The `:ro` flag ensures credentials are mounted read-only for security
### Server Code Already Supports This
The server code in `googlesheets_server.py` (lines 67-74) already supports reading from file paths:
```python
if GOOGLE_APPLICATION_CREDENTIALS and os.path.exists(GOOGLE_APPLICATION_CREDENTIALS):
try:
creds = service_account.Credentials.from_service_account_file(
GOOGLE_APPLICATION_CREDENTIALS, scopes=SCOPES)
logger.info("Using service account credentials from file")
return creds
except Exception as e:
logger.warning(f"Service account file auth failed: {e}")
```
---
## Implementation Steps Taken
### 1. Updated Catalog Configuration
```bash
# Edited ~/.docker/mcp/catalogs/custom.yaml
# Changed from secrets-based to volume mount configuration
```
### 2. Removed Conflicting Secrets
```bash
docker mcp secret rm GOOGLE_APPLICATION_CREDENTIALS
docker mcp secret rm SERVICE_ACCOUNT_EMAIL
docker mcp secret rm DRIVE_FOLDER_ID
docker mcp secret rm GOOGLE_CREDENTIALS_JSON
docker mcp secret rm googlesheets.credentials_json
docker mcp secret rm googlesheets.service_account_email
docker mcp secret rm googlesheets.drive_folder_id
```
### 3. Restarted Docker MCP Gateway
```bash
# Gateway started with new configuration
docker mcp gateway run
```
### 4. Verified Success
```bash
# Gateway logs showed:
# - 25 tools listed successfully
# - Initialized in 1.579412997s
# - Start stdio server (ready)
```
---
## Test Results
### Successful Gateway Initialization
```
- Reading configuration...
- Reading registry from registry.yaml
- Reading catalog from [docker-mcp.yaml custom.yaml]
- Reading config from config.yaml
- Reading tools from tools.yaml
- Configuration read in 39.482302ms
- Using images:
- googlesheets-mcp-server:latest
> Images pulled in 14.006511ms
- Those servers are enabled: googlesheets
- Listing MCP tools...
- Running googlesheets-mcp-server:latest with [run --rm -i --init --security-opt no-new-privileges --cpus 1 --memory 2Gb --pull never -l docker-mcp=true -l docker-mcp-tool-type=mcp -l docker-mcp-name=googlesheets -l docker-mcp-transport=stdio -e GOOGLE_APPLICATION_CREDENTIALS -v /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json:/app/credentials.json:ro]
> googlesheets: (25 tools)
> 25 tools listed in 1.524719974s
- Watching for configuration updates...
> Initialized in 1.579412997s
> Start stdio server
```
### Tool Testing: list_spreadsheets ✅
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "📊 Spreadsheets:\n- Influencer Marketing (ID: 1sE3lrF1AIdzCFuMcwyQLKi3scMKONN2jgKeIAJPQlOg)\n"
}
],
"isError": false
}
}
```
### Tool Testing: list_sheets ✅
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "📊 Sheets:\n- Clients (ID: 541801659)\n- Influencers (ID: 0)\n- Influencer Social Accounts (ID: 55579648)\n- Campaign (ID: 26526788)\n- Campaign Collaborations (ID: 664723324)\n- Content Deliverables (ID: 151091662)\n- Content Performance (ID: 467956941)\n- Shipped Products (ID: 1696625557)\n- Monthly Results Dashboard (ID: 1482832251)\n"
}
],
"isError": false
}
}
```
---
## Alternative Approaches Attempted
### ❌ Attempt 1: Docker MCP Secrets with JSON Content
- Set secret: `GOOGLE_CREDENTIALS_JSON` with full JSON credentials
- Updated catalog to use secret
- **Result**: Gateway still not injecting secret values
### ❌ Attempt 2: Template Variables in Volumes
- Used: `{{googlesheets.credentials_path}}:/app/credentials.json:ro`
- **Result**: Template variable not expanded, resulted in empty mount: `:/app/credentials.json:ro`
### ✅ Final Solution: Absolute Path in Volumes
- Used absolute path directly in catalog
- **Result**: Works perfectly, all tools load successfully
---
## Usage in Other Projects
### Project-Level MCP Configuration
To make Google Sheets tools available in a specific project (e.g., marketing automation):
**File**: `<project>/.claude/mcp.json`
```json
{
"mcpServers": {
"docker-mcp-gateway": {
"command": "docker",
"args": ["mcp", "gateway", "run"]
}
}
}
```
This allows Claude Code to use the Google Sheets MCP server when working in that project directory.
### Example: Marketing Automation Project
**Location**: `/home/talend/IntoData/Internal/n8n/marketing_automation/.claude/mcp.json`
Created this configuration file to enable Google Sheets access in the marketing automation project.
---
## Lessons Learned
### Critical Rules for Docker MCP Catalogs
1. **Volume Mounts Require Absolute Paths**
- ❌ Don't use: `{{template.variables}}`
- ✅ Use: `/home/user/path/to/file.json`
2. **Docker MCP Secret Injection is Unreliable**
- Secret names are passed, but values may not be injected
- Volume mounts are more reliable for file-based credentials
3. **Server Code Should Support Multiple Auth Methods**
- File paths: `GOOGLE_APPLICATION_CREDENTIALS=/path/to/file.json`
- JSON content: `GOOGLE_CREDENTIALS_JSON={"type":"service_account",...}`
- This flexibility allows different deployment methods
4. **Test Each Layer Independently**
- ✅ Direct Python: `python googlesheets_server.py`
- ✅ Direct Docker: `docker run -v /path:/app/creds.json ...`
- ✅ Docker MCP: Through gateway
5. **Gateway Logs Are Essential**
- Check stderr output for initialization errors
- Look for "0 tools listed" as sign of failure
- Verify the `-v` mount shows full paths, not empty
---
## Troubleshooting Guide
### Issue: "0 tools listed" in Gateway Logs
**Symptoms**:
```
- Running googlesheets-mcp-server:latest with [...]
> Can't start googlesheets: failed to connect: calling "initialize": EOF
> 0 tools listed
```
**Diagnosis**:
- Check the `-v` mount in gateway logs
- If you see `-v :/app/credentials.json:ro` (empty before colon), the path isn't being set
**Solution**:
- Use absolute path in `volumes` section of catalog
- Remove template variables
### Issue: Authentication Errors
**Symptoms**:
```
❌ Error: Unable to authenticate with Google API
```
**Diagnosis**:
- Check if file exists at the path specified
- Verify service account has access to the spreadsheet
- Check file permissions (should be readable by user running gateway)
**Solution**:
```bash
# Verify file exists
ls -la /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json
# Check service account email
cat /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json | grep client_email
# Share spreadsheet with service account email
```
### Issue: Template Variables Not Expanding
**Symptoms**:
- Gateway logs show `-v :/app/credentials.json:ro`
- Config file has `credentials_path` set correctly
**Diagnosis**:
- Docker MCP Gateway doesn't support template variables in `volumes` section
**Solution**:
- Replace template variables with absolute paths directly in catalog
---
## Security Considerations
### Current Implementation
1. **Read-Only Mounts**: Credentials mounted with `:ro` flag
2. **Non-Root User**: Container runs as `mcpuser` (UID 1000)
3. **No Hardcoded Credentials**: All credentials from mounted files
4. **Service Account Principle of Least Privilege**:
- Only has access to specific spreadsheets
- Uses service account, not user OAuth
### Best Practices
1. **Never Commit Credentials**: Keep credentials in `credential/` directory (in `.gitignore`)
2. **Restrict File Permissions**:
```bash
chmod 600 credential/*.json
```
3. **Share Spreadsheets Explicitly**: Only share with service account as needed
4. **Audit Access**: Regularly review which spreadsheets the service account can access
5. **Rotate Credentials**: Periodically generate new service account keys
---
## Service Account Details
- **Email**: `googlesheets-mcp-server@n8n-automation-455514.iam.gserviceaccount.com`
- **Project**: `n8n-automation-455514`
- **Credentials File**: `/home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json`
- **Access**: Shared with "Influencer Marketing" spreadsheet
- **APIs Enabled**:
- Google Sheets API
- Google Drive API
---
## Files Modified During Fix
1. **~/.docker/mcp/catalogs/custom.yaml**
- Removed `secrets` section
- Added `config`, `volumes`, and `env` sections
- Changed to volume mount approach
2. **Docker MCP Secrets Store**
- Removed all conflicting secrets
- Now empty (not using secret injection)
3. **Docker MCP Gateway**
- Restarted to pick up new catalog configuration
- Now successfully loading 25 tools
4. **Project MCP Configuration** (New)
- Created `/home/talend/IntoData/Internal/n8n/marketing_automation/.claude/mcp.json`
- Enables Google Sheets access in marketing automation project
---
## Complete Working Setup
### Directory Structure
```
/home/talend/IntoData/Internal/MCP/GoogleSheets/
├── Dockerfile
├── requirements.txt
├── googlesheets_server.py
├── readme.txt
├── CLAUDE.md
├── DOCKER_MCP_SETUP.md (this file)
├── TEST_RESULTS.md
├── mcp-builder-prompt.md
└── credential/
└── n8n-automation-455514-6d14237862c6.json
~/.docker/mcp/
├── catalogs/
│ └── custom.yaml (volume mount configuration)
├── config.yaml (credentials_path set)
└── registry.yaml (googlesheets entry)
/home/talend/IntoData/Internal/n8n/marketing_automation/
└── .claude/
└── mcp.json (project MCP configuration)
```
### Running the Gateway
```bash
# Start the gateway (automatically uses catalog configuration)
docker mcp gateway run
# Or in background
nohup docker mcp gateway run > /tmp/mcp_gateway.log 2>&1 &
# Check status
ps aux | grep "docker mcp gateway"
# View logs
tail -f /tmp/mcp_gateway.log
```
### Testing the Server
```bash
# Test with direct Docker run
docker run --rm -i \
-v /home/talend/IntoData/Internal/MCP/GoogleSheets/credential/n8n-automation-455514-6d14237862c6.json:/app/credentials.json:ro \
-e GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json \
googlesheets-mcp-server:latest \
python googlesheets_server.py
```
---
## Summary
The Docker MCP Gateway integration is now **fully functional** using volume mount authentication. This approach:
✅ Bypasses unreliable Docker MCP secret injection
✅ Uses standard Docker volume mounting (reliable)
✅ Works with existing server code (no modifications needed)
✅ Follows security best practices (read-only mount, non-root user)
✅ Successfully loads all 25 Google Sheets tools
✅ Verified working with real spreadsheet operations
The server is **production-ready** for use in Claude Code projects via the `.claude/mcp.json` configuration.