Skip to content

fix(connections): discover Linear MCP OAuth endpoints - #11078

Open
cryppadotta wants to merge 3 commits into
masterfrom
fix/linear-mcp-oauth-discovery
Open

fix(connections): discover Linear MCP OAuth endpoints#11078
cryppadotta wants to merge 3 commits into
masterfrom
fix/linear-mcp-oauth-discovery

Conversation

@cryppadotta

@cryppadotta cryppadotta commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Thinking Path

  • Paperclip is the open source app people use to manage AI agents for work.
  • Connected Apps gives governed agents access to provider tools through the MCP OAuth broker.
  • The Linear catalog entry pinned OAuth endpoints from Linear's classic API authorization server.
  • A complete catalog endpoint pair takes priority over OAuth protected-resource discovery.
  • The pinned pair therefore prevented the broker from finding Linear's MCP authorization server and its dynamic client registration endpoint.
  • This pull request removes the invalid pair, enables the Linear wizard path, and adds tests for both precedence branches.
  • The benefit is a discovery-first Linear MCP connection that keeps the broker's current precedence rule explicit and tested.

Linked Issues or Issue Description

What happened?

The Linear MCP catalog entry supplied linear.app authorization and api.linear.app token endpoints. The broker treated this complete pair as authoritative and did not discover the authorization server declared by mcp.linear.app.

Expected behavior

Paperclip must start from Linear's RFC 9728 protected-resource metadata. It must then use the RFC 8414 authorization-server metadata at mcp.linear.app and register a public client through DCR when no configured client exists.

Steps to reproduce

  1. Open the Linear Connected Apps wizard.
  2. Start OAuth with the prior Linear catalog defaults.
  3. Observe that the broker selects the classic Linear endpoint pair and skips MCP OAuth discovery.

Paperclip version or commit

master before this pull request.

Deployment mode

Local dev and self-hosted server.

Related research: https://github.com/paperclipai/paperclip-content/pull/15

What Changed

  • Removed the classic Linear authorization and token endpoint hints from the app definition.
  • Updated Linear guidance for discovery and dynamic client registration.
  • Added broker regression tests for complete-pair precedence and discovery when the pair is absent.
  • Added Linear to the direct MCP OAuth wizard allowlist and covered its deep link.
  • Expanded the Linear connector playbook entry with risk, scopes, connection flow, administrator setup, endpoint quirks, and QA requirements.

Verification

  • Pre-change data check: 0 live Linear connections, 0 stored classic authorization endpoint matches, and 0 stored classic token endpoint matches.
  • pnpm exec vitest run packages/shared/src/app-definitions.test.ts ui/src/pages/apps/app-connect-policy.test.ts server/src/__tests__/tool-access-service.test.ts -t 'AppDefinition catalog|app connect policy|endpoint pair|discovers Linear'
  • pnpm check:token-gates
  • pnpm -r typecheck
  • env -u AWS_ACCESS_KEY_ID -u AWS_SECRET_ACCESS_KEY -u AWS_SESSION_TOKEN pnpm test:run
  • The full-suite command removes ambient organization AWS credentials because the CLI doctor fixture asserts the profile-only credential path.
  • pnpm build
  • git diff --check

Risks

  • Linear OAuth now depends on provider metadata availability. The broker validates the protected-resource and authorization-server relationship before it uses discovered endpoints.
  • A future complete manifest pair would override discovery. The new precedence tests make that behavior explicit and detect a regression.
  • Linear's DCR redirect constraints and token lifetime remain undocumented. The manifest does not guess a redirect rule, and the playbook asks real-account QA to record both values.

For core feature work, check ROADMAP.md first and discuss it in #dev before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See CONTRIBUTING.md.

Model Used

OpenAI Codex with GPT-5. The hosted runtime does not expose a more specific model build ID or context-window size. The model used reasoning, tool use, and code execution.

Checklist

  • I have included a thinking path that traces from project context to this change
  • I have specified the model used (with version and capability details)
  • I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work
  • I have searched GitHub for duplicate or related PRs and linked them above
  • I have either (a) linked existing issues with Fixes: # / Closes # / Refs # OR (b) described the issue in-PR following the relevant issue template
  • I have not referenced internal/instance-local Paperclip issues or links (only public GitHub #NNN / github.com/paperclipai/paperclip URLs)
  • My branch name describes the change (e.g. docs/..., fix/...) and contains no internal Paperclip ticket id or instance-derived details
  • I have run tests locally and they pass
  • I have added or updated tests where applicable
  • I have updated relevant documentation to reflect my changes
  • I have considered and documented any risks above
  • All Paperclip CI gates are green
  • Greptile is 5/5 with no open P2s, recommendations, or follow-ups
  • I will address all Greptile and reviewer comments before requesting merge

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR changes Linear MCP OAuth from fixed classic API endpoints to protected-resource and authorization-server discovery, including dynamic client registration. It also enables Linear in the direct OAuth wizard and adds regression coverage for discovery and endpoint precedence.

  • Removes Linear’s fixed authorization and token endpoint hints.
  • Enables the Linear gallery card and direct connection deep link.
  • Documents the discovery-first connection flow and direct-API read-only workaround.
  • Adds catalog, UI policy, and broker tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/shared/src/app-definitions/linear.json Removes the classic Linear OAuth endpoint pair so the broker discovers the MCP authorization server and performs dynamic client registration.
server/src/tests/tool-access-service.test.ts Adds regression coverage for complete manifest-pair precedence and discovery-first Linear OAuth.
ui/src/pages/apps/app-connect-policy.ts Adds Linear to the direct MCP OAuth connection allowlist.
ui/src/pages/apps/Browse.tsx Generalizes gallery connection links to use the direct OAuth policy for both Notion and Linear.
doc/connections/CONNECTOR-PLAYBOOK.md Documents Linear’s discovery and registration flow, endpoint behavior, wizard limitations, and QA expectations.

Reviews (3): Last reviewed commit: "fix(apps): enable allowlisted OAuth tile..." | Re-trigger Greptile

Comment thread doc/connections/CONNECTOR-PLAYBOOK.md Outdated
Co-Authored-By: Paperclip <noreply@paperclip.ing>

@cryppadotta cryppadotta left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Security review verdict: changes requested (OWASP API: Unsafe Consumption of APIs; STRIDE: Spoofing / Information Disclosure; principles: Complete Mediation, Fail Securely).

Blocking finding — OAuth AS mix-up / unattested token endpoint fallback

discoverOAuthEndpoints builds candidates from the configured MCP serverUrl, but after the RFC 9728 protected-resource candidates it also tries /.well-known/oauth-authorization-server and /.well-known/openid-configuration directly. Consequently, when Linear's protected-resource metadata is missing, malformed, or returns no usable endpoints, startOAuth can still accept an AS document and persist/send the authorization code + PKCE verifier to its token_endpoint, even though the protected resource never named that authorization server.

PoC regression shape:

  1. https://mcp.linear.app/.well-known/oauth-protected-resource/mcp and the origin-level protected-resource URL return 404/unusable metadata.
  2. https://mcp.linear.app/.well-known/oauth-authorization-server returns authorization, token, and registration endpoints (the token endpoint can be another public origin).
  3. Current code completes DCR/start and later posts the code/verifier to that token endpoint. Expected: discovery fails before DCR/authorization because there is no RFC 9728 attestation.

Blast radius: a compromised/misconfigured discovery surface (or equivalent upstream control) can redirect OAuth code material and PKCE verifier to an unattested AS. Exploitability is low-to-moderate because HTTPS/provider-origin control is required; impact is high for the connecting Linear identity and potentially its authorized workspace data. Overall: medium.

Required fix:

  • For gallery MCP OAuth entries without a complete trusted manifest pair, require successful RFC 9728 resource metadata rooted at the configured protected resource.
  • Follow only an authorization_servers issuer advertised by that resource; do not fall through to bare AS/OIDC discovery.
  • Validate the protected-resource resource value against the configured resource when present, and validate returned AS issuer against the advertised issuer when present.
  • Add a negative regression test proving unavailable/unusable resource metadata never reaches DCR or a token endpoint. Keep the new positive Linear test and complete-pair precedence test; they correctly pin both requested branches and would fail if the wrong Linear pair were re-added.

Other review areas passed:

  • Complete manifest pair remains authoritative and skips discovery.
  • Linear's manifest omission drives RFC 9728 first in the happy path.
  • PKCE uses S256 with a random verifier; state is expiring, one-time, and actor/session-bound.
  • DCR requests a public client and validates the exact redirect URI/grants/response type/auth method returned.
  • Callback URI is server-derived rather than request-controlled, and non-GET OAuth redirects are rejected.
  • No access tokens, client secrets, or live credentials appear in the diff, fixtures, or connector playbook.

Residual risk after the fix: a genuinely attested malicious/compromised AS can still choose its own endpoints; that is inside the protected resource's delegated trust boundary and should remain constrained by SSRF checks and TLS.

@cryppadotta

Copy link
Copy Markdown
Contributor Author

UX review (UXDesigner, PAP-16806) — changes requested: one gating UI gap, core flow verified live

Ran this branch (f131cf69) on an isolated instance with a real browser (1440×900 + 390×844). Full verdict + 8 screenshots: PAP-16806.

Verified working: /apps/connect?source=linear auto-starts and redirects to https://mcp.linear.app/authorize with a DCR-issued client_id and PKCE S256 — the wrong hard-coded linear.app/oauth/authorize / api.linear.app/oauth/token pair is gone from the wire. Linear's consent interstitial shows the registered client + "Access: Read, Write", and Approve chains into Linear's login. Flow shape is identical to notion. New guidanceMd copy is accurate for DCR.

Gating (PAP-16826): the flow is unreachable by clicking. Browse.tsx#connectHrefFor still hard-codes only notion/zapier, so the Linear tile renders disabled "Coming soon" on /apps (Popular + All apps) even on this branch. Fix: isMcpDirectOAuthConnectSlug(slug) ? appSourceConnectHref(slug) : …, plus a Browse test asserting the tile state follows the allowlist.

Filed separately, not gating (PAP-16827, pre-existing broker behavior shared with notion): provider-cancel dead-ends at raw JSON on /api/tools/oauth/callback?error=access_denied (HTML redirect branch is success-only); raw technical error strings pass through to the wizard error card; abandoned OAuth drafts show as "Paused" on Connections.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@cryppadotta

Copy link
Copy Markdown
Contributor Author

@greptile review

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.

1 participant