Repository navigation
Check Atlassian API tokens at setup and give the model the cloudId - #1442
Merged
Merged
Conversation
6 of 7 tasks
helpcodeai
force-pushed
the
fix/atlassian-api-token-setup
branch
from
November 2, 2026 09:06
e6a0da7 to
f1ee308
Compare
The Atlassian Rovo MCP bridge had no setup check, so a token pasted twice and a token created without scopes were both saved as ready and failed every call. - Setup check for MCP bridges: the adapter's probe, or tools/list when it declares none. An isError tool result and probe.failWhen rules fail the check; a hint can name the field it belongs under; the status the MCP SDK keeps in data.status is read. - Atlassian probes the read-only discover: a 401 is put under the token with what to check, an empty searchableProducts or "missing the scope claim" asks for an API token with scopes. Token pattern capped at 300. - Optional ATLASSIAN_SITE: the cloudId is looked up from the site's public tenant_info (derivedEnvVars) at the check, at install and when the site changes in the variable editor, and stored as ATLASSIAN_CLOUD_ID. - instructionFacts: per-workspace sentences added to a catalog connector's instructions when served, so the model is told the site and cloudId. Only non-secret variables are rendered. - Instructions and cloudId descriptions use that cloudId and fall back to getAccessibleAtlassianResources, then to asking for the site. - Call-time hints for invalid_token and "missing the scope claim", also on MCP isError results, linking the connector page. - Regenerate llms-full.txt.
helpcodeai
force-pushed
the
fix/atlassian-api-token-setup
branch
from
November 2, 2026 10:03
f1ee308 to
c75a1b4
Compare
helpcodeai
enabled auto-merge (squash)
November 2, 2026 10:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merge order: #1437, then #1443, then this PR. This branch is built on
fix/stuck-connector-errors(#1437), so until #1437 is merged the diff below also shows its three commits. The commit of this PR is the last one. The MCP argument-filtering fix that this PR used to carry is now its own PR, #1443 ("Send MCP bridge tools only the variables their schema declares"), so it can ship first. Until #1443 is merged, the Atlassian setup probe and calls also send the connector's variables (email and token) to Atlassian's server as tool arguments, as every MCP bridge does today.The Atlassian (Jira, Confluence) adapter bridges Atlassian's Rovo MCP server with a personal API token. No call through it has ever succeeded on Cloud. Read-only checks showed two setup faults that the setup form accepted:
initializeanswers 401{"error":"invalid_token"}.initializeandtools/listwork, butdiscoverreturnssearchableProducts: []. Every Jira and Confluence tool then answers "Unable to resolve user scopes … missing the scope claim".The bridge also had no setup check at all, because MCP adapters had no probe. And the instructions told the model to "start with getAccessibleAtlassianResources … every call needs a cloudId". Atlassian says API tokens are not bound to a cloudId, and we could not confirm that this tool works with an API token.
This PR does the following:
mycompany.atlassian.net).Changes
Setup check for MCP bridges (generic)
verifyCredentialsruns the adapter'sprobefor an MCP adapter. Without a probe it lists the server's tools, which is what the install does anyway. Before this change every MCP bridge was skipped (no_probe).isError: trueresult, or when the answer matches a newprobe.failWhenrule (a regex over the result text with ahint, an optionalfieldand an optionalkind).data.status(or in an explained error'scause) is now read, so a 401 is classified asauth_failed.verifyHintsentry can name afield, and its message is then shown under that field on the setup form.Atlassian adapter
discoverwithquery: "get issue details".searchableProductsor "missing the scope claim" fails the check with: "This API token has no scopes. Create an 'API token with scopes' … agent-interface scopes …".ATLASSIAN_SITE(non-secret, labelled "strongly recommended"). The pattern accepts a host underatlassian.net, with or withouthttps://and a trailing slash. It is stored as a bare lower-case host.cloudIdparameter descriptions are rewritten:getAccessibleAtlassianResources.cloudId, and suggest setting the site on the connector.getAccessibleAtlassianResourcesno longer says "Call it first".Derived settings (
derivedEnvVars, generic,derived-settings.ts)ATLASSIAN_CLOUD_IDcomes from the publichttps://<site>/_edge/tenant_info, using one unauthenticated GET through the SSRF-guarded client.PUT :id/env-vars,PUT :id), only when the site changes.Instruction facts (
instructionFacts, generic,instruction-facts.ts){{VAR}}, and writing a fact into them at install would count as a user edit and block "Apply update".Call-time hints
error-hints.tshandles theatlassianadapter only (a hand-built OAuth connector to the same server keeps the OAuth advice):invalid_token/ 401 → the same advice as at setup.isError: truenow go throughderiveErrorHinttoo. Before, they were returned without any hint. Any hint is appended after the server's own words.extractErrorDetailkeeps the MCP SDK'sdata.status.Validator and docs
validate-adapters.mjsnow checksprobe.failWhen,derivedEnvVars,instructionFacts(non-secret variables only) andverifyHints.*.field.docs/tool-definition.mdanddocs/connectors/mcp-bridge.mdare updated, andllms-full.txtis regenerated.Catalog: structural vs read at call time
Installed Atlassian connectors need Apply update for:
cloudId/getAccessibleAtlassianResourcesdescriptions in the catalog snapshot (tools installed fromtools/listkeep the server's own descriptions)ATLASSIAN_SITEfield in the setup formThese are read from the catalog at check, call or serve time and reach installed connectors without "Apply update":
probe/failWhen/verifyHints(the next setup check)derivedEnvVars(the next variable edit)instructionFactsAn installed connector can therefore be fixed by setting the site in its variable editor and replacing the token. "Apply update" is only needed for the new instructions text.
Cloud vs self-hosted
Both deployments behave the same. Nothing here depends on
DEPLOYMENT_MODE. The tenant_info lookup and the MCP calls go out from the AnythingMCP server in both deployments, through the same SSRF guard.Type
Testing
New and updated specs:
adapters.service.atlassian-verify.spec.ts: 401 on the token field, token pasted twice, token too long, unscoped token (emptysearchableProductsand the scope-claimisError), scoped token OK, site → cloudId with normalisation, 404 site on its field, non-atlassian.net site refused with no lookup, timeout continues, install stores site and cloudId, "Save anyway" without cloudId, MCP bridge without probe → tools/list, and SDK status read fromcause.data.derived-settings.spec.ts,instruction-facts.spec.ts,probe.util.spec.tsdynamic-mcp-tools.atlassian-hints.spec.ts: the unscoped-token hint on anisErrorresult,invalid_tokenhint with status 401, and other MCP refusals are left untouched.error-hints.stuck-connectors.spec.ts: Atlassian rules, and the OAuth missing-scope advice is kept elsewhere.mcp-servers.instructions.spec.ts: facts in initialize instructions, visible content and the shared guide, with no secret.connectors.controller.spec.ts: the variable editors store, refuse and drop the cloudId.intl/atlassian.live.spec.ts: static checks always run (site pattern, token length, derived and facts, probe and rule, instructions). The live part is gated behindRUN_ATLASSIAN_LIVE=1and readsATLASSIAN_EMAIL/ATLASSIAN_API_TOKEN/ATLASSIAN_SITEfrom the environment only. It runs tenant_info,discoverand one JQL search, all read-only. It was not run here.Commands, all run from the repository root unless noted, on the current #1437 head (
03e91544), after splitting out #1443:node scripts/validate-adapters.mjs --warnintl/atlassian.json(existing warnings in other adapters unchanged)node scripts/validate-adapters.mjsnode scripts/regenerate-catalog.mjscatalog.tschanges only in the type declarations (in sync after regeneration)node scripts/adapter-count.mjs --checknode scripts/generate-llms-txt.mjs --checkllms-full.txtnode --test scripts/validate-adapters.test.mjs scripts/adapter-new.test.mjs scripts/generate-llms-txt.test.mjsnode --test scripts/satellites/satellites.test.mjsnode --test scripts/check-runtime-deps.test.mjs && node scripts/check-runtime-deps.mjsnpx prisma generatenpx tsc --noEmit -p tsconfig.jsonnpm run lint:checknpx jest --maxWorkers=4 src/adapters src/mcp-server/dynamic-mcp-tools src/mcp-server/error-hints src/connectors/connectors src/connectors/catalog-resync src/connectors/engines/mcp-client src/mcp-servers src/mcp-server/shared src/mcp-server/mcp-resourcesThe full backend
npm testwas not run: only the targeted suites above. Before the rebase,src/adapters/mcp-adapter.spec.ts"prefixes the tools of a bridge that sets a tool prefix (linear)" failed on #1437's own pattern enforcement. #1437 fixed this in03e91544, and it passes after the rebase.Checklist
npm test): targeted suites only, see aboveRelated Issues
Depends on #1437. Merge after #1437 and after #1443.
Open points
RUN_ATLASSIAN_LIVE=1needs a scoped test token. Thediscoverresult shape for unscoped and scoped tokens comes from the read-only production checks described above.cloudId. A third-party listing suggests it does. The instructions say "try", and the reliable path is the stored cloudId.cloudId. Filling it in automatically fromATLASSIAN_CLOUD_ID(for example a parameter default, or naming the derived variablecloudId, which the schema-based injection of Send MCP bridge tools only the variables their schema declares #1443 would then fill) is possible but left out of this PR.PUT :id/PUT :id/env-varseditors showATLASSIAN_CLOUD_IDas an ordinary variable. A user can edit it by hand, and it is only looked up again when the site changes.isErrorresults. For example, a missing-scope text from an OAuth MCP server now gets the existing "Authorize with Provider" advice.