Abílio Azevedo.

Building a Remote MCP Server for Google Workspace (Sheets, Docs and Presentation)

Cover Image for Building a Remote MCP Server for Google Workspace (Sheets, Docs and Presentation)
Abílio Azevedo
Abílio Azevedo

Building a Remote MCP Server for Google Workspace: From Zero to Production

Want to connect your AI assistant to Google Sheets, Docs, and Slides? Our MCP server gives Claude, Cursor, and other AI clients full access to your Google Workspace — read spreadsheets, create documents, edit presentations, and more. No API keys, no local setup. Just add a URL and start working.

Try it now at gwk-mcp.abilioazevedo.com.br — $5/month for 24 tools across Sheets, Docs, and Slides.


What is MCP?

The Model Context Protocol (MCP) is an open standard that lets AI assistants — like Claude, ChatGPT, and others — connect to external tools and data sources through a unified interface. Think of it as a USB-C port for AI: one protocol, many tools.

Instead of each AI client implementing custom integrations for every service, MCP defines a common language. A server exposes tools (functions the AI can call), and any MCP-compatible client can discover and use them automatically.

This means you can build one MCP server and it works everywhere — Claude Code, Claude.ai, Cursor, VS Code, and any other client that speaks the protocol.

Why Google Workspace?

Google Workspace — Sheets, Docs, and Slides — is at the core of how teams manage data, documents, and presentations. Connecting these tools to AI assistants opens up powerful workflows:

  • Ask Claude to "read the Q1 sales data from my spreadsheet and summarize trends"
  • Have an AI append rows to a tracking sheet as part of an automated workflow
  • Create new documents, presentations, or spreadsheets without leaving your terminal
  • Search and replace text across an entire presentation in seconds
  • Read and summarize the content of a Google Doc

The challenge? Google Workspace requires OAuth authentication, and most MCP servers run locally. We wanted something different: a remote MCP server that anyone can use by just adding a URL — no API keys, no local setup, no configuration files.

Architecture Overview

The server is built with Next.js deployed on Vercel, using Neon Postgres for session storage. The key insight is a two-layer OAuth flow:

┌─────────────┐      MCP OAuth       ┌──────────────────┐     Google OAuth     ┌─────────────┐
│  MCP Client  │ ◄──────────────────► │  MCP Server      │ ◄─────────────────► │  Google APIs │
│  (Claude,    │   Bearer tokens,     │  (Next.js on     │   Access/refresh    │  (Sheets,    │
│   Cursor)    │   PKCE, dynamic      │   Vercel)        │   tokens, consent   │   Docs,      │
│              │   client registration│                  │   screen            │   Slides,    │
│              │                      │                  │                     │   Drive)     │
└─────────────┘                       └──────────────────┘                     └─────────────┘
                                      ┌──────────────┐
                                      │ Neon Postgres │
                                      │ (sessions,    │
                                      │  auth codes,  │
                                      │  clients)     │
                                      └──────────────┘

Layer 1: MCP OAuth (Client ↔ Server)

When an MCP client connects, it discovers the auth requirements via standard well-known endpoints:

  1. /.well-known/oauth-protected-resource — tells the client this resource is OAuth-protected
  2. /.well-known/oauth-authorization-server — provides the authorization server metadata (endpoints, supported flows)
  3. /oauth/register — dynamic client registration (the client registers itself automatically)

This follows the MCP spec so any compliant client handles it seamlessly. PKCE is supported for security.

Layer 2: Google OAuth (Server ↔ Google)

When the user needs to authenticate:

  1. /oauth/authorize receives the MCP client's auth request and redirects to Google's consent screen
  2. The user grants access to their Google Sheets, Docs, Slides, and Drive
  3. /oauth/callback receives Google's tokens, stores them in Postgres, and redirects back to the MCP client with an authorization code
  4. /oauth/token exchanges the code for a session access token

The end result: the MCP client gets a Bearer token, and the server holds the Google credentials securely.

The MCP Endpoint

The core of the server is a single Next.js Route Handler at POST /mcp. Every request creates a fresh McpServer instance with a WebStandardStreamableHTTPServerTransport:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";

export async function POST(request: NextRequest) {
  const token = request.headers.get("authorization")?.replace("Bearer ", "");
  if (!token) return unauthorizedResponse();

  const server = new McpServer({
    name: "google-workspace",
    version: "0.2.0",
  });

  registerTools(server, () => resolveGoogleAuth(token));

  const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });
  await server.connect(transport);

  return await transport.handleRequest(request);
}

The WebStandardStreamableHTTPServerTransport is the key — it works with the Web Standard Request/Response APIs that Next.js Route Handlers use, making deployment on serverless platforms like Vercel straightforward.

Tools We Expose

The server registers 24 tools across three Google Workspace products:

Google Sheets (8 tools)

Tool Description
list_spreadsheets Search and list spreadsheets from Google Drive
get_spreadsheet Get spreadsheet metadata (sheet names, dimensions)
read_sheet Read data from a range (returns formatted table)
write_sheet Write data to a specific range (overwrites)
append_rows Append rows to the end of a sheet
update_cells Update individual cells at specific locations
create_spreadsheet Create a new spreadsheet
batch_get Read multiple ranges in one request

Google Docs (7 tools)

Tool Description
list_documents Search and list Google Docs from Drive
get_document Get document metadata and structure
read_document Read the full text content of a document
create_document Create a new Google Doc
append_text_to_document Append text at the end of a document
insert_text_in_document Insert text at a specific position
replace_text_in_document Find and replace text in a document

Google Slides (9 tools)

Tool Description
list_presentations Search and list presentations from Drive
get_presentation Get presentation metadata (slide count, IDs)
read_slide Read text and elements from a specific slide
read_all_slides Read text from all slides in a presentation
create_presentation Create a new presentation
add_slide Add a new slide with a predefined layout
add_text_to_slide Insert text into a shape/text box on a slide
replace_text_in_presentation Find and replace text across all slides
delete_slide Delete a slide from a presentation

Each tool uses Zod schemas for input validation and includes descriptions that help AI clients understand when and how to use them:

server.registerTool(
  "read_sheet",
  {
    description: "Read data from a spreadsheet range. Returns a formatted table.",
    inputSchema: {
      spreadsheet_id: z.string().describe("The spreadsheet ID"),
      range: z.string().describe("A1 notation range, e.g. 'Sheet1!A1:D10'"),
    },
  },
  async ({ spreadsheet_id, range }) => {
    const auth = await getAuth();
    const data = await sheetsLib.readSheet(auth, spreadsheet_id, range);
    // Format as readable table...
    return { content: [{ type: "text", text }] };
  }
);

The server also includes a prompt (google_workspace_guide) that provides best-practice guidance to AI assistants for using the tools efficiently — like preferring narrow ranges, using batch_get for multiple reads, and exploring structure before reading full content.

The Tech Stack

  • Next.js 15 — App Router with Route Handlers for all endpoints
  • Vercel — Serverless deployment with git-push deploys
  • Neon Postgres — Serverless PostgreSQL for session/token storage
  • Prisma — ORM with three tables: oauth_clients, auth_codes, sessions
  • @modelcontextprotocol/sdk — Official MCP TypeScript SDK
  • googleapis — Google's official Node.js client for Sheets, Docs, Slides, and Drive APIs
  • Zod — Schema validation for tool inputs

Deployment

The project deploys automatically on every push to master. The build command handles everything:

prisma generate && prisma migrate deploy && next build

Prisma migrations run automatically during build, so database schema changes deploy seamlessly alongside code changes.

How to Use It

Adding to Claude Code

Add the server URL to your MCP client configuration:

{
  "mcpServers": {
    "google-workspace": {
      "url": "https://gwk-mcp.abilioazevedo.com.br/mcp"
    }
  }
}

That's it. The first time you use a tool, the OAuth flow kicks in — your browser opens, you grant access to Google Workspace, and you're connected.

Adding to Claude.ai

Go to Settings > MCP Servers > Add Server and paste the URL:

https://gwk-mcp.abilioazevedo.com.br/mcp

Claude will handle the authentication flow automatically.

Inspecting and Debugging with MCP Inspector

The MCP Inspector is an essential tool for developing and debugging MCP servers. It provides a web UI where you can see the server's capabilities, test tools interactively, and inspect the protocol messages.

Running the Inspector

To inspect our remote MCP server, run:

npx @modelcontextprotocol/inspector https://gwk-mcp.abilioazevedo.com.br/mcp

This launches a local web interface (usually at http://localhost:6274) that connects to the remote server.

What You Can Do with the Inspector

  1. Authenticate — The Inspector supports the full MCP OAuth flow. Click "Connect" and it will walk you through the Google authentication, just like a real MCP client would.

  2. List Tools — See all 24 tools the server exposes, along with their descriptions and input schemas. This is great for verifying your tool definitions look correct.

  3. Call Tools — Fill in parameters and execute tools directly. For example, you can call list_spreadsheets to see your Google Sheets, then call read_sheet with a specific spreadsheet ID and range.

  4. Inspect Protocol Messages — See the raw JSON-RPC messages exchanged between client and server. This is invaluable for debugging issues with tool calls, authentication, or transport.

  5. Test Error Handling — Try calling tools with invalid parameters to verify your error responses are sensible.

Inspector Workflow Example

1. Run: npx @modelcontextprotocol/inspector https://gwk-mcp.abilioazevedo.com.br/mcp
2. Open http://localhost:6274 in your browser
3. Click "Connect" → Complete Google OAuth in the popup
4. Navigate to "Tools" tab → See all 24 registered tools
5. Select "list_spreadsheets" → Click "Run" → See your spreadsheets
6. Select "read_document" → Enter a document_id → See the document content
7. Select "get_presentation" → Enter a presentation_id → See the slide structure

The Inspector is also useful for local development:

# Start the dev server
pnpm dev

# In another terminal, point the inspector at localhost
npx @modelcontextprotocol/inspector http://localhost:3100/mcp

Lessons Learned

1. Accept Header Normalization

Some MCP clients send Accept: */* instead of the specific content types the SDK expects (application/json, text/event-stream). We had to normalize the header on incoming requests to prevent the transport from rejecting valid requests.

2. Don't Close the Server Too Early

The WebStandardStreamableHTTPServerTransport returns an SSE (Server-Sent Events) stream. The response body is populated asynchronously — if you call server.close() immediately after getting the response, it kills the stream before the client reads it. Let the serverless function's natural lifecycle handle cleanup.

3. CORS Matters for Remote Servers

Unlike local MCP servers, a remote server needs proper CORS headers. MCP clients running in browsers (like Claude.ai) need to make cross-origin requests to your server. Every endpoint — including OPTIONS preflight — needs the right headers.

4. Token Refresh is Critical

Google access tokens expire after ~1 hour. The server checks token expiry on each request and transparently refreshes using the stored refresh token. Without this, users would need to re-authenticate constantly.

5. Scaling to Multiple Google APIs

Starting with Sheets and then expanding to Docs and Slides taught us the value of keeping a clean separation between the MCP tool registration layer and the Google API wrappers. Each Google service (sheets.ts, docs.ts, slides.ts) exports pure functions that take a GoogleOAuth2Client and return structured data. The MCP route handler just orchestrates — register tools, resolve auth, format output. Adding a new Google service is straightforward: write the API wrapper, register the tools.

Conclusion

Building a remote MCP server is a powerful way to give AI assistants access to external services. The MCP protocol handles the complexity of tool discovery and authentication, while platforms like Vercel and Neon make deployment and data storage effortless.

The key advantage of a remote server over a local one is zero configuration for end users — they add a URL and authenticate once. No API keys to manage, no local processes to run, no config files to maintain.

By expanding from Google Sheets to the full Google Workspace suite — Sheets, Docs, and Slides — a single MCP server becomes a comprehensive productivity bridge between AI and the tools teams use every day.


More posts

Cover Image for UX/UI for developers

UX/UI for developers

UX/UI for Developers — A practical guide on design systems, communicating with Product Designers, and knowing when to reuse components. Covers Nielsen's heuristics, Atomic Design, Tailwind CSS component libraries like shadcn/ui and Radix UI, prototyping tools like Figma and Origami Studio, accessibility best practices, and curated courses, articles, and books for developers building better user experiences.

Abílio Azevedo
Abílio Azevedo
Cover Image for AI Dev Daily Tools

AI Dev Daily Tools

Learn how to debug smarter with AI prompts, audit SEO from your terminal, go from Sentry errors to PRs in minutes, and unlock hidden Claude Code features.

Abílio Azevedo
Abílio Azevedo

NewsLetter

I will send the content posted here. No Spam =)