Skip to content

Latest commit

 

History

History
244 lines (188 loc) · 9.78 KB

File metadata and controls

244 lines (188 loc) · 9.78 KB

Architecture

Overview

┌─────────────────┐
│  MCP Client     │
│  (ChatGPT)      │
└────────┬────────┘
         │ MCP Protocol (HTTP)
         ▼
┌─────────────────────────────────────────┐
│         server-http.ts                  │
│  ┌───────────────────────────────────┐  │
│  │  OAuth Handler (oauth/)           │  │
│  │  /authorize, /callback, /token    │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  MCP Transport                    │  │
│  │  WebStandardStreamableHTTP        │  │
│  └───────────────────────────────────┘  │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│         createMcpServer.ts              │
│  ┌───────────────────────────────────┐  │
│  │  Tool Handlers (tools/)           │  │
│  │  tasklists, task_create, etc.     │  │
│  └───────────────────────────────────┘  │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│       GoogleTasksService.ts             │
│  Google Tasks API wrapper               │
└────────────────┬────────────────────────┘
                 │ OAuth 2.0 / REST
                 ▼
┌─────────────────────────┐
│   Google Tasks API      │
└─────────────────────────┘

Project Structure

src/
├── server-http.ts          # HTTP entry point
├── server-stdio.ts         # stdio entry point (not working with OAuth yet)
├── mcp/
│   ├── createMcpServer.ts  # MCP server factory
│   ├── schemas/
│   │   └── task.ts         # Zod validation schemas
│   └── tools/              # MCP tool handlers
├── oauth/                  # OAuth 2.0 implementation
│   ├── handlers/           # Endpoint handlers
│   └── ...
├── services/
│   └── GoogleTasksService.ts
└── utils/
    ├── createSuccessResponse.ts
    └── createErrorResponse.ts

Files

Entry Points

server-http.ts

HTTP server using Bun's native Bun.serve(). Handles:

  • OAuth request routing (delegates to oauth/router.ts)
  • MCP session management (one McpServer + Transport per session)
  • Access token extraction from Authorization header
  • Accept header normalization for compatibility

server-stdio.ts

stdio transport for local MCP clients (Cursor, Claude Desktop). Currently requires environment variables for auth - OAuth not yet supported.

MCP Layer

mcp/createMcpServer.ts

Factory function that creates configured McpServer instance:

  • Registers all tools
  • Creates GoogleTasksService with appropriate auth mode (access token or refresh token)
  • Exports SERVER_INFO for version identification

mcp/schemas/task.ts

Shared Zod schemas:

  • taskSchema - Google Task object structure
  • dueDateSchema - RFC3339 date format validation

mcp/tools/*.ts

Each file exports:

  • inputSchema - Zod schema for tool parameters
  • outputSchema - Zod schema for response (documentation only)
  • create*Handler(service) - Factory returning tool callback

Pattern:

export function createSomeHandler(
  service: GoogleTasksService
): ToolCallback<typeof inputSchema> {
  return async (args) => {
    try {
      const result = await service.someMethod(args);
      return createSuccessResponse(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Unknown error';
      return createErrorResponse(message);
    }
  };
}

OAuth Layer

oauth/router.ts + oauth/handlers/

Routes requests to endpoint handlers:

  • /.well-known/*wellKnown.ts - OAuth/OIDC discovery metadata
  • /authorizeauthorize.ts - Redirects to Google OAuth
  • /callbackcallback.ts - Receives Google auth code, redirects to client
  • /tokentoken.ts - Exchanges codes for tokens, handles refresh
  • /registerregister.ts - Dynamic Client Registration (RFC 7591)

oauth/storage.ts

In-memory storage for:

  • Pending authorizations (state → redirect_uri mapping)
  • Token data (access_token → refresh_token mapping for auto-refresh)
  • Registered clients (DCR)

oauth/types.ts

TypeScript interfaces for OAuth entities.

oauth/config.ts

Creates OAuthConfig from environment variables.

oauth/helpers.ts

Utility functions: generateRandomString, jsonResponse.

Services

services/GoogleTasksService.ts

Google Tasks API wrapper using googleapis library. Supports two auth modes:

  • Refresh token mode: Has client credentials, can auto-refresh tokens
  • Access token mode: Token only, expires after ~1h

Methods:

  • getTaskLists() - List all task lists
  • getTasks(listId) - List tasks in a list
  • createTask(task, listId) - Create task
  • updateTask(listId, taskId, updates) - Update task
  • deleteTask(listId, taskId) - Delete task
  • checkConnection() - Health check

Utils

utils/createSuccessResponse.ts

Creates MCP CallToolResult with both content (text) and structuredContent (object).

utils/createErrorResponse.ts

Creates MCP CallToolResult with isError: true.

OAuth Flow

Client                    Server                      Google
  │                         │                           │
  │ GET /authorize          │                           │
  │ ?redirect_uri=...       │                           │
  │ &state=...              │                           │
  │────────────────────────>│                           │
  │                         │                           │
  │      302 Redirect       │                           │
  │<────────────────────────│                           │
  │                         │                           │
  │ GET accounts.google.com/o/oauth2/auth               │
  │─────────────────────────────────────────────────────>
  │                         │                           │
  │                    [User logs in]                   │
  │                         │                           │
  │      302 Redirect to /callback?code=...            │
  │<─────────────────────────────────────────────────────
  │                         │                           │
  │ GET /callback?code=...  │                           │
  │────────────────────────>│                           │
  │                         │                           │
  │      302 Redirect       │                           │
  │      ?code=our_code     │                           │
  │<────────────────────────│                           │
  │                         │                           │
  │ POST /token             │                           │
  │ code=our_code           │                           │
  │────────────────────────>│                           │
  │                         │ POST /token               │
  │                         │ code=google_code          │
  │                         │──────────────────────────>│
  │                         │                           │
  │                         │ {access_token, refresh}   │
  │                         │<──────────────────────────│
  │                         │                           │
  │ {access_token}          │                           │
  │<────────────────────────│                           │

Session Management

Each MCP session gets its own:

  • McpServer instance
  • WebStandardStreamableHTTPServerTransport instance
  • GoogleTasksService instance (with user's tokens)

This is required because McpServer can only be connected to one transport at a time.

Sessions are stored in a Map keyed by session ID (UUID generated on first request).

Security

  • Tokens stored in memory only (not persisted)
  • Tokens never reach the LLM - only tool results
  • HTTPS required in production
  • PKCE (S256) supported for OAuth
  • Scope limited to https://www.googleapis.com/auth/tasks