Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
abeef31
feat(#4815): implement MCP registry provider backend plugin
fullsend-ai-coder[bot] Sep 18, 2026
3f818af
fix: address review feedback on PR #4871
fullsend-ai-coder[bot] Sep 18, 2026
041d90a
fix: address review feedback on PR #4871
fullsend-ai-coder[bot] Sep 18, 2026
de4b2d8
fix(#4815): address review comments for package.json
michael-valdron Sep 18, 2026
d70dcf9
fix(#4815): expand more scripts in package.json files
michael-valdron Sep 18, 2026
e3fc838
fix(#4815): add standalone dev entry for mcp-registry-provider
michael-valdron Sep 18, 2026
3a0f6d5
fix(#4815): add staging MCP Registry provider config
michael-valdron Sep 18, 2026
7820ac7
fix(#4815): list ingested mcp-server APIs in the catalog
michael-valdron Sep 19, 2026
07d9a86
fix(#4815): record supertest in the workspace lockfile
michael-valdron Sep 19, 2026
12b9bad
fix(#4815): address SonarCloud feedback on mcp-registry-provider
michael-valdron Sep 19, 2026
fe9bd1f
docs(#4815): add mapping-common changeset for provider link
michael-valdron Sep 19, 2026
d212f11
fix(#4815): address review feedback on PR #4871
fullsend-ai-coder[bot] Sep 19, 2026
7297908
fix(#4815): restore lint:check/lint:fix/tsc/prettier scripts in packa…
fullsend-ai-coder[bot] Sep 19, 2026
19e876f
fix(#4815): align package.json scripts with workspace convention
fullsend-ai-coder[bot] Sep 19, 2026
663ef89
revert: undo package.json script removal from b255a04
fullsend-ai-coder[bot] Sep 19, 2026
d441ada
fix(#4815): add optional hostAllowList config for SSRF defense-in-depth
fullsend-ai-coder[bot] Sep 19, 2026
8a0302e
fix(#4815): add recent config fields to app-config.yaml files
michael-valdron Sep 19, 2026
c9cb074
fix(#4815): use registry baseUrl as the placeholder remote
michael-valdron Sep 19, 2026
226fa38
docs(#4815): add non-remote instruction to README
michael-valdron Sep 20, 2026
8bcc6cd
docs(#4815): document maxEntries in the provider README
michael-valdron Sep 20, 2026
e2e42b3
fix(#4815): resume pageLimit and soft-stop at maxEntries
michael-valdron Sep 20, 2026
1ed5be0
fix(#4815): add remotesOnly to skip non-remote MCP servers
michael-valdron Sep 20, 2026
4a9b5cb
refactor(#4815): rename mapping package to catalog-mcp-registry-serve…
michael-valdron Sep 20, 2026
402629f
fix(#4815): snapshot seenCursors on error and validate response.url
fullsend-ai-coder[bot] Sep 20, 2026
6941032
fix(#4815): address review feedback on PR #4871
fullsend-ai-coder[bot] Sep 20, 2026
89d2652
fix(#4815): make defaulted provider config fields optional
michael-valdron Sep 20, 2026
8eb8c48
fix(#4815): follow redirects manually with Location validation
michael-valdron Sep 20, 2026
19f4e66
refactor(#4815): rename client host allowlist guard
michael-valdron Sep 20, 2026
e316c85
docs(#4815): use bare hostnames in hostAllowList examples
michael-valdron Sep 20, 2026
43e2a53
refactor(#4815): extract provider helpers to providerUtils
michael-valdron Sep 20, 2026
b975db7
refactor(#4815): return seenCursors instead of mutating options
michael-valdron Sep 20, 2026
8d7a379
refactor(#4815): lower fetchRegistryServers cognitive complexity
michael-valdron Sep 20, 2026
900083b
refactor(#4815): extract McpRegistryEntityProviderOptions
michael-valdron Sep 20, 2026
c4c0228
fix(#4815): fail closed when response.url is missing
michael-valdron Sep 20, 2026
6a93f46
chore(#4815): add local MCP Registry deploy tooling
michael-valdron Sep 20, 2026
f2d28c2
chore(#4815): wire mcp-registry-provider into workspace backend
michael-valdron Sep 20, 2026
8da501e
chore(#4815): make app-config changes
michael-valdron Sep 20, 2026
c569dc0
chore(#4815): remove unused app-config from catalog-backend-module-mc…
michael-valdron Sep 20, 2026
691ec4a
fix(#4815): wait for MCP Registry readiness before returning
michael-valdron Sep 20, 2026
3842921
chore(#4815): rename hack/ to scripts/ for workspace consistency
michael-valdron Sep 20, 2026
924d0e8
chore(#4815): move MCP registry examples and type docs to workspace
michael-valdron Sep 20, 2026
953020e
fix(#4815): harden MCP Registry scripts for SonarCloud
michael-valdron Sep 20, 2026
dfe1116
chore(#4815): pin MCP Registry checkout and image via env vars
michael-valdron Sep 20, 2026
d2c834c
chore(#4815): make MCP Registry readiness API version configurable
michael-valdron Sep 20, 2026
2b95d57
chore(#4815): rename local MCP Registry scripts for clarity
michael-valdron Sep 20, 2026
8cdd302
chore(#4815): add example mcp-server API entities from registry seed
michael-valdron Sep 20, 2026
4321920
chore(#4815): nest MCP Registry provider config under reserved instan…
michael-valdron Sep 20, 2026
988ccb9
fix(#4815): clarify MCP Registry fetch error messages
michael-valdron Sep 20, 2026
0351933
chore(#4815): add 'example' tag to mcp-server examples
michael-valdron Sep 20, 2026
51119d3
fix(#4815): satisfy tsc for nested mcpRegistry config tests
michael-valdron Sep 20, 2026
a523195
chore(#4815): expand MCP Registry changesets for provider features
michael-valdron Sep 20, 2026
703de55
fix(#4815): avoid nested template literals in deploy script
michael-valdron Sep 20, 2026
a5699e0
fix(#4815): warn when hostAllowList is unset at startup
michael-valdron Sep 20, 2026
95ce5c3
feat(#4815): add defaultLifecycle to MCP Registry provider config
michael-valdron Sep 20, 2026
4147d7d
docs(#4815): reorganize MCP Registry provider installation section
michael-valdron Sep 21, 2026
b7b995a
fix(#4815): retain degraded MCP servers across soft-stop syncs
michael-valdron Sep 21, 2026
e61d2e0
chore(#4815): add secret value to seed.json entry and server.json for…
michael-valdron Sep 21, 2026
5dbd7ca
chore(#4815): regenerate MCP Registry provider API report
michael-valdron Sep 21, 2026
6cf2ecc
fix(#4815): address remaining PR #4871 review feedback
michael-valdron Sep 21, 2026
f406a6d
chore(#4815): restore mcp-registry openspec docs to main
michael-valdron Sep 21, 2026
3561874
feat(#4815): add latestVersion MCP Registry list query option
michael-valdron Sep 21, 2026
74fa58d
docs(#4815): document using official MCP registries with the provider
michael-valdron Sep 21, 2026
c3b8dfa
docs(#4815): self-revision on wording of official live production note
michael-valdron Sep 21, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
Comment thread
michael-valdron marked this conversation as resolved.
'@red-hat-developer-hub/backstage-plugin-catalog-mcp-registry-server-mapping': minor
---

Rename the mapping common library to `catalog-mcp-registry-server-mapping` (package, directory, and `pluginId`) to match workspace naming conventions. Consumers of `@red-hat-developer-hub/backstage-plugin-mcp-registry-server-mapping-common` should update to the new package name.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-catalog-backend-module-mcp-registry-provider': minor
---

Add MCP Registry provider backend module that ingests MCP servers from a configured registry into the catalog as mcp-server API entities. Supports cursor pagination with full-mutation semantics, per-entry failure isolation with last-good retention, nested config under `catalog.providers.mcpRegistry.mcpRegistry` (extra instance ids warn and are ignored), optional `defaultOwner` / `defaultLifecycle` / `remotesOnly` / `latestVersion` (`?version=latest`) / `hostAllowList` / `maxEntries` soft-stop with `pageLimit` resume (re-adding last-good as degraded on later syncs until the server is refreshed successfully), schedule and page controls, identity prefix override, redirect handling with Location validation, and clearer fetch error reporting.
2 changes: 1 addition & 1 deletion workspaces/ai-integrations/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
playwright.config.ts
!.eslintrc.js
!.prettierrc.js
!.prettierrc.js
12 changes: 12 additions & 0 deletions workspaces/ai-integrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,15 @@ If you would like to build with `docker`, add the `--user-docker` tag like so:
```
npx --yes @red-hat-developer-hub/cli@latest plugin package --tag --tag "${PLUGIN_CONTAINER_TAG}" --use-docker
```

## MCP Registry

### Official Live Deployments

To ingest MCP servers from the official MCP Registry into the catalog, see
[Using Official MCP Registries](./docs/using-official-mcp-registries.md).

### Deploy Locally

To run a local MCP Registry for provider development, see
[Deploy MCP Registry Locally](./docs/deploy-mcp-registry-locally.md).
45 changes: 44 additions & 1 deletion workspaces/ai-integrations/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ catalog:
target: ../../examples/ai-model-server-api.yaml
rules:
- allow: [AiModelServerAPI]
# Example MCP server API entities as produced by
# catalog-backend-module-mcp-registry-provider from the sample registry seed
# at examples/mcp-registry/seed-data/seed.json.
#
# Comment out this location when deploying the MCP Registry provider against
# the same seed (e.g. `MCP_REGISTRY_DATA_DIR=./examples/mcp-registry/seed-data yarn start-local-mcp-registry`).
- type: file
target: ../../examples/api-mcp-servers.yaml
rules:
- allow: [API]
providers:
modelCatalog:
# The field underneath should list the connector plugin ID that the entity provider accesses through
Expand All @@ -139,7 +149,40 @@ catalog:
kubeflow-model-catalog-url: '${KUBEFLOW_MODEL_CATALOG_URL:-}'
default-owner: '${OWNER:-default-owner}'
default-lifecycle: '${LIFECYCLE:-production}'
# Uncomment to use kubernetesPluginRef — the Backstage kubernetes plugin
mcpRegistry:
# Reserved instance id — only this key is supported today.
mcpRegistry:
# Required: base URL of the MCP Registry
baseUrl: '${MCP_REGISTRY_URL:-http://localhost:8080/}'
# Optional: base name (default: mcp.registry)
# baseName: mcp.registry
# Optional: API version (default: v1)
apiVersion: v0.1
# Optional: default entity owner (default: unknown)
defaultOwner: '${OWNER:-default-owner}'
# Optional: default entity lifecycle (default: production)
defaultLifecycle: '${LIFECYCLE:-production}'
# Optional: max pages fetched per sync (default: 10)
# pageLimit: 10
# Optional: registry page size sent as ?limit= (omitted by default)
# pageSize: 50
# Optional: max entries per complete traversal; soft-stops with end cursor (default: 5000)
# maxEntries: 5000
# Optional: ingest only servers with at least one native remote (default: false)
# remotesOnly: false
# Optional: request only the latest version of each server via ?version=latest (default: false)
# latestVersion: false
# Optional: allowlist of permitted hostnames for defense-in-depth SSRF protection.
# hostAllowList:
# - registry.modelcontextprotocol.io
# - staging.registry.modelcontextprotocol.io
# Optional: sync schedule (defaults shown below)
# schedule:
# frequency: { minutes: 30 }
# timeout: { minutes: 3 }
# # Optional: defer the first sync
# # initialDelay: { seconds: 15 }
# Uncomment to use kubernetesPluginRef — the Backstage Kubernetes plugin
# does NOT need to be installed, only its config section is needed.
#kubernetes:
# serviceLocatorMethod:
Expand Down
116 changes: 116 additions & 0 deletions workspaces/ai-integrations/docs/deploy-mcp-registry-locally.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Deploy MCP Registry Locally

For local provider development against a real registry instance, this workspace
includes Node scripts under [`scripts/`](../scripts/) that start the upstream
[MCP Registry](https://github.com/modelcontextprotocol/registry) with Podman or
Docker Compose. They use the published
`ghcr.io/modelcontextprotocol/registry` image instead of upstream
`make dev-compose` (which builds with `ko` and does not work with Podman).

## Prerequisites

- Node.js 22+ (type stripping for `.ts` scripts)
- `git`
- `podman compose` or `docker compose`

## Start

From the `ai-integrations` workspace root, or from
`plugins/catalog-backend-module-mcp-registry-provider`:

```bash
yarn start-local-mcp-registry
```

You can also run the script directly from the workspace root:

```bash
node scripts/deploy-local-mcp-registry.ts
```

This clones the registry into `~/.cache/rhdh-ai-integrations/mcp-registry`
(if needed; override with `MCP_REGISTRY_REPO_DIR`) at tag `v1.8.1` by default
(override with `MCP_REGISTRY_REPO_URL` / `MCP_REGISTRY_REPO_REVISION`), starts
PostgreSQL and the registry in the background, **waits until the HTTP API
responds** (seed import can take a few minutes when seeding from the public
registry), and serves the API at
[http://localhost:8080](http://localhost:8080).

Start the registry **before** `yarn dev`. If the provider syncs while the
registry is still importing seed data, you will see
`Failed to reach MCP Registry ...` (no mutation). Restart the backend after the
registry is ready, or wait for the next scheduled sync.

Optional environment variables:

| Variable | Default | Description |
| ------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MCP_REGISTRY_REPO_DIR` | `~/.cache/rhdh-ai-integrations/mcp-registry` | Local checkout path for the registry |
| `MCP_REGISTRY_REPO_URL` | `https://github.com/modelcontextprotocol/registry.git` | Git remote cloned into `MCP_REGISTRY_REPO_DIR` |
| `MCP_REGISTRY_REPO_REVISION` | `v1.8.1` | Git branch or tag checked out for compose/config |
| `MCP_REGISTRY_IMAGE_NAME` | `ghcr.io/modelcontextprotocol/registry` | Registry container image name (without tag) |
| `MCP_REGISTRY_IMAGE_TAG` | `1.8.1` | Registry container image tag |
| `MCP_REGISTRY_DATA_DIR` | _(checkout `./data`)_ | Host directory mounted at `/data` instead of the [default seed data](https://github.com/modelcontextprotocol/registry/blob/main/data/seed.json). When set, seeds from `data/seed.json` with validation off. |
| `MCP_REGISTRY_URL` | `http://localhost:8080` | URL probed for readiness (and typically used as `catalog.providers.mcpRegistry.mcpRegistry.baseUrl`) |
| `MCP_REGISTRY_API_VERSION` | `v0.1` | Registry HTTP API version path segment used for the readiness probe |
| `MCP_REGISTRY_READY_TIMEOUT_MS` | `300000` (5m) | How long `start-local-mcp-registry` waits for the API before failing |

Example with custom seed content (directory must contain `seed.json`):

```bash
MCP_REGISTRY_DATA_DIR=./examples/mcp-registry/seed-data yarn start-local-mcp-registry
```

View logs (example with Podman):

```bash
podman compose -f ~/.cache/rhdh-ai-integrations/mcp-registry/docker-compose.yml logs -f
```

## Point the provider at localhost

Configure `catalog.providers.mcpRegistry.mcpRegistry` to use the local
registry. The default local API version is `v0.1`:

```yaml
catalog:
providers:
mcpRegistry:
mcpRegistry:
baseUrl: http://localhost:8080
apiVersion: v0.1
# Optional when restricting outbound hosts:
# hostAllowList:
# - localhost
```

Then start the workspace as usual (`yarn dev` from `workspaces/ai-integrations`).

See also the
[MCP Registry Provider](../plugins/catalog-backend-module-mcp-registry-provider/)
plugin for full configuration options.

## Stop

From the workspace root or
`plugins/catalog-backend-module-mcp-registry-provider`:

```bash
yarn stop-local-mcp-registry
```

Or from the workspace root:

```bash
node scripts/undeploy-local-mcp-registry.ts
```

This runs `compose down` for the same stack. The
`~/.cache/rhdh-ai-integrations/mcp-registry` checkout is left in place so the
next deploy is faster.

## Official registries alternative

To point the provider at the production or staging official MCP Registry
instead of a local instance, see
[Using Official MCP Registries](./using-official-mcp-registries.md).
Loading
Loading