Skip to main content
Glama
README.md
# Google Classroom Model Context Protocol (MCP) Server

[![Ecosystem](https://img.shields.io/badge/Orchestration-Antigravity%20%2F%20Claude%20Fleet-7952b3)](https://github.com/Aaradhya-Dev-Tamrakar/brainstorm)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Runtime](https://img.shields.io/badge/Runtime-Node.js%20ESM-informational)](https://nodejs.org)

A native, lightweight, and robust **Model Context Protocol (MCP)** server for the Google Classroom API. It connects LLM reasoning engines (Antigravity, Claude Desktop, and autonomous fleet agents) directly to Google Classroom streams, assignments, submissions, rosters, and educational resources.

---

## šŸ— Architecture & Flow

```
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│     Antigravity / Claude Desktop (MCP Client)           │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                            │ JSON-RPC (Stdio)
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│               google-classroom-mcp                      │
│  - index.mjs            (MCP Protocol Dispatcher)       │
│  - auth.mjs             (OAuth 2.0 Loopback Receiver)   │
│  - sync-schemas.mjs     (Lazy Tool Schema Generator)    │
│  - sync.ps1             (Ecosystem Sync & Secret Guard) │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                            │ HTTPS REST with Auto Token Refresh
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│     Google Classroom REST API (v1)                      │
│     https://classroom.googleapis.com/v1/...             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
```

---

## šŸ›  Available Tools & Implementation Methods

The server implements 12 high-agency tools conforming to `@modelcontextprotocol/sdk`:

### 1. `list_courses`
* **Method**: `GET https://classroom.googleapis.com/v1/courses`
* **Parameters**:
  - `courseStates` *(array of strings, optional)*: Filter by status (`ACTIVE`, `ARCHIVED`, `PROVISIONED`, `DECLINED`, `SUSPENDED`). Defaults to `['ACTIVE']`.
  - `pageSize` *(number, optional)*: Maximum items to return (default 20).
  - `studentId` *(string, optional)*: Filter courses enrolled as student (`"me"` or user ID).
  - `teacherId` *(string, optional)*: Filter courses instructed as teacher (`"me"` or user ID).
* **Returns**: Markdown list of matching courses with ID, name, section, room, enrollment code, and web link.

### 2. `get_course`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}`
* **Parameters**:
  - `courseId` *(string, required)*: Unique Google Classroom course identifier.
* **Returns**: Full course object schema including enrollment code, description, teacher group email, and calendar ID.

### 3. `list_coursework`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/courseWork`
* **Parameters**:
  - `courseId` *(string, required)*: Target course identifier.
  - `courseWorkStates` *(array of strings, optional)*: Filter (`PUBLISHED`, `DRAFT`, `DELETED`).
  - `pageSize` *(number, optional)*: Maximum assignments to fetch (default 30).
  - `orderBy` *(string, optional)*: Order criteria (`dueDate desc`, `updateTime desc`).
* **Returns**: Formatted summary of assignments, problem sets, due dates/times, max points, and links.

### 4. `get_coursework`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/courseWork/{courseWorkId}`
* **Parameters**:
  - `courseId` *(string, required)*: Course identifier.
  - `courseWorkId` *(string, required)*: Coursework item identifier.
* **Returns**: Complete assignment metadata, instructions, rubrics, and attached materials (Google Drive files, YouTube videos, links).

### 5. `list_submissions`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions`
* **Parameters**:
  - `courseId` *(string, required)*: Course identifier.
  - `courseWorkId` *(string, required)*: Coursework item ID (or `"-"` for all coursework).
  - `userId` *(string, optional)*: Target student filter (`"me"` for current authenticated student).
  - `states` *(array of strings, optional)*: Filter (`NEW`, `CREATED`, `TURNED_IN`, `RETURNED`, `RECLAIMED_BY_STUDENT`).
* **Returns**: Student submission states, lateness flags, assigned grades, draft grades, and turn-in links.

### 6. `get_submission`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}`
* **Parameters**:
  - `courseId` *(string, required)*
  - `courseWorkId` *(string, required)*
  - `submissionId` *(string, required)*
* **Returns**: Detailed submission record with attached student drive files, links, and grade history.

### 7. `list_announcements`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/announcements`
* **Parameters**:
  - `courseId` *(string, required)*: Course identifier.
  - `announcementStates` *(array of strings, optional)*: Filter (`PUBLISHED`, `DRAFT`, `DELETED`).
  - `pageSize` *(number, optional)*: Max announcements (default 20).
* **Returns**: Course stream announcements, updates, creator info, timestamps, and attached assets.

### 8. `list_coursework_materials`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/courseWorkMaterials`
* **Parameters**:
  - `courseId` *(string, required)*: Course identifier.
  - `courseWorkMaterialStates` *(array of strings, optional)*: Defaults to `['PUBLISHED']`.
* **Returns**: Standalone class resources, lecture slide decks, syllabus documents, and shared materials.

### 9. `list_teachers`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/teachers`
* **Parameters**:
  - `courseId` *(string, required)*
* **Returns**: List of instructors with display name, email, and user IDs.

### 10. `list_students`
* **Method**: `GET https://classroom.googleapis.com/v1/courses/{courseId}/students`
* **Parameters**:
  - `courseId` *(string, required)*
* **Returns**: List of enrolled classmates with display name, email, and user IDs.

### 11. `turn_in_assignment`
* **Method**: `POST https://classroom.googleapis.com/v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}:turnIn`
* **Parameters**:
  - `courseId` *(string, required)*
  - `courseWorkId` *(string, required)*
  - `submissionId` *(string, required)*
* **Returns**: Confirmation that the student submission has been formally marked as turned in for grading.

### 12. `reclaim_assignment`
* **Method**: `POST https://classroom.googleapis.com/v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}:reclaim`
* **Parameters**:
  - `courseId` *(string, required)*
  - `courseWorkId` *(string, required)*
  - `submissionId` *(string, required)*
* **Returns**: Confirmation that the student submission has been unsubmitted/reclaimed for editing.

---

## šŸ”‘ Authentication & Token Lifecycle

### Course content copy tool

`copy_course_contents` previews published topics, coursework, class materials, announcements, and Drive attachments before making changes. It defaults to `dryRun: true`. To apply a copy, set `dryRun: false`; the destination must be ACTIVE and have no enrolled students. The tool stores an idempotency/resume ledger at `%LOCALAPPDATA%/google-classroom-mcp/copy-ledger.json` (or the user's home directory where `LOCALAPPDATA` is unavailable). Drive requests support shared-drive files. Google Forms, Gemini Gems, and NotebookLM attachments are recreated as titled links because Classroom does not permit creating those special attachment types directly. Classroom rejects new coursework with past due dates: the default `pastDueDatePolicy: "skip"` leaves those assignments uncopied; `pastDueDatePolicy: "omit"` publishes them without an expired due date and lists that loss in the result.

For example, extend the Classroom server's MCP `env` with the existing Drive MCP token and OAuth file paths:

```json
{
  "DRIVE_CREDENTIALS_PATH": "C:\\Users\\<user>\\.gdrive-server-credentials.json",
  "DRIVE_OAUTH_PATH": "C:\\Users\\<user>\\.gdrive-credentials.json"
}
```

Drive credentials are deliberately separate from Classroom credentials. Configure `DRIVE_CREDENTIALS_PATH` and `DRIVE_OAUTH_PATH` to the existing Google Drive MCP token and OAuth client files. The Drive OAuth token needs permission to copy the source files and create files under the target folder. Classroom OAuth requires `classroom.coursework.students`, `classroom.announcements`, `classroom.courseworkmaterials`, and `classroom.topics`; rerun `npm run auth` and grant the updated access after changing these scopes. Rubric creation depends on Google account/course support and is reported as a per-item failure when unavailable.

1. **Credentials**: Provide standard Google Cloud OAuth 2.0 Client credentials (Desktop Application).
2. **Initial Authorisation (`npm run auth`)**:
   - Launches a local HTTP loopback server on port `58246`.
   - Generates Google OAuth consent URL with offline access (`prompt=consent`).
   - Opens the browser to authorize.
   - Captures authorization code and exchanges it for a permanent `refresh_token` and initial `access_token`.
   - Persists securely to `.classroom-server-credentials.json` (gitignored).
3. **Automated Refreshing**:
   - `index.mjs` checks token expiration before every API request.
   - When remaining validity is `< 60 seconds`, or on receiving HTTP `401 Unauthorized`, it transparently calls `https://oauth2.googleapis.com/token` to refresh the access token.

---

## šŸš€ Installation & Setup

```bash
# 1. Clone repository
git clone https://github.com/Aaradhya-Dev-Tamrakar/google-classroom-mcp.git
cd google-classroom-mcp

# 2. Install dependencies
npm install

# 3. Authenticate with Google Classroom
npm run auth

# 4. Generate Antigravity tool schemas
npm run sync
```

---

## āš™ļø Configuration

### Antigravity & Claude Desktop Registration

Add this server block to your `mcp_config.json`:

```json
{
  "mcpServers": {
    "classroom": {
      "command": "node",
      "args": [
        "F:\\Aaradhya-Dev-Tamrakar\\Utility-MCPs\\google-classroom-mcp\\index.mjs"
      ],
      "env": {
        "CLASSROOM_CREDENTIALS_PATH": "C:\\Users\\Aaradhya\\.classroom-server-credentials.json",
        "CLASSROOM_OAUTH_PATH": "C:\\Users\\Aaradhya\\.classroom-credentials.json"
      }
    }
  }
}
```

> **Note on Path Integrity**: If legacy tools look for `F:\Aaradhya-Dev-Tamrakar\google-classroom-mcp`, maintain a Windows NTFS directory junction:
> ```powershell
> New-Item -ItemType Junction -Path "F:\Aaradhya-Dev-Tamrakar\google-classroom-mcp" -Target "F:\Aaradhya-Dev-Tamrakar\Utility-MCPs\google-classroom-mcp"
> ```

### Dual OAuth Scope Boundary (`INV-AUTH-001`)
* `.classroom-server-credentials.json` grants scopes strictly for Google Classroom REST API (`https://www.googleapis.com/auth/classroom.*`).
* If an agent needs to stream or download binary files attached to coursework (e.g. PDFs or archives via `https://www.googleapis.com/drive/v3/files/{id}?alt=media`), it must use the credentials from the companion `gdrive-mcp` server (`.gdrive-server-credentials.json`) which carry full Google Drive API scopes. Calling the Drive media download endpoint with Classroom-only tokens triggers HTTP 403 `ACCESS_TOKEN_SCOPE_INSUFFICIENT`.


---

## šŸ”„ Synchronization & Maintenance (`sync.ps1`)

This repository follows the centralized ecosystem Git and secret governance standard:

```powershell
# Routine synchronization & rebase push:
.\sync.ps1

# Custom semantic commit message:
.\sync.ps1 -m "feat(classroom): add rubric parsing support"

# Refresh Antigravity schemas before pushing:
.\sync.ps1 -SyncSchemas

# Dry-run inspection (runs secret scanner without touching git state):
.\sync.ps1 -WhatIf

# Safe pull only:
.\sync.ps1 -PullOnly

# Push the current clean feature branch to its matching origin branch:
.\sync.bat -PushCurrentBranch
```

### Safety Features
- **Secret Scanner Guard**: Blocks commits if OAuth credentials, tokens, private keys, or API secrets are staged.
- **Atomic conventional commit formatting**: Autodetects added/modified files and formats clean commit prefixes.
- **Rebase-safety**: Always executes `git pull --rebase --autostash` before pushing to avoid merge bubbles.

---

## šŸ“„ License

MIT License. Developed for Aaradhya's Personal Tool Ecosystem.

TDQS

A3.5/5.0

Scored across 13 tools

Disambiguation4/5

Most tools target distinct resources and actions (courses, teachers, students, coursework, submissions, announcements, turn-in/reclaim). The main overlap is between list_coursework (assignments/quizzes) and list_coursework_materials (syllabi/resources), but descriptions adequately distinguish them.

Naming Consistency5/5

All 13 tools follow a consistent snake_case verb_noun pattern (get_course, list_students, list_submissions, turn_in_assignment, copy_course_contents). The few multi-word verbs like turn_in and reclaim are still readable and consistent.

Tool Count5/5

13 tools is well-scoped for a Classroom integration, covering courses, members, coursework, materials, submissions, and announcements without redundancy. Each tool earns its place.

Completeness3/5

Covers read operations broadly plus a few actions (turn in, reclaim, copy contents), but has notable gaps: no create/update/delete for courses, coursework, or announcements, and no grading or return-submission operations, leaving teacher-side workflows incomplete.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive