File size: 5,715 Bytes
7dc28be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# Contributing

Thanks for your interest in contributing! This guide covers how to set up the project for local development, understand the architecture, and submit changes.

## Development Setup

### Prerequisites

- Node.js 20+ ([nodejs.org](https://nodejs.org/))
- Git ([git-scm.com](https://git-scm.com/downloads))
- A Google Account with access to test documents

### Clone and Build

```bash
git clone https://github.com/a-bonus/google-docs-mcp.git
cd google-docs-mcp
npm install
npm run build
```

### Authenticate

You need Google OAuth credentials to test the server against real APIs.

**Option A: credentials.json file**

1. Download your OAuth client JSON from [Google Cloud Console](https://console.cloud.google.com/)
2. Rename it to `credentials.json` and place it in the project root
3. Run `npm start auth` to open the browser-based OAuth flow

**Option B: Environment variables**

```bash
GOOGLE_CLIENT_ID="your-client-id" \
GOOGLE_CLIENT_SECRET="your-client-secret" \
npm start auth
```

Both options save the refresh token to `~/.config/google-docs-mcp/token.json`. OAuth client IDs and client secrets stay in your environment or `credentials.json`; they are not stored in the token file.

### Register Your Local Build

Point your MCP client at the local build for testing:

```json
{
  "mcpServers": {
    "google-docs": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-googledocs-server/dist/index.js"]
    }
  }
}
```

### Scripts

| Command                | Description                    |
| ---------------------- | ------------------------------ |
| `npm start`            | Start the MCP server           |
| `npm start auth`       | Run the interactive OAuth flow |
| `npm run build`        | Compile TypeScript to `dist/`  |
| `npm test`             | Run tests (Vitest)             |
| `npm run format`       | Format code with Prettier      |
| `npm run format:check` | Check formatting               |

---

## Project Architecture

### Entry Points

```
src/index.ts        Entry point: CLI (auth subcommand) and MCP server startup
src/auth.ts         OAuth / service account authentication
src/clients.ts      Google API client singletons (Docs, Drive, Sheets)
```

### Tools

Tools live in `src/tools/`, organized by domain. Each tool is a single file exporting a `register(server: FastMCP)` function.

```
src/tools/
β”œβ”€β”€ index.ts            Top-level router
β”œβ”€β”€ docs/               Google Docs tools (13)
β”‚   β”œβ”€β”€ comments/       Comment management (6)
β”‚   └── formatting/     Text and paragraph styling (2)
β”œβ”€β”€ drive/              Google Drive tools (15)
β”œβ”€β”€ sheets/             Google Sheets tools (37)
β”œβ”€β”€ gmail/              Gmail tools (13)
β”œβ”€β”€ calendar/           Google Calendar tools (5)
└── utils/              Cross-cutting utilities (3)
```

### Helpers

| File                            | Purpose                                                            |
| ------------------------------- | ------------------------------------------------------------------ |
| `src/googleDocsApiHelpers.ts`   | Text range finding, batch update execution, style request builders |
| `src/googleSheetsApiHelpers.ts` | A1 notation parsing, cell formatting, freeze, validation           |
| `src/markdown-transformer/`     | Markdown parsing and bidirectional Google Docs conversion          |
| `src/types.ts`                  | Zod schemas, hex color validation, shared type definitions         |
| `src/logger.ts`                 | Leveled logger (debug/info/warn/error) writing to stderr           |

### Authentication Flow

The auth module (`src/auth.ts`) resolves credentials in this order:

1. `SERVICE_ACCOUNT_PATH` env var -- service account JWT
2. `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` env vars -- OAuth (for `npx` consumers)
3. `credentials.json` in the project root -- OAuth (for local dev)

Tokens are persisted to `~/.config/google-docs-mcp/token.json` (respects `XDG_CONFIG_HOME`). The token file stores OAuth token credentials only, not OAuth client IDs or client secrets.

---

## Adding a New Tool

1. Create a new file in the appropriate domain folder (e.g., `src/tools/sheets/myNewTool.ts`)
2. Export a `register(server: FastMCP)` function that calls `server.addTool({...})`
3. Import and call it from the domain's `index.ts` router
4. Add tests if the tool involves non-trivial logic

### Tool Conventions

- **Names:** camelCase, verb-first (e.g., `readDocument`, `formatCells`)
- **Descriptions:** Start with what the tool does, mention when to use it, note any caveats
- **Parameters:** Use Zod schemas with `.describe()` on every field
- **Errors:** Throw `UserError` from `fastmcp` for user-facing errors
- **Output:** Return `JSON.stringify`'d structured data for tools that return actionable information

---

## Testing

Tests use [Vitest](https://vitest.dev/) and live alongside source files or in `src/`:

```bash
npm test              # Run all tests
npm test -- --watch   # Watch mode
```

Tests mock Google API clients -- they don't make real API calls.

---

## Code Style

- TypeScript with strict mode
- ESM modules (`.js` extensions in imports)
- Prettier for formatting (`npm run format`)
- All log output goes to stderr (stdout is reserved for MCP protocol)

---

## Releasing

Releases are automated via GitHub Actions. To publish a new version:

1. Update the version in `package.json`
2. Commit and push to `main`
3. Tag the commit: `git tag v1.2.3 && git push origin v1.2.3`
4. The [release workflow](.github/workflows/release.yml) will run CI checks, publish to npm, and create a GitHub Release

The npm package is published as `@a-bonus/google-docs-mcp`.