-
Notifications
You must be signed in to change notification settings - Fork 46
refactor: PLTF-2954 Remove vendor-specific entry.id transport patches from generic MCP catalog #1339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
refactor: PLTF-2954 Remove vendor-specific entry.id transport patches from generic MCP catalog #1339
Changes from all commits
96dab03
32f0a1c
28ed601
f0cd4ee
2ae38a1
4f00ec7
1e986b4
136c54a
418d29d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,56 +69,10 @@ export function getDefaultMcpTransport( | |
| return getDefaultMcpConnectionOption(entry)?.transport; | ||
| } | ||
|
|
||
| const LINEAR_DEPRECATED_SSE_URL = "https://mcp.linear.app/sse"; | ||
| const LINEAR_SHTTP_URL = "https://mcp.linear.app/mcp"; | ||
| const LINEAR_DOCS_URL = "https://linear.app/docs/mcp"; | ||
|
|
||
| /** | ||
| * Upstream @openhands/extensions still ships Linear's deprecated SSE | ||
| * transport (removed upstream on 2026-04-08; the /sse endpoint now | ||
| * rejects every call). Rewrite the entry to streamable HTTP at the | ||
| * /mcp replacement endpoint until the pinned dependency catches up. | ||
| * | ||
| * The /mcp endpoint authenticates via OAuth 2.1 or a Linear API key | ||
| * sent as "Authorization: Bearer <token>". This client has no | ||
| * interactive OAuth flow for MCP installs, so switch the auth | ||
| * strategy from "none" to "bearer" — the install modal then offers | ||
| * an (optional) API key field and the agent server forwards it as a | ||
| * Bearer header. | ||
| * | ||
| * Patches immutably — the imported catalog JSON is shared module | ||
| * state and must not be mutated. | ||
| */ | ||
| function patchLinearEntry(entry: MarketplaceEntry): MarketplaceEntry { | ||
| if (entry.id !== "linear") return entry; | ||
| return { | ||
| ...entry, | ||
| docsUrl: LINEAR_DOCS_URL, | ||
| installHint: | ||
| "Authenticate with a Linear API key (Linear → Settings → Security & access) — sent as a Bearer token. Optional when the endpoint accepts your OAuth session.", | ||
| connectionOptions: entry.connectionOptions.map((option) => | ||
| option.transport?.kind === "sse" && | ||
| urlsMatch(option.transport.url, LINEAR_DEPRECATED_SSE_URL) | ||
| ? { | ||
| ...option, | ||
| auth: { ...option.auth, strategy: "bearer" as const }, | ||
| transport: { | ||
| kind: "shttp" as const, | ||
| url: LINEAR_SHTTP_URL, | ||
| apiKeyOptional: option.transport.apiKeyOptional, | ||
| }, | ||
| } | ||
| : option, | ||
| ), | ||
| }; | ||
| } | ||
|
|
||
| export function getMcpMarketplaceCatalog( | ||
| catalog: MarketplaceEntry[], | ||
| ): MarketplaceEntry[] { | ||
| return catalog | ||
| .map(patchLinearEntry) | ||
| .filter((entry) => !!getDefaultMcpConnectionOption(entry)); | ||
| return catalog.filter((entry) => !!getDefaultMcpConnectionOption(entry)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line now trusts the upstream catalog verbatim, but the pinned This inline comment was created by an AI agent (OpenHands) on behalf of the user. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm on it! enyst can track my progress at all-hands.dev
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😅 My agent talks to itself. I was under the impression we fixed this one, oops. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the last summary:
Status against the original PR-comment request:
|
||
| } | ||
|
|
||
| const tryUrl = (raw: string): URL | null => { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your thoughts on maintaining these tests? Maybe a CI that checks for breaking changes for mcp configs between version bumps is a more helpful signal (which can be a follow up, not necessary for the scope of this pr)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be nice to have now is a generic test that ensures that we're not individually patching mcp catalog entries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like you may benefit from contract testing for the first question to verify changes did not break some known contract. https://docs.pact.io/ is a standard tool for this although you have to typically run a pact broker to store the contracts. For a project like agent canvas where I think the client and server live in the same repo, typically we can get away with lighter contract testing. What are some ways MCP configs have been breaking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an interface for the mcp catalog? That would be a generic concept and we can have a test suite against that and clean up the vendor specific tests. I am seeing some examples for https://import-linter.readthedocs.io/en/stable/ which seems like it would allow you to prevent importing vendor specific logic in core modules:
Then you can run import linter as a CI check:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@malhotra5 what do you think about doing a spike for documenting the ways MCP configs have been breaking and coming up with an import linter POC to catch those issues sooner in CI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were actually no imports here for these patches so import linter does not look like the right tool 🤔
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about testing! I've addressed the comment cleanup in this PR. The suggestion about contract testing for MCP configs between version bumps would be a great follow-up. The import-linter approach mentioned in the thread could also help prevent vendor-specific code from creeping into the generic layer in the future.
This reply was generated by an AI assistant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, unrelated to this PR,
I like this! I was looking for something like this a bit ago. We need this in the sdk IMHO. So we have
sdkpackage should never import `tools, etcThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh awesome I am glad there is a use case for a random tool I found 😁
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@malhotra5 you may be able to use an eslint rule: