Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions .env.sample
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
# Terminal49 MCP Server - Environment Variables
# Copy this file to .env.local and fill in your credentials

# Terminal49 API Token
# Get your token from: https://app.terminal49.com/settings/api
T49_API_TOKEN=your_api_token_here

# Terminal49 API Base URL (optional)
# Default: https://api.terminal49.com/v2
T49_API_BASE_URL=https://api.terminal49.com/v2
# Terminal49 MCP Server - Environment Variables
# Copy this file to .env.local and fill in your credentials

# Terminal49 API Token
# Get your token from: https://app.terminal49.com/settings/api
T49_API_TOKEN=your_api_token_here

# Terminal49 API Base URL (optional)
# Default: https://api.terminal49.com/v2
T49_API_BASE_URL=https://api.terminal49.com/v2

# Sentry MCP Monitoring (optional)
# Leave SENTRY_DSN unset to disable monitoring.
SENTRY_ENABLED=true
SENTRY_DSN=
# SENTRY_ENVIRONMENT=production
# SENTRY_RELEASE=
SENTRY_TRACES_SAMPLE_RATE=1.0
SENTRY_MCP_RECORD_INPUTS=false
SENTRY_MCP_RECORD_OUTPUTS=false
SENTRY_SEND_DEFAULT_PII=false
3 changes: 3 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,3 +30,6 @@ mcp-ts/test-*.sh
dist/
packages/*/dist/
sdks/*/dist/
# Auto-generated by dotagents — do not commit these files.
agents.lock
.agents/.gitignore
9 changes: 7 additions & 2 deletions MCP_README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -113,7 +113,9 @@ Pre-built workflows for common tasks:
The MCP package consumes published `@terminal49/sdk` by default.

**Stack:**
- [Model Context Protocol SDK](https://modelcontextprotocol.io) v1.22.0
- [Model Context Protocol SDK](https://modelcontextprotocol.io) v1.29.0
- Terminal49 TypeScript SDK v0.2.0
- [Sentry MCP Monitoring](https://docs.sentry.io/ai/monitoring/mcp/) via `@sentry/node` v10.55.0 when `SENTRY_DSN` is configured
- TypeScript
- Vercel Serverless Functions
- Terminal49 JSON:API
Expand All@@ -123,7 +125,7 @@ The MCP package consumes published `@terminal49/sdk` by default.
## 🔧 Development

### Prerequisites
- Node.js 18+
- Node.js 24.x
- Terminal49 API token

### Local Setup
Expand DownExpand Up@@ -191,6 +193,9 @@ vercel deploy --prod
**Environment Variables:**
- `T49_API_TOKEN` - Your Terminal49 API token (required)
- `T49_API_BASE_URL` - Optional (defaults to https://api.terminal49.com)
- `SENTRY_DSN` - Optional; enables Sentry MCP Monitoring
- `SENTRY_TRACES_SAMPLE_RATE` - Optional trace sample rate (`1.0` by default)
- `SENTRY_MCP_RECORD_INPUTS` / `SENTRY_MCP_RECORD_OUTPUTS` - Optional; disabled by default to avoid storing shipment/customer payloads in Sentry

### Claude Desktop (Local)

Expand Down
14 changes: 14 additions & 0 deletions agents.toml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
version = 1
agents = ["claude", "codex", "cursor"]

[trust]
github_orgs = ["getsentry", "greptileai"]


[[skills]]
name = "dotagents"
source = "getsentry/dotagents"

[[skills]]
name = "*"
source = "greptileai/skills"
14 changes: 13 additions & 1 deletion api/mcp.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,11 +5,14 @@
* Endpoint: POST /api/mcp
*/

import '../packages/mcp/src/instrument.js';
import type { IncomingMessage, ServerResponse } from 'node:http';
import { randomUUID, timingSafeEqual } from 'node:crypto';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import * as Sentry from '@sentry/node';
import { createTerminal49McpServer } from '../packages/mcp/src/server.js';
import { captureMcpException } from '../packages/mcp/src/sentry.js';

type RequestLike = {
method?: string;
Expand All@@ -29,7 +32,10 @@ type ResponseLike = {
function setCorsHeaders(res: ResponseLike): void {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader(
'Access-Control-Allow-Headers',
'Content-Type, Authorization, MCP-Protocol-Version, Mcp-Session-Id',
);
}

function getHeaderValue(value: string | string[] | undefined): string | undefined {
Expand DownExpand Up@@ -210,6 +216,7 @@ export default async function handler(req: RequestLike, res: ResponseLike): Prom
let server: McpServer | undefined;
let transport: StreamableHTTPServerTransport | undefined;
let cleanupPromise: Promise<void> | null = null;
let shouldFlushSentry = false;

const runCleanup = (reason: string): Promise<void> => {
if (cleanupPromise) {
Expand DownExpand Up@@ -328,6 +335,8 @@ export default async function handler(req: RequestLike, res: ResponseLike): Prom
logLifecycle('mcp.request.complete', requestId, { reason: 'handled' });
} catch (error) {
const err = error as Error;
captureMcpException(error);
shouldFlushSentry = true;
logLifecycle('mcp.request.error', requestId, {
error: err.name,
message: err.message,
Expand All@@ -346,5 +355,8 @@ export default async function handler(req: RequestLike, res: ResponseLike): Prom
}
} finally {
await runCleanup('finally');
if (shouldFlushSentry || Sentry.isInitialized()) {
await Sentry.flush(2000).catch(() => undefined);
}
}
Comment thread
dodeja marked this conversation as resolved.
}
34 changes: 30 additions & 4 deletions docs/api-docs/in-depth-guides/mcp.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,7 +29,7 @@ Before you begin, make sure you have:
<Card title="API token" icon="key">
A `T49_API_TOKEN` from the [dashboard](https://app.terminal49.com/developers/api-keys)
</Card>
<Card title="Node.js 18+" icon="node-js">
<Card title="Node.js 24.x" icon="node-js">
Required if running the MCP server locally
</Card>
<Card title="MCP client" icon="robot">
Expand All@@ -38,9 +38,10 @@ Before you begin, make sure you have:
</CardGroup>

**Technical Details:**
- **MCP SDK**: `@modelcontextprotocol/sdk ^1.26.0`
- **TypeScript SDK**: `@terminal49/sdk`
- **Runtime**: Node.js 18+
- **MCP SDK**: `@modelcontextprotocol/sdk ^1.29.0`
- **TypeScript SDK**: `@terminal49/sdk 0.2.0`
- **Sentry MCP Monitoring**: `@sentry/node ^10.55.0` (optional)
- **Runtime**: Node.js 24.x

---

Expand All@@ -62,6 +63,24 @@ Claude Desktop and Cursor use the HTTP transport. For hosted production usage, u

---

## Observability

The MCP server supports optional [Sentry MCP Monitoring](https://docs.sentry.io/ai/monitoring/mcp/). Set `SENTRY_DSN` to capture MCP server connections, tool executions, resource access, prompts, performance spans, and errors in Sentry.

```bash
SENTRY_DSN=___PUBLIC_DSN___
SENTRY_TRACES_SAMPLE_RATE=1.0
SENTRY_MCP_RECORD_INPUTS=false
SENTRY_MCP_RECORD_OUTPUTS=false
SENTRY_SEND_DEFAULT_PII=false
```

<Warning>
`SENTRY_MCP_RECORD_INPUTS` and `SENTRY_MCP_RECORD_OUTPUTS` are disabled by default because MCP payloads can include shipment identifiers, references, and customer data. Enable them only if your Sentry project is approved for that data.
</Warning>

---

## Configure your MCP client

### Claude Desktop
Expand DownExpand Up@@ -358,6 +377,13 @@ The `vercel.json` configures the MCP server:
| `T49_API_BASE_URL` | No | Override API URL (default: `https://api.terminal49.com/v2`) |
| `T49_MCP_ALLOWED_HOSTS` | No | Comma-separated host allowlist for request Host validation |
| `T49_MCP_ALLOWED_ORIGINS` | No | Comma-separated origin allowlist for request Origin validation |
| `SENTRY_DSN` | No | Enables Sentry MCP Monitoring |
| `SENTRY_ENVIRONMENT` | No | Sentry environment name; defaults to `NODE_ENV` |
| `SENTRY_RELEASE` | No | Sentry release identifier; defaults to `VERCEL_GIT_COMMIT_SHA` |
| `SENTRY_TRACES_SAMPLE_RATE` | No | Trace sampling rate from `0` to `1`; defaults to `1.0` |
| `SENTRY_MCP_RECORD_INPUTS` | No | Records MCP inputs in Sentry when set to `true`; defaults to `false` |
| `SENTRY_MCP_RECORD_OUTPUTS` | No | Records MCP outputs in Sentry when set to `true`; defaults to `false` |
| `SENTRY_SEND_DEFAULT_PII` | No | Enables Sentry default PII behavior; defaults to `false` |

---

Expand Down
10 changes: 10 additions & 0 deletions docs/mcp/home.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -96,6 +96,16 @@ The same [rate limits](/api-docs/in-depth-guides/rate-limiting) apply to MCP end

---

## Monitoring

Self-hosted deployments can enable [Sentry MCP Monitoring](https://docs.sentry.io/ai/monitoring/mcp/) by setting `SENTRY_DSN`. This captures MCP tool calls, resource reads, prompt usage, performance spans, and errors in Sentry.

<Warning>
Input and output recording is disabled by default. Leave `SENTRY_MCP_RECORD_INPUTS=false` and `SENTRY_MCP_RECORD_OUTPUTS=false` unless your Sentry project is approved to store shipment identifiers, references, and customer data.
</Warning>

---

## Tools reference

### `search_container`
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/AuthenticationError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "AuthenticationError class reference"
description: "Reference for AuthenticationError, thrown by the Terminal49 SDK when the API token is missing or invalid and the request returns HTTP 401."
title: "Class: AuthenticationError"
---

# Class: AuthenticationError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/AuthorizationError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "AuthorizationError class reference"
description: "Reference for AuthorizationError, thrown by the Terminal49 SDK when the API token lacks permission for a request and the response is HTTP 403."
title: "Class: AuthorizationError"
---

# Class: AuthorizationError
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "FeatureNotEnabledError class reference"
description: "Reference for FeatureNotEnabledError, thrown by the Terminal49 SDK when the requested feature requires a plan upgrade and returns HTTP 403."
title: "Class: FeatureNotEnabledError"
---

# Class: FeatureNotEnabledError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/NotFoundError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "NotFoundError class reference"
description: "Reference for NotFoundError, thrown by the Terminal49 SDK when the requested resource does not exist and the API response is HTTP 404."
title: "Class: NotFoundError"
---

# Class: NotFoundError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/RateLimitError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "RateLimitError class reference"
description: "Reference for RateLimitError, thrown by the Terminal49 SDK after exhausting automatic retries when the API rate limit returns HTTP 429."
title: "Class: RateLimitError"
---

# Class: RateLimitError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/Terminal49Client.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Terminal49Client class reference"
description: "API reference for Terminal49Client, the main entry point for the Node.js SDK to create tracking requests and fetch shipments and containers."
title: "Class: Terminal49Client"
---

# Class: Terminal49Client
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/Terminal49Error.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Terminal49Error base class reference"
description: "Reference for Terminal49Error, the base class extended by every typed error the Terminal49 TypeScript SDK throws for API failures."
title: "Class: Terminal49Error"
---

# Class: Terminal49Error
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/UpstreamError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "UpstreamError class reference"
description: "Reference for UpstreamError, thrown by the Terminal49 SDK when a carrier or terminal upstream API is unavailable and returns an HTTP 5xx status."
title: "Class: UpstreamError"
---

# Class: UpstreamError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/classes/ValidationError.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "ValidationError class reference"
description: "Reference for ValidationError, thrown by the Terminal49 SDK when the request payload fails server-side validation with HTTP 400 or 422."
title: "Class: ValidationError"
---

# Class: ValidationError
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/index.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Client module reference"
description: "API reference for the Terminal49 SDK client module: Terminal49Client, configuration interface, and the typed error classes thrown by the SDK."
title: "Client Module"
---

# client
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "AuthInterceptor class reference"
description: "Reference for AuthInterceptor, the SDK request interceptor that attaches the bearer token authorization header to every outbound API request."
title: "Class: AuthInterceptor"
---

# Class: AuthInterceptor
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "ErrorMappingInterceptor class reference"
description: "Reference for ErrorMappingInterceptor, the SDK interceptor that converts API error responses into typed Terminal49Error subclasses on rejection."
title: "Class: ErrorMappingInterceptor"
---

# Class: ErrorMappingInterceptor
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "RetryInterceptor class reference"
description: "Reference for RetryInterceptor, the SDK interceptor that retries failed requests with exponential backoff on rate limit and transient errors."
title: "Class: RetryInterceptor"
---

# Class: RetryInterceptor
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/interceptors/index.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Client interceptors reference"
description: "Reference for SDK interceptors that wrap HTTP requests: authentication header injection, automatic retries, and error response mapping."
title: "client/interceptors"
---

# client/interceptors
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Interceptor type alias reference"
description: "Reference for the Interceptor type alias used by the Terminal49 SDK to compose request and response middleware around HTTP transport calls."
title: "Type Alias: Interceptor"
---

# Type Alias: Interceptor
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Terminal49ClientConfig interface reference"
description: "Reference for Terminal49ClientConfig, the configuration object accepted by Terminal49Client, including API token, base URL, and retry settings."
title: "Interface: Terminal49ClientConfig"
---

# Interface: Terminal49ClientConfig
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/managers/classes/BaseManager.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "BaseManager class reference"
description: "Reference for BaseManager, the shared parent class for SDK resource managers that handles transport, response mapping, and default options."
title: "Class: BaseManager"
---

# Class: BaseManager
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "ContainerManager class reference"
description: "Reference for ContainerManager, the SDK resource manager used to fetch, list, and refresh containers and their transport events from the API."
title: "Class: ContainerManager"
---

# Class: ContainerManager
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "ShipmentManager class reference"
description: "Reference for ShipmentManager, the SDK resource manager used to list, fetch, and update shipments returned by the Terminal49 tracking API."
title: "Class: ShipmentManager"
---

# Class: ShipmentManager
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "ShippingLineManager class reference"
description: "Reference for ShippingLineManager, the SDK resource manager used to list and fetch supported ocean carriers and their SCAC codes from the API."
title: "Class: ShippingLineManager"
---

# Class: ShippingLineManager
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "TrackingRequestManager class reference"
description: "Reference for TrackingRequestManager, the SDK manager used to create, list, and inspect tracking requests for bills of lading and containers."
title: "Class: TrackingRequestManager"
---

# Class: TrackingRequestManager
Expand Down
3 changes: 1 addition & 2 deletions docs/sdk/reference/client/managers/index.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "Client managers reference"
description: "Reference for SDK resource managers that group methods for shipments, containers, tracking requests, shipping lines, and shared base behavior."
title: "client/managers"
---

# client/managers
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
---
title: "CreateTrackingRequestFromInferOptions reference"
description: "Reference for the options interface used to create a tracking request with auto-detected carrier inference from a bill of lading or booking number."
title: "Interface: CreateTrackingRequestFromInferOptions"
---

# Interface: CreateTrackingRequestFromInferOptions
Expand Down
Loading
Loading