Skip to content

feat(client): make HTTP User-Agent header configurable - #41

Open
jdforrester wants to merge 1 commit into
cortex-app:mainfrom
jdforrester:feat/configurable-user-agent
Open

feat(client): make HTTP User-Agent header configurable#41
jdforrester wants to merge 1 commit into
cortex-app:mainfrom
jdforrester:feat/configurable-user-agent

Conversation

@jdforrester

Copy link
Copy Markdown

Summary:
The Phabricator/Phorge client previously hardcoded a single User-Agent string ("ModelContextProtocol/1.0 (Autonomous; ...)") across all three HTTP client construction sites. Some Phabricator/Phorge operators (notably Wikimedia) inspect the User-Agent header for rate-limiting and require identifying contact information for automated clients, which made the server unusable against those instances without patching.

This change introduces a new optional PHABRICATOR_USER_AGENT environment variable that, when set, overrides the default User-Agent sent on every outbound request. When unset, behavior is unchanged — the existing default string is preserved verbatim via a new DEFAULT_USER_AGENT constant in conduit/client/base.py, so the change is fully backwards compatible.

The new setting follows the exact same wiring pattern as the existing PHABRICATOR_PROXY and PHABRICATOR_DISABLE_CERT_VERIFY options: environment variable → PhabricatorConfig field → PhabricatorClient kwarg → httpx.Client header. Both stdio and HTTP/SSE transport modes forward the value.

Changes:

  • Added DEFAULT_USER_AGENT constant in conduit/client/base.py as the single source of truth for the default header value
  • Added user_agent: Optional[str] = None parameter to BasePhabricatorClient.init, EnhancedPhabricatorClient.init, and the backwards-compatible PhabricatorClient.init wrapper
  • Added PHABRICATOR_USER_AGENT env var handling to PhabricatorConfig
  • Forwarded config.user_agent through ConduitApp.get_client in both stdio and SSE code paths
  • Added unit tests covering default and override behavior across all three client flavors (basic, enhanced-via-wrapper, direct enhanced)
  • Documented the new env var in README.md and AGENTS.md alongside the existing optional PHABRICATOR_* variables

Key Features:

  • Fully backwards compatible: unset env var preserves the original User-Agent string byte-for-byte
  • Works in both stdio and HTTP/SSE transport modes
  • Single source of truth for the default value — future changes to the default touch exactly one line
  • Enables use against Phabricator/Phorge instances that require identifying User-Agent headers (e.g. Wikimedia) without source patches

Test Plan:

  • Added test_user_agent_default: asserts DEFAULT_USER_AGENT is applied on the basic path, the enhanced path (triggered via timeout=60.0), and direct EnhancedPhabricatorClient construction
  • Added test_user_agent_override: asserts a user_agent kwarg overrides the default on all three of the above paths
  • Ran full test suite against phorge_debug Docker container per AGENTS.md instructions: 299 passed, 1 skipped (was 297 passed before the two new tests)
  • Ran `pre-commit run -a`: ruff check, ruff format, and bandit all pass
  • Manually verified via MCP client config that setting PHABRICATOR_USER_AGENT="MyOrg-Phabricator-MCP/1.0 (contact@example.org)" causes the expected header to be sent on outbound requests

Copilot AI review requested due to automatic review settings April 8, 2026 13:49

Copilot AI 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.

Pull request overview

Adds support for configuring the outbound HTTP User-Agent used by the Phabricator/Phorge client via a new PHABRICATOR_USER_AGENT environment variable, wiring it through config → client construction → httpx.Client headers.

Changes:

  • Introduces DEFAULT_USER_AGENT and a user_agent override parameter in client constructors.
  • Plumbs PHABRICATOR_USER_AGENT through PhabricatorConfig and ConduitApp.get_client (stdio + SSE paths).
  • Adds unit tests and documentation updates for default vs overridden behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Documents PHABRICATOR_USER_AGENT usage.
AGENTS.md Documents PHABRICATOR_USER_AGENT for dev/test workflows.
conduit/conduit.py Reads env var into config and forwards to PhabricatorClient.
conduit/client/base.py Adds DEFAULT_USER_AGENT and user_agent parameter to base client creation.
conduit/client/unified.py Adds user_agent parameter and applies it to basic/enhanced httpx.Client headers.
conduit/client/tests/test_enhanced_client.py Adds tests asserting default and override User-Agent behavior across client variants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread conduit/client/unified.py
Comment thread conduit/client/base.py
Comment on lines 39 to 43
self.client = httpx.Client(
headers={
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "ModelContextProtocol/1.0 (Autonomous; +https://github.com/modelcontextprotocol/servers)",
"User-Agent": user_agent or DEFAULT_USER_AGENT,
},

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

The new user_agent parameter is only applied when BasePhabricatorClient constructs its own httpx.Client (http_client is None). If a caller provides http_client, user_agent is silently ignored, which can be surprising given the parameter name/docstring; consider either documenting this explicitly, raising when both are provided, or applying the override to the provided client in a controlled way.

Copilot uses AI. Check for mistakes.
Summary:
The Phabricator/Phorge client previously hardcoded two User-Agent strings
("ModelContextProtocol/1.0 (Autonomous; …)" and "… (Enhanced; …)") across
all three HTTP client construction sites. Some Phabricator/Phorge sites
(notably Wikimedia) inspect the User-Agent header for rate-limiting and
require identifying contact information for automated clients, which
made the server unusable against those instances without patching.

This change introduces a new optional PHABRICATOR_USER_AGENT environment
variable that, when set, overrides the default User-Agent sent on every
outbound request. When unset, behavior is unchanged — the existing
default string is preserved verbatim via two new DEFAULT_USER_AGENT
and DEFAULT_ENHANCED_USER_AGENT constants in conduit/client/base.py, so
the change is fully backwards compatible.

The new setting follows the exact same wiring pattern as the existing
PHABRICATOR_PROXY and PHABRICATOR_DISABLE_CERT_VERIFY options:
environment variable → PhabricatorConfig field → PhabricatorClient
kwarg → httpx.Client header. Both stdio and HTTP/SSE transport modes
forward the value.

Changes:
- Added constants in conduit/client/base.py as the single source of
  truth for the default header values
- Added user_agent: Optional[str] = None parameter to
  BasePhabricatorClient.__init__, EnhancedPhabricatorClient.__init__,
  and the backwards-compatible PhabricatorClient.__init__ wrapper
- Added PHABRICATOR_USER_AGENT env var handling to PhabricatorConfig
- Forwarded config.user_agent through ConduitApp.get_client in both
  stdio and SSE code paths
- Added unit tests covering default and override behavior across all
  three client flavors (basic, enhanced-via-wrapper, direct enhanced)
- Documented the new env var in README.md and AGENTS.md alongside the
  existing optional PHABRICATOR_* variables

Key Features:
- Fully backwards compatible: unset env var preserves the original
  User-Agent string byte-for-byte
- Works in both stdio and HTTP/SSE transport modes
- Single source of truth for the default value — future changes to the
  default touch exactly one line
- Enables use against Phabricator/Phorge instances that require
  identifying User-Agent headers (e.g. Wikimedia) without source patches

Test Plan:
- Added test_user_agent_default: asserts DEFAULT_USER_AGENT is applied
  on the basic path, DEFAULT_ENHANCED_USER_AGENT on the enhanced path
  (triggered via timeout=60.0), and on direct EnhancedPhabricatorClient
  construction
- Added test_user_agent_override: asserts a user_agent kwarg overrides
  the default on all three of the above paths
- Ran full test suite against phorge_debug Docker container per
  AGENTS.md instructions: 299 passed, 1 skipped (was 297 passed before
  the two new tests)
- Ran \`pre-commit run -a\`: ruff check, ruff format, and bandit all pass
- Manually verified via MCP client config that setting
  PHABRICATOR_USER_AGENT="MyOrg-Phabricator-MCP/1.0 (contact@example.org)"
  causes the expected header to be sent on outbound requests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jdforrester
jdforrester force-pushed the feat/configurable-user-agent branch from 6941102 to 10998c2 Compare April 8, 2026 23:22
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.

2 participants