# gws-mcp-server
Google Workspace for AI agents: Gmail, Calendar, Drive, Sheets, Docs, and Tasks as a curated set of 39 [Model Context Protocol](https://modelcontextprotocol.io/) tools, built on the official [Google Workspace CLI (`gws`)](https://github.com/googleworkspace/cli).
[](https://www.npmjs.com/package/gws-mcp-server)
[](LICENSE)
[](https://nodejs.org/)
[](https://chainofthought.show)
[](https://x.com/ConorBronsdon)
---
## Why?
The `gws` CLI had a built-in MCP server that was [removed in v0.8.0](https://github.com/googleworkspace/cli/pull/275) because it exposed 200-400 tools — causing context window bloat in MCP clients. This server takes a curated approach: you choose which Google services to expose, and only a focused set of high-value, narrowly scoped operations are registered as tools. Every tool declares MCP `readOnlyHint`/`destructiveHint` annotations so clients can reason about side effects and surface clearer consent prompts.
## Prerequisites
- [Node.js](https://nodejs.org/) 18+
- [`gws` CLI](https://github.com/googleworkspace/cli) installed and authenticated (`npm install -g @googleworkspace/cli && gws auth login`)
## Quick start
```bash
# Install
npm install -g gws-mcp-server
# Or run from source
git clone https://github.com/conorbronsdon/gws-mcp-server.git
cd gws-mcp-server
npm install && npm run build
```
## Configuration
### Claude Code (`.mcp.json`)
```json
{
"mcpServers": {
"google-workspace": {
"command": "npx",
"args": [
"gws-mcp-server",
"--services", "drive,sheets,calendar,docs,gmail,tasks"
]
}
}
}
```
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"google-workspace": {
"command": "npx",
"args": [
"gws-mcp-server",
"--services", "drive,sheets,calendar"
]
}
}
}
```
## Options
| Flag | Description | Default |
|------|-------------|---------|
| `--services, -s` | Comma-separated list of services to expose | All services |
| `--gws-path` | Path to the `gws` binary | `gws` |
## Available services & tools
### `drive` (9 tools)
- `drive_files_list` — Search and list files
- `drive_files_get` — Get file metadata
- `drive_files_create` — Create files (with optional upload)
- `drive_files_copy` — Copy files (useful for format conversion)
- `drive_files_update` — Update file metadata/content
- `drive_files_delete` — Delete files
- `drive_files_export` — Export Google Workspace files (Doc, Sheet, Slide) to other formats
- `drive_files_download` — Download file content (text inline, binary as base64 or saved to a path; Google-native files are exported to a readable format)
- `drive_permissions_create` — Share files
### `sheets` (4 tools)
- `sheets_get` — Get spreadsheet metadata
- `sheets_values_get` — Read cell values
- `sheets_values_update` — Write cell values
- `sheets_values_append` — Append rows
### `calendar` (5 tools)
- `calendar_events_list` — List events
- `calendar_events_get` — Get event details
- `calendar_events_insert` — Create events
- `calendar_events_update` — Update events (only supplied fields change)
- `calendar_events_delete` — Delete events
### `docs` (3 tools)
- `docs_get` — Get document content
- `docs_create` — Create documents
- `docs_batchUpdate` — Apply document updates
### `gmail` (6 tools)
- `gmail_messages_list` — Search messages
- `gmail_messages_get` — Read a message
- `gmail_threads_list` — Search threads
- `gmail_threads_get` — Read a full thread
- `gmail_threads_modify` — Add/remove labels on a thread (archive, mark read, star)
- `gmail_drafts_create` — Create a draft (plain text and/or HTML, with reply threading via `threadId`). Drafts are never auto-sent
### `tasks` (12 tools)
- `tasks_tasklists_list` — List task lists
- `tasks_tasklists_get` — Get a task list
- `tasks_tasklists_insert` — Create a task list
- `tasks_tasklists_update` — Update a task list (only supplied fields change)
- `tasks_tasklists_delete` — Delete a task list
- `tasks_tasks_list` — List tasks (filters: completed/hidden/due dates)
- `tasks_tasks_get` — Get a task
- `tasks_tasks_insert` — Create a task (optionally nested or positioned)
- `tasks_tasks_update` — Update a task (only supplied fields change; common use: mark complete)
- `tasks_tasks_move` — Move a task within/across lists or reorder
- `tasks_tasks_delete` — Delete a task
- `tasks_tasks_clear` — Hide all completed tasks in a list
> **Update semantics:** the `*_update` tools (calendar events, tasks, task lists) use the Google API's `patch` verb — they merge the fields you supply and leave the rest untouched. To *clear* an existing value, pass it explicitly (e.g. an empty string) rather than omitting it.
**Total: 39 tools** (vs 200-400 in the old implementation)
## Adding new tools
Edit `src/services.ts` to add tool definitions. Each tool maps directly to a `gws` CLI command:
```typescript
{
name: "drive_files_list", // MCP tool name
description: "List files in Drive", // Shown to AI
command: ["drive", "files", "list"],// gws CLI args
params: [ // Maps to --params JSON
{ name: "q", description: "Search query", type: "string", required: false },
],
bodyParams: [ // Maps to --json body
{ name: "name", description: "File name", type: "string", required: true },
],
}
```
### Typed errors
Tool call failures are mapped to a typed error hierarchy (`src/errors.ts`): `AuthenticationError` (401/403), `RateLimitError` (429), `ValidationError` (400), `NotFoundError` (404, with a shared-drive access hint for `drive` commands), and `ServerError` (5xx), all extending a base `GwsError`. Unlike an HTTP API client, this server has no response object to read a status code from — it spawns the `gws` CLI as a subprocess and only sees plain text (stdout/stderr, or a rejected promise's `.message`). `mapGwsErrorToTyped()` recovers a status-like code from that text, handling both a raw JSON error body (Google's own `{"error":{"code":...,"message":...}}` shape) and plain text containing an HTTP-status-like token (e.g. `"Error 404: ..."`). If neither pattern is found, the original message passes through unchanged rather than forcing an invented status onto it.
## Architecture
```
MCP Client (Claude) ←→ stdio ←→ gws-mcp-server ←→ gws CLI ←→ Google APIs
```
The server is a thin wrapper: it translates MCP tool calls into `gws` CLI invocations, passes `--params` and `--json` as appropriate, and returns the JSON output. Authentication stays in the `gws` CLI — this server never sees or stores your Google credentials.
## Development
```bash
git clone https://github.com/conorbronsdon/gws-mcp-server.git
cd gws-mcp-server
npm ci
npm run lint # type-check
npm run build
npm test # vitest, mocks the executor layer — no real gws calls
```
## Contributing
Issues and pull requests are welcome. The most useful contributions are new tool definitions in `src/services.ts` for high-value `gws` operations (see "Adding new tools" above). Keep the curated contract: a focused set of narrowly scoped tools, not a 1:1 mirror of every Google API surface. See [SECURITY.md](./SECURITY.md) for how to report vulnerabilities.
## About
Built and maintained by [Conor Bronsdon](https://github.com/conorbronsdon). I host the [Chain of Thought](https://chainofthought.show) podcast, which covers AI infrastructure, developer tools, and how practitioners actually use this stuff. I built this to give the agent workflows that run the show safe, curated access to Gmail, Calendar, Drive, Sheets, Docs, and Tasks.