Skip to content

feat(security-agent-mcp-server): Add custom User-Agent - #4482

Open
ljainiaz wants to merge 1 commit into
awslabs:mainfrom
ljainiaz:feat/security-agent-custom-useragent-ljaini
Open

feat(security-agent-mcp-server): Add custom User-Agent#4482
ljainiaz wants to merge 1 commit into
awslabs:mainfrom
ljainiaz:feat/security-agent-custom-useragent-ljaini

Conversation

@ljainiaz

@ljainiaz ljainiaz commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a custom User-Agent string to all boto3 API calls from the security-agent-mcp-server, enabling service-side tracking of MCP usage by IDE/tool.

User-Agent format

md/awslabs#mcp#security-agent-mcp-server#0.1.2 md/client#kiro/1.5.0

Follows the repo-wide md/awslabs#mcp#<server-name>#<version> convention, with an additional md/client#<name>/<version> suffix for IDE tracking.

How it works

  1. aws_client.py: SecurityAgentClient builds a botocore.config.Config(user_agent_extra=...) and passes it to every .client() call (securityagent, sts, s3, iam). Uses the package __version__
    constant directly.
  2. server.py: @ensure_client_ua decorator extracts clientInfo from the MCP session context (sent by the IDE during initialize) and calls set_mcp_client_info() on the shared AWS client singleton.

Design decisions

  • __version__ constant: Uses the package-level __version__ instead of importlib.metadata.version() to avoid silent degradation to "unknown" in editable/source installs.
  • Sanitized client name: clientInfo.name is normalized with .lower().replace(" ", "-") before injection into the UA string, preventing malformed tokens (e.g. "Claude Code" → "claude-code").
  • Decorator pattern: @ensure_client_ua applied to all tool functions as a single choke point — no per-tool boilerplate, and new tools cannot forget it.
  • Lazy injection: The SecurityAgentClient singleton is created at module level before any MCP session connects, so clientInfo is injected on first tool invocation.
  • No-op optimization: set_mcp_client_info() short-circuits if the info has not changed.
  • Graceful fallback: Falls back to unknown when clientInfo is unavailable.
  • Concurrency note: Current stdio transport guarantees one client per process. Under future HTTP/SSE transport with concurrent sessions, _config would need per-session isolation.

Tracking values by IDE

IDE md/client# value
Kiro kiro/<version>
Claude Code claude-code/<version>
Cursor cursor/<version>
Unknown unknown

Tested

  • All 41 unit tests pass (197 total including existing)
  • E2E verified: API call to SecurityAgent service confirmed the custom UA on the wire
  • Works with Kiro, Claude Code, and any MCP-compliant client that sends clientInfo

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.14%. Comparing base (cdd87a8) to head (783e1c8).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4482   +/-   ##
=======================================
  Coverage   93.14%   93.14%           
=======================================
  Files        1038     1038           
  Lines       87536    87587   +51     
  Branches    14123    14128    +5     
=======================================
+ Hits        81535    81586   +51     
  Misses       3638     3638           
  Partials     2363     2363           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To triage

Development

Successfully merging this pull request may close these issues.

2 participants