Skip to content
Open
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
112 changes: 81 additions & 31 deletions MCP_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,81 @@

## 🚀 Quick Start

### Use with Claude Desktop
`@terminal49/mcp` is a private workspace in this repository. Connect to the hosted server, or build the stdio server from a clone.

Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
### Use the hosted server

The connector URL is `https://mcp.terminal49.com` (Streamable HTTP). Use that root origin, with no extra path. It is the canonical OAuth resource identifier.

**OAuth 2.1 (recommended).** No API key. Add `https://mcp.terminal49.com` to your client. It discovers the authorization server (`https://auth.terminal49.com`) via protected resource metadata, registers itself with Dynamic Client Registration, and opens your browser so you can sign in with your Terminal49 credentials.

In Claude, add Terminal49 from the [Claude Directory](https://claude.ai/directory/connectors/terminal49). For a custom connector, go to **Settings → Connectors → Add custom connector**, enter `Terminal49` as the name, use `https://mcp.terminal49.com`, and leave the advanced OAuth fields empty.

```json
{
"mcpServers": {
"terminal49": {
"command": "npx",
"args": ["-y", "@terminal49/mcp"],
"env": {
"T49_API_TOKEN": "your_token_here"
"url": "https://mcp.terminal49.com"
}
}
}
```

**API key.** For clients that can't run a browser OAuth flow, create a key in the [developer portal](https://app.terminal49.com/developers/api-keys) and pass `Authorization: Token YOUR_API_KEY`. Use the `Token` scheme for API keys. The `Bearer` scheme is used for OAuth access tokens, which OAuth clients obtain automatically.

```json
{
"mcpServers": {
"terminal49": {
"url": "https://mcp.terminal49.com",
"headers": {
"Authorization": "Token YOUR_API_KEY"
}
}
}
}
```

**Get your API token:** https://app.terminal49.com/developers/api-keys
claude.ai and Claude Desktop cannot send a static API-key header. They authenticate through the OAuth connector flow. For an API key on your own machine, run the stdio server in the next section. The local process reads `T49_API_TOKEN` instead of an `Authorization` header.

### Run it from this repository

Use Node.js 24.22.1 or a newer Node 24 release (`.tool-versions` pins `24.22.1`). From a clone:

```bash
git clone https://github.com/Terminal49/API.git
cd API
npm ci
npm run build --workspace @terminal49/sdk
npm run build --workspace @terminal49/mcp
```

The stdio entrypoint is `packages/mcp/dist/index.js`. Set `T49_API_TOKEN` to an API key from the [developer portal](https://app.terminal49.com/developers/api-keys). The process exits if that variable is unset.

### Deploy to Vercel
```bash
T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js
```

Point a local MCP client at that file. Claude Desktop's config is `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows, and `~/.config/Claude/claude_desktop_config.json` on Linux:

```json
{
"mcpServers": {
"terminal49": {
"command": "node",
"args": ["/absolute/path/to/API/packages/mcp/dist/index.js"],
"env": {
"T49_API_TOKEN": "YOUR_API_KEY"
}
}
}
}
```

### Deploy your own copy to Vercel

1. Click "Deploy" button above
2. Add environment variable: `T49_API_TOKEN=your_token_here`
1. Click the Deploy button above
2. Add environment variable: `T49_API_TOKEN=YOUR_API_KEY`
3. Your MCP server will be at: `https://your-deployment.vercel.app/api/mcp`

---
Expand Down Expand Up @@ -128,11 +179,11 @@ Pre-built workflows for common tasks:
│ └── README.md # Full documentation
```

The MCP package consumes published `@terminal49/sdk` by default.
The MCP server depends on the workspace package `@terminal49/sdk`. Build that package before you build `packages/mcp`.

**Stack:**
- [Model Context Protocol SDK](https://modelcontextprotocol.io) v1.29.0
- Terminal49 TypeScript SDK v0.2.0
- Terminal49 TypeScript SDK v0.6.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
Expand All @@ -143,29 +194,28 @@ The MCP package consumes published `@terminal49/sdk` by default.
## 🔧 Development

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

### Local Setup
- Node.js 24.22.1 or a newer Node 24 release
- A Terminal49 API key from the [developer portal](https://app.terminal49.com/developers/api-keys), for tool calls that reach the API

```bash
# Install dependencies
npm install

cd packages/mcp
T49_SDK_SOURCE=published npm run sdk:setup
### Local setup

# Optional: switch to local SDK build for development
# T49_SDK_SOURCE=local npm run sdk:setup
From the repository root, on Node.js 24.22.1 or a newer Node 24 release:

# Run MCP server locally (stdio)
npm run dev
```bash
npm ci
npm run build --workspace @terminal49/sdk
npm run build --workspace @terminal49/mcp
```

# Run tests
npm test
Smoke-test the built stdio entrypoint. This sends `initialize`, then `tools/list`:

# Build
npm run build
```bash
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js
```

### Testing with MCP Inspector
Expand Down Expand Up @@ -209,7 +259,7 @@ vercel deploy --prod
```

**Environment Variables:**
- `T49_API_TOKEN` - Your Terminal49 API token (required)
- `T49_API_TOKEN` - Your Terminal49 API key (required for this self-hosted deploy)
- `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)
Expand All @@ -231,7 +281,7 @@ MIT

- [Terminal49 API Docs](https://docs.terminal49.com)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [Get API Token](https://app.terminal49.com/developers/api-keys)
- [Create an API key](https://app.terminal49.com/developers/api-keys)
- [Full MCP Documentation](packages/mcp/README.md)

---
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This repository holds the public developer docs, the OpenAPI spec, and the clien
| OpenAPI spec (source of truth for the API reference) | [`docs/openapi.json`](docs/openapi.json) | [API reference](https://terminal49.com/docs/api-docs/api-reference/shipments/list-shipments) |
| TypeScript SDK | [`sdks/typescript-sdk/`](sdks/typescript-sdk/) | [`@terminal49/sdk`](https://www.npmjs.com/package/@terminal49/sdk) on npm |
| CLI (`t49`) | [`sdks/typescript-sdk-cli/`](sdks/typescript-sdk-cli/) | [`@terminal49/cli`](https://www.npmjs.com/package/@terminal49/cli) on npm |
| MCP server | [`packages/mcp/`](packages/mcp/) | `@terminal49/mcp`, hosted at `https://mcp.terminal49.com` |
| MCP server | [`packages/mcp/`](packages/mcp/) | Hosted at `https://mcp.terminal49.com`. `@terminal49/mcp` is a private workspace; build it from this repo |
| MCP OAuth gateway | [`api/`](api/) | Vercel functions behind `https://mcp.terminal49.com` |
| Postman collection (generated from the OpenAPI spec) | [`Terminal49-API.postman_collection.json`](Terminal49-API.postman_collection.json) | Import into Postman |

Expand Down Expand Up @@ -58,9 +58,9 @@ t49 track MSCU1234567

### Connect the MCP server

Point your MCP client at `https://mcp.terminal49.com`. Use the root URL, not `/mcp`. The client signs you in with OAuth, so you do not need an API key. In Claude, add Terminal49 from the [Claude Directory](https://claude.ai/directory/connectors/terminal49).
Point your MCP client at `https://mcp.terminal49.com` (Streamable HTTP). Use that root origin, with no extra path. It is the canonical OAuth resource identifier. The client signs you in with OAuth, so you do not need an API key. In Claude, add Terminal49 from the [Claude Directory](https://claude.ai/directory/connectors/terminal49).

For ChatGPT, Claude Code, Cursor, VS Code, and other clients, see the [MCP server docs](https://terminal49.com/docs/mcp/home).
Clients that can't run a browser OAuth flow send `Authorization: Token YOUR_API_KEY`. For ChatGPT, Claude Code, Cursor, VS Code, and other clients, see the [MCP server docs](https://terminal49.com/docs/mcp/home). To run the stdio server on your machine, follow [Run it from this repository](MCP_README.md#run-it-from-this-repository).

## Develop in this repository

Expand Down
65 changes: 32 additions & 33 deletions docs/api-docs/in-depth-guides/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,24 @@ Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` for all proje

### Local stdio (development)

For local development without a hosted server:
`@terminal49/mcp` is a private workspace in this repository. Build it from a clone when you want a local stdio process instead of the hosted server. Use Node.js 24.22.1 or a newer Node 24 release (`.tool-versions` pins `24.22.1`).

```bash
git clone https://github.com/Terminal49/API.git
cd API
npm ci
npm run build --workspace @terminal49/sdk
npm run build --workspace @terminal49/mcp
```

The stdio entrypoint is `packages/mcp/dist/index.js`. It reads `T49_API_TOKEN` and exits if that variable is unset. Create the key in the [developer portal](https://app.terminal49.com/developers/api-keys).

```json
{
"mcpServers": {
"terminal49": {
"command": "node",
"args": ["/path/to/API/packages/mcp/dist/index.js"],
"args": ["/absolute/path/to/API/packages/mcp/dist/index.js"],
"env": {
"T49_API_TOKEN": "YOUR_API_KEY"
}
Expand All @@ -138,24 +148,7 @@ For local development without a hosted server:
}
```

<Warning>
Build the MCP server first:
`cd packages/mcp && npm install && T49_SDK_SOURCE=published npm run sdk:setup && npm run build`
</Warning>

<Accordion title="Contributor mode: switch SDK source">
Use published SDK by default:
```bash
cd packages/mcp
T49_SDK_SOURCE=published npm run sdk:setup
```

Use local SDK build during development:
```bash
cd packages/mcp
T49_SDK_SOURCE=local npm run sdk:setup
```
</Accordion>
The MCP server depends on the workspace package `@terminal49/sdk`. The build above compiles that package first.

---

Expand Down Expand Up @@ -204,10 +197,13 @@ Need test container numbers? See [Test Numbers](/api-docs/useful-info/test-numbe
<Accordion title="Check MCP server logs">
If using the hosted server, check your Terminal49 dashboard for API logs.

If running locally:
If running locally, from the repository root after the build above:
```bash
cd packages/mcp
T49_API_TOKEN=YOUR_API_KEY npm run mcp:stdio 2>&1 | head -20
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js
```
</Accordion>

Expand Down Expand Up @@ -377,16 +373,19 @@ Clients can remove tools per request with the `X-T49-MCP-Toolsets` and `X-T49-MC
## Testing locally

```bash
# Build the MCP server
cd packages/mcp
npm install
npm run build

# Test tools/list
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | T49_API_TOKEN=YOUR_API_KEY npm run mcp:stdio

# Test search_container
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"search_container","arguments":{"query":"CAIU1234567"}},"id":2}' | T49_API_TOKEN=YOUR_API_KEY npm run mcp:stdio
# Build the MCP server from a clone (Node.js 24.22.1 or a newer Node 24 release)
git clone https://github.com/Terminal49/API.git
cd API
npm ci
npm run build --workspace @terminal49/sdk
npm run build --workspace @terminal49/mcp

# initialize, then tools/list, on the built stdio entrypoint
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js

# Test the hosted endpoint
curl -X POST https://mcp.terminal49.com \
Expand Down
54 changes: 27 additions & 27 deletions packages/mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

**Vercel-native** Model Context Protocol server for Terminal49's API, built with TypeScript and the official MCP SDK.

`@terminal49/mcp` is a private workspace in this repository. Connect a client to the hosted server at `https://mcp.terminal49.com` (Streamable HTTP). OAuth 2.1 needs no API key: the client discovers `https://auth.terminal49.com` and opens a browser sign-in. Clients that can't run that flow send `Authorization: Token YOUR_API_KEY`. Use the `Token` scheme for API keys. The `Bearer` scheme is used for OAuth access tokens. A local stdio process reads `T49_API_TOKEN` instead. Build steps are in [Local Development](#local-development).

## 🚀 Quick Deploy to Vercel

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Terminal49/API)
Expand Down Expand Up @@ -84,7 +86,7 @@ Tool results separate the human-readable answer from agent-steering metadata. Th
- Type-safe Zod schemas for all tool inputs
- Cleaner, maintainable code (71% code reduction in HTTP handler)
- **MCP SDK**: @modelcontextprotocol/sdk ^1.29.0
- **Terminal49 SDK**: @terminal49/sdk 0.2.0
- **Terminal49 SDK**: @terminal49/sdk 0.6.0

#### ✅ Production Transport Support
- **HTTP (streamable)**: `POST /api/mcp` - stateless, JSON responses
Expand Down Expand Up @@ -125,11 +127,11 @@ Tool results separate the human-readable answer from agent-steering metadata. Th
└── package.json
```

MCP uses published `@terminal49/sdk` by default, with optional local override for contributors.
The MCP server depends on the workspace package `@terminal49/sdk`. Build that package before you build `packages/mcp`.

**Transport:**
- **HTTP**: Vercel serverless function at `/api/mcp` (for hosted use)
- **stdio**: Local binary for Claude Desktop (run via `npm run mcp:stdio`)
- **stdio**: Local process for Claude Desktop (`node packages/mcp/dist/index.js` after the build in [Local Development](#local-development))

---

Expand Down Expand Up @@ -190,47 +192,45 @@ namespace.

---

<a id="local-development"></a>

## 🛠️ Local Development

### Prerequisites
- Node.js 24.x
- Terminal49 API token ([get yours here](https://app.terminal49.com/developers/api-keys))

### Setup
- Node.js 24.22.1 or a newer Node 24 release (`.tool-versions` pins `24.22.1`)
- A Terminal49 API key ([create one](https://app.terminal49.com/developers/api-keys)) for tool calls that reach the API

```bash
cd packages/mcp
npm install
T49_SDK_SOURCE=published npm run sdk:setup
cp .env.example .env
# Add your T49_API_TOKEN to .env
```
### Setup

Use a local SDK build during MCP development:
`@terminal49/mcp` is a private workspace. From a clone of this repository, on Node.js 24.22.1 or a newer Node 24 release:

```bash
cd packages/mcp
T49_SDK_SOURCE=local npm run sdk:setup
git clone https://github.com/Terminal49/API.git
cd API
npm ci
npm run build --workspace @terminal49/sdk
npm run build --workspace @terminal49/mcp
```

### Run Locally
The MCP server depends on the workspace package `@terminal49/sdk`. Build that package first, as the commands above do. The stdio entrypoint is `packages/mcp/dist/index.js`. It reads `T49_API_TOKEN` and exits if that variable is unset.

```bash
# Stdio mode (for Claude Desktop testing)
npm run mcp:stdio
### Run locally

# Development mode with auto-reload
npm run dev
```bash
T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js
```

### Test the API

```bash
# List tools
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | npm run mcp:stdio
Smoke-test `initialize`, then `tools/list`:

# Get container
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_container","arguments":{"id":"123e4567-e89b-12d3-a456-426614174000"}},"id":2}' | npm run mcp:stdio
```bash
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js
```

---
Expand Down
Loading
Loading