Skip to content

feat(mcp): capture models from client metadata - #4829

Merged
lucasheriques merged 2 commits into
mainfrom
codex/mcp-model-client-metadata
Sep 8, 2026
Merged

lucasheriques merged 2 commits into
mainfrom
codex/mcp-model-client-metadata

Conversation

@lucasheriques

Copy link
Copy Markdown
Contributor

Problem

MCP servers miss Codex model attribution because Codex sends the model in request metadata instead of the injected tool argument.

Changes

  • Model capture now prefers recognized Codex request metadata and labels its source as client_metadata.
  • Self-reported model capture remains the fallback for clients without stable model metadata.
  • Model capture stays opt-in, unverified, and unsuitable for billing or access control.
  • Application-owned llm_model arguments remain untouched.
  • The dual-era harness verifies the precedence rule on MCP SDK v1 and v2, including protocol version 2026-07-28.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common
  • @posthog/mcp

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Codex implemented this change after local Claude Code and Codex probes exposed different model carriers. The debugging-mcp-analytics, writing-tests, and writing-pr-descriptions skills guided the provenance contract, regression coverage, and review summary.

The design treats both sources as unverified because MCP does not standardize model identity. Client metadata wins only for a recognized vendor shape.

Prefer recognized Codex request metadata over the self-reported tool argument while preserving provenance and opt-in behavior.

Keep application-owned llm_model arguments untouched and validate both MCP SDK generations, including the 2026-07-28 stateless protocol.

Verified with @posthog/mcp unit tests, package lint, package build, root formatting, and both MCP Apps harness lanes.
@lucasheriques
lucasheriques requested review from a team as code owners September 7, 2026 15:32
@lucasheriques lucasheriques self-assigned this Sep 7, 2026
@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
packages/mcp/src/__tests__/model-parameters.test.ts:360
**Assertion checks wrong path**

The captured request keeps `llm_model` under `$mcp_parameters.params.arguments`, but this assertion checks `$mcp_parameters.llm_model`. It therefore passes even if the argument leaks into the captured parameters, leaving the intended stripping behavior without effective regression coverage.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(mcp): capture models from client me..." | Re-trigger Greptile

expect(toolCalls).toHaveLength(1)
expect(toolCalls[0].properties.$mcp_llm_model).toBe('gpt-5.6-sol')
expect(toolCalls[0].properties.$mcp_llm_model_source).toBe('client_metadata')
expect((toolCalls[0].properties.$mcp_parameters as any)?.llm_model).toBeUndefined()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Assertion checks wrong path

The captured request keeps llm_model under $mcp_parameters.params.arguments, but this assertion checks $mcp_parameters.llm_model. It therefore passes even if the argument leaks into the captured parameters, leaving the intended stripping behavior without effective regression coverage.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/mcp/src/__tests__/model-parameters.test.ts
Line: 360

Comment:
**Assertion checks wrong path**

The captured request keeps `llm_model` under `$mcp_parameters.params.arguments`, but this assertion checks `$mcp_parameters.llm_model`. It therefore passes even if the argument leaks into the captured parameters, leaving the intended stripping behavior without effective regression coverage.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Assert against the nested request arguments that MCP capture actually stores. This closes a false-positive gap in model-parameter stripping coverage.\n\nVerification:\n- pnpm --filter @posthog/mcp test:unit\n- pnpm --filter @posthog/mcp lint
@lucasheriques

Copy link
Copy Markdown
Contributor Author

Fixed in 1101d6f. The assertions now verify the actual nested request.params.arguments payload, and cover every equivalent model-stripping assertion in the integration suites.

@graphite-app

graphite-app Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Graphite Automations

"sdk release label" took an action on this PR • (09/07/26)

1 label was added to this PR based on Adam Bowker's automation.

"Add graphite merge queue [copy]" took an action on this PR • (09/07/26)

1 label was added to this PR based on Lucas Faria's automation.

@lucasheriques

Copy link
Copy Markdown
Contributor Author

Live model-in-the-loop validation is complete:

  • Codex 0.151.0 + gpt-5.6-sol: the tool call omitted llm_model; capture resolved gpt-5.6-sol from request metadata with source client_metadata.
  • Codex 0.146.0 + gpt-5.6-terra: same metadata-only path and provenance.
  • Claude Code 2.1.263 + sonnet: capture resolved the canonical claude-sonnet-5 through the injected fallback with source self_reported.
  • The v1 and v2 MCP harnesses pass, including the 2026-07-28 raw-wire lane where client metadata deliberately conflicts with self-report and wins.

gpt-6-astra could not start a turn on the available Codex CLI, so I am not claiming that exact model/client combination. The capture path is client metadata rather than a model-name allowlist.

@lucasheriques

Copy link
Copy Markdown
Contributor Author

Python SDK parity is ready in PostHog/posthog-python#927. It matches the JavaScript model-capture contract and covers MCP Python SDK 1.x, 2.x, and the 2026-07-28 wire path.

@lucasheriques
lucasheriques merged commit 6724f10 into main Sep 8, 2026
63 of 78 checks passed
@lucasheriques
lucasheriques deleted the codex/mcp-model-client-metadata branch September 8, 2026 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants