Skip to content

feat(sdk)!: sync the SDK with the OpenAPI spec - #433

Merged
dodeja merged 14 commits into
mainfrom
sdk-upto-date
Oct 15, 2026
Merged

dodeja merged 14 commits into
mainfrom
sdk-upto-date

Conversation

@dodeja

@dodeja dodeja commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Why

The SDK fell out of sync with the API. About half of the API had no SDK method, and many methods built URLs by hand, so the compiler could not catch drift.

What changed

  • The spec moves "Edit a container" to PATCH /containers/{id}, the route the live API serves, and adds the missing data.type to the parties bodies. The SDK now covers all 89 spec operations, including documents, email submissions, party roles, per-entity custom fields, and webhook triggers. Calls go through the typed openapi-fetch client.
  • containers.route() now reads route v2 (GET /containers/{id}/map_geojson). The mapped format returns a ContainerRoute summary of ports and the current vessel. containers.map() is deprecated and still returns GeoJSON. The MCP tool get_container_route uses the same summary.
  • vessels.futurePositions and futurePositionsWithCoords send the query parameters that the spec requires. trackContainer({ bookingNumber }) sends booking_number instead of bill_of_lading, and a new billOfLading input covers bills of lading.

Scope

  • Covers the SDK, its CLI, the MCP route tool, and their docs.
  • Leaves out the per-entity custom field lists and custom field options. They stay on untyped requests because the spec omits include=definition and the page parameters. A spec follow-up can move them.
  • The live CLI fixture for containers route needs a capture with a real token.

Tradeoffs

  • Methods that existed before keep their loose payload types, because the CLI forwards parsed JSON. One callerPayload cast holds that trust. New methods take spec-derived types.
  • The MCP route output drops route ID, LOCODE, city, mode, SCAC, and per-leg vessels. Route v2 does not return them, and backfilling them would need extra paid calls. Track geometry stays out of the tool output to keep model context small.

Blast Radius

Breaking for SDK users of the old Route type, the mapped route() shape, the vessel future-position signatures, and trackContainer callers who passed bill of lading numbers as bookingNumber. The commits declare each break. The old /route endpoint returns 404 and the vessel calls could not send required parameters, so those breaks affect no working caller. The MCP server does not call trackContainer, so MCP tracking is unchanged. CLI users of vessels future-positions* must pass the new required options.

Verification

  • Rebased on main, including the validated list filters from feat(sdk): complete verified shipment and container filters #396. vp run check exits 0 and vp run test passes on every commit. At the tip: SDK 334, MCP 400, CLI 31.
  • An adversarial review covered the whole diff in 8 rounds, until a round found nothing new. Three reviewers judged each finding. The last commit fixes every finding that at least two upheld.
  • Request-shape tests pin the method, path, query, and body for each new or migrated call. Mapping tests use the spec's own map_geojson example.
  • I did not test against the live API, because no token was available.

🤖 Generated with Claude Code

@mintlify

mintlify Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
terminal49 🟢 Ready View Preview Oct 14, 2026, 8:55 PM

@vercel

vercel Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
api Ready Ready Preview Oct 14, 2026 9:13pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-14T21:16:21.253716Z 8bc8d7c New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42c97b01e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sdks/typescript-sdk-cli/src/output/table.ts Outdated
Comment thread sdks/typescript-sdk/src/generated/terminal49.ts Outdated
dodeja and others added 13 commits October 14, 2026 14:01
"Edit a container" was documented as PATCH /containers. The live API
answers PATCH /containers/{id} (401 unauthenticated) and 404s on
PATCH /containers, so move the operation under /containers/{id}.
Types are regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the operations the SDK was missing:

- documents, email submissions, and document schemas managers
- container, shipment, and tracking-request custom field update/delete
- container and shipment party roles
- container update, shipping line get, webhook events and trigger,
  party create/update, and custom field list filters

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Webhooks, webhook notifications, vessels, ports, terminals, parties, metro
areas, and custom field resources now call transport.client with literal
spec paths, so the compiler checks path params, query keys, and bodies.
Pagination goes through applyTypedPagination, which clamps page[size].
endpoint() and listQuery() are gone.

Caller-owned payloads on pre-existing methods meet the spec type through
one callerPayload() cast. New methods take spec-derived types: parties
create/update take the request body, and the trigger and list filter
params derive from the spec.

Three routes stay on executeManual because the spec does not match what
the pre-existing signatures send: vessel future positions (spec requires
query params the methods never took) and custom field options list (spec
omits the page params the CLI forwards).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ager

Containers, shipments, and tracking requests call their own literal spec
paths (container_id, shipment_id, tracking_request_id) instead of the
shared string-URL helpers, and entity-subresources.ts is deleted.

Methods added in the previous commit are now strict. updateCustomField
and the tracking request setCustomField take the spec custom_field_value
type. addPartyRole takes { role, partyId } with role derived per route,
so containers accept only pickup_dray_carrier as the spec documents. The
hand-written PartyRoleName export is dropped. containers.update takes the
spec attributes and loses its as-any cast.

The custom_fields list GETs stay on executeManual: include=definition is
absent from the spec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The legacy GET /containers/{id}/route endpoint is gone from the API.
map_geojson is its replacement, so containers.route() now calls it
through the typed client and keeps the "route" name users know.

The raw format is the GeoJSON FeatureCollection. The mapped format is a
new ContainerRoute: ports in ports_sequence order (name, country code,
POL/POD/TS label, coordinates, inbound eta/ata, outbound etd/atd), the
current vessel when it is at sea, and totalPorts. Absent properties map
to null. Track LineStrings stay in the raw format only.

containers.map() becomes a deprecated alias of route(), and
getContainerRoute() keeps delegating to route(). The mapping tests use
a fixture copied from the spec example.

BREAKING CHANGE: the exported Route type and mapRoute are removed. The
mapped result of containers.route() / getContainerRoute() is now
ContainerRoute ({ ports, currentVessel, totalPorts }) instead of Route
({ id, totalLegs, locations, createdAt, updatedAt }). Port code/city,
transport mode, carrier SCAC and per-leg vessels are no longer
available because map_geojson does not return them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… table

GET /vessels/{id}/future_positions requires port_id and
previous_port_id, and future_positions_with_coordinates also requires
latitude and longitude. The SDK methods could not send them, so every
call was malformed. Both now take a params object and use the typed
client. The CLI commands take the matching options.

The CLI table view for t49 containers route lists the route's ports in
order: sequence, POL/POD/TS label, name, country, and arrival and
departure times.

BREAKING CHANGE: vessels.futurePositions(id, options) is now
futurePositions(id, { portId, previousPortId }, options), and
futurePositionsWithCoords(id, options) is now
futurePositionsWithCoords(id, { portId, previousPortId, latitude,
longitude }, options). The getVesselFuturePositions* client methods
change the same way. The CLI commands vessels future-positions and
future-positions-coords now require --port-id and --previous-port-id,
and the coords command also requires --latitude and --longitude.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
get_container_route read the JSON:API document of the retired
GET /containers/{id}/route endpoint, so it could only return NotFound.
It now calls client.containers.route(id, { format: 'mapped' }) and
builds its output from the SDK's ContainerRoute: ports in order with
POL/POD/TS label, country code, ETA/ATA and ETD/ATD, plus the current
vessel's name, IMO, voyage, position, heading, speed and its departure
and arrival ports. Track geometry stays out of the output to keep the
model's context small.

Fields map_geojson cannot source (route_id, port code and city, mode,
carrier SCAC, per-leg vessels) are dropped from the output schema. The
schema now lives beside the formatter and the formatter's return type
is inferred from it, so the two cannot drift.

An empty FeatureCollection returns a NoRouteData soft result. The
feature-gate message points to sales@terminal49.com, as the spec does.
The unused getContainerRouteTool descriptor is removed. Tests and the
live eval use the spec-example fixture; the eval now fails on NotFound
for a known container instead of accepting any soft error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
containers.route() / get_container_route now read
GET /containers/{id}/map_geojson, and the vessel future-position
methods take their required port and coordinate params. Update the SDK
quickstart and methods page (new Vessels section), the MCP tool page
(output fields, NoRouteData, REST equivalent map_geojson), the MCP
guide table, the READMEs and TOOLS_OVERVIEW.

Regenerate docs/sdk/reference and fix docs.json nav: drop the removed
Route page, add ContainerRoute, RoutePort, RouteVessel,
RouteCoordinates and the vessel params pages, plus the pages earlier
commits on this branch added without a nav entry (document managers,
custom field filters, TriggerWebhookParams).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
map() shipped in 0.5.0 returning the map_geojson FeatureCollection in
every format. It now fetches through route() and applies no mapper, so
its output is unchanged and it is marked deprecated in favor of
route(). The CLI map subcommand keeps printing GeoJSON, and its table
view no longer renders the GeoJSON as an empty route table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
containers.route.error.json recorded the 404 page from the removed
/containers/{id}/route endpoint, and no test reads it. The capture
script now saves containers route stdout as containers.route.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The quickstart still described routes as locations with inbound and
outbound legs. It now describes the ordered ports with arrival and
departure times and the current vessel. Regenerated the SDK reference
for the updated containers.map() JSDoc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Container

An adversarial review of this branch upheld these defects, each by at
least two of three independent reviewers:

- Spec: parties create/update bodies lacked `data.type`; the container
  PATCH body lacked `id`/`type`; custom_field_value rejected non-empty
  objects. Types are regenerated.
- SDK: trackContainer sent `bill_of_lading` for booking numbers.
  webhookNotifications.list/get accept `include`, and the custom field
  entityType filter accepts TrackingRequest. containers.map() keeps its
  0.5.0 output for every format.
- MCP: get_container_route returns the vessel position timestamp and
  the departure and arrival port names.
- CLI: the route table shows the current vessel and handles raw
  output; map's README claims match each output mode.
- Tests now assert return values for the new and migrated methods,
  and the route, NoRouteData, and trackContainer edge cases.
- Docs: methods.mdx lists every new method, and the removed Route
  reference page redirects.

BREAKING CHANGE: trackContainer({ bookingNumber }) now sends
request_type "booking_number". Pass bill of lading numbers with the
new billOfLading input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dodeja
dodeja merged commit cc26fc5 into main Oct 15, 2026
5 checks passed
dodeja added a commit that referenced this pull request Oct 16, 2026
The SDK sync in #433 removed the manual endpoint helper that client.me()
used. /me is in the generated paths now, so go through the typed client
like the other single-resource reads.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dodeja added a commit that referenced this pull request Oct 17, 2026
* docs(api): document GET /me, the current-credential endpoint

Adds the Account tag, the /me path, and the credential, credential_account,
credential_user, and feature_availability schemas, with an API reference page
and navigation entry. The endpoint is implemented in Terminal49/t49.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(sdk): add client.me() for the current credential

Calls GET /me and, in mapped format, returns a CurrentCredential with the
account, the signed-in user (or null), the accounts that user can switch to,
and the per-feature availability map. Regenerates the OpenAPI types and the
SDK reference docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(mcp): 1.2.0, add the whoami tool

whoami reports which credential the session uses, the account it is scoped
to (company name, business type, plan, location, tracking slots), the other
accounts a signed-in user can switch to, and a per-feature availability map
with the reason when a feature is unavailable. No inputs; read-only.

Updates the tool enumerations in the test suites and both connector listings.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(mcp): document the whoami tool

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(mcp): expect 14 tools in the protocol smoke checks

The stdio and preview protocol smokes hard-code the tool count. whoami brings
it to 14; both now also require whoami to be listed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(sdk): require complete credential identity resources

* test(docs): verify generated credential account selector

* test(sdk): reject a linked credential user without email

* fix(sdk): require complete selectable-account linkage

* test(sdk): reject omitted selectable account resources

* fix(sdk): call GET /me through the typed openapi-fetch client

The SDK sync in #433 removed the manual endpoint helper that client.me()
used. /me is in the generated paths now, so go through the typed client
like the other single-resource reads.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: regenerate the Postman collection from openapi.json

Generated with openapi-to-postmanv2@6.3.0, the version the
generate_postman workflow pins, so the bot has nothing to add on push.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* chore: Auto-generate Postman collection from openapi.json [skip ci]

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
dodeja added a commit that referenced this pull request Oct 17, 2026
Regenerated once on top of main after the rebase (main's SDK resync in
#433 and the whoami contract in #420 changed the same generated files).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
dodeja added a commit that referenced this pull request Oct 17, 2026
* feat(sdk): export the party role, container update, party, and custom field value types

addPartyRole on containers and shipments, containers.update,
parties.create and parties.update, and the setCustomField methods take
types derived from the spec, but none of those types were exported, so
callers could not name what they pass. Export
ContainerAddPartyRoleParams, ShipmentAddPartyRoleParams,
ContainerUpdateAttributes, PartyAttributes, and CustomFieldValue. The
three managers share CustomFieldValue from the models module instead of
each declaring its own copy.

The containers.update test now sends every attribute the spec
documents for PATCH /containers/{id}, and a type test pins the new
exports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: update documents with documentType and classificationNotes

PATCH /documents/{id} accepts document_type, classification_notes, and
extracted_data_manual. documents.update took documentTypeManual, which
named a field the API never read. It now takes documentType, which
sends document_type, and classificationNotes, which sends
classification_notes and accepts null to clear the notes.

BREAKING CHANGE: documents.update no longer accepts documentTypeManual.
Pass documentType instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: map a tracking request's shipment from tracked_object

The API serializes a tracking request's shipment as the polymorphic
`tracked_object` relationship. The mapper read `shipment` and
`container` relationships that the serializer never sends, so
`mapped.shipment` was always null. It now resolves `tracked_object`:
the included shipment gives the id, bill of lading, and SCAC, and a
shipment that is not included still yields its id.

BREAKING CHANGE: mapped tracking requests no longer have a `container`
key, and `TrackingRequest` no longer declares it. The API never links a
container to a tracking request, so the value was always null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: limit tracking request includes to tracked_object, customer, user

The tracking request serializer exposes only the tracked_object,
customer, and user relationships. `TrackingRequestInclude` offered
`shipment` and `container`, and the API rejects both with 400.

BREAKING CHANGE: `TrackingRequestInclude` is now
'tracked_object' | 'customer' | 'user'. Replace `include: ['shipment']`
with `include: ['tracked_object']`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): keep the server's detail on 401 errors

The API answers 401 both for a bad token and for a valid token that the
action's policy denies, such as resume_tracking on a shipment that is
not stopped. The SDK replaced every 401 message with "Invalid or
missing API token", which hid the real reason. AuthenticationError now
carries the server's detail and falls back to the generic message only
when the response has none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: map containers.get and containers.update in mapped and both formats

containers.get and containers.update passed no mapper, so `mapped`
returned the raw JSON:API document and `both` returned it twice. With
`defaultFormat: 'mapped'`, `id`, `number`, and `events` were undefined.
Both now map through mapContainer, like containers.list. getDemurrage
and getRailMilestones read raw attributes, so they now request the raw
format and keep working under a mapped default.

BREAKING CHANGE: containers.get, containers.update, and getContainer
return a mapped `Container` for format `mapped`, and `{ raw, mapped }`
with a mapped `Container` for format `both`. Request format `raw` to
keep the JSON:API document. The CLI defaults to format `mapped`, so
`t49 containers get` now prints the mapped `Container` instead of the
JSON:API document. Pass `--format raw` to keep the old output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): keep shipment container ids that are not included

mapShipment built `containers` from the included container resources
only. A shipment fetched without `include=containers` still links its
containers by id, but the mapped shipment showed none. The mapper now
reads `relationships.containers.data`, emits `{ id }` for each linked
container, and adds `number` when the container is included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: map vessels and vessel future positions

vessels.get, getByImo, futurePositions, and futurePositionsWithCoords
passed no mapper, so format `mapped` returned the raw JSON:API document
and `both` returned it twice. They now map to a `Vessel` (name, IMO,
MMSI, last position, speed, and heading). The future-position methods
map to a `VesselWithFuturePositions`, which adds the estimated
`positions` (latitude, longitude, heading, timestamp, estimated).

BREAKING CHANGE: the vessel methods return `Vessel` or
`VesselWithFuturePositions` for format `mapped`, and `{ raw, mapped }`
with the mapped model for format `both`. Request format `raw` to keep
the JSON:API document. The CLI defaults to format `mapped`, so
`t49 vessels get`, `get-by-imo`, `future-positions`, and
`future-positions-coords` now print the mapped model instead of the
JSON:API document. Pass `--format raw` to keep the old output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): send stop_tracking and resume_tracking without a body

The spec defines no request body for PATCH /shipments/{id}/stop_tracking
or resume_tracking, and the backend reads only the path id. The SDK sent
a JSON:API document through an `as any` cast. Both calls now send the
path id only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): filter shipping lines by search on the client

GET /shipping_lines has no search parameter. The SDK sent `search`
through an `as any` cast, the server ignored it, and
listShippingLines('hapag') returned every line. The SDK now requests
the full list and keeps the lines whose SCAC, alternative SCACs, name,
or short name contain the search text, ignoring case. The filter
applies to the raw document too, so every format agrees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): search shipping lines whose name columns are null

The spec marks a shipping line's name, short_name, and alternative_scacs
as required strings, but the backing columns are nullable. The search
filter called toLowerCase on each and spread alternative_scacs, so one
line with a null column made listShippingLines(search) throw. The
filter now skips null values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(sdk): list entity custom fields through the typed client

The spec now documents `include` on GET /containers/{id}/custom_fields,
/shipments/{id}/custom_fields, and /tracking_requests/{id}/custom_fields.
The three customFields() methods drop their hand-built executeManual
URLs and call the typed client with `include: 'definition'`. The request
is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: list custom field options through the typed client

The spec now documents that GET /custom_field_definitions/{id}/options
is not paginated: the API ignores page[number] and page[size] and
returns every option. The SDK sent those params through a hand-built
executeManual URL. It now calls the typed client without them.

customFieldOptions.list and listCustomFieldOptions take CallOptions, so
passing `page` or `pageSize` is a type error instead of a silently
ignored option. `t49 custom-field-options list` drops --page,
--page-size, and --all for the same reason.

BREAKING CHANGE: customFieldOptions.list and listCustomFieldOptions take
CallOptions; page and pageSize no longer compile. t49
custom-field-options list drops --page, --page-size, and --all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: use the account routes for custom field definitions

GET and POST /custom_field_definitions are the Terminal49 template
routes. For a customer account, list returned the templates (often an
empty list) instead of the account's definitions, and create answered
401. customFieldDefinitions.list and create now call
/accounts/{account_id}/custom_field_definitions. The API scopes that
route to the authenticated account, so the SDK fills account_id from
the client's `accountId` or sends the placeholder `current`.
`list({ scope: 'templates' })` still lists the templates.

BREAKING CHANGE: customFieldDefinitions.list() returns the account's
definitions instead of the Terminal49 templates. Pass
`scope: 'templates'` for the templates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(sdk): cancel tracking requests

The spec now documents PATCH /tracking_requests/{id}/cancel, the one
operation the SDK did not cover. trackingRequests.cancel(id) cancels a
request that is still pending or awaiting a manifest. The API returns
an empty object, and 422 for any other status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: stop sending page params to unpaginated custom field lists

The spec now documents that GET /custom_fields and the custom field
definition lists are not paginated: the API ignores page[number] and
page[size] and returns every row. customFields.list and
customFieldDefinitions.list no longer send them, matching
customFieldOptions.list. The PaginatedQuery intersections that let the
SDK send undeclared params are gone.

Both methods now take CallOptions instead of ListOptions, so passing
`page` or `pageSize` is a type error instead of a silently ignored
option. CustomFieldDefinitionListOptions extends CallOptions. `t49
custom-fields list` and `t49 custom-field-definitions list` drop
--page, --page-size, and --all, and the live fixture capture script
stops passing --page-size to them.

BREAKING CHANGE: customFields.list, listCustomFields,
customFieldDefinitions.list, and listCustomFieldDefinitions take
CallOptions; page and pageSize no longer compile. t49 custom-fields
list and t49 custom-field-definitions list drop --page, --page-size,
and --all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk,cli)!: require the event for webhook notification examples

GET /webhook_notifications/examples answers 400 without an event, and
the spec marks the parameter required. The SDK typed it optional and
cast any string past the generated enum, so examples() with no event
always threw ValidationError: Bad Request.

webhookNotifications.examples and getWebhookNotificationExamples now
take a required WebhookEvent, exported from the generated paths, and
pass it through without a cast. The CLI calls examples(), so
webhook-notifications examples makes --event a required option typed
as WebhookEvent. The CLI README documents it, and the live fixture
capture script gets its 400 envelope from an unknown event instead of
a missing one, which the CLI now rejects before calling the API.

BREAKING CHANGE: webhookNotifications.examples(event, options?) and
getWebhookNotificationExamples(event, options?) require event, typed as
the exported WebhookEvent union. Calls without an event, or with a
string outside the documented events, no longer compile. The CLI
command webhook-notifications examples now requires --event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(sdk): cover a container with no POD terminal

The generated container type accepts relationships.pod_terminal with
data: null, and containers.get maps such a container with null
podTerminal and destinationTerminal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: type tracking request writes from the spec

trackingRequests.update and updateTrackingRequest took any attributes
and cast the body to any, so `{ ref_number: 'X' }` compiled and the API
answered 200 without changing anything. Both now take
TrackingRequestUpdateAttributes, derived from PATCH /tracking_requests/{id}
(`ref_numbers` only). create and inferNumber also send bodies typed from
their operations instead of casting to any. The wire payloads are
unchanged.

BREAKING CHANGE: trackingRequests.update and updateTrackingRequest accept
only `{ ref_numbers?: string[] }`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: infer Transport.execute's result from the openapi-fetch call

execute returned `any` by default, so the typed mappers
(mapContainerRoute, and mapVessel and mapVesselFuturePositions from
earlier in this series) were never checked against their endpoint:
handing containers.route() the vessel mapper still compiled. execute
now returns the data type of the call's success branch, so each mapper
is checked against its route's 200 response, and a bodyless success
such as a 204 DELETE resolves to undefined. The redundant
`ShippingLineResource` annotation in shippingLines.list() goes away
for the same reason.

BREAKING CHANGE: Transport.execute no longer takes a result type
argument; it infers the result from the request it runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk)!: type shipment updates from the spec

shipments.update and updateShipment took any attributes and cast the
body to any, so `{ tags: 'a,b' }` or `{ ref_number: 'X' }` compiled and
went out unchecked. Both now take ShipmentUpdateAttributes, derived
from PATCH /shipments/{id} (`ref_numbers` and `tags`, each a string
list), the same way tracking request updates are typed. The wire
payload is unchanged.

BREAKING CHANGE: shipments.update and updateShipment accept only
`{ ref_numbers?: string[]; tags?: string[] }`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: update the SDK method list for mapped results and corrected routes

methods.mdx now says what `mapped` returns for containers.get and the
vessel methods, lists the includes a tracking request accepts and where
its mapped shipment comes from, and adds trackingRequests.cancel. It
names the account routes that customFieldDefinitions.list and create
call, notes that the custom field lists are not paginated, describes
the client-side shippingLines search, marks the webhook notification
examples event as required, and documents documents.update with
documentType and classificationNotes. Methods without mapping return
the JSON:API response unchanged in `mapped` format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: describe the 401 AuthenticationError the SDK now throws

AuthenticationError covers every HTTP 401, including an action the API
refuses for the key, and its message carries the API's detail.
AuthorizationError is the HTTP 403 case. The example logs the message
instead of assuming the key is invalid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(sdk): send the caller's numberType from createTrackingRequestFromInfer

createFromInfer resolved the type as the inferred number_type first and
the caller's numberType second. infer_number always returns a
number_type, so the option was never used. A booking number that infer
classified as bill_of_lading was submitted as bill_of_lading, and a
retry with numberType after an unrecognized inferred type failed the
same way. The caller's numberType now wins over the inferred value.
A numberType that is not container, bill_of_lading, booking_number, or
booking throws a ValidationError that names it, before any request is
sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(cli): list custom field definition templates with --templates

customFieldDefinitions.list() now reads the account definitions route
by default and takes scope: 'templates' for the top-level template
route, but custom-field-definitions list had no way to pass the scope.
That left the CLI unable to list the templates whose ids
custom-field-definitions create needs as template_id. list --templates
reads the templates, and list without it still reads the account
definitions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: list client.me() in the SDK method reference

The method reference says it lists every SDK method, but it left out
client.me(), which describes the credential, its account, and the
gated features it can use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: Auto-generate Postman collection from openapi.json [skip ci]

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
dodeja added a commit that referenced this pull request Oct 17, 2026
* fix(cli): read fixture ids from the list row array

List JSON prints the mapped rows as the data array, with no items key,
so every read_id "data.items.0.*" returned an empty string and the
capture script then ran "shipments get ''". Read data.0.* instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli)!: print one list shape that keeps included in raw and both

`--format raw` on containers, shipments, and tracking-requests list kept
only `body.data`, which dropped `included`. shipping-lines, webhooks, and
webhook-notifications list printed the whole body with no pagination, so
the raw shape depended on the command.

Every list command now goes through listOutput: raw prints the whole
JSON:API document, mapped prints the rows, and both pairs them. The
effective format comes from createClient, so list output no longer
guesses the format from the result's shape. The seven copies of
listDataFrom and paginationFrom are gone.

BREAKING CHANGE: list commands with --format raw print the full JSON:API
document under data, so the rows move from data to data.data (for
example, jq '.data.data[]' instead of jq '.data[]'). With --format both,
data.raw holds the full document instead of its row array. This affects
containers, shipments, tracking-requests, parties, custom-fields,
custom-field-definitions, and custom-field-options list, which printed
only the rows before. shipping-lines, webhooks, and
webhook-notifications list already printed the whole document in raw.

BREAKING CHANGE: webhooks list and webhook-notifications list print the
row array under data in the default mapped format, with links and meta
under pagination. Before, data held the whole JSON:API document, so
jq '.data.data[]' becomes jq '.data[]' and --fields data.id becomes
--fields id. With --format both, data.mapped holds the row array instead
of the whole document, so jq '.data.mapped.data[]' becomes
jq '.data.mapped[]'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): advertise --all only on lists that can iterate

parties list advertised --all, --max-pages, and --max-rows, then exited
2 with "--all is not supported for this command".

defineList now registers a list's paging flags and its action together:
--page and --page-size only when the API pages the list, and --all only
when the command can iterate. parties list iterates its JSON:API pages
through links.next. The webhooks list help names its page values <n>
like the other lists. The README says which lists page, which iterate,
and which the API returns whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): describe shipping-lines --search as a client-side filter

The SDK now filters shipping lines itself because GET /shipping_lines has
no search parameter. The --search help text said it searched "by name or
code", which hid that the CLI fetches every line and that alternative
SCACs and short names also match. The help text and README now say what
matches, and a test pins that the CLI sends no query and prints only the
matching lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): print vessel future positions as a table

`vessels future-positions --table` and `future-positions-coords --table`
printed one row with the vessel id, type, and name and none of the
positions, because the table renderer had no columns for these commands.

They now print the vessel name and IMO, then one row per position with
timestamp, latitude, longitude, heading, and estimated. The renderer reads
the mapped vessel, the `{ raw, mapped }` pair, and the raw document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): show the columns that identify webhooks, custom fields, and options

Table output fell back to guessed columns for these commands, so webhook
tables showed only ID and Type, custom-field tables lacked the slug and
value, and option tables lacked the label. shipments list printed a Status
column that the mapped shipment never has.

Webhook tables now show URL, active, and the event count. Custom-field
tables show slug and value, plus name and data type when the definition
is included. Option tables show label, value, and position. shipments list
swaps Status for the POD and its ETA. A `{ raw, mapped }` pair now renders
its mapped half even when that half is a JSON:API document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): honor --table and --fields in config and commands

The config subcommands and `t49 commands` built their formatter from
--json and --compact only, so --table still printed a JSON envelope and
--fields was ignored. They now pass every global output flag to the
formatter. config output renders as key and value rows, and `commands`
renders one row per command group with its subcommands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli)!: parse shipments update --attr values whole and as arrays

`--attr key=value` split on every `=` and kept the first two parts, so
`user_provided_mbl_number=a=b` sent "a". Every value was a string, so
`--attr tags=x` sent a string where PATCH /shipments/{id} expects an array.
Malformed pairs were silently dropped.

Each pair now splits on its first `=`. Values that start with `[`, `{`,
or `"` parse as JSON, and so do true, false, and null on keys other
than ref_numbers and tags. Other values stay strings so long numeric
references keep every digit. ref_numbers and tags are arrays of
strings: plain and repeated values collect into the array, a bare true,
false, or null is a string element, and a JSON value that is not a
string or an array of strings is a usage error. A pair without a key or
with invalid JSON is also a usage error before any request.

BREAKING CHANGE: shipments update --attr sends different values for the
same input. A value after the first `=` is kept whole, so
`--attr key=a=b` sends "a=b" instead of "a". Values starting with `[`,
`{`, or `"`, and true, false, or null on keys other than ref_numbers and
tags, are sent as JSON instead of strings. ref_numbers and tags are
always sent as arrays of strings. A pair without `=`, with an empty key,
or with invalid JSON now exits 2 with a USAGE_ERROR instead of being
dropped. Quote a value as JSON, for example --attr 'key="true"', to send
it as a string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): accept --max-retries 0 and keep JSON stderr pure

--max-retries used the positive-integer parser, so `--max-retries 0`
exited 2 even though config maxRetries accepts 0 and the SDK treats it as
"no retries". It now takes any non-negative integer.

Usage errors also wrote Commander's "(run --help for usage)" line before
the JSON error, so JSON.parse(stderr) failed. The hint now comes from
printError and only in human-readable output.

The entry point's parse and error handling moved from bin/t49.ts into
main() in src/index.ts, and errors set process.exitCode instead of calling
process.exit(), so piped output flushes and tests run the shipped path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): name the set-custom-field argument api-slug and resolve definition ids

`shipments set-custom-field <id> <field-id>` and the containers variant
sent the second argument as `api_slug`. Passing a definition id, which the
name invited, returned 404.

The argument is now `<api-slug>` in help, `t49 commands`, and the README.
A UUID is resolved to its definition's api_slug with one extra request;
the backend strips everything but letters, digits, and `_` from api_slugs,
so a UUID cannot be a slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cli): pin the webhook-notifications examples request and usage error

webhook-notifications examples requires --event, but no CLI test
covered the option. The new tests assert the exact USAGE_ERROR JSON
envelope with exit status 2 when --event is missing, and the GET
request with its event query when it is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): fill raw list table columns from the resource attributes

`--table --format raw` on containers, shipments, tracking-requests, and
shipping-lines list printed the ID column and left every other column
blank. The columns read only the mapped camelCase paths, and a raw row
keeps its values under `attributes` in snake_case. Each column now falls
back to its raw attribute, as the custom field columns already do. The
POD Terminal column stays blank in raw, because a raw container row
carries only the terminal's relationship id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cli): cover the vessel future-position params and the route table

vessels future-positions must send --port-id and --previous-port-id as
port_id and previous_port_id, and future-positions-coords must reject
an empty --latitude before it sends a request. containers route
--table must print the ports and the current vessel that the SDK maps
from the GET /containers/{id}/map_geojson fixture. No CLI test covered
any of the three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: describe the mapped container and vessel output in the CLI README

The CLI defaults to format mapped, and containers get and the vessel
commands now print the SDK's mapped model, so JSON output reads
data.number instead of data.data.attributes.number. The README says
which commands changed, how to keep the JSON:API document with
--format raw, and what containers route prints in each format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cli): replay the live fixtures through the current list and error output

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli)!: shape single-result output in the resolved format

track, tracking-requests create, infer, and create-from-infer, containers
demurrage and rail, and search shaped their output from the --format
flag alone. Without --format they ignored config defaultFormat, and the
tracking request commands printed the raw JSON:API document. They now
use the resolved format: --format, then config defaultFormat, then
mapped.

BREAKING CHANGE: without --format or a config defaultFormat, t49 track
and t49 tracking-requests create, infer, and create-from-infer print the
mapped result instead of the raw JSON:API document. Pass --format raw to
keep the old output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot mentioned this pull request Oct 17, 2026
dodeja added a commit that referenced this pull request Oct 17, 2026
* test(mcp): run get_container_route through the real SDK client

The tool tests stub the SDK, so nothing checked that the summary the
tool builds matches what containers.route() returns from
GET /containers/{id}/map_geojson. A test now gives the real SDK client
the map_geojson fixture and asserts the request path and the route
summary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp): stop sending the container owner prefix as track_container's SCAC

A container prefix (MSKU, ZZQU) names the equipment owner, not the
carrier. track_container passed it to createTrackingRequestFromInfer as
an explicit scac, which overrode the carrier that infer_number selected
(MSKU4330011 went out as MSKU instead of MAEU) and sent an invalid SCAC
when infer had no prediction (ZZQU4330056 got a 422 reported as an
invalid identifier).

Only a caller-supplied scac now reaches the API. When neither inference
nor the caller provides a carrier or number type, the tool returns a
TrackContainerInputError that tells the model what to pass, instead of
the old hint that formatToolError replaced with a generic message. The
pending and 404 results report the SCAC the API recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp)!: limit list_tracking_requests status to the API's filter values

The status enum offered succeeded, which the API does not recognize. Its
filter[status] handler treats anything other than created, failed, or
cancelled as pending, so status: succeeded silently returned pending
requests. A tracking request that succeeded has status created.

The enum is now pending, created, failed, and cancelled, typed against
the generated filter[status] parameter so it fails to compile if the
spec adds or drops a value. The descriptions say that created means the
request succeeded and that each item's shipment.id (mapped from
tracked_object) feeds get_shipment_details.

BREAKING CHANGE: list_tracking_requests rejects status: 'succeeded'.
Pass 'created' for requests that succeeded. The new 'cancelled' value
selects cancelled requests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp)!: report why track_container could not create a request

formatToolError turned every 422 from POST /tracking_requests into
"Tracking identifier X is invalid". The live run hit the account's
tracking request limit and told the user the number was invalid, and
the backend's duplicate, tracking_slot_limit_reached, and
insufficient_credits 422s were reported the same way.

track_container now parses the 422 body and classifies it by code
before pointer. A duplicate returns a non-error result with the
existing tracking_request id and shipment_id. Limit and credit refusals
pass the API's message through. Errors that point at request_number,
request_type, number, or scac with an identifier code (blank,
invalid_format, not_recognized, and the like), and infer_number's bare
detail with no code or pointer, say the identifier is invalid. Any
other refusal, such as container_number_tracking_disabled,
no_container_request_type_support, or a party that does not belong to
the account, passes its detail through.

search_container also dropped tracking_request search hits, so a number
with a pending request was tracked again and refused as a duplicate. It
now returns tracking_requests, with shipment_id on a request whose
tracking was stopped, and track_container answers with a request that is still in
progress (pending or awaiting_manifest, the statuses the API treats as
blocking) instead of posting, and reports its real status. The API
scopes its duplicate check by carrier, so when the caller names a SCAC,
an in-progress request under another SCAC (or with none yet) is ignored
and the new request is sent.

BREAKING CHANGE: search_container's output gains a required
tracking_requests array, and total_results now counts containers,
shipments, and tracking requests. track_container returns a result with
tracking_request_created: false and source 'duplicate' or
'search_match' for a number that is already tracked or has an
in-progress request, where it used to fail with an error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp): give the track-shipment prompt a check-digit-valid example

track_container rejects CAIU1234567 on the ISO 6346 check digit, so the
prompt's example number now uses MSKU4330011, which passes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: describe the MCP tracking request statuses and track_container

list_tracking_requests accepts pending, created, failed, or cancelled.
created matches requests that succeeded and are still tracking; a
stopped request has status tracking_stopped, which the filter cannot
select. track_container needs scac when the carrier cannot be inferred
and never uses the container prefix as the SCAC. It returns an existing
container or in-progress (pending or awaiting_manifest) request with
tracking_request_created false before it creates one.

The examples use MSKU4330011, which passes the ISO 6346 check digit;
CAIU1234567 fails it and never reaches the API. The overview examples
drop the request_type argument the tool does not accept and use number
instead of the deprecated containerNumber alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: list the real list_tracking_requests parameters in the MCP guide

The MCP guide's tool table listed filters and request_type, which the
strict input schema rejects, and left out request_number and scac.
Match the server.ts schema and docs/mcp/home.mdx.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: list the real list_shipments and list_containers inputs

The MCP guide and TOOLS_OVERVIEW still showed status, port, carrier,
updated_after, and a comma-separated include string. Both tools use
strict input schemas, so those calls fail validation. The guide table
now lists the inputs the schemas accept, and the examples use
voyage_status, current_status, pod_code, shipping_line_scac,
pickup_lfd, and an include array.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: show search_container's tracking_requests and snake_case fields

The example response used camelCase keys the tool never emits and had
no tracking_requests array. Show the real snake_case output, add
pending and failed tracking requests, say that only a request whose
tracking was stopped carries shipment_id, and say total_results counts
all three result types. TOOLS_OVERVIEW.md's Returns line says the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: list summarize_containers, list_parties, search_docs, and whoami in the MCP guides

The MCP guide's tools table, TOOLS_OVERVIEW.md, and the package README
left out tools the server registers. Add summarize_containers,
list_parties, and search_docs to each, add whoami to the package
README, which now counts all 14 tools, and add a search_docs section
to the MCP tools reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp): return the created request's id and number type from track_container

A new request was described by the submitted number and the locally
inferred type, without the request's id. Every path that creates a
request now returns tracking_request with the id, request_number,
number_type, and scac the API sent back, falling back to the submitted
values for an attribute the response leaves out. That includes the
path that also returns the linked container's details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp): create a tracking request when the matching container is no longer tracked

track_container returned early on any container search hit for the
number. Search returns every container with a shipment, including one
whose shipment stopped tracking, and the API accepts a new request for
such a container because container numbers are reused on later voyages.
It also treated a lone search hit with a different number as a match,
although search matches substrings and reference numbers.

track_container now checks for an in-progress tracking request first.
It then reads every container whose number matches exactly, in search
order, because a reused number can match a stopped container and a
tracked one. It returns the first whose shipment has no
line_tracking_stopped_at. Otherwise it sends the request
and lets the API's duplicate check decide. get_container's shipment
summary now includes line_tracking_stopped_at.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: say track_container returns only a container that is still tracked

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: show the real get_container and transport events output in the MCP guide

The get_container and get_container_transport_events examples showed
camelCase fields that the tools never return. Both examples now hold
actual tool output with snake_case keys, and track_container says that
an existing container comes back in the get_container shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: use valid shipment filters in the MCP guide's SDK example

The example passed status and carrier to client.shipments.list, which
the SDK rejects before sending a request, and said the call was not
available through MCP although list_shipments is an MCP tool. It now
filters by voyage_status and pod_code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(mcp): say track_container returns container details only for a tracked container

The tool description promised detailed container information after it
creates a tracking request. The create response carries the request,
not a container, so a new request returns its id, request_number,
number_type, and scac. The description now says container details come
back only for a container that is still being tracked, and tells the
caller to poll list_tracking_requests and then use search_container or
get_shipment_details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: show the container number and pickup fields the SDK returns in the MCP guide

The Raw vs Mapped example used attributes.container_number and a mapped
containerNumber and availableForPickup at the top level. The API
serializes the container number as number, and mapContainer returns
number and nests availableForPickup under location.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
dodeja pushed a commit that referenced this pull request Oct 17, 2026
Lets an agent assign a party (such as the drayage carrier) or set an account
custom field on up to 50 containers or shipments, reporting per-record
updated, unchanged, failed and not_attempted results.

The tools call the SDK methods #433 and #439 added (partyRoles,
addPartyRole, removePartyRole, setCustomField, deleteCustomField). The
party_role list is parsed in the tool, since the SDK returns it unmapped.

set_custom_field accepts an array of option values for multi-select fields
and treats the same options in another order as unchanged. A call stops
starting new records after 20s, under the 30s /mcp maxDuration, and lists
the records it did not reach in not_attempted.

The server now lists 16 tools; the protocol smoke scripts and tests expect
that count and the two new names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

2 active (1 outdated) deployments
Preview — 67750608 Deployed Oct 14, 2026 by vercel[bot]
staging - docs — 5f53ec18 Deployed Oct 14, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant