mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-06 12:03:07 +08:00
fix: sync MCP marketplace with extensions catalog (#645)
Update the extensions dependency to the commit that removes deprecated MCP entries, assert those entries stay absent from the marketplace, and keep legacy installed servers visible/searchable in the MCP settings UI. Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
@@ -400,7 +400,7 @@ return new ConversationClient(getAgentServerClientOptions()).someMethod(...);
|
||||
|
||||
- Custom secrets are NOT auto-attached by the agent-server. `POST /api/conversations` only persists what the client sends in `request.secrets`; the persisted secrets store (`/api/settings/secrets`) is never read at conversation-start. `buildStartConversationRequestWithEncryptedSettings` enumerates `SecretsService.getSecrets()` and turns each entry into a `LookupSecret` whose `url` points back at `/api/settings/secrets/{name}` and whose `headers` carry `X-Session-API-Key` for auth. Pre-1.21.x agent-server SDKs would silently drop that header during validation when `secrets_encrypted=true` (the cipher in the validation context tried to `cipher.decrypt(plaintext_session_key)`, failed, and the validator removed the header — the conversation runtime then got 401s for every saved secret). The SDK fix preserves plaintext header values when decryption fails; if you still see saved secrets unavailable inside a conversation, verify the running agent-server bundles a `LookupSecret._validate_secrets` that falls back to plaintext on decrypt failure.
|
||||
|
||||
- MCP page layout: MCP is a **top-level** nav entry at `/mcp` (rendered by `src/routes/mcp.tsx`), shown right below "Skills" in `src/components/features/sidebar/sidebar.tsx`. The legacy `/settings/mcp` route still works as a redirect via `src/routes/mcp-settings-redirect.tsx`, and `src/routes/mcp-settings.tsx` re-exports the new page so the published `MCPSettings` library symbol (in `src/components/settings/index.ts`) keeps the same shape. Marketplace catalog data and MCP logo mappings live in `@openhands/extensions/mcps`; the Slack catalog entry there should point at `https://github.com/zencoderai/slack-mcp-server` and use `@zencoderai/slack-mcp-server`. `src/utils/mcp-marketplace-utils.ts` matches installed servers back to catalog entries. Tavily is a regular stdio MCP entry (`tavily-mcp` + `TAVILY_API_KEY`), not a special built-in sentinel anymore. Components are colocated under `src/components/features/mcp-page/` and reuse the existing `MCPServerForm` for the "Add custom server" / edit flow.
|
||||
- MCP page layout: MCP is a **top-level** nav entry at `/mcp` (rendered by `src/routes/mcp.tsx`), shown right below "Skills" in `src/components/features/sidebar/sidebar.tsx`. The legacy `/settings/mcp` route still works as a redirect via `src/routes/mcp-settings-redirect.tsx`, and `src/routes/mcp-settings.tsx` re-exports the new page so the published `MCPSettings` library symbol (in `src/components/settings/index.ts`) keeps the same shape. Marketplace catalog data and MCP logo mappings live in `@openhands/extensions/mcps`; the Slack catalog entry there should point at `https://github.com/zencoderai/slack-mcp-server` and use `@zencoderai/slack-mcp-server`. Deprecated marketplace entries removed upstream (for example GitLab / Google Maps / Postgres / Puppeteer / SQLite) should disappear from the marketplace grid, but existing installed servers with those names must still render in the Installed section and stay searchable/editable/deletable via the raw server `name` / `command` fallback in `src/utils/mcp-marketplace-utils.ts` + `InstalledServerCard`. Tavily is a regular stdio MCP entry (`tavily-mcp` + `TAVILY_API_KEY`), not a special built-in sentinel anymore. Components are colocated under `src/components/features/mcp-page/` and reuse the existing `MCPServerForm` for the "Add custom server" / edit flow.
|
||||
|
||||
- Library packaging notes:
|
||||
- Public npm entrypoints now come from `src/index.ts` → `src/lib/index.ts`, with domain barrels under `src/components/{conversation,terminal,browser,files,settings,sidebar}/index.ts`.
|
||||
|
||||
@@ -31,6 +31,16 @@ describe("OpenHands extensions catalogs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("drops deprecated MCP entries that no longer have maintained replacements", () => {
|
||||
const catalogIds = new Set(MCP_CATALOG.map((entry) => entry.id));
|
||||
|
||||
expect(catalogIds.has("gitlab")).toBe(false);
|
||||
expect(catalogIds.has("google-maps")).toBe(false);
|
||||
expect(catalogIds.has("postgres")).toBe(false);
|
||||
expect(catalogIds.has("puppeteer")).toBe(false);
|
||||
expect(catalogIds.has("sqlite")).toBe(false);
|
||||
});
|
||||
|
||||
it("loads recommended automations from @openhands/extensions", () => {
|
||||
expect(AUTOMATION_CATALOG.length).toBeGreaterThan(0);
|
||||
|
||||
|
||||
@@ -107,10 +107,44 @@ describe("MCPPage", () => {
|
||||
screen.queryByTestId("mcp-marketplace-card-github"),
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId("mcp-marketplace-card-postgres"),
|
||||
screen.queryByTestId("mcp-marketplace-card-gitlab"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps installed legacy servers visible even after their marketplace entries are removed", async () => {
|
||||
vi.spyOn(SettingsService, "getSettings").mockResolvedValue(
|
||||
buildSettings({
|
||||
agent_settings: {
|
||||
...MOCK_DEFAULT_USER_SETTINGS.agent_settings,
|
||||
mcp_config: {
|
||||
mcpServers: {
|
||||
gitlab: {
|
||||
command: "npx",
|
||||
args: ["-y", "@modelcontextprotocol/server-gitlab"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
renderPage();
|
||||
|
||||
await screen.findByTestId("mcp-installed-list");
|
||||
expect(screen.getByText("gitlab")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId("mcp-marketplace-card-gitlab"),
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
const search = screen.getByTestId("mcp-search-input");
|
||||
fireEvent.change(search, { target: { value: "gitlab" } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("gitlab")).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTestId("mcp-marketplace-empty")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows a search-empty state when the query matches nothing", async () => {
|
||||
vi.spyOn(SettingsService, "getSettings").mockResolvedValue(buildSettings());
|
||||
|
||||
|
||||
Generated
+3
-3
@@ -12,7 +12,7 @@
|
||||
"@heroui/react": "2.8.10",
|
||||
"@microlink/react-json-view": "1.31.20",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#c3f896acc55d8ee8717ab40f236960e71c2d477d",
|
||||
"@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#7b33f64ffccf95f7ccd2ec640aeae84ab1cc2c75",
|
||||
"@openhands/typescript-client": "git+https://github.com/OpenHands/typescript-client.git#v0.6.0",
|
||||
"@react-router/node": "7.14.2",
|
||||
"@react-router/serve": "7.14.2",
|
||||
@@ -3441,8 +3441,8 @@
|
||||
},
|
||||
"node_modules/@openhands/extensions": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "git+https://github.com/OpenHands/extensions.git#c3f896acc55d8ee8717ab40f236960e71c2d477d",
|
||||
"integrity": "sha512-PzLYaZA9ys8is9dNqNDDAExkz40DJ7t1sXUUrUUdha6vrO1/J4xqspK4YLOp0V5i4DewP3U9Rzqi2nFC/bVIMQ==",
|
||||
"resolved": "git+https://github.com/OpenHands/extensions.git#7b33f64ffccf95f7ccd2ec640aeae84ab1cc2c75",
|
||||
"integrity": "sha512-vozWq4MJiKoColb7zvXYgtxmWJsk7LdjdRH9SQebheHDOKvDAn7xy+sM7d0mEFRCk3QDEaVyR5HMH9w/1HH25Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.20.0"
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
"@heroui/react": "2.8.10",
|
||||
"@microlink/react-json-view": "1.31.20",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#c3f896acc55d8ee8717ab40f236960e71c2d477d",
|
||||
"@openhands/extensions": "git+https://github.com/OpenHands/extensions.git#7b33f64ffccf95f7ccd2ec640aeae84ab1cc2c75",
|
||||
"@openhands/typescript-client": "git+https://github.com/OpenHands/typescript-client.git#v0.6.0",
|
||||
"@react-router/node": "7.14.2",
|
||||
"@react-router/serve": "7.14.2",
|
||||
|
||||
Reference in New Issue
Block a user