Terminal49

Terminal49 MCP Server (TypeScript)

Community Terminal49
Updated

Terminal49 Developer Platform - Global Shipment and Container Tracking.

Terminal49 MCP Server (TypeScript)

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.

๐Ÿš€ Quick Deploy to Vercel

Deploy with Vercel

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

๐Ÿ“ฆ What's Included

๐Ÿ› ๏ธ Tools (30 Available)

Tool Description Key Features
search_container Search by container#, BL, booking, or reference Fast fuzzy search
track_container Create tracking request and get container data SCAC autocomplete โœจ
identify_tracking_number Predict a number's type and carrier and check whether it is already tracked Creates nothing
get_container Get detailed container info with flexible data loading Optional custom fields and party roles
get_shipment_details Get shipment routing, BOL, containers, ports Optional custom fields and party roles
get_container_transport_events Get full event timeline for a container Milestone history
get_supported_shipping_lines List 40+ major carriers with SCAC codes Filterable by name/code
get_container_route Get ports in route order with ETAs and the current vessel Premium feature
get_location Get a port, terminal, or metro area FIRMS code, address, time zone
get_vessel Get a vessel's position and, optionally, its projected track to a port Projection is a premium feature
list_shipments List shipments with filters and pagination Fleet-level visibility
list_containers List containers with filters and pagination Returns ResourceLinks โœจ
summarize_containers Count containers grouped by terminal, status, carrier, port, hold, or date Same filters as list_containers
list_parties Find parties by company name, or read one by ID Feeds advanced_filters.parties
list_custom_field_definitions List the account's custom fields, their types, and enum options Needs a signed-in user
list_tracking_requests List tracking requests and statuses Audit and monitoring
get_tracking_request Get one tracking request's status, failure reason, and shipment Follow-up after tracking
list_documents Find documents by file name, reference, or type Never returns extracted data or file links
get_document Get one document, with opt-in extracted data, source email, and download link Untrusted content is labeled
search_docs Search the public Terminal49 documentation Returns links to cite
whoami Identify the credential, its account, the features it can use, and the session's toolsets Explains empty or unauthorized results
set_party_role Attach, replace, or detach a party (such as the drayage carrier) on containers or shipments Destructive write, only on request
set_custom_field Set or clear one of the account's custom fields on containers or shipments Destructive write, only on request
search_importers Find US importers by name, by what they import, or both Trade intelligence, per account
get_importer_profile One importer's totals, monthly series, ports, origins, carriers, and products Trade intelligence, per account
search_commodities Turn a product description or HS prefix into four-digit HS codes Trade intelligence, per account
rank_importers Rank importers by containers for a product, US port, or origin country Trade intelligence, per account
get_trade_trends Time series of containers, TEUs, or estimated value Trade intelligence, per account
get_trade_breakdown Nested totals over one to three dimensions Trade intelligence, per account
get_trade_data_coverage Where trade data starts, the latest and last full month Trade intelligence, per account

๐ŸŽฏ Prompts (3 Workflows)

Prompt Description Use Case
track-shipment Track container with optional carrier Quick tracking start (SCAC autocomplete โœจ)
check-demurrage Analyze demurrage/detention risk LFD calculations
analyze-delays Identify delays and root causes Timeline analysis

The track-shipment prompt's carrier argument supports MCP completions (completion/complete): suggestions are sourced live from get_supported_shipping_lines, filtered by what the user has typed, and returned as SCAC codes.

๐Ÿ“š Resources

  • โœ… terminal49://docs/milestone-glossary - Complete milestone reference guide
  • โœ… terminal49://docs/mcp-query-guidance - Internal tool-routing hints
  • โœ… terminal49://container/{id} - Dynamic container data access (also the target of list_containers ResourceLinks)

๐Ÿงญ Server Instructions

The server advertises MCP instructions (a server-level operating guide) at initialize time: it explains the ocean container/shipment tracking domain, key vocabulary (SCAC, BOL/booking, POL/POD, LFD, demurrage, holds), the read tools vs the single write tool (track_container), and the canonical tool-chaining order.

๐Ÿ”— ResourceLinks (context reduction)

list_containers returns MCP resource_link content blocks โ€” one per container row โ€” that point at the registered terminal49://container/{id} resource. Clients can render the compact list and resolve full per-container detail on demand via resources/read, instead of paying for every container's full payload up front.

๐Ÿ™ˆ Content Audience Annotations

Tool results separate the human-readable answer from agent-steering metadata. The steering block (presentation guidance + suggested follow-up tools, derived from the _response_contract) is tagged with annotations: { audience: ['assistant'] } so spec-aware clients can hide it from end users, while the answer block stays user-visible.

โœจ Current Features (v1.0.0 - Phase 1 & 2.1 Complete)

โœ… Modern McpServer API
  • High-level registerTool(), registerPrompt(), registerResource() patterns
  • 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.6.0
โœ… Production Transport Support
  • HTTP (streamable): POST /api/mcp - stateless, JSON responses
  • SSE was removed from the hosted deployment path in favor of Streamable HTTP transport.
โœ… Sentry MCP Monitoring
  • Optional instrumentation with @sentry/node ^10.55.0
  • Captures MCP connections, tool calls, resources, prompts, performance spans, and errors when SENTRY_DSN is set
  • Tool input/output recording is disabled by default; enable it only after reviewing data handling requirements
โœ… 3 Workflow Prompts
  • track-shipment: Quick container tracking with optional carrier
  • check-demurrage: Demurrage/detention risk analysis
  • analyze-delays: Journey delay identification and root cause
โœ… MCP Spec Adherence
  • Server instructions: server-level operating guide advertised at initialize
  • SCAC code completions: completion/complete on the track-shipment prompt's carrier arg, sourced from get_supported_shipping_lines
  • ResourceLinks: list_containers rows link to the terminal49://container/{id} resource
  • Content audience annotations: steering metadata tagged audience: ['assistant']
๐Ÿšง Deferred (future RFC โ€” needs a stateful transport)
  • Resource subscriptions, progress notifications, server logging, elicitation, and sampling all require a stateful (non-stateless-HTTP) transport and are out of scope here.
  • Shipment ResourceLinks await a dedicated terminal49://shipment/{id} resource template (only the container template is currently registered).

๐Ÿ—๏ธ Architecture

/api/mcp.ts                  # Vercel serverless function (HTTP)
/packages/mcp/
  โ”œโ”€โ”€ src/
  โ”‚   โ”œโ”€โ”€ server.ts          # MCP server (stdio)
  โ”‚   โ”œโ”€โ”€ index.ts           # Stdio entry point
  โ”‚   โ”œโ”€โ”€ tools/             # MCP tools
  โ”‚   โ””โ”€โ”€ resources/         # MCP resources
  โ””โ”€โ”€ package.json

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 process for Claude Desktop (node packages/mcp/dist/index.js after the build in Local Development)

Store submission

The public connector URL is https://mcp.terminal49.com. Store assets andsubmission metadata are checked in at the repository root:

  • chatgpt-app-submission.json โ€” locked ChatGPT listing copy and review cases
  • claude-connector-submission.json โ€” values to enter in Claude's submission portal
  • server.json โ€” official MCP Registry metadata used for Copilot discovery
  • public/store-icons/terminal49-{light,dark}.png โ€” 512ร—512 brand icons

Cline and other clients that read a marketplace install guide from the serversubfolder use packages/mcp/llms-install.md.

Verify the domain for ChatGPT

OpenAI generates a unique domain-verification token during submission. Add thatexact value to the existing MCP Vercel project:

vercel env add OPENAI_APPS_CHALLENGE

After the project redeploys, verify that the well-known endpoint returns onlythe token you pasted:

curl --fail --silent \
  https://mcp.terminal49.com/.well-known/openai-apps-challenge

Do not commit the token. The endpoint returns an empty 404 response whileOPENAI_APPS_CHALLENGE is unset. Submit the connector and the values inchatgpt-app-submission.json through theOpenAI plugin submission flow.

Submit to Claude

Use the Claude Connectors Directory portaland enter the values in claude-connector-submission.json. Upload the lighticon from public/store-icons/terminal49-light.png; the dark variant isavailable for clients that support theme-specific assets.

Publish for Copilot discovery

GitHub's Copilot registry is a curated downstream discovery surface. The rootserver.json is the official MCP Registry entry(io.github.Terminal49/terminal49).

.github/workflows/publish-mcp.ymlpublishes that file to https://registry.modelcontextprotocol.io. It runs whena push to main changes server.json, and a maintainer can start it withworkflow_dispatch on main. The job authenticates with GitHub OIDC(mcp-publisher login github-oidc) and then runs mcp-publisher publish. Theio.github.Terminal49 namespace is authorized for OIDC from this organizationrepository, so the workflow needs no registry secret.

Bump version in server.json for each metadata change. The registry keepspublished versions, and a second publish of the same version is rejected.

๐Ÿ› ๏ธ Local Development

Prerequisites

  • Node.js 24.22.1 or a newer Node 24 release (.tool-versions pins 24.22.1)
  • A Terminal49 API key (create one) for tool calls that reach the API

Setup

@terminal49/mcp is a private workspace. From a clone of this repository, on 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

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.

Run locally

T49_API_TOKEN=YOUR_API_KEY node packages/mcp/dist/index.js

Test the API

Smoke-test initialize, then tools/list:

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

๐ŸŒ Using with Vercel Deployment

Deploy

# Install Vercel CLI
npm i -g vercel

# Deploy to Vercel
vercel

# Set environment variable
vercel env add T49_API_TOKEN

Configure MCP Client

Once deployed, your MCP server will be at: https://your-deployment.vercel.app/api/mcp

For Claude Desktop or other MCP clients:

{
  "mcpServers": {
    "terminal49": {
      "url": "https://your-deployment.vercel.app/api/mcp",
      "headers": {
        "Authorization": "Token your_api_token_here"
      }
    }
  }
}

For Cursor IDE:

{
  "mcp": {
    "servers": {
      "terminal49": {
        "url": "https://your-deployment.vercel.app/api/mcp",
        "headers": {
          "Authorization": "Token your_api_token_here"
        }
      }
    }
  }
}

๐Ÿ”ง API Reference

HTTP Endpoint

URL: POST /api/mcp

Headers:

Authorization: Token your_api_token_here
Content-Type: application/json

Request (JSON-RPC):

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "get_container",
    "arguments": {
      "id": "123e4567-e89b-12d3-a456-426614174000"
    }
  },
  "id": 1
}

Response:

{
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"id\":\"...\",\"container_number\":\"...\", ...}"
      }
    ]
  },
  "id": 1
}

Available Methods

Method Description
initialize Initialize MCP connection
tools/list List available tools
tools/call Execute a tool
resources/list List available resources
resources/read Read a resource

๐Ÿ” Authentication

For Vercel Deployment (HTTP)

Set as environment variable in Vercel dashboard:

T49_API_TOKEN=your_token_here

Or include in request headers:

Authorization: Token your_token_here

Token is the preferred scheme. Bearer your_token_here is also accepted for backward compatibility.

For Local stdio

Set in your environment:

export T49_API_TOKEN=your_token_here

๐Ÿงช Testing

# Run tests
npm test

# Type checking
npm run type-check

# Linting
npm run lint

๐Ÿ“ Environment Variables

Variable Required Default Description
T49_API_TOKEN โœ… Yes - Terminal49 API token
T49_API_BASE_URL No https://api.terminal49.com/v2 API base URL
T49_MCP_TOOLSETS No core,documents,operations,trade Comma-separated toolsets this deployment serves. See Toolsets.
T49_MCP_READ_ONLY No false Serve only tools whose readOnlyHint is true. Accepts true, false, 1 or 0, in any case.
T49_MCP_ALLOW_SHARED_TOKEN_WRITES No false Serve toolsets other than core and trade when callers share T49_API_TOKEN
OPENAI_APPS_CHALLENGE Only for ChatGPT submission - Exact domain-verification token issued by the OpenAI submission portal
NODE_ENV No development Environment
LOG_LEVEL No info Logging level
REDACT_LOGS No true Redact tokens in logs
SENTRY_ENABLED No true Enables or disables Sentry when a DSN is configured
SENTRY_DSN No - Enables Sentry MCP Monitoring when set
SENTRY_ENVIRONMENT No NODE_ENV Sentry environment name
SENTRY_RELEASE No VERCEL_GIT_COMMIT_SHA Sentry release identifier
SENTRY_TRACES_SAMPLE_RATE No 1.0 Trace sampling rate from 0 to 1
SENTRY_MCP_RECORD_INPUTS No false Record MCP tool/prompt inputs in Sentry
SENTRY_MCP_RECORD_OUTPUTS No false Record MCP tool/prompt outputs in Sentry
SENTRY_SEND_DEFAULT_PII No false Enables Sentry default PII behavior

Only enable SENTRY_MCP_RECORD_INPUTS or SENTRY_MCP_RECORD_OUTPUTS after confirming that your Sentry project is approved to store shipment identifiers, references, and customer data.

Credential headers (Authorization, cookies, and any header whose name contains auth, token, secret, cookie, session, api-key, password, or signature) and request cookies are removed from every error and transaction event before it is sent, regardless of SENTRY_SEND_DEFAULT_PII.

Signed URLs, such as the document download link that get_document returns, are replaced with [REDACTED_URL] in logs, Sentry events and PostHog events. This holds even when SENTRY_MCP_RECORD_OUTPUTS is on.

Toolsets

Each tool belongs to one toolset in src/tools/registry.ts: core, documents, operations, documents_write, developer or trade. list_documents and get_document are in documents. set_party_role and set_custom_field are in operations. The trade intelligence tools are in trade. Every other tool today is in core. whoami reports the toolsets a session serves and whether it has write tools.

  • T49_MCP_TOOLSETS lists the toolsets the server allows. stdio and the HTTP gateway both read it. An unknown name, or a value made only of commas, stops stdio with an error that names the variable. HTTP requests fail with a generic 500, and the gateway logs the cause.
  • The X-T49-MCP-Toolsets request header can only narrow that list. The server serves the toolsets that appear in both. An unknown name, or a value made only of commas, returns 400.
  • X-T49-MCP-Read-Only: true or T49_MCP_READ_ONLY=true removes every tool whose readOnlyHint is false, including track_container. Both accept true, false, 1 or 0, in any case. Any other header value returns 400. The header cannot turn off read-only mode that the env turned on.
  • The server instructions name only the tools the session serves.
  • When the gateway uses one shared T49_API_TOKEN, it serves only core and the read-only trade toolset unless T49_MCP_ALLOW_SHARED_TOKEN_WRITES=true.
  • Toolsets are never read from the connector URL. The OAuth resource stays the root origin.

๐Ÿ†š Ruby vs TypeScript

This repo includes two implementations:

Feature Ruby (/mcp) TypeScript (/packages/mcp + /api)
Deployment Railway, Fly.io, Heroku โœ… Vercel (native)
HTTP Transport Rack/Puma โœ… Vercel Serverless
stdio Transport โœ… Yes โœ… Yes
Status Complete Complete
Use Case Standalone servers Vercel deployments

Recommendation: Use TypeScript for Vercel deployments (zero-config, auto-scaling).

๐Ÿšฆ Vercel Configuration

The project includes vercel.json for optimal Vercel deployment:

{
  "functions": {
    "api/mcp.ts": {
      "runtime": "nodejs20.x",
      "maxDuration": 30,
      "memory": 1024
    }
  }
}

Configuration Notes

  • Runtime: Node.js 20.x
  • Max Duration: 30 seconds (adjustable for Pro/Enterprise)
  • Memory: 1024 MB
  • CORS: Enabled for all origins (Access-Control-Allow-Origin: *)

๐Ÿ› Troubleshooting

"T49_API_TOKEN is required" error

Solution: Set environment variable in Vercel dashboard or locally:

vercel env add T49_API_TOKEN

"Method not allowed" error

Solution: Ensure you're using POST method, not GET:

curl -X POST https://your-deployment.vercel.app/api/mcp \
  -H "Authorization: Token your_token" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

CORS errors in browser

Solution: CORS is configured in vercel.json. If issues persist, check Vercel deployment logs:

vercel logs

Timeout errors

Solution: Increase maxDuration in vercel.json (requires Vercel Pro/Enterprise):

{
  "functions": {
    "api/mcp.ts": {
      "maxDuration": 60
    }
  }
}

๐Ÿ“š Documentation

๐Ÿค Contributing

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/my-tool
  3. Make changes in /packages/mcp/src/
  4. Add tests
  5. Run type check: npm run type-check
  6. Submit PR

๐Ÿ“„ License

Copyright 2024 Terminal49. All rights reserved.

๐Ÿ†˜ Support

Built with MCP TypeScript SDK ๐Ÿš€

MCP Server ยท Populars

MCP Server ยท New