Troubleshooting¶
Start with Diagnostics: wslite doctor --live --deployments localizes most failures (missing env vars, bad token, wrong URL wiring, stale deployment) in one run, with redaction-safe output you can share directly. Use the sections below once doctor has told you which service and what kind of failure you have.
Deployment Issues¶
Web App Not Accessible¶
Symptom: MCP server returns "FetchError" or "Connection refused" when calling the proxy URL.
Likely causes:
- Web app not deployed. Each service requires a manual deployment via the Apps Script editor.
- Deployment URL is incorrect. Verify the URL in your
.envfile matches the deployment URL from the Apps Script editor. - Execute-as setting is wrong. The deployment must be "Execute as: Me (USER_DEPLOYING)".
- Access setting is wrong. The deployment must allow anonymous access, not only signed-in Google users.
- Initial deployment was created only with
clasp deploy. Use the Apps Script editor GUI for initial setup so the deployment type, anonymous access, and OAuth scopes are explicitly verified.
Resolution:
# Verify the deployment is accessible
curl -sL "https://script.google.com/macros/s/<deployment-id>/exec"
# Expected output (healthy check):
# {"success":true,"data":{"status":"healthy","version":"<health-version>","service":"google-workspace-proxy-drive"}}
If this returns an error or no response, re-deploy:
In the Apps Script editor: Deploy → New deployment → Select type: Web app → Execute as: Me → Who has access: Anyone. Update the URL in your .env file.
Do not use clasp deploy as the replacement for the GUI deployment step during installation. It can create a deployment record that still returns a Google access-denied HTML page when used as the public web app URL. After a user-created web app deployment exists, clasp redeploy <deployment-id> -V <version> is appropriate for refreshing that same URL.
Scopes Not Authorized¶
Symptom: Every request returns "INTERNAL_ERROR" or "Authorization is required to perform that action".
Resolution:
In the Apps Script editor, run any function (e.g., doGet). Google will prompt you to authorize the required scopes. Accept the permissions. After authorization, re-deploy the web app to apply the new scopes.
Each service requires its own set of OAuth scopes:
| Service | Required Scope |
|---|---|
| Drive | https://www.googleapis.com/auth/drive |
| Gmail | https://www.googleapis.com/auth/gmail.modify, https://www.googleapis.com/auth/gmail.settings.basic, https://www.googleapis.com/auth/script.send_mail |
| Calendar | https://www.googleapis.com/auth/calendar |
| Sheets | https://www.googleapis.com/auth/spreadsheets |
| Slides | https://www.googleapis.com/auth/presentations |
| Docs | https://www.googleapis.com/auth/documents |
| Tasks | https://www.googleapis.com/auth/tasks |
| Forms | https://www.googleapis.com/auth/forms, https://www.googleapis.com/auth/spreadsheets |
Token Issues¶
Lost Token¶
Symptom: MCP server returns "UNAUTHORIZED: Invalid or missing auth token".
Resolution (if you have access to the script):
The token is stored under PROXY_AUTH_TOKEN. If it is missing locally but bootstrap has already completed, rotate it with the setup key:
- Read the setup key from the generated, untracked
BootstrapSecret.gsfile. - Hit the rotation endpoint:
TOKEN_RESPONSE="$(curl -sL -X POST -H 'Content-Type: application/json' -d '{"setupKey":"<bootstrap-setup-key>","rotate":true}' "https://script.google.com/macros/s/<deployment-id>/exec")"
TOKEN_RESPONSE="$TOKEN_RESPONSE" node -e 'const fs = require("fs"); const r = JSON.parse(process.env.TOKEN_RESPONSE); if (!r.success) throw new Error(r.error?.message || "Bootstrap failed"); fs.appendFileSync(".env", `export GOOGLE_WORKSPACE_<SERVICE>_PROXY_TOKEN=${JSON.stringify(r.data.token)}\n`)'
- Restart OpenCode or re-source your environment.
Already Bootstrapped¶
Symptom: Bootstrap endpoint returns "FORBIDDEN: Bootstrap has already been completed."
This is expected for bootstrap itself. If the token is not in .env, rerun ./scripts/setup.sh and accept the rotation prompt, or call the rotation endpoint shown above.
Common Errors¶
UNAUTHORIZED¶
{ "success": false, "error": { "code": "UNAUTHORIZED", "message": "Invalid or missing auth token" } }
Causes:
- Environment variable
GOOGLE_WORKSPACE_<SERVICE>_PROXY_TOKENis not set or is wrong. - Token in
.envdoesn't match the token in Apps Script Properties. - Token was rotated but environment variable wasn't updated.
Resolution: Verify both the environment variable and the script property value match.
node -e 'const key = "GOOGLE_WORKSPACE_DRIVE_PROXY_TOKEN"; console.log(process.env[key] ? `${key} is set` : `${key} is missing`)'
NOT_FOUND¶
Causes:
- The resource ID is valid in format but doesn't exist.
- The resource exists but the deploying user doesn't have access.
- The resource was deleted or moved.
Resolution: Search for the resource by name before using its ID. Use drive_search_files or gmail_search_messages to verify existence and access.
RATE_LIMITED¶
{ "success": false, "error": { "code": "RATE_LIMITED", "message": "Too many requests. Try again in 60 seconds." } }
Causes: The proxy received more than 100 weighted request units in a 60-second window.
Resolution: Wait 60 seconds and retry. Reduce batch size or operation risk. Batch tools reduce round trips, but they are still charged by the sum of child operation weights.
INTERNAL_ERROR¶
{ "success": false, "error": { "code": "INTERNAL_ERROR", "message": "An internal error occurred. Check developer console logs for details." } }
Causes:
- Unhandled exception in the Apps Script code.
- Google API threw an unexpected error.
- Action name was misspelled outside the registered tool surface.
Resolution: Check the Apps Script logs:
- Open the script at
https://script.google.com/d/<script-id>/edit - Go to Executions in the left sidebar
- Find the failed execution and expand the log
BAD_REQUEST¶
Causes: Malformed JSON, missing required fields, invalid resource ID formats, or validation failure at the Zod schema layer.
Resolution: The MCP server validates most parameters before sending to the proxy. If this occurs, check the tool description for required parameters and ID formats.
VALIDATION_ERROR¶
Returned when Zod schema validation fails on the MCP server side (before the request reaches the proxy). The error message includes the specific field that failed validation:
Debugging¶
Apps Script Logs¶
The most powerful debugging tool. Each proxy logs errors to console.error with the action name and error message:
To view logs:
In the Apps Script editor: Executions (left sidebar) → click on the failed execution → expand for full log.
clasp Status¶
Verify the pushed code matches what's deployed:
This shows the script ID, last push date, and deployment history. If the script ID doesn't match what you expect, you may have pushed to the wrong project.
clasp Logs¶
View recent Apps Script logs from the command line:
Shows console.log and console.error output (limited to recent executions).
Health Check¶
Every proxy responds to a GET request with a health check:
Expected response (without token):
{
"success": true,
"data": {
"status": "healthy",
"version": "<health-version>",
"service": "google-workspace-proxy-drive"
}
}
This confirms the web app is deployed, accessible, and functional. No auth token is required for the health check.
Token Verification¶
Verify your local token is set, then compare the private value with Apps Script Script Properties without pasting it into logs, issues, or support threads:
node -e 'const key = "GOOGLE_WORKSPACE_DRIVE_PROXY_TOKEN"; console.log(process.env[key] ? `${key} is set` : `${key} is missing`)'
Check the proxy value in the Apps Script editor under Project Settings → Script Properties → PROXY_AUTH_TOKEN.
If they don't match, update the environment variable to match the script property value, or rotate the token.