How to Integrate TREK with MCP (Model Context Protocol): A Complete Developer Guide

TREK exposes a built-in MCP server at /mcp that enables AI assistants to securely query and manipulate travel data through a JSON-RPC API, requiring only the MCP add-on to be enabled and a valid OAuth 2.1, static, or JWT token for authentication.

Integrating TREK with the Model Context Protocol (MCP) allows Claude, Cursor, and other AI assistants to interact with your travel data using a standardized JSON-RPC interface. According to the mauriceboe/TREK source code, the integration centers on a single HTTP endpoint that handles authentication, session management, and tool registration. This guide walks through the architectural flow, authentication requirements, and implementation details needed to connect your AI client to a TREK instance.

Enable the MCP Add-On

Before any client can connect, the MCP feature must be activated in the database. In server/src/mcp/index.ts (lines 18-22), the handler checks isAddonEnabled(ADDON_IDS.MCP) and returns a 403 Forbidden if the add-on is disabled.

Enable the add-on by inserting the record into your SQLite database:

INSERT INTO addons (id, enabled) VALUES ('mcp', 1);

Once enabled, the /mcp endpoint becomes active and accepts POST requests carrying JSON-RPC 2.0 payloads.

Authenticate Incoming Requests

The verifyToken function in server/src/mcp/index.ts (lines 71-102) supports three credential types, returning a payload of {user, scopes, clientId, isStaticToken} that drives permission enforcement:

  • OAuth 2.1 access tokens (prefix trekoa_): Validated via getUserByAccessToken in server/src/services/oauthService.ts. The audience must match the MCP URL, and the resulting scopes control which tools the client can invoke.
  • Legacy static tokens (prefix trek_): Verified with verifyMcpToken in server/src/services/authService.ts. These grant full access but trigger a deprecation notice that the server automatically appends to the model’s response.
  • Short-lived JWTs: Used by the TREK web UI, verified via verifyJwtToken.

Client implementations should obtain an OAuth token from TREK Settings → MCP → OAuth Clients, then include it in the Authorization: Bearer header.

Handle Sessions and Rate Limits

TREK enforces a multi-layered gatekeeping system after authentication.

Rate Limiting

An in-memory rateLimitMap tracks requests per user and client. The isRateLimited utility (lines 11-21 of server/src/mcp/index.ts) reads the MCP_RATE_LIMIT environment variable, defaulting to 300 requests per minute. Exceeding this returns a rate-limit error before the request reaches the business logic.

Session Creation and Resumption

The server distinguishes between new and existing sessions via the Mcp-Session-Id header:

  1. New Session: For requests without a session ID, the server checks MCP_MAX_SESSION_PER_USER (default 20) against the in-memory sessions registry in server/src/mcp/sessionManager.ts. If under the limit, it instantiates an McpServer from @modelcontextprotocol/sdk/server/mcp, configures capabilities (tools, resources, prompts) with listChanged: true, and attaches base instructions describing TREK’s data model. The StreamableHTTPServerTransport generates a UUID, stores the session, and returns it in the Mcp-Session-Id response header.
  2. Resuming: Requests bearing an existing Mcp-Session-Id validate ownership and client-id, update the activity timestamp, and forward the payload to the existing transport.

A sweep interval periodically removes stale sessions after a one-hour TTL and cleans expired rate-limit entries.

Expose Travel Data via Tools and Resources

Each session registers a curated catalog scoped to the authenticated user. In server/src/mcp/resources.ts and the server/src/mcp/tools/ directory, the server calls registerResources and registerTools to expose:

  • Tools: Domain-specific operations like list_trips, search_place, create_accommodation, and budget/* grouped by functionality (vacations, packing, etc.).
  • Resources: Read-only snapshots of travel data.

The scopes array from the OAuth token determines which tools are available, enforcing fine-grained permissions at runtime.

Audit and Monitor Usage

Every tool invocation passes through writeAudit (implemented near lines 4-16 of server/src/mcp/index.ts), logging the user ID, tool name, client ID (or "native" for static tokens), and source IP to logToolCallAudit. This creates an immutable trail of AI interactions for security review.

Graceful Shutdown and Invalidation

When the MCP add-on state changes, invalidateMcpSessions() forces all clients to reconnect, ensuring they receive an updated tool catalog. The closeMcpSessions() function (bottom of server/src/mcp/index.ts) stops the sweep timer and terminates all transports cleanly during server shutdown.

Code Examples

Initialize a Connection with OAuth

Use this Node.js pattern to establish an MCP session:

import fetch from 'node-fetch';

const token = 'trekoa_abc123…'; // From TREK Settings → MCP → OAuth Clients
const response = await fetch('https://your-trek.example.com/mcp', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Accept': 'application/json, text/event-stream',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'initialize',
    id: 1,
    params: {
      protocolVersion: '2024-11-05',
      capabilities: {},
      clientInfo: { name: 'my-assistant', version: '1.0' },
    },
  }),
});

const json = await response.json();
console.log('MCP Session ID:', response.headers.get('Mcp-Session-Id'));

Reuse an Existing Session

Subsequent calls reuse the session ID to maintain context:

const sessionId = 'c1d2e3f4-…';
await fetch('https://your-trek.example.com/mcp', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Mcp-Session-Id': sessionId,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'tools/call',
    id: 2,
    params: { name: 'list_trips', args: {} },
  }),
});

Handle Static Token Deprecation

When authenticating with a legacy trek_ token, the server prepends STATIC_TOKEN_DEPRECATION_NOTICE to the response result. Your client should surface this warning to the user before displaying tool results, as these tokens are scheduled for removal.

Summary

  • Enable first: The MCP add-on must be active in the database (isAddonEnabled) or the endpoint returns 403.
  • Token flexibility: Support OAuth 2.1 (trekoa_), legacy static (trek_), and JWT tokens via verifyToken.
  • Session aware: Use Mcp-Session-Id headers to persist state, respecting the default limit of 20 sessions per user.
  • Rate guarded: Default 300 req/min limit controlled by MCP_RATE_LIMIT.
  • Scoped access: OAuth scopes filter available tools during registerTools execution.
  • Fully audited: Every tools/call is logged with user ID and client context.

Frequently Asked Questions

What authentication method should I use for production integrations?

OAuth 2.1 access tokens are the recommended method for production. According to the mauriceboe/TREK source code, these tokens provide scoped access via the scopes array and are validated against the MCP URL audience. Legacy static tokens (trek_ prefix) function but trigger a deprecation notice, while JWTs are intended primarily for the native web UI.

How do I handle rate limiting when making consecutive tool calls?

The server enforces a default limit of 300 requests per minute per user via the MCP_RATE_LIMIT environment variable. If you receive a rate-limit error, implement exponential backoff in your client. The rateLimitMap tracks both user and client IDs, so distributing requests across multiple clients for the same user does not bypass the limit.

Why does my client receive a 403 error when calling /mcp?

A 403 response indicates the MCP add-on is disabled. In server/src/mcp/index.ts (lines 18-22), the handler explicitly checks isAddonEnabled(ADDON_IDS.MCP) and rejects the request if the value is false. Run the SQL INSERT INTO addons (id, enabled) VALUES ('mcp', 1) to enable the endpoint.

How are tool permissions determined for OAuth-authenticated clients?

Permissions are derived from the scopes field returned by getUserByAccessToken in server/src/services/oauthService.ts. During session initialization in server/src/mcp/index.ts, these scopes are passed to registerTools, which filters the available tool catalog to only those matching the granted scopes. This ensures AI assistants cannot access travel data outside their OAuth permission grant.

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 →