Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 67 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ When filtering, use these exact tool names (comma-separated, no spaces):
- `create_sheet`
- `create_spreadsheet`
- `find_in_spreadsheet`
- `get_multiple_sheet_data`
- `get_multiple_spreadsheet_summary`
- `get_sheet_data`
- `get_sheet_formulas`
Expand Down Expand Up @@ -193,17 +192,57 @@ _Refer to the [ID Reference Guide](#-id-reference-guide) for more information ab
* `title` (string): The desired title for the spreadsheet. Example: "Quarterly Report Q4".
* `folder_id` (optional string): Google Drive folder ID where the spreadsheet should be created. Get from its URL. If omitted, uses configured default or root.
* _Returns:_ Object with spreadsheet info, including `spreadsheetId`, `title`, and `folder`.
* **`get_sheet_data`**: Reads data from a range in a sheet/tab.
* **`get_sheet_data`**: Reads data from one or more ranges in a SINGLE spreadsheet. **Supports batching** - multiple ranges are fetched in a single API call (5-10x faster than separate calls).
* `spreadsheet_id` (string): The spreadsheet ID (from its URL).
* `sheet` (string): Name of the sheet/tab (e.g., "Sheet1").
* `range` (optional string): A1 notation (e.g., `'A1:C10'`, `'Sheet1!B2:D'`). If omitted, reads the whole sheet/tab specified by `sheet`.
* `include_grid_data` (optional boolean, default `False`): If `True`, returns full grid data including formatting and metadata (much larger). If `False`, returns values only (more efficient).
* _Returns:_ If `include_grid_data=True`, full grid data with metadata ([`get` response](https://developers.google.com/workspace/sheets/api/reference/rest/v4/spreadsheets/get#response-body)). If `False`, a values result object from the Values API ([`values.get` response](https://developers.google.com/workspace/sheets/api/reference/rest/v4/spreadsheets.values/get#response-body)).
* **`get_sheet_formulas`**: Reads formulas from a range in a sheet/tab.
* `ranges` (string or array of strings): Either a single range or multiple ranges in A1 notation with sheet name.
* Single range: `"Sheet1!A1:B10"` or just `"Sheet1"` for entire sheet
* Multiple ranges (batched): `["Sheet1!A1:B10", "Sheet2!C1:D20", "Data!E:F"]`
* **Note:** All ranges must be from the SAME spreadsheet. For multiple different spreadsheets, call this tool separately for each.
* _Returns:_ Dictionary with `spreadsheetId` and `valueRanges` (array of results). Each result has `range` and `values` (2D array).

**Examples:**
```python
# Single range
data = get_sheet_data("spreadsheet-id", "Sheet1!A1:B10")

# Multiple ranges - BATCHED in one API call (recommended for multiple ranges)
data = get_sheet_data("spreadsheet-id", ["Sheet1!A1:B10", "Sheet2!C1:D20"])

# Entire sheets
data = get_sheet_data("spreadsheet-id", ["Sales", "Inventory", "Reports"])
```
* **`get_sheet_formulas`**: Reads formulas from one or more ranges in a SINGLE spreadsheet. **Supports batching** - multiple ranges are fetched in a single API call (5-10x faster than separate calls).
* `spreadsheet_id` (string): The spreadsheet ID (from its URL).
* `sheet` (string): Name of the sheet/tab (e.g., "Sheet1").
* `range` (optional string): A1 notation (e.g., `'A1:C10'`, `'Sheet1!B2:D'`). If omitted, reads all formulas in the sheet/tab specified by `sheet`.
* _Returns:_ 2D array of cell formulas (array of arrays) ([`values.get` response](https://developers.google.com/workspace/sheets/api/reference/rest/v4/spreadsheets.values/get#response-body)).
* `ranges` (string or array of strings): Either a single range or multiple ranges in A1 notation with sheet name.
* Single range: `"Sheet1!A1:C10"` or just `"Sheet1"` for entire sheet
* Multiple ranges (batched): `["Sheet1!B:B", "Sheet2!C:C", "Sheet3!D:D"]`
* **Note:** All ranges must be from the SAME spreadsheet. For multiple different spreadsheets, call this tool separately for each.
* `format` (optional string, default `'A1'`): Formula notation format.
* `'A1'`: Returns formulas in A1 notation (e.g., `=SUM(A1:A3)`, `=B2*2`)
* `'R1C1'`: Returns formulas in R1C1 notation (e.g., `=SUM(R[-2]C:RC)`, `=RC[-1]*2`)
* R1C1 format is useful for identifying unique formula patterns across ranges, as relative references normalize to the same pattern regardless of cell position.
* _Returns:_ Dictionary with `spreadsheetId` and `valueRanges` (array of results). Each result has `range` and `values` (2D array of formulas).

**Examples:**
```python
# Single range - formulas in A1 notation (default)
data = get_sheet_formulas('spreadsheet-id', 'Sheet1!B1:B10')
# Returns: {valueRanges: [{range: "Sheet1!B1:B10", values: [['=SUM(A1:A3)'], ...]}]}

# Multiple ranges - BATCHED, with R1C1 for pattern analysis
data = get_sheet_formulas('spreadsheet-id', ['Sheet1!B:B', 'Sheet2!C:C'], format='R1C1')
# Returns: {valueRanges: [{range: "Sheet1!B:B", values: [['=SUM(RC[-1]:R[2]C[-1])'], ...]}, ...]}

# Use R1C1 to identify unique formula patterns across sheets
from collections import defaultdict
formula_patterns = defaultdict(list)
for vr in data['valueRanges']:
for row_idx, row in enumerate(vr['values']):
for col_idx, formula in enumerate(row):
if formula.startswith('='):
formula_patterns[formula].append((vr['range'], row_idx, col_idx))
# Now formula_patterns maps unique formulas to their locations across all sheets
```
* **`update_cells`**: Writes data to a specific range. Overwrites existing data.
* `spreadsheet_id` (string): The spreadsheet ID (from its URL).
* `sheet` (string): Name of the sheet/tab (e.g., "Sheet1").
Expand All @@ -228,9 +267,6 @@ _Refer to the [ID Reference Guide](#-id-reference-guide) for more information ab
* `spreadsheet_id` (string): The spreadsheet ID (from its URL).
* `title` (string): Name for the new sheet/tab.
* _Returns:_ New sheet properties object.
* **`get_multiple_sheet_data`**: Fetches data from multiple ranges across potentially different spreadsheets in one call.
* `queries` (array of objects): Each object needs `spreadsheet_id`, `sheet`, and `range`. Example: `[{"spreadsheet_id": "abc", "sheet": "Sheet1", "range": "A1:B2"}, ...]`.
* _Returns:_ List of objects, each containing the query params and fetched `data` or an `error`. Each `data` is a [`values.get` response](https://developers.google.com/workspace/sheets/api/reference/rest/v4/spreadsheets.values/get#response-body).
* **`get_multiple_spreadsheet_summary`**: Gets titles, sheet/tab names, headers, and first few rows for multiple spreadsheets.
* `spreadsheet_ids` (array of strings): IDs of the spreadsheets (from their URLs).
* `rows_to_fetch` (optional integer, default `5`): How many rows (including header) to preview. Example: `5`.
Expand Down Expand Up @@ -314,6 +350,18 @@ _Refer to the [ID Reference Guide](#-id-reference-guide) for more information ab
* `CREDENTIALS_PATH`: Path to the downloaded OAuth credentials JSON file (default: `credentials.json`).
* `TOKEN_PATH`: Path to store the user's refresh token after first login (default: `token.json`). Must be writable.

### Method B2: Token Relay Mode (OpenShift/Kubernetes + End User Auth) 🚢

* **Why?** Perfect for containerized deployments (OpenShift, Kubernetes) where you need end-user authentication but can't use interactive browser flows. Your frontend handles OAuth, and passes tokens to the MCP server.
* **Use Case:** OpenShift/Kubernetes deployments with frontend applications that need to relay end-user identity.
* **Steps:**
1. **Frontend OAuth:** Your frontend app (React, Vue, Angular, etc.) handles the OAuth flow and obtains user access tokens.
2. **Pass Token to MCP:** Frontend passes the access token to MCP server via environment variable.
3. **Set Environment Variable:**
* `USER_ACCESS_TOKEN`: OAuth access token obtained by your frontend application.
4. **Token Refresh:** Your frontend is responsible for refreshing tokens (they expire in ~1 hour).
* **📖 Full Guide:** See [Token Relay Mode Documentation](docs/TOKEN_RELAY_MODE.md) for complete setup instructions, frontend examples (JavaScript, Python), OpenShift deployment manifests, and security best practices.
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references TOKEN_RELAY_MODE.md which is not included in this PR. The file is mentioned as "📖 Full Guide: See Token Relay Mode Documentation" but doesn't exist in the changes. Either include this documentation file in the PR or remove the reference until it's available.

Suggested change
* **📖 Full Guide:** See [Token Relay Mode Documentation](docs/TOKEN_RELAY_MODE.md) for complete setup instructions, frontend examples (JavaScript, Python), OpenShift deployment manifests, and security best practices.
* **📖 Full Guide:** A dedicated Token Relay Mode guide with setup instructions, frontend examples, OpenShift manifests, and security best practices will be added to the documentation in a future update.

Copilot uses AI. Check for mistakes.

### Method C: Direct Credential Injection (Advanced) 🔒

* **Why?** Useful in environments like Docker, Kubernetes, or CI/CD where managing files is hard, but environment variables are easy/secure. Avoids file system access.
Expand Down Expand Up @@ -359,15 +407,17 @@ _Refer to the [ID Reference Guide](#-id-reference-guide) for more information ab

The server checks for credentials in this order:

1. `CREDENTIALS_CONFIG` (Base64 content)
2. `SERVICE_ACCOUNT_PATH` (Path to Service Account JSON)
3. `CREDENTIALS_PATH` (Path to OAuth JSON) - triggers interactive flow if token is missing/expired
4. **Application Default Credentials (ADC)** - automatic fallback
1. `USER_ACCESS_TOKEN` (External OAuth token - **Token Relay Mode**)
2. `CREDENTIALS_CONFIG` (Base64 content)
3. `SERVICE_ACCOUNT_PATH` (Path to Service Account JSON)
4. `CREDENTIALS_PATH` (Path to OAuth JSON) - triggers interactive flow if token is missing/expired
5. **Application Default Credentials (ADC)** - automatic fallback

**Environment Variable Summary:**

| Variable | Method(s) | Description | Default |
|:---------------------------------|:----------------------------|:-----------------------------------------------------------------|:-------------------|
| `USER_ACCESS_TOKEN` | Token Relay | OAuth access token from external source (frontend app). Enables end-user auth in containers. | - |
| `SERVICE_ACCOUNT_PATH` | Service Account | Path to the Service Account JSON key file (MCP server specific). | - |
| `GOOGLE_APPLICATION_CREDENTIALS` | ADC | Path to service account key (Google's standard variable). | - |
| `DRIVE_FOLDER_ID` | Service Account | ID of the Google Drive folder shared with the Service Account. | - |
Expand Down
227 changes: 227 additions & 0 deletions docs/LOCAL_TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Local Testing Guide

This guide explains how to test the MCP Google Sheets server on your local machine.

## Prerequisites

### 1. Python 3.10 or Higher

Check your Python version:
```bash
python --version
```

If you need to upgrade, visit [python.org](https://www.python.org/downloads/).

### 2. Install `uv` (Python Package Manager)

```bash
# Linux/macOS
curl -LsSf https://astral.sh/uv/install.sh | sh

# Or using pip
pip install uv
```

Follow the installer instructions to add `uv` to your PATH if needed.

### 3. Google Cloud Platform Setup

You must configure Google Cloud Platform credentials and enable the necessary APIs:

1. **Create/Select a GCP Project**
- Go to [Google Cloud Console](https://console.cloud.google.com/)
- Create a new project or select an existing one

2. **Enable Required APIs**
- Navigate to "APIs & Services" → "Library"
- Search for and enable:
- **Google Sheets API**
- **Google Drive API**

### 4. Set Up Authentication

We recommend using a **Service Account** for local testing.

#### Create a Service Account

1. In GCP Console → "IAM & Admin" → "Service Accounts"
2. Click "+ CREATE SERVICE ACCOUNT"
3. Name it (e.g., `mcp-sheets-service`)
4. Grant **Editor** role
5. Click "Done"
6. Find the account, click Actions (⋮) → "Manage keys"
7. Click "ADD KEY" → "Create new key" → **JSON** → "CREATE"
8. **Download and securely store** the JSON key file

#### Create & Share a Google Drive Folder

1. In [Google Drive](https://drive.google.com/), create a folder (e.g., "MCP Test Sheets")
2. Note the **Folder ID** from the URL:
```
https://drive.google.com/drive/folders/1xcRQCU9xrNVBPTeNzHqx4hrG7yR91WIa
└────────── Folder ID ──────────┘
```
3. Right-click the folder → "Share"
4. Enter the Service Account's email (from the JSON file `client_email`)
5. Grant **Editor** access
6. Uncheck "Notify people"
7. Click "Share"

#### Set Environment Variables

**Linux/macOS:**
```bash
export SERVICE_ACCOUNT_PATH="/path/to/your/service-account-key.json"
export DRIVE_FOLDER_ID="YOUR_DRIVE_FOLDER_ID"
```

**Windows CMD:**
```cmd
set SERVICE_ACCOUNT_PATH="C:\path\to\your\service-account-key.json"
set DRIVE_FOLDER_ID="YOUR_DRIVE_FOLDER_ID"
```

**Windows PowerShell:**
```powershell
$env:SERVICE_ACCOUNT_PATH = "C:\path\to\your\service-account-key.json"
$env:DRIVE_FOLDER_ID = "YOUR_DRIVE_FOLDER_ID"
```

## Running the Server

### Option 1: Development Mode (From Cloned Repo)

If you've cloned the repository and want to test local changes:

```bash
# Navigate to the project directory
cd /path/to/mcp-google-sheets

# Run using uv
uv run mcp-google-sheets
```

The server will start and print logs indicating it's ready.

### Option 2: Using `uvx` (Test Published Package)

To test the server as end-users would experience it:

```bash
uvx mcp-google-sheets@latest
```

This downloads and runs the latest published version.

## Testing with an MCP Client

You need an MCP-compatible client to test the functionality. The most common option is **Claude Desktop**.

### Configure Claude Desktop

Add the server configuration to your `claude_desktop_config.json`:

**For Development Testing (local code):**
```json
{
"mcpServers": {
"mcp-google-sheets-local": {
"command": "uv",
"args": [
"run",
"--directory",
"/home/jfenal/dev/gh/mcp-google-sheets",
"mcp-google-sheets"
],
"env": {
"SERVICE_ACCOUNT_PATH": "/path/to/service-account.json",
"DRIVE_FOLDER_ID": "your_folder_id"
}
}
}
}
```

**For Production Testing (published package):**
```json
{
"mcpServers": {
"google-sheets": {
"command": "uvx",
"args": ["mcp-google-sheets@latest"],
"env": {
"SERVICE_ACCOUNT_PATH": "/path/to/service-account.json",
"DRIVE_FOLDER_ID": "your_folder_id"
}
}
}
}
```

**macOS Note:** If you encounter a `spawn uvx ENOENT` error, use the full path:
```json
"command": "/Users/yourusername/.local/bin/uvx"
```

## Testing the Functionality

Once the server is running and connected to Claude Desktop, try these test prompts:

### Basic Operations
- "List all spreadsheets I have access to."
- "Create a new spreadsheet titled 'Test Spreadsheet'."
- "List the sheets in spreadsheet ID `<your_spreadsheet_id>`."

### Data Operations
- "Get data from range A1:C10 in Sheet1 of spreadsheet `<id>`."
- "Update cell B2 to 'Test Value' in Sheet1 of spreadsheet `<id>`."
- "Add a new sheet named 'Testing' to spreadsheet `<id>`."

### Advanced Operations
- "Get summaries of multiple spreadsheets."
- "Share spreadsheet `<id>` with test@example.com as a reader."
- "Copy Sheet1 from spreadsheet `<id1>` to spreadsheet `<id2>`."

## Testing Token Relay Mode (OpenShift Feature)

If you're testing the token relay functionality for containerized deployments, see the [Token Relay Mode Documentation](TOKEN_RELAY_MODE.md) for detailed setup instructions.
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment references a non-existent documentation file. The code mentions "See Token Relay Mode Documentation" but the PR doesn't include this file in the changes. Either:

  1. Add the TOKEN_RELAY_MODE.md file to this PR
  2. Update the comment to reference the correct documentation location
  3. Remove the reference if the documentation doesn't exist yet

Copilot uses AI. Check for mistakes.

## Troubleshooting

### Authentication Errors
- Verify your service account JSON file path is correct
- Ensure the folder is shared with the service account's email
- Check that both Google Sheets API and Google Drive API are enabled in GCP

### Connection Issues
- Verify environment variables are set correctly
- Check that Claude Desktop config JSON is valid
- Look for errors in the server logs
- Restart Claude Desktop after config changes

### Permission Errors
- Ensure the service account has Editor access to the shared folder
- Verify the folder ID is correct
- Check that spreadsheets are within the shared folder (for service accounts)

## Alternative Authentication Methods

### OAuth 2.0 (Interactive Login)
See the main [README.md](../README.md#method-b-oauth-20-interactive--personal-use-) for OAuth setup instructions.

### Application Default Credentials (ADC)
For Google Cloud environments or local development with `gcloud`:

```bash
gcloud auth application-default login --scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/spreadsheets,https://www.googleapis.com/auth/drive
gcloud auth application-default set-quota-project <project_id>
```

Then run the server without explicit credential environment variables.

## Next Steps

- Review the [README.md](../README.md) for complete feature documentation
- Check [TOKEN_RELAY_MODE.md](TOKEN_RELAY_MODE.md) for containerized deployment testing
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment references a non-existent documentation file TOKEN_RELAY_MODE.md (line 226). This documentation file is not included in the PR changes but is referenced in multiple places (README line 363, LOCAL_TESTING.md line 188). Ensure this documentation file exists or will be added, otherwise users will encounter broken links.

Suggested change
- Check [TOKEN_RELAY_MODE.md](TOKEN_RELAY_MODE.md) for containerized deployment testing
- Review the containerized deployment "token relay mode" instructions in the main README or deployment documentation

Copilot uses AI. Check for mistakes.
- Explore all 19 available tools and their parameters
Loading