Skip to content

Latest commit

 

History

History
423 lines (326 loc) · 11.8 KB

File metadata and controls

423 lines (326 loc) · 11.8 KB
title MCP server
description Expose typed, allowlisted gog tools to MCP clients without a generic command runner.

MCP server

gog mcp runs a Model Context Protocol server over stdio. It is for agent clients that need Google Workspace tools but should not receive a generic shell or arbitrary gog command bridge.

The server registers a small set of typed tools such as gmail_search, docs_get, and sheets_read_range. Each tool has a fixed schema, maps to one specific gog operation, and returns a structured result containing the tool name, service, risk level, exit code, parsed stdout, and stderr.

Quick start

Start a read-only server for one account:

gog --account you@example.com mcp

List the tools this server would expose and exit:

gog --account you@example.com mcp --list-tools

Limit the server to Gmail search and Docs reads:

gog --account you@example.com mcp \
  --allow-tool gmail_search,docs_get

Expose Docs read/write tools:

gog --account you@example.com mcp \
  --allow-write \
  --allow-tool 'docs.*'

--allow-write is always required for write tools. A write tool that matches --allow-tool is still hidden until --allow-write is present.

The exception is an explicit persistent MCP policy. It can authorize a narrow write surface without repeating --allow-write in every client definition; runtime flags can only reduce that configured surface.

Why this is not gog_exec

MCP clients are often LLM-driven. A generic "run this command" tool would expose every current and future CLI behavior through one broad capability, including commands that were not reviewed for MCP use.

gog mcp uses a narrower contract:

  • no generic command execution tool
  • no model-supplied argv passthrough
  • fixed tool schemas validated before command execution, including required fields, types, and rejection of unknown fields
  • read-only tools by default
  • write tools require explicit server startup flags
  • existing gog account, auth, dry-run, no-input, and command safety flags are preserved

This keeps MCP useful for agents while making the permission surface visible at server startup.

Tool selection

By default, all read tools are registered and write tools are hidden.

Use --allow-tool to narrow the registered set. Values can be comma-separated or repeated:

gog mcp --allow-tool gmail_search --allow-tool docs_get
gog mcp --allow-tool gmail_search,docs_get

Accepted selectors:

Selector Meaning
gmail_search One exact tool
gmail All Gmail tools allowed by risk mode
gmail.* All Gmail tools allowed by risk mode
read All read tools
write All write tools, only when --allow-write is also set
* or all All tools allowed by risk mode

Examples:

# Read-only Gmail tools.
gog mcp --allow-tool gmail

# Only Docs tools, including writes.
gog mcp --allow-write --allow-tool 'docs.*'

# Read-only server, but only Calendar and Sheets reads.
gog mcp --allow-tool calendar,sheets

# All current write tools. Read tools are not included unless also selected.
gog mcp --allow-write --allow-tool write

Persistent capability policy

For several MCP clients or accounts, put the maximum registered tool surface in config.json instead of duplicating capability arguments. Without an mcp block, behavior is unchanged: all read tools are available, writes require --allow-write, and --allow-tool filters the result.

{
  "mcp": {
    "allow_tools": ["read"],
    "allow_write": false,
    "accounts": {
      "personal@example.com": {
        "allow_tools": ["read", "docs.*", "calendar.*"],
        "allow_write": true
      },
      "work@example.com": {
        "allow_tools": ["read"],
        "allow_write": false
      }
    }
  }
}

An account entry is a complete replacement for the global policy, not a partial merge. Account keys are matched case-insensitively after aliases and automatic account selection are resolved, then that resolved account is pinned for every MCP child command. Per-account policies require stored account credentials; direct access tokens and ADC can use only the global policy because an account label does not prove the authenticated principal. An omitted allow_tools value defaults to ["read"]; an explicitly empty list is rejected. allow_write: true requires an explicit tool list so a typo cannot accidentally expose every write tool.

The configured policy is a ceiling. --allow-tool can intersect it with a smaller runtime set, --readonly removes all writes, and --allow-write cannot widen a read-only policy. Baked safety profiles remain the outer immutable ceiling. Unknown configured selectors and attempted write widening fail before the MCP server starts. Use gog mcp --list-tools with the same account and flags to inspect the final registered surface.

Initial tools

Read tools:

Tool Purpose
gmail_search Search Gmail messages with Gmail query syntax.
gmail_get_message Read one Gmail message by ID. Sanitized content is on by default.
gmail_get_thread Read one Gmail thread by ID. Sanitized content is on by default.
drive_search Search Drive files by text or Drive query language.
drive_get Read Drive file metadata by ID.
docs_get Read a Google Doc as wrapped text, optionally one tab or all tabs.
sheets_read_range Read values from a Sheets range.
calendar_events List Calendar events.

Write tools, hidden unless --allow-write:

Tool Purpose
docs_write Append or replace Google Docs text, optionally as Markdown.
sheets_update_range Update values in a Sheets range from a literal JSON 2D array.

The generated command reference for the server itself is gog mcp.

MCP clients discover the registered surface through the protocol's standard tools/list request. For shell-side inspection before starting the server, use gog mcp --list-tools; no model-callable discovery tool is added.

Client configuration

MCP clients usually need a command and an argument list. Put account selection and safety policy on the server command, not inside tool calls.

Minimal stdio configuration:

{
  "command": "gog",
  "args": ["--account", "you@example.com", "mcp"]
}

Read-only Docs and Sheets configuration:

{
  "command": "gog",
  "args": [
    "--account", "you@example.com",
    "--enable-commands-exact", "mcp,docs.cat,sheets.get",
    "mcp",
    "--allow-tool", "docs_get,sheets_read_range"
  ]
}

Docs read/write configuration:

{
  "command": "gog",
  "args": [
    "--account", "you@example.com",
    "--enable-commands-exact", "mcp,docs.cat,docs.write",
    "--no-input",
    "mcp",
    "--allow-write",
    "--allow-tool", "docs.*"
  ]
}

For headless services, set GOG_KEYRING_BACKEND=file and GOG_KEYRING_PASSWORD on the MCP client process or service unit. A successful interactive shell check does not prove the MCP client inherited those variables; verify through the same process manager that launches the server.

mcporter examples

List registered tools and their schemas:

mcporter list \
  --stdio gog \
  --stdio-arg --account \
  --stdio-arg you@example.com \
  --stdio-arg mcp \
  --stdio-arg --allow-tool \
  --stdio-arg 'docs.*' \
  --schema \
  --json

Dry-run a Docs write through MCP:

mcporter call \
  --stdio gog \
  --stdio-arg --account \
  --stdio-arg you@example.com \
  --stdio-arg --dry-run \
  --stdio-arg mcp \
  --stdio-arg --allow-write \
  --stdio-arg --allow-tool \
  --stdio-arg docs_write \
  docs_write \
  '{"document_id":"DOCUMENT_ID","text":"MCP smoke test\n","append":true}'

Read a Sheet range:

mcporter call \
  --stdio gog \
  --stdio-arg --account \
  --stdio-arg you@example.com \
  --stdio-arg mcp \
  --stdio-arg --allow-tool \
  --stdio-arg sheets_read_range \
  sheets_read_range \
  '{"spreadsheet_id":"SPREADSHEET_ID","range":"Sheet1!A1:C10"}'

Update a Sheet range:

mcporter call \
  --stdio gog \
  --stdio-arg --account \
  --stdio-arg you@example.com \
  --stdio-arg mcp \
  --stdio-arg --allow-write \
  --stdio-arg --allow-tool \
  --stdio-arg sheets_update_range \
  sheets_update_range \
  '{"spreadsheet_id":"SPREADSHEET_ID","range":"Sheet1!A1:B1","values_json":"[[\"status\",\"ok\"]]","input":"RAW"}'

sheets_update_range.values_json must be literal JSON. MCP rejects @file, @-, and - expansion forms so a model cannot cause the server process to read arbitrary local files or stdin.

Safety model

Tool calls run as subprocesses of the same gog executable. The server adds a non-interactive, agent-oriented root context to every child command:

  • --json
  • --wrap-untrusted
  • --no-input
  • --color=never

The server also preserves selected parent root flags:

  • --account
  • --client
  • --home
  • --dry-run
  • --results-only
  • --select
  • direct access tokens

And it preserves command safety flags:

  • --gmail-no-send
  • --enable-commands
  • --enable-commands-exact
  • --disable-commands

Use both MCP tool allowlists and command allowlists when the server is exposed to an untrusted or semi-trusted agent:

gog --account you@example.com \
  --enable-commands-exact mcp,docs.cat,docs.write \
  --disable-commands gmail.send,gmail.drafts.send \
  --gmail-no-send \
  mcp \
  --allow-write \
  --allow-tool 'docs.*'

If a tool maps to a disabled command, the tool call returns a non-zero exit code and the child command error in stderr.

Output shape

Successful calls return structured MCP content shaped like:

{
  "tool": "docs_get",
  "service": "docs",
  "risk": "read",
  "exit_code": 0,
  "stdout": {
    "documentId": "..."
  },
  "stderr": ""
}

If a child command prints valid JSON, stdout is parsed as JSON with numeric literals preserved. Otherwise stdout is returned as a string. Empty stdout is omitted.

If the child command exits non-zero, the MCP result is marked as an error and includes the same structured fields with exit_code and stderr.

Limits and timeouts

Each tool call has a subprocess timeout and bounded stdout/stderr capture:

gog mcp --timeout-seconds 30 --max-output-bytes 262144

Defaults:

  • timeout: 60 seconds
  • max captured stdout/stderr: 102400 bytes each

Use command-specific limits too. For example, docs_get has a max_bytes argument, and search tools have max arguments.

Authentication

The MCP server uses normal gog auth. Before wiring a client, verify the same account and scopes from a shell:

gog --account you@example.com auth doctor --check
gog --account you@example.com mcp --list-tools

Then verify through the MCP client entrypoint. In services and desktop MCP clients, most auth failures are environment inheritance problems: missing GOG_ACCOUNT, missing file-keyring password, different GOG_HOME, or a different OAuth client selected by --client.

Troubleshooting

no MCP tools enabled

: Your --allow-tool filters excluded everything, or you selected only write tools without --allow-write.

command "..." is disabled

: The MCP tool was registered, but the child gog command was blocked by --enable-commands, --enable-commands-exact, --disable-commands, or a baked safety profile.

Tool missing in the client

: Run gog mcp --list-tools with the same flags. If the tool is not listed, fix --allow-tool or add --allow-write for write tools. If it is listed, refresh or restart the MCP client.

Auth works in Terminal but not in the MCP client

: Compare --account, --client, --home, GOG_HOME, GOG_KEYRING_BACKEND, and GOG_KEYRING_PASSWORD in the process that starts the MCP server.

Large output is truncated

: Increase --max-output-bytes, narrow the request, or use tool arguments such as max, max_bytes, date ranges, or Drive field masks.