Skip to content

fix(mcp): advertise whole-string ID patterns so connector clients accept returned IDs [v2] - #2188

Closed
jameswyse wants to merge 1 commit into
UsefulSoftwareCo:v2from
jameswyse:fix/full-string-id-patterns
Closed

jameswyse wants to merge 1 commit into
UsefulSoftwareCo:v2from
jameswyse:fix/full-string-id-patterns

Conversation

@jameswyse

Copy link
Copy Markdown

Summary

MCP tool schemas advertise prefixed IDs with prefix-only patterns such as ^dpl_, which Effect's Schema.isStartsWith emits. That is valid JSON Schema, but the OpenAI connector used by Codex matches pattern against the whole string. It therefore rejects the IDs Executor returns: skills deployment and profile selection, and resume request IDs.

This PR replaces the prefix checks in the shared SDK Id helper and ElicitationRequestId with one whole-string check, ^<prefix>_[\s\S]+$. That check drives both runtime validation and the advertised schema.

-Schema.check(Schema.isStartsWith(`${prefix}_`), Schema.isMinLength(prefix.length + 2)),
+Schema.check(Schema.isPattern(new RegExp(`^${prefix}_[\\s\\S]+$`))),
  • Runtime validation: unchanged. The new check accepts exactly the strings the old startsWith plus minLength checks accepted, which I compared across 78 boundary samples in six ID families.
  • Error text: an invalid ID now reports the RegExp instead of "starting with".
  • AccountId (acc_): unchanged. Released app protocol snapshots freeze its schema, and it never appears in an MCP tool input.

Linked issue

Fixes #2186

Verification

  • bun run check (format, lint, typecheck, apps:protocols, e2e:check). v2 has no bun run test script.
  • e2e, both run against the unfixed code first:
    • local-skills.spec.ts (local): expected 'dpl_1302…' to match /^(?:(?:^dpl_))$/u before the fix, passes after. The scenario now checks the returned deployment and profile against the advertised skills patterns as whole strings, then calls skills with both.
    • pat-mcp.spec.ts, "PAT MCP approvals bind continuations…" (self-host): expected 'apr_4c23…' to match /^(?:(?:^apr_)|(?:^elc_))$/u before the fix, passes after. Its existing approval and token-binding assertions still pass.
  • Real connector A/B. Self-host images were built from 828a680 and from this branch, with the same data and the same temporary ChatGPT connected app, called from Codex. The connector's tools were refreshed after the image swap.
Call through the connector v2 828a680 This branch
skills + returned revision (^[a-f0-9]{64}$) accepted accepted
skills + returned deployment rejected, ^dpl_ accepted
skills + returned profile rejected, ^ins_ accepted
skills document + deployment + profile not run accepted
resume + returned apr_ ID, decline rejected, ^apr_ completed, ApprovalDenied
skills + deployment: "ins_0000" not run rejected, ^dpl_[\s\S]+$

A direct MCP client accepted the returned IDs on both images. The rejections came from the connector, not from Executor. elc_ uses the same pattern shape but wasn't exercised through the connector, because no scenario produces an input-required pause.

all

all because the shared Id helper validates every SDK ID across the HTTP API and MCP.

Checklist

  • Added a changeset (bun run changeset), or this change needs none.
  • Added or updated tests for the new behaviour.
  • No secrets, credentials, or private data in the diff.

Effect's isStartsWith emits a prefix-only JSON Schema pattern such as
^dpl_. That is valid JSON Schema, but the OpenAI connector used by Codex
matches pattern against the whole string, so it rejected the deployment,
profile and approval IDs Executor returns.

Prefixed IDs now use one check, ^<prefix>_[\s\S]+$, for both runtime
validation and the advertised schema. It accepts exactly the strings the
previous startsWith plus minLength checks accepted, and it is correct
under both substring and whole-string pattern semantics.

AccountId keeps its prefix check because released app protocol snapshots
freeze its schema and it never appears in an MCP tool input.

Refs UsefulSoftwareCo#2186
@jameswyse jameswyse changed the title fix(mcp): advertise whole-string ID patterns so connector clients accept returned IDs fix(mcp): advertise whole-string ID patterns so connector clients accept returned IDs [v2] Oct 5, 2026
@jameswyse

Copy link
Copy Markdown
Author

Closing this, since the change landed on v2 in e780e12 ("Export 72d2449") alongside the closure of #2186 via the export sync.

Thanks @RhysSullivan for picking it up so quickly!

@jameswyse jameswyse closed this Oct 6, 2026
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