# How MCP Scopes Control AI Permissions in TREK: A Complete Guide to OAuth 2.1 Access Control

> Master MCP scopes and OAuth 2.1 in TREK to precisely control AI permissions. Learn how 27 access tokens manage AI data read/write control, ensuring secure AI operations.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: tutorial
- Published: 2026-07-04

---

**MCP scopes in TREK use OAuth 2.1 to granularly control AI client permissions through 27 functional access tokens that define exactly what data an AI can read or write.**

TREK implements Machine-Client Protocol (MCP) authentication to secure AI integrations with fine-grained access control. The permission system defined in [`server/src/mcp/scopes.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/scopes.ts) enforces strict boundaries around trips, places, budgets, and collaboration features, ensuring AI clients operate within precisely defined authorization boundaries.

## Understanding MCP Scopes in TREK

MCP scopes follow an OAuth 2.1 standard format of `<group>:<action>`, creating a hierarchical permission structure that governs AI access to the travel planning platform. Each scope belongs to a functional domain such as **Trips**, **Places**, or **Budget**, with permissions escalating from read-only to full write access.

### Scope Structure and Naming Conventions

TREK defines 27 distinct scopes across 13 functional groups. The naming convention follows a predictable pattern:

- `trips:read` – View trips, days, notes, and members
- `trips:write` – Create, update, delete trips and manage accommodations
- `budget:write` – Modify budget items and allocations
- `geo:read` – Search locations and resolve map coordinates

### Permission Hierarchy Rules

The scope system implements specific inheritance rules that simplify permission management:

1. **Write implies read** – Any `:write` scope automatically grants read access for the same group
2. **Trips wildcard** – Any `trips:*` scope (write, delete, or share) satisfies read requirements for trips
3. **Journey exception** – `journey:share` manages share links only and does **not** grant read access to journey data
4. **Static token bypass** – Static tokens and web-session JWTs bypass scope checks entirely, receiving full access

## The Complete MCP Scopes Reference

TREK organizes permissions into logical groups covering every aspect of travel planning:

| Group | Read Scope | Write Scope | Description |
|-------|------------|-------------|-------------|
| **Trips** | `trips:read` | `trips:write` | Core trip management including days, notes, and members |
| **Places** | `places:read` | `places:write` | Location data, assignments, and tagging |
| **Atlas** | `atlas:read` | `atlas:write` | Visited countries and bucket list management |
| **Packing** | `packing:read` | `packing:write` | Packing items and bag configurations |
| **To-dos** | `todos:read` | `todos:write` | Trip task management |
| **Budget** | `budget:read` | `budget:write` | Financial planning and expense tracking |
| **Reservations** | `reservations:read` | `reservations:write` | Booking and reservation data |
| **Collaboration** | `collab:read` | `collab:write` | Collaborative notes, polls, and messages |
| **Notifications** | `notifications:read` | `notifications:write` | Alert management and marking |
| **Vacation** | `vacay:read` | `vacay:write` | Vacation planning data |
| **Geo** | `geo:read` | — | Location search and reverse-geocoding |
| **Weather** | `weather:read` | — | Forecast retrieval |
| **Journey** | `journey:read` | `journey:write` | Journey management and public sharing |

Additional specialized scopes include `trips:delete` for permanent trip removal, `trips:share` for public link management, and `journey:share` for journey-specific sharing.

## Server-Side Enforcement Logic

The permission validation resides in [`server/src/mcp/scopes.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/scopes.ts), which exports helper functions that enforce scope rules at the API boundary. When an AI client authenticates, the server extracts scopes from the OAuth token and consults these utilities before processing requests.

### Core Permission Checking Functions

The enforcement layer centers on three primary functions that implement the hierarchy rules:

```typescript
// server/src/mcp/scopes.ts
export function canReadTrips(scopes: string[] | null): boolean {
  if (!scopes) return true;                         // static token → full access
  return scopes.some(s => s === 'trips:read' ||
                         s === 'trips:write' ||
                         s === 'trips:delete' ||
                         s === 'trips:share');
}

export function canWrite(scopes: string[] | null, group: string): boolean {
  if (!scopes) return true;
  return scopes.includes(`${group}:write`);
}

export function canRead(scopes: string[] | null, group: string): boolean {
  if (!scopes) return true;
  return scopes.some(s => s === `${group}:read` ||
                         s === `${group}:write`);
}

```

The `canRead` function implements the write-implies-read rule by checking for either the explicit read scope or the write scope for the requested group. The `canReadTrips` function specifically handles the trips wildcard logic, accepting any trips-related scope as valid for read operations.

### Static Token Handling

When `scopes` is `null`, the system assumes a static token or web-session JWT, automatically granting full access. This bypass mechanism allows internal services and authenticated web users to operate without explicit scope enumeration while maintaining strict boundaries for external AI clients.

## Implementing Scope Checks in Practice

API endpoints import these helpers to gate access based on the authenticated client's permissions. The standard pattern extracts scopes from the request context and validates before executing business logic.

### Basic Write Permission Check

```typescript
import { canWrite } from '@/mcp/scopes';

app.put('/api/trips/:id', async (req, res) => {
  const scopes = req.user?.mcpScopes ?? null;
  if (!canWrite(scopes, 'trips')) {
    return res.status(403).json({ error: 'Insufficient scope' });
  }
  // Perform update...
});

```

### Group-Specific Read Validation

```typescript
import { canRead } from '@/mcp/scopes';

function canViewPacking(scopes: string[] | null) {
  return canRead(scopes, 'packing');
}

```

### Trip Sharing Enforcement

```typescript
import { canShareTrips } from '@/mcp/scopes';

if (!canShareTrips(userScopes)) {
  throw new Error('Missing trips:share scope');
}

```

### Scope Validation

Before processing client requests, validate the requested scope strings against the supported set:

```typescript
import { validateScopes } from '@/mcp/scopes';

const { valid, invalid } = validateScopes(requestedScopes);
if (!valid) {
  console.warn('Invalid scopes requested:', invalid);
}

```

## Add-On Gated Features

Certain advanced features require both the relevant MCP scope **and** an enabled add-on flag set by an administrator. This dual-layer permission prevents AI clients from accessing premium functionality even if they possess the OAuth scope.

**Atlas**, **Collab**, **Vacay**, and **Journey** features implement this pattern. An AI client must present `atlas:read` or `atlas:write` scopes **and** the admin must have enabled the Atlas add-on for the workspace. The server checks both conditions before serving Atlas-related data, creating a marketplace-style permission model for AI capabilities.

## Key Files and Architecture

Understanding the scope system requires familiarity with these specific source locations:

- **[`server/src/mcp/scopes.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/scopes.ts)** – Central definition of all 27 OAuth scopes, their human-readable descriptions, and the enforcement helper functions
- **[`server/src/mcp/index.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/index.ts)** – Entry point where the server extracts scopes from tokens and initializes the MCP instruction set
- **[`wiki/MCP-Scopes.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/MCP-Scopes.md)** – Human-focused documentation describing each scope's boundaries and use cases
- **[`server/tests/integration/mcp.test.ts`](https://github.com/mauriceboe/TREK/blob/main/server/tests/integration/mcp.test.ts)** – Integration tests verifying scope enforcement, rate limiting, and permission edge cases

The architecture separates token extraction (handled in the MCP index) from permission logic (centralized in scopes.ts), allowing consistent enforcement across REST endpoints, GraphQL resolvers, and WebSocket handlers.

## Summary

- **MCP scopes** in TREK follow OAuth 2.1 format `<group>:<action>` with 27 distinct permissions across 13 functional groups
- **Write implies read** automatically through the `canRead` helper function in [`server/src/mcp/scopes.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/mcp/scopes.ts)
- **Static tokens** bypass scope checks entirely, receiving full access when scopes parameter is `null`
- **Add-on gating** requires both the proper scope and admin-enabled feature flags for Atlas, Collab, Vacay, and Journey
- **Server enforcement** uses `canWrite`, `canRead`, and `canReadTrips` helpers to return 403 errors for unauthorized AI requests
- **Special rules** apply to trips (any scope grants read) and journey sharing (does not include read access)

## Frequently Asked Questions

### What happens if an AI client requests a scope it doesn't have?

The server returns a **403 Forbidden** response with an `Insufficient scope` error message. The enforcement occurs in the API route handler before any data access occurs, preventing unauthorized reads or writes at the boundary level.

### How do static tokens differ from OAuth tokens in TREK's MCP system?

**Static tokens** and web-session JWTs pass `null` to the scope checking functions, triggering immediate `return true` responses that grant full access. **OAuth tokens** for AI clients contain explicit scope arrays that undergo strict validation against the 27 supported permission types.

### Can an AI client with `trips:write` delete trips permanently?

No. While `trips:write` grants create, update, and duplicate permissions, **permanent deletion** requires the specific `trips:delete` scope. This separation prevents accidental data loss while allowing AI assistants to modify trip content freely.

### Do MCP scopes control access to weather and geolocation data?

Yes, but with limitations. The `weather:read` and `geo:read` scopes control access to weather forecasts and location search functionality. However, these are **read-only scopes**—no write variants exist for these services, and they do not require add-on activation, making them universally available to authorized AI clients.