Google Forms MCP
MCP server for the Google Forms API: create forms, add and edit questions, publish, read responses and set up push notifications for new submissions — from Claude, Cursor, Codex and other AI clients, in natural language.
Ask your assistant to "make a customer-feedback survey with a rating question and publish it", "show me yesterday's responses", or "close the form for responses" — it drives the Forms API for you, from a blank form to response analysis.
Quick start
-
Get OAuth credentials for the Google Forms API.
-
Add the server — for example, in Claude Code (other clients):
claude mcp add google-forms \ -e GOOGLE_FORMS_CLIENT_ID=your_client_id \ -e GOOGLE_FORMS_CLIENT_SECRET=your_client_secret \ -e GOOGLE_FORMS_REFRESH_TOKEN=your_refresh_token \ -- npx -y mcp-google-forms@latest -
Ask the assistant: "Create a form called 'Team lunch survey' with a dropdown of three restaurants and publish it."
Tools
| Tool | Description |
|---|---|
create_form | Create a form (optionally publish it right away — API-created forms start unpublished). |
get_form | Full form structure: info, settings, items with ids, publish state, responder URL. |
update_form_info | Change the title, description or document title. |
update_form_settings | Toggle quiz mode and email collection. |
add_question | Add a question: text, paragraph, radio, checkbox, dropdown, scale, date, time, rating. |
update_question | Update an existing item by index with an explicit update mask. |
delete_item | Delete the item at an index. |
move_item | Reorder items. |
set_publish_settings | Publish/unpublish, open/close response collection. |
list_responses | List submissions, incrementally with submitted_after; paginated. |
get_response | Fetch one submission by id. |
manage_watches | Create/list/delete/renew Cloud Pub/Sub push-notification watches. |
raw_request | Escape hatch: any Forms API v1 path (e.g. a custom batchUpdate with grids). |
Plus resilience built in: automatic OAuth token refresh (including on 401), retries with backoff on 429 (and on 5xx/network errors for reads only — writes are never replayed), a request timeout, and an SSRF guard so the token can't leak to a foreign host.
Example prompts
- "Create an RSVP form for the offsite, ask for name, meal preference (veg/meat/fish) and arrival date, then publish it and give me the link."
- "Turn the 'Onboarding quiz' form into a quiz and make every question required."
- "How many responses came in since Monday? Summarize the free-text feedback."
- "Stop accepting responses on the feedback form."
Limitations (the API's, not the server's)
- Responses are read-only. The Forms API cannot submit or edit responses — there is no such endpoint, so this server has no submit tool either.
- API-created forms start unpublished and don't accept responses until published — use
publish: trueoncreate_formorset_publish_settings. Legacy forms (from before the publish model) don't supportset_publish_settingsat all. - File-upload questions can't be created via the API (existing ones are readable).
- Quotas are per minute (reads 975/project,
list_responses450, writes 375); the server backs off on 429 automatically.
Installation
Requires Node.js 20+ (runs via npx, no separate install).
Claude Code
claude mcp add google-forms \
-e GOOGLE_FORMS_CLIENT_ID=your_client_id \
-e GOOGLE_FORMS_CLIENT_SECRET=your_client_secret \
-e GOOGLE_FORMS_REFRESH_TOKEN=your_refresh_token \
-- npx -y mcp-google-forms@latest
Claude Desktop
claude_desktop_config.json — macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\
{
"mcpServers": {
"google-forms": {
"command": "npx",
"args": ["-y", "mcp-google-forms@latest"],
"env": {
"GOOGLE_FORMS_CLIENT_ID": "your_client_id",
"GOOGLE_FORMS_CLIENT_SECRET": "your_client_secret",
"GOOGLE_FORMS_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}
Cursor
~/.cursor/mcp.json (or .cursor/mcp.json in the project)
{
"mcpServers": {
"google-forms": {
"command": "npx",
"args": ["-y", "mcp-google-forms@latest"],
"env": {
"GOOGLE_FORMS_CLIENT_ID": "your_client_id",
"GOOGLE_FORMS_CLIENT_SECRET": "your_client_secret",
"GOOGLE_FORMS_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}
VS Code
.vscode/mcp.json — note the servers key (not mcpServers)
{
"servers": {
"google-forms": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-google-forms@latest"],
"env": {
"GOOGLE_FORMS_CLIENT_ID": "your_client_id",
"GOOGLE_FORMS_CLIENT_SECRET": "your_client_secret",
"GOOGLE_FORMS_REFRESH_TOKEN": "your_refresh_token"
}
}
}
}
Getting credentials
The Forms API has no API-key access — every call needs OAuth 2.0. One-time setup, ~10 minutes:
- Create a Google Cloud project (or reuse one) at console.cloud.google.com, then enable the Google Forms API: APIs & Services → Library → Google Forms API → Enable.
- Configure the OAuth consent screen (APIs & Services → OAuth consent screen): choose External, fill in the app name and your email, and add your Google account under Test users (in Testing mode only listed users can authorize — no app verification needed).
- Create an OAuth client (APIs & Services → Credentials → Create credentials → OAuth client ID), application type Desktop app. Save the client ID and client secret.
- Mint a refresh token. The easiest way is the
OAuth 2.0 Playground:
- Click the gear icon → check Use your own OAuth credentials → paste your client ID and
secret (add
https://developers.google.com/oauthplaygroundas an authorized redirect URI to the OAuth client first). - In Step 1, enter the scopes
https://www.googleapis.com/auth/forms.body https://www.googleapis.com/auth/forms.responses.readonlyand click Authorize APIs, signing in with the test-user account. - In Step 2, click Exchange authorization code for tokens and copy the refresh token.
- Click the gear icon → check Use your own OAuth credentials → paste your client ID and
secret (add
- Put the three values into
GOOGLE_FORMS_CLIENT_ID,GOOGLE_FORMS_CLIENT_SECRETandGOOGLE_FORMS_REFRESH_TOKEN. The server exchanges the refresh token for short-lived access tokens automatically.
Scope notes: forms.body + forms.responses.readonly is the minimal, recommended pair (no
broad Drive access). While the consent screen stays in Testing mode, refresh tokens expire
after 7 days — publish the app (or keep it Internal in a Workspace domain) for long-lived tokens.
⚠️ The credentials are stored in plain text in your client's config — treat them like a password. The refresh token grants access to your forms until revoked at myaccount.google.com/permissions.
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
GOOGLE_FORMS_CLIENT_ID | yes* | — | OAuth2 client id (refresh flow). |
GOOGLE_FORMS_CLIENT_SECRET | yes* | — | OAuth2 client secret (refresh flow). |
GOOGLE_FORMS_REFRESH_TOKEN | yes* | — | OAuth2 refresh token (refresh flow). |
GOOGLE_FORMS_ACCESS_TOKEN | yes* | — | Alternative: a static access token (~1 h lifetime), mostly for testing. |
GOOGLE_FORMS_API_BASE | no | https://forms.googleapis.com | API root override. |
GOOGLE_FORMS_TIMEOUT_MS | no | 60000 | Per-request timeout, ms. |
GOOGLE_FORMS_MAX_RETRIES | no | 3 | Retries on transient errors. |
* Either the three refresh-flow variables together, or GOOGLE_FORMS_ACCESS_TOKEN.
Documentation
- All tools — full reference with parameters and notes.
- Development — build, tests, smoke check, telemetry.
- Publishing — releasing and MCP-catalog listing.
Support
Questions, ideas, issues — Telegram @gistrec or GitHub issues.
License
MIT — see LICENSE.