Skip to content

feat(lib): route Automate, App Automate, Accessibility and Observability to the account's GRR region - #489

Open
SavioBS629 wants to merge 29 commits into
browserstack:mainfrom
SavioBS629:feat/grr-regional-routing
Open

SavioBS629 wants to merge 29 commits into
browserstack:mainfrom
SavioBS629:feat/grr-regional-routing

Conversation

@SavioBS629

@SavioBS629 SavioBS629 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Routes EU accounts to BrowserStack's EU hosts automatically. Nothing to configure: the server reads the account's region from BrowserStack auth, using the username and access key it already has.

  • Local: the region is looked up once, before the server starts.
  • Hosted: servers for the same account share one lookup (kept for an hour), and every tool call runs in its own account's region, so concurrent users on different regions don't affect each other.
  • Other regions: IN accounts keep the default hosts for now (Test Management and capability discovery still probe for them).
  • If the lookup fails: an account already looked up keeps its last known region. Otherwise, calls that need the region return an error asking the user to retry rather than guessing a host; Test Management still finds the account's region by probing. The lookup is retried after 5 seconds.

Routed

  • Test Management (tools and tm capability)
  • Automate and App Automate, including uploads, hubs, and the devicecontrol / mobiledevicecontrol capabilities
  • Accessibility and App Accessibility (tools and the app_accessibility / web_accessibility capabilities)
  • Test Reporting & Analytics, RCA, build insights, self-heal and AI test failure analysis (tools and tra capability)

Hosts resolve in one place (src/lib/regional-host.ts). Explicit CAPABILITY_REGISTRY_BASE_URL_*, BROWSERSTACK_AUTOMATION_BASE_URL and O11Y_TFA_RCA_BASE_URL overrides still win.

No telemetry is sent for EU and IN accounts, and submitFeedback isn't offered to them. While the region is unknown, telemetry sends only usage fields (no error text or free-text inputs) and submitFeedback declines.

For library users

BrowserStackMcpServer.create(config) looks up the region before building the server, so the tool list matches the account. new BrowserStackMcpServer(config) still routes every call by region, but lists tools as for a US account.

Not routed yet

  • Regional hosts for IN accounts
  • Percy, askBrowserStackAI and the loadtesting capability
  • App Live upload
  • Automate and App Automate dashboard links, and generated SDK config snippets

Testing

npm run build passes. Unit tests cover the region lookup (token parsing, one lookup per account, expiry, failure), per-call routing for concurrent accounts, each product's regional host, telemetry fields and submitFeedback. Verified end to end against an EU account: local stdio, and hosted with OAuth, AccessToken and browserstack-* header sign-in all reached the EU hosts directly.

Squash on merge.

🤖 Generated with Claude Code

…ity to the account's GRR region

Add src/lib/regional-host.ts, which probes each product's US, EU and IN
hosts in order and keeps the first that accepts the caller's credentials,
the same approach tm-base-url.ts uses for Test Management. A GRR account
is rejected by every region except its own, so it lands on its regional
host; a non-GRR account is served by the US host and never reaches the
others. If every region refuses, the call fails rather than falling back
to the US host.

Hosts routed:
- Automate / App Automate REST: api-<region>-only.browserstack.com
- App Automate uploads and Espresso/XCUITest builds: api-cloud (US) or
  api-<region>-only
- App Automate hub: hub-<region>-only.browserstack.com
- Accessibility: api-accessibility-<region>, accessibility-<region>
- Test Reporting & Analytics / RCA / build insights / self-heal:
  api-observability-<region>, api-automation-<region>

The region is cached per product in stdio mode only; remote mode probes
on every call so one user's region cannot reach another
(rules/multi-tenant-safety.md). BROWSERSTACK_AUTOMATION_BASE_URL still
overrides the api-automation host for non-prod targets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Central YAML (base), Organization UI (inherited), Workspace UI (inherited); Enforced overrides: Organization
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: b4f2abc0-7ebf-4c35-ae5d-3437ebc9fef7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

SavioBS629 and others added 18 commits October 16, 2026 15:11
When every regional probe fails (bad credentials, no access to the
product, a network failure), use the US host instead of throwing, so the
tool behaves as it did before region routing and the product's own error
reaches the user. The fallback is logged and not cached, so the next call
probes again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of probing

Replace the per-product host probe with a startup flag. BROWSERSTACK_GRR_REGION
is read once in config.ts:

- unset or "us": every host stays on its US default, as before; Test
  Management keeps its existing probe
- "eu" / "in": Automate, App Automate (REST, uploads, builds, hub),
  Accessibility and Test Reporting/RCA/build insights/self-heal use that
  region's hosts, and Test Management goes straight to
  test-management-<region> without probing
- any other value fails at startup, so a typo cannot quietly route a GRR
  account to the US

No extra requests are made in any region, and getRegionalHost is now a
synchronous, config-free lookup, so remote mode needs no cache. The flag is
documented in llms-install.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the one conflict, in src/tools/automate-utils/fetch-screenshots.ts:
the GRR change added the regional-host import where browserstack#488 added the log and
screenshot size caps. Both are kept; the screenshot fetch uses the regional
host and the size caps together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The capability registry took tra's host from its index, which declares only
the US host, so an EU deployment sent every invokeCapability call for tra to
api-observability.browserstack.com and the EU account was rejected there.

Resolve tra through the same getRegionalHost("observabilityApi") lookup the
hand-written Test Reporting tools use, next to tm in the registry's built-in
map. Unset or "us" returns the host the index already declares, and
CAPABILITY_REGISTRY_BASE_URL_TRA and per-environment overrides still win.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test Management is the one product that probes its regional hosts. Instead of
skipping the probe when the flag is set, probe in the flag's order: the
configured region first, then the rest in their standard order
(unset/us: us, eu, in; eu: eu, us, in; in: in, us, eu).

A correct flag still answers on the first request, and a missing or wrong
flag still finds the account's region, because the other regions reject it.
The order comes from regionPreference() in regional-host.ts, derived from the
region host table rather than hardcoded per region.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…TACK_GRR_REGION lookup

Replace the TM-only probe ordering with one path for every product: when
BROWSERSTACK_GRR_REGION is set, Test Management (tools and the tm capability),
the tra capability, Automate, App Automate, Accessibility and Test Reporting
all take their host from getRegionalHost() - a lookup on the env flag, with
no probing and nothing to cache.

The flag now stays undefined when unset, so "not configured" is distinct from
"us". Only in that case does Test Management keep its existing US -> EU -> IN
probe, so EU/IN accounts that never set the flag keep working as on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…REGION is eu or in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s eu or in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… resolved TM host

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to the regional host

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Routes main's new Accessibility code by BROWSERSTACK_GRR_REGION: App Accessibility
API and dashboard hosts, App Automate build lookups, the website-scanner call, and
getAutomationBaseUrl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…_REGION

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…overy

With BROWSERSTACK_GRR_REGION set to eu or in, tra no longer probes its base_urls, and
devicecontrol and mobiledevicecontrol (hub and api hosts) use the region's hosts.
Unset keeps the existing discovery and declared hosts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…outing

# Conflicts:
#	src/tools/accessiblity-utils/app-report-fetcher.ts
…bility by region

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review of the GRR region routing. Inline comments cover lines in the diff; three issues are outside it:

  1. AI-TFA / RCA collaboration tools are not routed (src/tools/tfa-rca-utils/constants.ts:6). submit-turn, trigger-report, build-failure-themes and tfa-rca-collaboration still get their host from O11Y_TFA_RCA_BASE_URL, which defaults to US api-automation.browserstack.com, and getRegionalHost never reaches them. With eu, the build data and turn text go to the US host and either fail with 401/404 or put GRR data in the US. The PR description says TRA/RCA are routed, so this looks like a gap.
  2. Dashboard-link parsing is inconsistent (src/tools/accessiblity-utils/report-fetcher.ts:~207, app-report-fetcher.ts:654/660). manualReportIdFromDashboardLink / buildIdFromDashboardLink accept only the regional app-accessibility host, so a US link pasted under eu used to resolve and now doesn't. The automate.browserstack.com / APP_AUTOMATE_HOST checks still accept only US hostnames, so EU dashboard links are never recognised either. Accepting every known regional host would fix both.
  3. Duplicated host-kind selection (src/lib/regional-host.ts:~177). automateApi and appAutomateApi point to the same table, and the sessionType === Automate ? ... : ... ternary is repeated in about 7 files (fetch-screenshots, video, selfheal, list-session-ids, resolve-hashed-build-id…). Some call sites also use getRegionalHost("automationApi") where getAutomationBaseUrl() exists. A single hostForSession(sessionType) helper would keep them from drifting.

Comment thread src/lib/tm-base-url.ts Resolved
Comment thread src/server-factory.ts Resolved
Comment thread src/lib/instrumentation.ts Resolved
Comment thread src/lib/regional-host.ts Resolved
Comment thread src/tools/capability-registry/config.ts Resolved
Comment thread src/config.ts Resolved
SavioBS629 and others added 4 commits October 29, 2026 11:58
- Route the AI-TFA/RCA collaboration host by region
- Compare host overrides by origin, so a trailing slash is not an override
- Keep the Test Management probe for us, matching the other products
- Apply the region to the tm capability at the same point as the others
- Ignore the process-wide region in remote mode
- Accept App Accessibility links from any region
- One sessionApiHost helper instead of repeated host selection

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Look up the account's region once per server config from a user profile
token minted with the configured username and access key, and use it for
routing, telemetry fields and the feedback tool. BROWSERSTACK_GRR_REGION
is used when the lookup fails.

- Each tool call runs in its account's region, so concurrent calls for
  different accounts route independently in hosted mode.
- Telemetry outside a tool call waits for the lookup; when it fails and
  no region is configured, only usage fields are sent.
- BrowserStackMcpServer.create() resolves the region before building the
  server, so the tool list and instructions match it. The local entry
  point uses it.
- submitFeedback declines at call time when the account's region is EU
  or IN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The account's region from BrowserStack auth is now the only source, so
BROWSERSTACK_GRR_REGION is removed. When the lookup fails, hosts keep
their US defaults (Test Management still probes each region) and
telemetry sends only usage fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep only an answer from BrowserStack auth. After a failure the region
is "unknown" for 30 seconds, then the next call looks up again, so a
network blip no longer fixes an account to the default hosts for the
life of the server. Also drop BROWSERSTACK_GRR_REGION from the install
guide, since it was removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed the commits since my last review (24266f6…1efef0d, excluding the upstream/main merge).

Thanks. These are resolved:

  • The us flag no longer disables the TM probe; the flag itself is gone and the region now comes from the account.
  • The override check now compares origins (hostOverride).
  • tm is in REGIONAL_HOSTS, and web_accessibility is now covered too.
  • Multi-tenant: the region is looked up per account and scoped per call through AsyncLocalStorage.
  • sessionApiHost() plus default host params remove the duplicated ternaries.
  • TFA/RCA collaboration now routes through getO11yBaseUrl() → hostFor("automationApi", region). This was item 1 of my previous summary.
  • I accept the decision to keep Percy, askBrowserStackAI, App Live upload, load testing and the US telemetry endpoint out of scope, since they're listed under "Not routed yet".

New, inline: an account whose region lookup fails is routed to US hosts and keeps feedback enabled, while telemetry treats it as restricted. There's also a question about how the region cache behaves in the hosted wrapper.

Still open from the last review (item 2, outside the diff): only the App Accessibility links were switched to isRegionalHostname. report-fetcher.ts:207 (automate.browserstack.com) and app-report-fetcher.ts:651 (APP_AUTOMATE_HOST) still accept only US hostnames, so EU/IN Automate and App Automate dashboard links still aren't recognised. If those dashboards have regional hosts, adding them to HOSTS and using isRegionalHostname would close this.

Comment thread src/lib/region-context.ts Resolved
Comment thread src/lib/feedback-hint.ts Resolved
Comment thread src/lib/account-region.ts Resolved
@sarve-shreyas

Copy link
Copy Markdown
Collaborator

@SavioBS629 I re-reviewed up to 1efef0d (#489 (review)). Most of the earlier points are resolved, thanks! Three new points:

  1. Fail-open on lookup failure (region-context.ts:30): if the auth lookup fails or returns an unrecognised region, the account is unknown and calls route to US hosts for 30s. Telemetry treats the same case as restricted.
  2. Feedback for unknown accounts (feedback-hint.ts:4): submitFeedback stays enabled for unknown accounts, which is inconsistent with telemetry.
  3. Region cache in hosted mode (account-region.ts:21): could you confirm the hosted wrapper reuses one config object per tenant? Otherwise every call re-mints a token.

Also still open from last time: Automate and App Automate dashboard-link parsing (report-fetcher.ts:207, app-report-fetcher.ts:651) still accepts only US hostnames.

SavioBS629 and others added 3 commits October 29, 2026 17:45
Telemetry is now off for accounts in the EU or IN region. When the
account's region can't be looked up, rows still carry usage fields only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IN accounts keep the default hosts, as before this change, and Test
Management and capability discovery still probe for them. They are still
treated as region-restricted for telemetry and submitFeedback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Calls that need the account's region now return an error asking the user
to retry instead of using the default hosts. Test Management still finds
the region by probing. submitFeedback is also unavailable in this case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Servers built per request for the same account now reuse one lookup.
The region is kept for an hour, a failed lookup is retried after 5
seconds, and region values are matched in any case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed df5fef1…1851231.

Resolved from my last review:

  • Fail-open on unknown region. assertRegionKnown() / routedRegion() now refuse with a retry message instead of falling back to US, TM still probes, and a 5s retry window fits the message.
  • Feedback for unknown accounts. feedbackEnabled() now uses isRestrictedRegion.
  • Region cache in hosted mode. It's keyed on a credential hash, bounded, and has a TTL, so servers built per request share one lookup.
  • Region value casing. regionFromToken lowercases the value, so "EU" resolves.

New, inline: the known region is dropped when a refresh fails after the TTL, which now fails closed. IN accounts route to US, and the PR description doesn't say so. A startup-only nit on submitFeedback.

Still open (outside the diff): Automate and App Automate dashboard-link parsing (report-fetcher.ts:207, app-report-fetcher.ts:651) still accepts only US hostnames.

Comment thread src/lib/account-region.ts Resolved
Comment thread src/lib/regional-host.ts Resolved
Comment thread src/server-factory.ts Resolved
A failed refresh no longer drops an account's known region, so an auth
outage doesn't stop tools for accounts already looked up. submitFeedback
stays listed when the region is unknown at startup, and each call
decides whether it can send.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@SavioBS629

Copy link
Copy Markdown
Collaborator Author

On the Automate and App Automate dashboard-link parsing (report-fetcher.ts, app-report-fetcher.ts): keeping it out of this PR. Dashboard links are listed under "Not routed yet" and will follow once their regional hosts are confirmed.

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed 390c066. No new issues; everything from my earlier rounds is either fixed or explicitly deferred:

  • Region kept on a failed refresh: accountRegion serves the last known region while a refresh runs and when it fails, and resets failedAt once a refresh succeeds. Only accounts that have never been looked up get the retry error.
  • Startup with an unknown region: feedbackListed() keeps submitFeedback listed. The call check (feedbackEnabled()) and withFeedbackHint still decline or hide the hint while the region is unknown, so this is consistent.
  • Deferred, as listed in the description under "Not routed yet": IN routing, Automate and App Automate dashboard links, and switching the hosted server to create().

Looks good from my side.

sarve-shreyas
sarve-shreyas previously approved these changes Oct 30, 2026

@sarve-shreyas sarve-shreyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving at 390c066. The deferred items (IN routing, Automate and App Automate dashboard links, and the hosted server switching to create()) are tracked under "Not routed yet".

When BrowserStack auth can't be reached or names a region not known here,
the region is taken from the first Test Management host that accepts the
account, trying the regional hosts first. A probed region is asked of auth
again after five minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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