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
6 changes: 6 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ T49_API_BASE_URL=http://localhost:3000/v2
# T49_MCP_READ_ONLY=false
# T49_MCP_ALLOW_SHARED_TOKEN_WRITES=false

# --- Write confirmation (see packages/mcp/README.md#confirming-writes) ---
# Signs the confirmation tokens that destructive write tools need. Use at least
# 32 random characters, for example from `openssl rand -hex 32`. Without it,
# those tools refuse to write on HTTP. stdio makes a random one per process.
# T49_MCP_CONFIRMATION_SECRET=

# --- Optional hardening / observability ---
# T49_MCP_ALLOWED_HOSTS=localhost:4000
# Paste the exact token issued by the OpenAI submission portal when testing
Expand Down
12 changes: 11 additions & 1 deletion MCP_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Search for bill of lading 123456789

---

## 🛠️ Available Tools (28)
## 🛠️ Available Tools (30 by default)

| Tool | Description |
|------|-------------|
Expand All @@ -129,6 +129,8 @@ Search for bill of lading 123456789
| `summarize_containers` | Count containers by terminal, status, carrier, port, hold, or date |
| `list_shipments` | Browse all shipments |
| `list_parties` | Find parties by company name or ID |
| `set_party_role` | Attach, replace, or detach a party on up to 50 containers or shipments; asks before a record loses a party |
| `set_custom_field` | Set or clear a custom field on up to 50 containers or shipments; asks before overwriting or clearing a value |
| `list_custom_field_definitions` | List the account's custom fields |
| `list_tracking_requests` | Browse tracking requests |
| `get_tracking_request` | Get one tracking request |
Expand All @@ -144,6 +146,14 @@ Search for bill of lading 123456789
| `get_trade_breakdown` | Nested totals over one to three dimensions (trade intelligence) |
| `get_trade_data_coverage` | Where trade data starts, the latest and last full month (trade intelligence) |

The opt-in `tracking_lifecycle` toolset adds three write tools. A deployment serves them only when `T49_MCP_TOOLSETS` lists `tracking_lifecycle`. `stop_shipment_tracking` and `cancel_tracking_request` return a preview first and change data only after you approve it. A client that declares MCP 2026-07-28 form elicitation shows an `input_required` dialog and asks you to confirm. Any other client gets the preview and a `confirmation_token`, and sends the token back on a second call after you approve. See [Confirming writes](packages/mcp/README.md#confirming-writes).

| Tool | Description |
|------|-------------|
| `stop_shipment_tracking` | Stop updates for a shipment and its containers, after a confirmed preview |
| `resume_shipment_tracking` | Start tracking a stopped shipment again |
| `cancel_tracking_request` | Cancel a pending tracking request, after a confirmed preview. It cannot be undone. |

### 🎯 Workflow Prompts (3)

Pre-built workflows for common tasks:
Expand Down
3 changes: 3 additions & 0 deletions api/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ export default async function handler(
credentialType: resolvedTerminal49Auth.credentialType,
toolsets: toolSelection.toolsets,
readOnly: toolSelection.readOnly,
// Serverless instances share no memory, so HTTP has no fallback
// secret: without this env var, tier C tools refuse to write.
confirmationSecret: process.env.T49_MCP_CONFIRMATION_SECRET,
writeDeadlineAt: deadlineAt,
},
),
Expand Down
4 changes: 2 additions & 2 deletions chatgpt-app-submission.json
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@
"justifications": {
"read_only_justification": "Attaches, replaces, or detaches a party, such as the drayage carrier, on the user's own containers or shipments when the user asks; it changes those records.",
"open_world_justification": "Changes only records in the user's own Terminal49 account; does not publish content or change public or third-party systems.",
"destructive_justification": "Replacing or detaching a party removes that party's assignment from the record. The party, container, and shipment are not deleted, and calling the tool again can restore the assignment."
"destructive_justification": "Replacing or detaching a party removes that party's assignment from the record. A call that would detach a party never changes anything on its first call: it builds a preview of every record that changes, and the user approves it before the change is made, either in a confirmation dialog the client shows (MCP form elicitation) or by approving the preview in the chat so the client can call again with the confirmation token from that preview. A call that only attaches a party runs at once. The party, container, and shipment are not deleted."
}
},
"set_custom_field": {
Expand All @@ -365,7 +365,7 @@
"justifications": {
"read_only_justification": "Sets or clears one of the account's own custom fields on the user's containers or shipments when the user asks; it changes those records.",
"open_world_justification": "Changes only records in the user's own Terminal49 account; does not publish content or change public or third-party systems.",
"destructive_justification": "Setting a field overwrites its previous value, and null clears it. The container or shipment is not deleted, and calling the tool again with the old value restores it."
"destructive_justification": "Setting a field overwrites its previous value, and null clears it. A call that would overwrite or clear a value never changes anything on its first call: it builds a preview of every record that changes, and the user approves it before the change is made, either in a confirmation dialog the client shows (MCP form elicitation) or by approving the preview in the chat so the client can call again with the confirmation token from that preview. A call that only fills empty fields runs at once. The container or shipment is not deleted."
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion claude-connector-submission.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"listing": {
"name": "Terminal49",
"tagline": "Track ocean shipments",
"description": "Terminal49 helps users get live visibility into every ocean shipment and container. Track by container, bill of lading, or booking across all major carriers; find what needs attention, from ETA delays to holds, fees, and last free days; filter and count container worklists; create new tracking requests; and update shipment records. Direct connections to North American ports, terminals, and rail make it the most complete import data available. Where trade intelligence is enabled, it also researches US ocean import markets: importers, products, origins, ports, and carriers.",
"description": "Terminal49 helps users get live visibility into every ocean shipment and container. Track by container, bill of lading, or booking across all major carriers; find what needs attention, from ETA delays to holds, fees, and last free days; filter and count container worklists; create new tracking requests; and update shipment records. Changes that remove or replace data show a preview first and run only after the user confirms. Direct connections to North American ports, terminals, and rail make it the most complete import data available. Where trade intelligence is enabled, it also researches US ocean import markets: importers, products, origins, ports, and carriers.",
"categories": [
"Business"
],
Expand Down Expand Up @@ -67,6 +67,7 @@
"Inspect routes and transport events",
"Check supported shipping lines",
"Create new tracking requests",
"Set parties and custom field values on containers and shipments",
"Research US ocean import markets: importers, products, origin countries, ports, and carriers"
]
}
Expand Down
13 changes: 13 additions & 0 deletions docs/api-docs/in-depth-guides/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,18 @@ printf '%s\n' \
| `search_docs` | Search the public Terminal49 documentation | `query: string`, `limit?` (1-10, default 5) |
| `whoami` | Identify the credential, its account, available features, and the session's toolsets | none |

The `operations` toolset adds `set_party_role` and `set_custom_field` and is in the default toolsets. Send `X-T49-MCP-Toolsets: core,documents,trade` to leave them out. The `tracking_lifecycle` toolset adds `stop_shipment_tracking`, `resume_shipment_tracking` and `cancel_tracking_request`; a deployment serves it only when `T49_MCP_TOOLSETS` lists it.

| Tool | Description | Parameters |
|------|-------------|------------|
| `stop_shipment_tracking` | Stop updates for a shipment and its containers. Asks you to approve a preview first. | `shipment_id: uuid`, `confirmation_token?: string` |
| `resume_shipment_tracking` | Start tracking a stopped shipment again | `shipment_id: uuid` |
| `cancel_tracking_request` | Cancel a pending tracking request. Asks you to approve a preview first. It cannot be undone. | `tracking_request_id: uuid`, `confirmation_token?: string` |
| `set_party_role` | Attach, replace, or detach a party on up to 50 containers or shipments. `add` runs at once; `remove`, and a `replace` that detaches another party, ask you to approve a preview of every record that changes. | `container_ids?` or `shipment_ids?` (1 to 50), `role`, `party_id: uuid`, `action` (`add`, `replace`, or `remove`), `confirmation_token?: string` |
| `set_custom_field` | Set or clear a custom field on up to 50 containers or shipments. Filling empty fields runs at once; overwriting or clearing a value asks you to approve a preview of every record that changes. | `entity` (`container` or `shipment`), `ids` (1 to 50), `api_slug`, `value` (string, number, boolean, string array, or `null` to clear), `confirmation_token?: string` |

See [Write tools](/mcp/home#write-tools) for how you approve a preview, in a client that asks you directly or with a confirmation token.

### Prompts

| Prompt | Description | Arguments |
Expand Down Expand Up @@ -358,6 +370,7 @@ The `vercel.json` configures the MCP server (excerpt):
| `T49_MCP_TOOLSETS` | No | Comma-separated toolsets the server allows; defaults to `core,documents,operations,trade`. An unknown name or a value made only of commas stops stdio and fails HTTP requests |
| `T49_MCP_READ_ONLY` | No | Serves only read-only tools when set to `true` or `1`; defaults to `false` |
| `T49_MCP_ALLOW_SHARED_TOKEN_WRITES` | No | Serves toolsets other than `core` and `trade` when callers share `T49_API_TOKEN`; defaults to `false` |
| `T49_MCP_CONFIRMATION_SECRET` | For write tools over HTTP | Signs the preview approvals that `stop_shipment_tracking`, `cancel_tracking_request`, and a destructive `set_party_role` or `set_custom_field` call need, on both the elicitation and the token channel. Use at least 32 random characters. Without it, those tools change nothing over HTTP. Local stdio makes a random secret when it is unset |
| `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` |
Expand Down
Loading
Loading