redhat-developer / redhat-developer/rhdh-plugins

feat(ai-integrations): implement MCP registry provider backend plugin - 1 / 1 (`mcp-registry-provider`)

Open
#4,815 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement feature triaged workspace/ai-integrations
Dominant language
TypeScript
Stars
48
Forks
120
Avg merge
2d 6h
Merged PRs (30d)
337

Description

ref: https://redhat.atlassian.net/browse/RHIDP-15655

Summary

Implement a Backstage catalog entity provider backend plugin that periodically ingests MCP servers from one configured MCP Registry: list servers via cursor pagination, transform each server.json through the composed mcp-registry-server-mapping transform (#4813 + #4795), stamp sync status and provider attribution, and commit a full mutation so the catalog converges to the registry’s current server set.

This capability is specified in OpenSpec change mcp-registry-provider and is the first runtime consumer of the sibling mapping library.

Normative spec (source of truth):
openspec/changes/mcp-registry-provider/specs/mcp-registry-provider/spec.md

Related design decisions: D1 (config shape), D2 (catalog-backend-module), D3 (schedule defaults), D4 (pagination), D5–D8 (mutation, last-good retention, sync status) in
openspec/changes/mcp-registry-provider/design.md

Problem

The mapping change defines a pure server.jsonmcp-server API transform but leaves ingestion out of scope. Operators who point RHDH at a registry still get no catalog entities until a scheduled provider fetches registry pages, applies the transform, and prunes removed servers.

Scope

In scope
  • catalog-backend-module plugin: createBackendModule, EntityProvider with getProviderName() / mutation locationKey mcp-registry-provider.
  • Config at catalog.providers.mcpRegistry (single object): baseUrl (required), optional baseName, apiVersion (default v1), schedule, pageLimit (default 10 pages/sync), pageSize (?limit=), defaultOwner; inert when key absent; reject keyed multi-registry maps.
  • Scheduler-driven sync only (no sync from connect()); default schedule 30m / 3m timeout.
  • Registry client: GET <baseUrl>/<apiVersion>/servers, opaque cursor pagination, page safeguards (page cap, repeated cursor).
  • Per-entry mapping via sibling transform (defaultOwner, optional baseName → prefix); no reimplementation of mapping rules.
  • Full mutation on successful runs; no mutation on failed runs (transport/protocol/pagination trip).
  • Resilient per-entry failures: log, continue; last-good retention (D6) with redhat.com/rhdh-mcp-registry-sync-status ok / degraded.
  • backstage.io/managed-by-location: url: + normalized baseUrl.
Out of scope
  • The server.json → entity transform itself (#4813, #4795).
  • Registry proxy/pass-through API, auth credentials, multiple registries, runtime MCP invocation, catalog UI.

Implementation checklist (from tasks.md)

Group 1 — scaffolding:

  • 1.1 catalog-backend-module package layout.
  • 1.2 Backend module skeleton + extension point.
  • 1.3 README install / app-config example.

Group 2 — configuration:

  • 2.1 config.d.ts with @visibility backend.
  • 2.2 Absent config → no provider registered.
  • 2.3 Validation, defaults (apiVersion, schedule, pageLimit).
  • 2.4 Config unit tests.

Group 3 — registry client:

  • 3.1–3.6 Types, URL construction, cursor loop, safeguards, errors, client tests.

Group 4 — provider & scheduling:

  • 4.1–4.5 EntityProvider, scheduler wiring, full mutation, annotations, tests.

Group 5 — mapping integration:

  • 5.1–5.3 Invoke mapping library; per-entry isolation; integration tests.

Group 6 — verification & docs:

  • 6.1–6.5 E2E test, schema check, apiVersion docs, README, CI.

Acceptance criteria (map to spec scenarios)

Area Must hold
Config Single object; missing baseUrl / multi-registry map fail fast; defaults for schedule, apiVersion, pageLimit.
Schedule Scheduler-only; documented default; optional initialDelay.
Pagination Full cursor traversal; optional pageSize; pageLimit caps pages; repeated cursor fails run.
Endpoint <baseUrl>/<apiVersion>/servers with slash normalization.
Mapping Delegates to #4813/#4795; defaultOwner / baseName passed as caller overrides.
Mutation Full sync prunes removed servers; failed run leaves prior catalog state.
Resilience One bad entry does not abort batch; last-good + degraded when applicable.
Attribution locationKey, managed-by-location, sync status per spec.

Dependencies

  • Prerequisite: Composed mcp-registry-server-mapping library — #4813 (direct mapping) and #4795 (annotation projection).
  • Upstream: Backstage EntityProvider, SchedulerService, MCP Registry generic API.

References

  • OpenSpec change: openspec/changes/mcp-registry-provider/
  • Mapping change: openspec/changes/mcp-registry-server-mapping/
  • GitHub issues: #4813, #4795

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with openspec/changes/mcp-registry-provider/specs/mcp-registry-provider/spec.md, design.md, and tasks.md, then inspect the sibling mcp-registry-server-mapping work and Backstage EntityProvider and SchedulerService entry points. Done means the provider package, configuration, paginated client, scheduled synchronization, mapping integration, tests, schema checks, documentation, and CI verification satisfy the listed acceptance criteria.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.