Skip to content

feat(mcp): add reference number tools - #452

Open
dodeja wants to merge 38 commits into
mcp-v2/04-write-kitfrom
mcp-v2/05-refs-parties
Open

dodeja wants to merge 38 commits into
mcp-v2/04-write-kitfrom
mcp-v2/05-refs-parties

Conversation

@dodeja

@dodeja dodeja commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Why

Tagging records with PO numbers is the most common account edit.

What changed

add_reference_numbers (tier A, union with read-back) and remove_reference_numbers (tier C, confirmed preview) on containers, shipments and tracking requests. list_parties matches a search against every name a party goes by.

Both reference number tools are in a new opt-in reference_numbers toolset, not in the default toolsets. A deployment serves them only when T49_MCP_TOOLSETS lists reference_numbers, so merging this PR adds no write tool to the default tools/list, which stays at 30 tools.

This PR no longer adds assign_party and unassign_party. Main's set_party_role, confirmed through the write kit in #451, covers both: add attaches a party at once, and remove detaches it after the user approves a preview, on up to 50 records per call. The two single record tools, their tests, fixtures, eval case, manifest entries, docs and the helpers only they used are gone. remove_reference_numbers declares confirms: 'always'.

Verification

  • vp run check, vp run test (1,012 MCP tests) and npm run agent-verify pass at the head.
  • The reference number tools are called through the MCP client in packages/mcp/src/reference-numbers.transport.test.ts.

🤖 Generated with Claude Code

https://claude.ai/code/session_01V8cPhgia7FZpMP7q5BJ5nw

dodeja and others added 11 commits October 17, 2026 06:16
add_reference_numbers adds reference numbers, such as PO numbers, to a
container, shipment or tracking request. It is tier A in the operations
toolset.

The API replaces the whole ref_numbers list on every PATCH. The tool reads
the current list, sends the union of that list and the new numbers, and
reads the record back. The result has the list before (previous), the
list after (ref_numbers), and which numbers were added or already there.
When every number is already on the record it returns already_present and
makes no PATCH, so a repeated call changes nothing.

The API has no ETag, so a race is reported, not prevented.
concurrent_change_detected is true when the list read back differs from
the list sent. If the read-back fails after the write, the result still
says added, with the sent list, concurrent_change_detected null and a
note. A 422 returns noop. A 404 names the record type and id.

The PATCH replaces the list, so a list the tool cannot read must not read
as empty. A list with an entry that is not a string, or no list at all,
returns unreadable_reference_numbers and sends nothing. Null entries hold
no number and are left out.

Matching trims spaces on both sides. A number on the record with
surrounding spaces counts as already there, so the tool never adds a
near-duplicate of it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
remove_reference_numbers removes reference numbers from a container,
shipment or tracking request. It is tier C in the operations toolset,
because searches, filters and integrations that use a removed number stop
finding the record.

Called without a token, it reads the record and returns a preview with
the list now, the list after, the numbers it would remove and the numbers
that are not on the record. The token is bound to the whole current list,
so a list that changed after the preview returns stale_preview. When none
of the numbers are on the record it returns not_present and no token.

Called with a valid token, it sends the difference and reads the record
back, like add_reference_numbers, and reports
concurrent_change_detected. A 422 returns noop. The result names
add_reference_numbers as the undo.

Matching trims spaces on both sides, as in add_reference_numbers. Each
number to remove can be up to 1000 characters, not 64, so a long number
added another way can still be removed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
list_parties now loads parties through loadParties and ranks names
through rankParties and matchRank, all exported, so assign_party can find
a party by name the same way. Each party row is parsed on its own, so one
malformed row is skipped and the rest of the page is kept. getParty is
exported too. The tool's output does not change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
list_parties now matches a search on a party's company name, name or
nickname, and ranks each party by its best matching name. A party with
only a nickname, or with a blank company name, is now listed under its
next name. Before, the tool skipped such a party. The display name is
unchanged: the company name, else the name, else the nickname.
loadParties keeps every name of each party, so assign_party can match a
name the same way.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
assign_party links a party, such as a customer, shipper or dray carrier,
to a container or shipment in a role. It is tier A in the operations
toolset. A container accepts only pickup_dray_carrier, so any other role
on a container is refused before any request.

The caller passes party_id, or party_name to match one party exactly by
its company name, name or nickname, ignoring case and punctuation, the
same names list_parties searches. Two exact
matches return ambiguous_party, and no match returns party_not_found;
both list candidates and change nothing. With create_party_if_missing the
tool creates the party, but only when no party has that name. If
Terminal49 refuses the create with 422, the tool looks the name up again
and reuses the party another call created. If it still finds none, the
result says the party probably exists and asks for party_id.

Names are matched against at most the first 1000 parties. When the
account has more, the tool neither uses nor creates a party by name. It
returns party_lookup_incomplete and asks for party_id. Because any of a
party's names counts, a name the account already uses is never created
again.

The tool reads the record's party roles first. When the party already
holds the role it returns already_present and makes no write, so a
repeated call changes nothing. A 422 on the assignment reads the roles
again and returns already_present if the role now exists, else noop.
When the tool created the party and the assignment then fails, the
result carries party_created true and created_party, so the caller knows
the party now exists. That result is noop after a 422, rate_limited after
a 429, and party_not_linked after any other failure. When another call
linked the created party in the same role first, the result is
already_present, still with party_created true and created_party. The
result lists other parties in the same role, and names unassign_party as
the undo.

Creating a party is a second write, on the account and not the record.
The tool emits a separate audit event for it, with entity type party, the
new party id and outcome created, so the party stays traceable whatever
the assignment's outcome. The audit schema gains the party entity type.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
unassign_party removes one party role from a container or shipment. It
is tier C in the operations toolset. Only the link is removed; the party
and its other assignments stay. To replace a party, a caller unassigns
the old one and then calls assign_party.

Called without a token, it reads the record's party roles and returns a
preview with the role and the party, plus a token bound to the role's
id, role name and party. A role id that is not on the record returns
not_assigned with the current roles and no token. Called with a valid
token, it deletes the role. A 404 on the delete means another call
removed it first, so the result is not_assigned. The result names
assign_party as the undo.

The server instructions now tell the model to read party roles with
get_container or get_shipment_details before unassign_party. The
sentence is left out when those tools are not served.

The fake API in tests now answers a 204 with no body, as a real server
does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ools

contracts.test.ts now covers add_reference_numbers,
remove_reference_numbers, assign_party and unassign_party. Each case
calls the executor with a stubbed SDK client and checks the SDK call it
makes and the result it returns. A tier C case previews first and then
writes with the token from that preview.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…client

refs-parties.transport.test.ts runs each tool through the HTTP handler
and the MCP client, building a new server per call as the stateless
gateway does. It covers an add then remove round trip and an assign then
unassign round trip, with the confirmation token carried between
requests, and checks each result against its output schema. It also
checks that party_not_found is a soft result, that a non-dray role on a
container gets a fixed error, and that a 404 names the record type and
id for all four tools.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
writes.eval.ts gains two round trips on the sandbox account's first
shipment. One adds a unique reference number and removes it with a
confirmed preview. The other assigns the first party as notify_party and
unassigns it with a confirmed preview. The party case skips when the
party already holds that role, so it never removes a role it did not
create. Both undo their change in a finally block when an assertion
fails. The cases still need MCP_EVAL_ENABLE_WRITE and
MCP_EVAL_SANDBOX_TOKEN, and skip when the gateway does not serve the
tools.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
TOOLS_OVERVIEW.md describes add_reference_numbers,
remove_reference_numbers, assign_party and unassign_party: their tiers,
inputs, previews and results. It covers the union and difference merge,
the read-back and concurrent_change_detected, party matching by name,
party-create dedupe, already_present and not_assigned. It adds example
requests that use them. The tool count is 28, and 21 by default.

The package README and MCP_README.md list the four tools in the
operations tables, and the README names them in the Toolsets and
Confirming writes sections.

list_parties search now matches a party's company name, name or
nickname, and the docs say so.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The MCP home page documents add_reference_numbers,
remove_reference_numbers, assign_party and unassign_party: parameters,
results, previews and REST links. It lists them in the operations
toolset, which the hosted server does not serve yet. The Not yet
supported table and note no longer send reference number edits to the
REST API.

The quickstart lists the four tools in the operations table, and the
confirmation secret row names every tool that needs it.

list_parties search now matches a party's company name, name or
nickname, and the home page and quickstart say so.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@vercel

vercel Bot commented Oct 17, 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 30, 2026 1:01am UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 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-30T01:04:05.272217Z 6354100 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.

Comment thread packages/mcp/src/tools/list-parties.ts Resolved
dodeja and others added 3 commits October 17, 2026 22:31
…g it as complete

loadParties replaced a malformed page with an empty one and dropped rows
it could not read, then reported the list as complete. assign_party could
then create a party that already existed. The page is now parsed strictly.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…e every number

remove_reference_numbers accepts numbers up to 1000 characters but named
add_reference_numbers, which caps at 64, as its undo. A removal of a
longer number now omits undo and says how to restore it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@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: 25bc64d661

ℹ️ 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 docs/mcp/home.mdx Resolved
dodeja and others added 2 commits October 17, 2026 23:45
Brings main's trade intelligence tools up the stack. The default toolsets
serve 28 tools and all toolsets 35.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The tool leaves out undo when a removed number is longer than the 64
characters add_reference_numbers accepts, and its message says to re-add
the number in the dashboard. The docs promised the undo unconditionally.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
github-actions Bot and others added 2 commits October 18, 2026 06:55
Keeps this branch's generated Postman collection. Both sides were
generated by the Postman workflow, which writes random ids, so they
always conflict.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@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: d4a1bc02ff

ℹ️ 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 on lines +116 to +118
const sent = [...previous, ...added];
try {
await writeReferenceNumbers(client, entity_type, entity_id, sent);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve concurrent reference updates before replacing the list

When another client adds a reference after this initial read but before this PATCH, the request sends the stale previous list plus this call's additions and silently deletes the other client's value. The subsequent read-back equals sent, so concurrent_change_detected is also false; for example, [A] can become [A, B] concurrently and then be overwritten with [A, C]. Because the API replaces the entire list, this operation needs an atomic/conditional update mechanism rather than relying on the post-write comparison.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed, and there is no atomic option to use. docs/openapi.json gives PATCH /containers/{id}, /shipments/{id} and /tracking_requests/{id} only a full ref_numbers array: no append or remove endpoint, and no ETag, If-Match or version field anywhere in the spec. Re-reading right before the PATCH wouldn't help, because the tool already reads immediately before it writes, so the window stays one round trip either way. The read-back can't see a value overwritten before the PATCH, as you say. So I've made the contract honest instead of implying detection: 5405034 adds to the tool description that a number added by someone else between the read and the write is lost and concurrent_change_detected doesn't report it, and corrects the module comment. 26ff193 says the same in docs/mcp/home.mdx, and 8ea2e2d updates the 08 tools/list snapshot. remove_reference_numbers has the same one-round-trip window inside its confirmed call, since the confirming call re-reads the list, checks the token's fingerprint against it, then PATCHes. A change after the preview is caught as stale_preview; one inside that final round trip isn't. A real fix needs a conditional update or append/remove endpoint in the API. Separately, 6fb888e adds a test that a remove token replayed after add_reference_numbers restores the list is refused (reason used, from b310174 on #451).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Dismissed with a concrete reason. The finding is real but cannot be fixed in this repo. docs/openapi.json gives the PATCH routes only a full ref_numbers array, with no append endpoint, ETag or version field. The tool description and docs state that a number added between the read and the write is lost and concurrent_change_detected does not report it (5405034, 26ff193). A real fix needs a conditional update in the Terminal49 API. Leaving the thread open for that follow-up.


Generated by Claude Code

Comment on lines +175 to +179
const added = await client.callTool('add_reference_numbers', {
...target,
add: [refNumber],
});
needsRemove = structured(added).status === 'added';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Arm reference cleanup before issuing the write

In the live write eval, if callTool reaches the server and adds the reference but its response is lost or the client rejects, execution enters finally while needsRemove is still false, leaving the generated reference on the sandbox shipment. This contradicts the eval's round-trip cleanup guarantee and can pollute later runs; set the cleanup flag before the write, as the stop-tracking case already does.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Right for this branch's eval. The live write eval only runs from 08 (mcp-sandbox-write-eval in ci.yml), and 08 rewrote it to touch only the three demo-account fixtures, so 05 to 07's version, which writes to the first shipment and party on the account, is not the one to fix. On 08 the reference case already arms its cleanup before the write: removed starts false and the finally sends remove_reference_numbers unless the remove succeeded, and a number that was never added comes back not_present with nothing changed (ef21140).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Dismissed for this branch. The live write eval runs only from the 08 branch, which replaces this file with a fixture-only version whose reference case arms cleanup before the write (ef21140, per the earlier reply). Editing it here would only conflict with 08, and #452 does not touch other mcp-v2 branches.


Generated by Claude Code

Comment thread packages/mcp/eval/writes.eval.ts Outdated
Comment on lines +210 to +214
const assigned = structured(
await client.callTool('assign_party', {
...target,
role: 'notify_party',
party_id: partyId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Protect party assignment with cleanup before awaiting it

This assignment occurs before the cleanup try/finally is established. If the server creates the role but the response is lost, or if the returned payload fails the assertion before line 224, the test exits without discovering and removing the new role; subsequent runs then see already_present and skip the coverage entirely. Record the pre-existing roles and wrap the assignment itself in cleanup logic that can locate any newly created matching role.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in the eval that runs, on 08 (9e026b3). 05 to 07's eval doesn't run in CI and is replaced on 08 by the fixture-only version, so I fixed it there rather than on this branch. The assign_party call now sits inside the try. On failure, the finally reads the fixture shipment with get_shipment_details include_party_roles and unassigns every notify_party role held by "MCP Eval (do not use)". Only this eval assigns that party, so every such role is one an eval run created, and a role whose assign response was lost is removed too. The selector matches the exact party name, the role, and the party id once known. Its unit tests in write-fixtures.test.ts failed before the selector existed. The eval README describes the cleanup.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moot. The assign_party eval case no longer exists on this branch: the tool was removed in bcb0cde in favour of set_party_role, and grep assign_party finds nothing in code at 86a6e98.


Generated by Claude Code

Also trims the token sentences from the remove_reference_numbers and
unassign_party descriptions, which the registrar's tier C clause now
covers, and names both tools in the README and in-depth guide.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
dodeja and others added 2 commits October 18, 2026 20:20
…used

remove_reference_numbers caught its 422 and unassign_party its 404
inside the write, so the kit never saw the refusal and the confirmation
stayed spent although nothing changed. Both now answer the refusal from
the kit's refused callback, after the confirmation is released.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@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: 790f8176c9

ℹ️ 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 packages/mcp/src/tools/assign-party.ts Outdated
Comment on lines +433 to +436
try {
return await refused(error);
} catch (failure) {
return createdNotLinked(failure, record, party);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recheck the role before declaring a created party unlinked

When create_party_if_missing creates the party and the subsequent assignment commits but its response is lost or returns a 5xx, this catch converts the ambiguous failure into party_not_linked without reading the roles again. The caller is therefore told definitively that the party is unlinked even though the role may exist; re-read the party roles and return already_present when the assignment actually landed before reporting it as unlinked.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moot. assign_party, including create_party_if_missing, was removed in bcb0cde. set_party_role requires an existing party_id and never creates a party.


Generated by Claude Code

@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: 9ed292a555

ℹ️ 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 packages/mcp/src/tools/assign-party.ts Outdated
const added = after.find(
(other) => other.role === role && other.party_id === party.id,
);
if (added) return alreadyPresent(added, created ? party : undefined);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the post-conflict roles for co-assignees

When the POST returns 422 because another request assigned this party concurrently, this branch finds the new role in after but alreadyPresent still derives other_parties_in_role from the pre-write inRole snapshot. Any other same-role parties added during that window are therefore omitted, so callers can be incorrectly told there are no additional assignees and fail to remove them during a replacement workflow; build this result from the freshly read after roles.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moot. assign_party and its 422 conflict path were removed in bcb0cde.


Generated by Claude Code

dodeja and others added 3 commits October 18, 2026 22:49
Brings main and the confirmed batch record writes into the reference number
and party branch. Every tier C tool now declares when it asks, so
remove_reference_numbers and unassign_party gain confirms: 'always'. The
docs, manifests and test tables cover the nine operations tools the default
toolsets serve at this point in the stack.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
set_party_role from main covers both: add attaches a party at once, and
remove detaches it after the user approves a preview of every record that
changes, on up to 50 records per call. The single-record tools, their
tests, fixtures, eval case, feature-map entries, manifest entries and the
party helpers only they used go with them. The reference number transport
test keeps its reference cases under a name that says so.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The docs site, tool overview, READMEs and eval notes describe set_party_role
in their place and count the seven operations tools.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions github-actions Bot added the risk-shadow:high Shadow-only risk signal: high label Oct 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Shadow risk calibration

Signal Result Authority
Path classifier risk:high Deterministic advisory policy
heuristic fallback risk-shadow:high Shadow only

Calibration result: agreement.

Shadow risk never blocks or enables merge. Keep it in observation mode until roughly 50 pull requests have human-reviewed labels, then calibrate before considering any policy use.

@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: 4a4a1754af

ℹ️ 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 packages/mcp/src/server.ts Resolved
Comment thread docs/mcp/home.mdx Resolved
The branch's docs/openapi.json matches main's, so the generated collection
should too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@dodeja dodeja changed the title feat(mcp): add reference number and party assignment tools feat(mcp): add reference number tools Oct 19, 2026
Resolves conflicts in favour of the write kit's design. The reference
number tools move to a new opt-in reference_numbers toolset so no default
toolset gains a write tool, the instructions' write paragraph is tightened
to fit 2,048 bytes with all toolsets on, the not-found message names the
reference record, and the docs describe the toolset and drop assign_party.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V8cPhgia7FZpMP7q5BJ5nw
@github-actions github-actions Bot added the risk:unknown Advisory evidence unavailable or changed; no merge permission label Oct 30, 2026
A change between the preview and the approval gets a new preview. A change
that lands while the confirmed write is running can still be lost, because
Terminal49 replaces the whole list and has no conditional update. Say so in
the tool description, the MCP home page, and the tools overview, matching
add_reference_numbers. Also drop comments that only narrate the code.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V8cPhgia7FZpMP7q5BJ5nw
dodeja pushed a commit that referenced this pull request Oct 30, 2026
Brings in the base as of 6354100: main's 2 KB instruction cap and
idempotentHint (#493), the opt-in tracking_lifecycle toolset and the
read-first write kit (#451), and the opt-in reference_numbers toolset
(#452).

Conflicts were resolved in favour of the base's design:

- packages/mcp/src/instructions.ts takes the base's segment model. The
  write paragraph still names each write tool, so with update_document
  and relink_document the largest selection is 2,092 bytes. The next
  commit redesigns that paragraph; three instruction tests stay red at
  this commit.
- packages/mcp/src/server.ts keeps the base's reference-number error
  message and adds the webhook read cases after it. This branch's own
  copy had add_reference_numbers and remove_reference_numbers falling
  through to the webhook message.
- The docs (home.mdx, README, TOOLS_OVERVIEW, WORKOS_MCP_SETUP, eval
  README) use the base's wording and add documents_write and developer
  as opt-in toolsets: 39 tools in all, 30 by default.
- Terminal49-API.postman_collection.json is the base's copy, because
  docs/openapi.json is identical to the base's.

Generated filter schemas come from npm run generate:filters. The
annotations test lists the two document writes, and the update_document
fail-closed test allows the read that the base's write kit makes before
it refuses.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01V8cPhgia7FZpMP7q5BJ5nw

This branch was successfully deployed

1 active deployment
Preview — 63541005 Deployed Oct 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:unknown Advisory evidence unavailable or changed; no merge permission risk-shadow:high Shadow-only risk signal: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants