Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .agents/skills/custom-codereview-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,12 @@ If a PR adds or modifies OpenHands SDK-specific documentation (API guides, SDK u
- The canonical source of truth for SDK documentation is <https://docs.openhands.dev/sdk> and its `llms.txt` index.
- The `skills/openhands-sdk/SKILL.md` in this repo is a thin pointer to the docs site. It should NOT contain duplicated SDK content.
- **Push back**: ask the submitter to contribute SDK documentation changes to [OpenHands/docs](https://github.com/OpenHands/docs) instead.

## Pre-release Integration Catalog Changes

The `@openhands/extensions/mcps` catalog was experimental and pre-release. If a
PR intentionally replaces it with the broader `integrations` catalog and updates
known downstream consumers in the same coordinated stack, do not require
backward-compatible `mcps` aliases or a deprecation window. Require migration
documentation for consumers, but accept a clean breaking change for this
pre-release surface.
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ When editing or adding skills in this repo, follow these rules (and add new skil
- Keep formatting consistent across skills.
- If you change a skill’s behavior or scope, update its `README.md` (if present) accordingly.
- If you change top-level documentation, ensure links still resolve.
- `mcps/catalog/*.json` is the source of truth consumed by `@openhands/extensions`; agent-canvas imports this package directly, so MCP marketplace fixes belong here rather than in app-local constants. When upstream MCP projects move repos, verify both `docsUrl` and the install template (`command`/`args`), not just links.
- `integrations/catalog/*.json` and `integrations/index.js` are the source of truth consumed by `@openhands/extensions`; agent-canvas and integrations-hub import this package directly, so integration marketplace fixes belong here rather than in app-local constants. When upstream MCP projects move repos, verify both `docsUrl` and the connection option (`transport`, `command`/`args`, or URL), not just links.
- For Python test runs, prefer `uv sync --group test` followed by `uv run pytest -q`; the full suite depends on `openhands-sdk`, which is not available in the base environment.
- Agent-driven plugins (for example `plugins/pr-review` and `plugins/release-notes`) use `uv run --with openhands-sdk --with openhands-tools ...` and require an `LLM_API_KEY` in addition to `GITHUB_TOKEN`.
- For OpenHands Cloud API guidance, automations, and CLI integration, use `plugins/openhands`. It is the canonical unified OpenHands plugin covering the V1 Cloud API, Automations API, and CLI. The individual skills (`skills/openhands-api`, `skills/openhands-automation`) are also available standalone.
Expand Down
62 changes: 62 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Migration Guide

## MCP catalog to integration catalog

This package version is still `0.0.0`, and the MCP catalog was an experimental
pre-release API. This migration intentionally removes the old MCP-only export
paths and names instead of keeping deprecated aliases.

### Import paths and symbols

Before:

```js
import { MCP_CATALOG } from "@openhands/extensions/mcps";
import { MCP_LOGOS } from "@openhands/extensions/mcps/logos";
```

After:

```js
import { INTEGRATION_CATALOG } from "@openhands/extensions/integrations";
import { INTEGRATION_LOGOS } from "@openhands/extensions/integrations/logos";
```

TypeScript consumers should replace `McpCatalogEntry` with
`IntegrationCatalogEntry`.

### Catalog entries

Before, MCP entries exposed a single `template`:

```js
const template = entry.template;
```

After, integrations expose one or more `connectionOptions`:

```js
const option =
entry.connectionOptions.find(
(candidate) => candidate.id === entry.defaultConnectionOptionId,
) ?? entry.connectionOptions[0];
```

MCP-backed options use `provider: "mcp"` and include their transport details.
Other integration types can use the same catalog entry shape without pretending
to be MCP servers.

### Automation entries

Automation templates now refer to integrations, not MCP-only records:

```diff
- requiredMcpIds
+ requiredIntegrationIds
```

### Deprecation timeline

There is no deprecation window for the old `mcps` exports. They were removed in
this PR because downstream consumers are being updated in the same coordinated
change and the API had not been treated as stable.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ Browse available plugins in [`plugins/`](plugins/).
This repository also publishes catalog data through the `@openhands/extensions` package. It requires Node.js 18.20.0 or newer because the catalog entry points import JSON modules with import attributes.

```js
import { AUTOMATION_CATALOG, MCP_CATALOG } from "@openhands/extensions";
import { MCP_CATALOG as MCP_MARKETPLACE } from "@openhands/extensions/mcps";
import { AUTOMATION_CATALOG, INTEGRATION_CATALOG } from "@openhands/extensions";
import { INTEGRATION_CATALOG as MCP_MARKETPLACE } from "@openhands/extensions/integrations";
import { AUTOMATION_CATALOG as RECOMMENDED_AUTOMATIONS } from "@openhands/extensions/automations";
```

React logo components are isolated behind a separate export so data-only consumers do not need React peer dependencies:

```js
import { MCP_LOGOS } from "@openhands/extensions/mcps/logos";
import { INTEGRATION_LOGOS } from "@openhands/extensions/integrations/logos";
```

See [`mcps/README.md`](mcps/README.md) and [`automations/README.md`](automations/README.md) for catalog-specific details.
See [`integrations/README.md`](integrations/README.md), [`automations/README.md`](automations/README.md), and [`MIGRATION.md`](MIGRATION.md) for catalog-specific details.

## Extensions Catalog

Expand Down
2 changes: 1 addition & 1 deletion automations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ Consumers can import the package export:
import { AUTOMATION_CATALOG } from "@openhands/extensions/automations";
```

Each automation references required MCPs by ID. Those IDs should match entries in `mcps/catalog/*.json`.
Each automation references required integrations by ID. Those IDs should match entries in `integrations/catalog/*.json`.
2 changes: 1 addition & 1 deletion automations/catalog/github-pr-reviewer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "GitHub PR review copilot",
"category": "Code review",
"description": "Watch pull requests, inspect the diff, and leave a concise review with risks and suggested follow-ups.",
"requiredMcpIds": [
"requiredIntegrationIds": [
"github"
],
"popularityRank": 100,
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/github-repo-monitor.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "GitHub repository monitor",
"category": "Developer tools",
"description": "Watch a repository for @OpenHands mentions in issues and PR comments, start a conversation, and post the agent's reply back to GitHub.",
"requiredMcpIds": ["github"],
"requiredIntegrationIds": ["github"],
"popularityRank": 98,
"estimatedSetupMinutes": 5,
"prompt": "Set up a GitHub repository monitor automation that polls a repository for comments containing a trigger phrase (default: @OpenHands) and starts an OpenHands conversation in response, then posts the agent's reply back to GitHub. Walk me through the setup.",
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/incident-retrospective-drafter.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Incident retrospective drafter",
"category": "Reliability",
"description": "Collect incident chatter and issue updates, then draft a timeline and follow-up checklist.",
"requiredMcpIds": [
"requiredIntegrationIds": [
"slack",
"linear",
"notion"
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/linear-triage-assistant.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Linear issue triage assistant",
"category": "Project management",
"description": "Classify new Linear issues, suggest labels, find duplicates, and ask clarifying questions.",
"requiredMcpIds": [
"requiredIntegrationIds": [
"linear"
],
"popularityRank": 90,
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/research-brief-writer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Research brief writer",
"category": "Research",
"description": "Monitor a topic, gather sources from the web, and publish a short brief for your team.",
"requiredMcpIds": [
"requiredIntegrationIds": [
"tavily",
"notion"
],
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/slack-channel-monitor.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Slack channel monitor",
"category": "Team communication",
"description": "Watch Slack channels for @openhands mentions, open a conversation with the message context, and reply in the thread when the agent finishes.",
"requiredMcpIds": ["slack"],
"requiredIntegrationIds": ["slack"],
"popularityRank": 92,
"estimatedSetupMinutes": 7,
"prompt": "Set up a Slack channel monitor automation that polls Slack channels for messages containing a trigger phrase (default: @openhands) and starts an OpenHands conversation in response, then posts the agent's reply back to the Slack thread. Walk me through the setup — ask me which channels to monitor and what trigger phrase to use.",
Expand Down
2 changes: 1 addition & 1 deletion automations/catalog/slack-standup-digest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Slack standup digest",
"category": "Team updates",
"description": "Summarize yesterday’s Slack activity into an async standup note with blockers, decisions, and owners.",
"requiredMcpIds": [
"requiredIntegrationIds": [
"slack"
],
"popularityRank": 94,
Expand Down
2 changes: 1 addition & 1 deletion automations/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface RecommendedAutomation {
description: string;
prompt: string;
exampleImplementation: string;
requiredMcpIds: string[];
requiredIntegrationIds: string[];
popularityRank: number;
estimatedSetupMinutes: number;
}
Expand Down
22 changes: 15 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
export { MCP_CATALOG } from "./mcps/index.js";
export type {
McpCatalogEntry,
MarketplaceField,
MarketplaceFieldType,
MarketplaceTemplate,
} from "./mcps/index.js";
export {
INTEGRATION_CATALOG,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Important: Breaking change - MCP_CATALOG renamed to INTEGRATION_CATALOG.

Downstream consumers using import { MCP_CATALOG } from '@openhands/extensions' will break. Consider:

  1. Migration guide: Document the rename and type changes in a CHANGELOG or MIGRATION.md
  2. Deprecation period: If possible, export both names temporarily with a deprecation warning
  3. Version bump: Since package.json shows version 0.0.0, ensure the next publish is clearly marked as breaking (e.g., 0.1.0 or 1.0.0)

Example migration:

// Before
import { MCP_CATALOG, McpCatalogEntry } from '@openhands/extensions';

// After  
import { INTEGRATION_CATALOG, IntegrationCatalogEntry } from '@openhands/extensions';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Uh oh! There was an unexpected error starting the job :(

type IntegrationAuthConfig,
type IntegrationAuthStrategy,
type IntegrationCatalogEntry,
type IntegrationConnectionOption,
type IntegrationHttpConfig,
type IntegrationOAuthConfig,
type IntegrationProvider,
type IntegrationTransport,
type MarketplaceField,
type MarketplaceFieldType,
type OAuthProviderCatalogOption,
type OAuthProviderRegistrationDefaults,
} from "./integrations/index.js";
export { AUTOMATION_CATALOG } from "./automations/index.js";
export type { RecommendedAutomation } from "./automations/index.js";
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { MCP_CATALOG } from "./mcps/index.js";
export { INTEGRATION_CATALOG } from "./integrations/index.js";
export { AUTOMATION_CATALOG } from "./automations/index.js";
39 changes: 39 additions & 0 deletions integrations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Integration catalog

This directory contains curated integration metadata for OpenHands clients.
Most current entries are MCP-backed, but the schema also supports HTTP/OpenAPI
integrations so clients can consume one source of truth.

- `catalog/*.json` contains one source file per direct integration entry.
- `index.js` assembles and exports the catalog for Node.js and bundlers.
- `index.d.ts` contains the public TypeScript shape.

Consumers can import the package export:

```js
import { INTEGRATION_CATALOG } from "@openhands/extensions/integrations";
```

## Migration from the MCP catalog

This catalog replaces the experimental `@openhands/extensions/mcps` export.
The MCP-only `mcps/` directory has been renamed to `integrations/`, and the
old package exports were removed rather than kept as aliases.

- Import `INTEGRATION_CATALOG` from `@openhands/extensions/integrations`
instead of `MCP_CATALOG` from `@openhands/extensions/mcps`.
- Import logo mappings from `@openhands/extensions/integrations/logos`
instead of `@openhands/extensions/mcps/logos`.
- Use `IntegrationCatalogEntry` instead of `McpCatalogEntry`.
- Read MCP configuration from `entry.connectionOptions[]`. Direct MCP entries
have `provider: "mcp"` and a `transport`; entries may expose multiple
options such as `id: "oauth"` for a hosted OAuth MCP endpoint and `id:
"api"` for an API-key or stdio fallback.
- Use `entry.defaultConnectionOptionId` to choose the preferred option.
- Automation catalog entries now use `requiredIntegrationIds` instead of
`requiredMcpIds`.

The `mcps` API was intentionally broken because it was pre-release and had not
been adopted as a stable public surface.

The catalog intentionally stores only serializable data. Client applications are responsible for mapping entries to UI-specific icons or styling.
42 changes: 42 additions & 0 deletions integrations/catalog/airtable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"id": "airtable",
"name": "Airtable",
"description": "List bases, query records, and update fields across your Airtable workspace.",
"docsUrl": "https://github.com/domdomegg/airtable-mcp-server",
"iconBg": "#FCB400",
"iconColor": "var(--oh-surface-deep)",
"keywords": [
"spreadsheet",
"database",
"records",
"bases"
],
"kind": "mcp",
"defaultConnectionOptionId": "api",
"connectionOptions": [
{
"id": "api",
"provider": "mcp",
"transport": {
"kind": "stdio",
"serverName": "airtable",
"command": "npx",
"args": [
"-y",
"airtable-mcp-server"
],
"envFields": [
{
"key": "AIRTABLE_API_KEY",
"label": "Airtable personal access token",
"type": "password",
"required": true
}
]
},
"auth": {
"strategy": "api_key"
}
}
]
}
41 changes: 41 additions & 0 deletions integrations/catalog/apify.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"id": "apify",
"name": "Apify Actors",
"description": "Run any of Apify's 5,000+ Actors (scrapers, automations) from the agent.",
"docsUrl": "https://docs.apify.com/platform/integrations/mcp",
"iconBg": "#10b981",
"keywords": [
"scraping",
"automation",
"crawl",
"actors"
],
"kind": "mcp",
"defaultConnectionOptionId": "api",
"connectionOptions": [
{
"id": "api",
"provider": "mcp",
"transport": {
"kind": "stdio",
"serverName": "apify",
"command": "npx",
"args": [
"-y",
"@apify/actors-mcp-server"
],
"envFields": [
{
"key": "APIFY_TOKEN",
"label": "Apify token",
"type": "password",
"required": true
}
]
},
"auth": {
"strategy": "api_key"
}
}
]
}
31 changes: 31 additions & 0 deletions integrations/catalog/atlassian.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"id": "atlassian",
"name": "Atlassian (Jira & Confluence)",
"description": "Search Jira issues and Confluence pages via Atlassian's hosted MCP server.",
"docsUrl": "https://www.atlassian.com/platform/remote-mcp-server",
"iconBg": "#0052CC",
"keywords": [
"jira",
"confluence",
"tickets",
"wiki",
"issues"
],
"kind": "mcp",
"defaultConnectionOptionId": "none",
"connectionOptions": [
{
"id": "none",
"provider": "mcp",
"transport": {
"kind": "sse",
"url": "https://mcp.atlassian.com/v1/sse",
"apiKeyOptional": true
},
"auth": {
"strategy": "none",
"apiKeyOptional": true
}
}
]
}
Loading
Loading