|
| 1 | +# Deploying this fork to Railway (org-restricted) |
| 2 | + |
| 3 | +Self-host the Google Workspace MCP as a remote server, with sign-in locked to your |
| 4 | +`construct.sg` Google Workspace. Docker-based, persistent, HTTPS, auto-redeploy on push. |
| 5 | + |
| 6 | +The MCP endpoint will be: `https://<your-domain>/mcp` |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## 1. Google Cloud — OAuth (the org restriction lives here) |
| 11 | + |
| 12 | +1. [console.cloud.google.com](https://console.cloud.google.com/) → create/select a project **inside the construct.sg org**. |
| 13 | +2. **APIs & Services → OAuth consent screen → User Type = Internal.** ← restricts login to construct.sg. Fill app name + support email. |
| 14 | +3. **Enabled APIs & services → Enable APIs** for what you'll use: Gmail, Drive, Calendar, Docs, Sheets, Slides, Forms, Tasks, People. (Custom Search / Chat / Apps Script only if needed — Chat needs extra app config.) |
| 15 | +4. **Credentials → Create credentials → OAuth client ID → Web application.** |
| 16 | + - Leave redirect URI empty for now (added in step 3 below). |
| 17 | + - Save the **Client ID** and **Client secret**. |
| 18 | + |
| 19 | +## 2. Railway — create the service |
| 20 | + |
| 21 | +1. [railway.com](https://railway.com/) → **New Project → Deploy from GitHub repo** → `edisonb24/google_workspace_mcp`. It builds from the `Dockerfile` (via `railway.json`). |
| 22 | +2. **Add a Volume** on the service, mount path **`/data`**. |
| 23 | +3. **Variables** → add the ones below (Raw Editor makes this a single paste). |
| 24 | + - Fill `GOOGLE_OAUTH_CLIENT_ID` / `GOOGLE_OAUTH_CLIENT_SECRET` from step 1. |
| 25 | + - Generate the signing key once: |
| 26 | + `python3 -c "import secrets;print(secrets.token_urlsafe(48))"` |
| 27 | + - Leave `WORKSPACE_EXTERNAL_URL` / `GOOGLE_OAUTH_REDIRECT_URI` as placeholders for now. |
| 28 | +4. **Settings → Networking → Generate Domain.** Copy the `https://<name>.up.railway.app`. |
| 29 | + |
| 30 | +```dotenv |
| 31 | +# Google OAuth (from Google Cloud → Credentials → Web application) |
| 32 | +GOOGLE_OAUTH_CLIENT_ID=<your-client-id>.apps.googleusercontent.com |
| 33 | +GOOGLE_OAUTH_CLIENT_SECRET=<your-client-secret> |
| 34 | +
|
| 35 | +# Transport / OAuth 2.1 multi-user mode |
| 36 | +MCP_ENABLE_OAUTH21=true |
| 37 | +WORKSPACE_MCP_TRANSPORT=streamable-http |
| 38 | +WORKSPACE_MCP_HOST=0.0.0.0 |
| 39 | +# Do NOT set WORKSPACE_MCP_PORT — Railway injects PORT and the server reads it. |
| 40 | +
|
| 41 | +# Public URL — set to the real domain AFTER step 4 (no trailing slash) |
| 42 | +WORKSPACE_EXTERNAL_URL=https://<name>.up.railway.app |
| 43 | +GOOGLE_OAUTH_REDIRECT_URI=https://<name>.up.railway.app/oauth2callback |
| 44 | +
|
| 45 | +# Persistence — one volume mounted at /data |
| 46 | +WORKSPACE_MCP_CREDENTIALS_DIR=/data/creds |
| 47 | +WORKSPACE_MCP_OAUTH_PROXY_STORAGE_BACKEND=disk |
| 48 | +WORKSPACE_MCP_OAUTH_PROXY_DISK_DIRECTORY=/data/oauth-proxy |
| 49 | +FASTMCP_SERVER_AUTH_GOOGLE_JWT_SIGNING_KEY=<paste-generated-key> |
| 50 | +
|
| 51 | +# Let the non-root image write to the root-owned Railway volume |
| 52 | +RAILWAY_RUN_UID=0 |
| 53 | +# Leave OAUTHLIB_INSECURE_TRANSPORT / OAUTH2_ALLOW_INSECURE_TRANSPORT unset in prod. |
| 54 | +``` |
| 55 | + |
| 56 | +## 3. Wire the domain back |
| 57 | + |
| 58 | +1. Railway → Variables → set the two URL vars to the real domain (no trailing slash): |
| 59 | + - `WORKSPACE_EXTERNAL_URL=https://<name>.up.railway.app` |
| 60 | + - `GOOGLE_OAUTH_REDIRECT_URI=https://<name>.up.railway.app/oauth2callback` |
| 61 | +2. Google Cloud → your OAuth client → **Authorized redirect URIs** → add |
| 62 | + `https://<name>.up.railway.app/oauth2callback` → Save. |
| 63 | +3. Railway redeploys automatically on the variable change. |
| 64 | + |
| 65 | +## 4. Verify |
| 66 | + |
| 67 | +```bash |
| 68 | +curl https://<name>.up.railway.app/health # → 200 OK |
| 69 | +curl https://<name>.up.railway.app/.well-known/oauth-protected-resource # → JSON metadata |
| 70 | +``` |
| 71 | + |
| 72 | +Then add the server to your MCP client as a **streamable-http / remote** server at |
| 73 | +`https://<name>.up.railway.app/mcp`, run the OAuth flow, and sign in with your |
| 74 | +`construct.sg` account. A non-org Google account should be rejected at the consent screen. |
| 75 | + |
| 76 | +## Updating later |
| 77 | + |
| 78 | +`git fetch upstream && git merge upstream/main && git push` → Railway auto-redeploys. |
| 79 | + |
| 80 | +## Custom domain (optional) |
| 81 | + |
| 82 | +Railway → add domain `mcp.construct.sg` (set the CNAME) → then update |
| 83 | +`WORKSPACE_EXTERNAL_URL`, `GOOGLE_OAUTH_REDIRECT_URI`, and the GCP redirect URI to match. |
0 commit comments