Skip to content

Forward MCP client identity in the API User-Agent - #130

Merged
mklocek merged 1 commit into
mainfrom
user-agent-client-info
Aug 4, 2026
Merged

Forward MCP client identity in the API User-Agent#130
mklocek merged 1 commit into
mainfrom
user-agent-client-info

Conversation

@mklocek

@mklocek mklocek commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What

The MCP server sent a generic User-Agent for every Mailtrap API call, so we couldn't tell which AI client (Claude Desktop, Cursor, Windsurf, Lovable, …) was driving a request. This forwards the client identity so adoption can be measured per client.

How

  • Capture the MCP client's name + version from the initialize handshake (server.oninitializedgetClientVersion()).
  • Append it to the outgoing API User-Agent, e.g.
    mailtrap-mcp/0.6.0 (+https://github.com/mailtrap/mailtrap-mcp) (client: Claude Desktop/1.5.3).
  • The default client is now built lazily so it picks up the identity captured during the handshake (the singleton was previously constructed at import time, before the handshake).
  • Client name/version are sanitized before going into the header (strip non-printable ASCII and parentheses, collapse whitespace, cap length) to avoid header injection.
  • The base User-Agent now includes the server version to match the intended format.

Summary by CodeRabbit

  • New Features

    • Outgoing requests now identify the connected MCP client in the User-Agent.
    • Client names and versions are safely formatted and limited to prevent malformed headers.
    • The default User-Agent now includes the server version and repository information.
  • Tests

    • Added coverage for client identity forwarding, formatting, sanitization, and fallback behavior.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mklocek, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8695b8f0-b287-4370-8b89-b1ba6c11c86c

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7203e and c4abb4f.

📒 Files selected for processing (6)
  • src/__tests__/client.test.ts
  • src/client.ts
  • src/config/index.ts
  • src/server.ts
  • src/utils/__tests__/userAgent.test.ts
  • src/utils/userAgent.ts
📝 Walkthrough

Walkthrough

The server captures MCP client name and version after initialization. User-Agent utilities sanitize and format this identity. Mailtrap clients append the identity to a version-aware base User-Agent and create the default client lazily.

Changes

MCP identity forwarding

Layer / File(s) Summary
User-Agent formatting contract
src/utils/userAgent.ts, src/config/index.ts, src/utils/__tests__/userAgent.test.ts
Adds MCP identity types and formatting utilities. Sanitizes names and versions, limits their length, and preserves the base User-Agent when identity data is unusable. Updates the base User-Agent to include the server version.
Dynamic API client User-Agent construction
src/client.ts
Stores MCP client metadata and builds User-Agent values dynamically for default, sandbox, bulk, and organization clients. Replaces the eager exported client with lazy initialization and exports setMcpClientInfo.
Initialization wiring and forwarding coverage
src/server.ts, src/__tests__/client.test.ts
Captures connected client metadata after the MCP handshake. Tests verify identity forwarding and base User-Agent fallback behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: igordobryn

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient as MCP client
  participant MCPServer as src/server.ts
  participant APIClients as src/client.ts
  participant MailtrapAPI as Mailtrap API
  MCPClient->>MCPServer: complete initialization with client name and version
  MCPServer->>APIClients: setMcpClientInfo(client metadata)
  APIClients->>MailtrapAPI: send request with dynamically built User-Agent
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes forwarding MCP client identity in the API User-Agent.
Description check ✅ Passed The description clearly explains the motivation and implementation, but omits the template's testing and Images/GIFs sections.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/__tests__/client.test.ts (1)

30-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for getDefaultClient/requireClient identity capture timing.

These tests exercise getSandboxClient, which rebuilds its MailtrapClient on every call. They do not exercise getDefaultClient (used by requireClient), which memoizes its client instance after the first call in src/client.ts. Add a test that calls getDefaultClient (or a function that uses it) once before setMcpClientInfo, then again after, to confirm intended behavior. This directly documents and would catch the caching risk noted in the src/client.ts review.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/client.test.ts` around lines 30 - 45, Add coverage in the
client identity tests for the memoized getDefaultClient/requireClient path:
obtain the default client once before setMcpClientInfo, set the MCP identity,
then obtain it again and assert the intended User-Agent behavior. Keep the
existing getSandboxClient tests unchanged and use the public helper that
exercises getDefaultClient where appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client.ts`:
- Around line 6-7: Remove the defaultClient memoization used by getDefaultClient
and construct a fresh MailtrapClient on every call, so later setMcpClientInfo
updates are reflected in the User-Agent. Keep the existing client configuration
and other getters unchanged.

---

Nitpick comments:
In `@src/__tests__/client.test.ts`:
- Around line 30-45: Add coverage in the client identity tests for the memoized
getDefaultClient/requireClient path: obtain the default client once before
setMcpClientInfo, set the MCP identity, then obtain it again and assert the
intended User-Agent behavior. Keep the existing getSandboxClient tests unchanged
and use the public helper that exercises getDefaultClient where appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a7807afa-4963-4ae8-8bd3-902af63c9454

📥 Commits

Reviewing files that changed from the base of the PR and between 2d14301 and 8b7203e.

📒 Files selected for processing (6)
  • src/__tests__/client.test.ts
  • src/client.ts
  • src/config/index.ts
  • src/server.ts
  • src/utils/__tests__/userAgent.test.ts
  • src/utils/userAgent.ts

Comment thread src/client.ts Outdated
The MCP server sent a generic User-Agent for every Mailtrap API call, so
we could not tell which AI client (Claude Desktop, Cursor, Windsurf, ...)
was driving a request.

Capture the client name and version reported during the `initialize`
handshake and append them to the outgoing API User-Agent, e.g.
`mailtrap-mcp/0.6.0 (+https://github.com/mailtrap/mailtrap-mcp) (client: Claude Desktop/1.5.3)`.

The identity is read lazily from `server.getClientVersion()` at client
construction. That value is populated during the `initialize` request,
which always precedes any tool call that builds an API client, so the
User-Agent is never stale and no client caches a value captured before
the identity was known. The name/version are sanitized before going into
the header. The base User-Agent also gains the server version.
@mklocek
mklocek merged commit 7f907cb into main Aug 4, 2026
2 checks passed
@mklocek
mklocek deleted the user-agent-client-info branch August 4, 2026 11:26
@github-actions github-actions Bot mentioned this pull request Aug 4, 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.

3 participants