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

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 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, 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:

// 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

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

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

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

Trip Sharing Enforcement

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:

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:

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
  • 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →