-
Notifications
You must be signed in to change notification settings - Fork 513
Description
π Epic: Backstage Integration - MCP/A2A federation, catalog sync, and developer portal experience
Goal
Deliver a bidirectional integration between Backstage and ContextForge that positions ContextForge as the MCP federation, A2A agent gateway, and governance layer behind Backstage's developer portal experience. This includes a Backstage backend plugin, a frontend plugin, a catalog entity provider, and ContextForge-side API extensions β enabling developers to discover, manage, invoke, and govern MCP tools, A2A agents, and federated services directly from their Backstage portal.
Why Now?
The Internal Developer Platform (IDP) space and the AI tooling ecosystem are converging rapidly, but the integration seam between them remains underserved:
-
Backstage Has MCP β But No Registry: Backstage shipped
@backstage/plugin-mcp-actions-backendin v1.40 (mid-2025), exposing Backstage actions as MCP tools. However, the community MCP Registry proposal (backstage/community-plugins #4034) remains open and stalled. There is no built-in way to discover, register, or govern MCP servers at scale within Backstage. -
Backstage Has No A2A Support: There is zero A2A protocol integration in Backstage β no plugins, no proposals, no community efforts. As agentic AI adoption accelerates, this becomes a significant gap. ContextForge already supports A2A agent registration, invocation, team scoping, and metrics.
-
Federation Gap: Organisations deploying multiple MCP servers across teams need a federation layer that aggregates, governs, and exposes them through a single endpoint. Backstage alone cannot federate upstream MCP servers β ContextForge can.
-
Governance and Multi-Tenancy: Backstage's permission framework handles UI-level access control. ContextForge adds wire-level governance: RBAC, team-scoped visibility, rate limiting, plugin-based policy enforcement, and audit logging for every tool invocation. Together they cover the full stack.
-
Market Positioning: Spotify Portal (commercial Backstage) already registers MCP servers as catalog API entities. Red Hat Developer Hub has shipped MCP integration. An open-source ContextForge integration fills this space for the broader Backstage community β and does more by adding A2A, federation, and policy enforcement.
-
Developer Experience: Engineers should not need to leave their portal to manage AI tools, agents, and service integrations. Surfacing ContextForge capabilities inside Backstage reduces context-switching and makes governed AI tooling a first-class part of the developer workflow.
π User Stories
US-1: Platform Engineer β Register ContextForge as a Backstage Integration
As a Platform Engineer
I want to connect my Backstage instance to a ContextForge gateway
So that all federated MCP tools, A2A agents, and resources appear in our developer portal
Acceptance Criteria:
Given the ContextForge Backstage backend plugin is installed
When I configure app-config.yaml:
contextforge:
baseUrl: https://contextforge.internal.example.com
auth:
method: bearer
token: ${CONTEXTFORGE_TOKEN}
sync:
intervalSeconds: 300
entityKinds:
- tools
- resources
- prompts
- servers
- a2a-agents
- gateways
Then the plugin should:
- Connect to the ContextForge API on startup
- Authenticate using the configured method
- Begin periodic sync of entities into the Backstage catalog
- Expose ContextForge health status on the plugin's health endpoint
- Log sync results with entity counts and any errorsTechnical Requirements:
- Backstage backend plugin using
createBackendPlugin()(New Backend System) - Support bearer, basic, and OAuth authentication to ContextForge
- Configurable sync interval with jitter to prevent thundering herd
- Health check endpoint for monitoring
- Graceful degradation if ContextForge is unreachable
US-2: Developer β Discover MCP Tools in the Backstage Catalog
As a Developer
I want to browse all available MCP tools from ContextForge in the Backstage software catalog
So that I can find and understand AI tools available to my team without leaving the portal
Acceptance Criteria:
Given ContextForge has 50 federated tools across 5 upstream gateways
When the catalog entity provider syncs
Then each tool should appear as a Backstage catalog entity:
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: contextforge-tool-customer-lookup
description: "Look up customer details by ID"
annotations:
contextforge.io/tool-id: "abc-123"
contextforge.io/gateway-id: "gateway-456"
contextforge.io/gateway-name: "crm-service"
contextforge.io/transport: "STREAMABLEHTTP"
contextforge.io/visibility: "team"
contextforge.io/team-id: "engineering"
tags:
- mcp-tool
- contextforge
- crm
links:
- url: https://contextforge.internal/tools/abc-123
title: "View in ContextForge"
spec:
type: mcp-tool
lifecycle: production
owner: group:engineering
system: contextforge-crm-gateway
definition:
$text: |
name: customer-lookup
description: Look up customer details by ID
inputSchema:
type: object
properties:
customer_id:
type: string
description: The customer identifier
required:
- customer_id
And tools should be searchable by name, tag, gateway, and team
And team-scoped tools should respect Backstage group membershipTechnical Requirements:
- Catalog entity provider implementing
EntityProviderinterface - Map ContextForge tools β
kind: APIwithspec.type: mcp-tool - Map ContextForge resources β
kind: APIwithspec.type: mcp-resource - Map ContextForge prompts β
kind: APIwithspec.type: mcp-prompt - Map ContextForge servers β
kind: Componentwithspec.type: mcp-server - Map ContextForge gateways β
kind: Componentwithspec.type: mcp-gateway - Map ContextForge A2A agents β
kind: Componentwithspec.type: a2a-agent - Preserve ContextForge team scoping via Backstage group ownership
- Include input schemas in API definitions for documentation rendering
- Incremental sync (delta updates) to avoid catalog churn
US-3: Developer β Invoke MCP Tools from Backstage
As a Developer
I want to invoke an MCP tool directly from its Backstage catalog page
So that I can test and use tools without switching to a separate UI or CLI
Acceptance Criteria:
Given I am viewing an MCP tool entity in the Backstage catalog
And the tool has an input schema with required parameters
When I click "Invoke Tool" on the entity page
Then I should see:
- A form generated from the tool's input schema
- Pre-populated defaults where available
- A "Run" button to execute the tool
When I submit the form
Then the backend plugin should:
- Forward the invocation to ContextForge: POST /tools/{tool_id}/invoke
- Pass my Backstage identity for ContextForge RBAC evaluation
- Display the tool result in a formatted output panel
- Show execution time, status, and any errors
- Log the invocation in ContextForge's audit trailTechnical Requirements:
- Frontend card component for tool invocation on API entity pages
- JSON Schema form renderer for tool input schemas
- Backend proxy route to ContextForge tool invocation endpoint
- Identity forwarding: map Backstage user β ContextForge JWT claims
- Result rendering with syntax highlighting for JSON/text/markdown
- Error handling with user-friendly messages
- Rate limiting awareness (show 429 status clearly)
US-4: Developer β Interact with A2A Agents from Backstage
As a Developer
I want to discover and invoke A2A agents registered in ContextForge from Backstage
So that I can interact with AI agents without managing direct API integrations
Acceptance Criteria:
Given ContextForge has 3 A2A agents registered:
- "code-review-agent" (anthropic, team: engineering)
- "test-generator-agent" (openai, team: engineering)
- "docs-agent" (custom, team: documentation)
When I navigate to the A2A Agents section in Backstage
Then I should see agents available to my team
And each agent card should show:
- Agent name, type, and description
- Capabilities and supported models
- Team ownership and visibility
- Health status and response time metrics
- Last invocation timestamp
When I click "Chat" on an agent
Then I should see a conversational interface
And messages should be proxied through ContextForge: POST /a2a-agents/{id}/invoke
And the conversation should respect ContextForge RBAC and rate limitsTechnical Requirements:
- A2A agent entities in catalog (
kind: Component,spec.type: a2a-agent) - Frontend page:
/contextforge/agentswith agent cards - Conversational UI component for agent interaction
- Backend proxy to ContextForge A2A invocation API
- Streaming response support (SSE) for long-running agent tasks
- Agent metrics display (invocations, success rate, avg response time)
US-5: Platform Engineer β Manage ContextForge Gateways from Backstage
As a Platform Engineer
I want to view and manage ContextForge's federated gateways from Backstage
So that I can monitor upstream MCP server health and manage federation from the portal
Acceptance Criteria:
Given ContextForge has 8 upstream gateways registered
When I navigate to the ContextForge Gateways page in Backstage
Then I should see each gateway with:
- Name, URL, and transport type (SSE, STREAMABLEHTTP, STDIO)
- Health status (healthy, unhealthy, disabled)
- Last refresh timestamp
- Count of tools, resources, and prompts provided
- Team ownership and visibility scope
When I click on a gateway
Then I should see:
- Detailed gateway configuration
- List of tools/resources/prompts it provides
- Health check history
- Dependency graph showing which virtual servers use this gateway
When I click "Refresh"
Then the plugin should call POST /gateways/{id}/refresh
And update the catalog entities with any new or removed capabilitiesTechnical Requirements:
- Gateway management page:
/contextforge/gateways - Real-time health status via polling or SSE
- Gateway β tool/resource dependency visualization
- Refresh capability with progress indication
- Gateway registration form (for platform engineers with admin RBAC)
US-6: Platform Engineer β Sync Backstage Groups with ContextForge Teams
As a Platform Engineer
I want Backstage groups to sync with ContextForge teams
So that team-scoped visibility in ContextForge aligns with our organisational structure in Backstage
Acceptance Criteria:
Given Backstage has groups:
- group:engineering (members: alice, bob)
- group:security (members: carol)
- group:platform (members: dave)
And ContextForge has teams:
- engineering (members: alice@corp.com, bob@corp.com)
- security (members: carol@corp.com)
When team sync runs
Then ContextForge teams should match Backstage groups
And team-scoped tools visible to "engineering" in ContextForge
should appear owned by "group:engineering" in Backstage
And a developer in group:engineering should see engineering-scoped
tools but not security-scoped tools in their catalog viewTechnical Requirements:
- Configurable group β team mapping (name-based or explicit mapping)
- Sync direction: Backstage β ContextForge (Backstage as source of truth for org structure)
- Member email resolution from Backstage user entities
- Conflict resolution strategy for mismatched memberships
- Dry-run mode for validating sync before applying
US-7: AI Assistant β Use ContextForge Tools via Backstage MCP Endpoint
As an AI Assistant (Claude, Cursor, ChatGPT) connected to Backstage's MCP endpoint
I want to discover and invoke ContextForge's federated tools through Backstage
So that I can access the full tool ecosystem without direct ContextForge connectivity
Acceptance Criteria:
Given Backstage's MCP Actions backend is running at /api/mcp-actions/v1
And the ContextForge plugin registers federated tools as Backstage actions
When an MCP client connects to Backstage's MCP endpoint
And calls tools/list
Then the response should include ContextForge tools alongside native Backstage actions
And each tool should have:
- Correct name and description from ContextForge
- Input schema matching the original tool definition
- Annotations indicating ContextForge origin
When the MCP client calls tools/call for a ContextForge tool
Then Backstage should proxy the call to ContextForge
And return the result to the MCP client
And ContextForge's plugin chain (PII filter, rate limiter, etc.) should executeTechnical Requirements:
- Register ContextForge tools as Backstage Actions via
ActionsRegistryService - Map ContextForge tool schemas to Backstage Action schemas (Zod)
- Proxy tool invocations through ContextForge's
/tools/{id}/invokeendpoint - Honour ContextForge plugin chain (pre/post hooks execute server-side)
- Handle tool pagination (ContextForge may have hundreds of tools)
- Respect team scoping: only register actions visible to the requesting user
US-8: Security Engineer β Audit ContextForge Activity from Backstage
As a Security Engineer
I want to view ContextForge audit logs and access metrics from within Backstage
So that I can monitor AI tool usage and governance compliance from a single pane
Acceptance Criteria:
Given ContextForge has observability and audit logging enabled
When I navigate to the ContextForge Observability page in Backstage
Then I should see:
- Tool invocation counts by team, user, and tool
- A2A agent usage metrics
- Plugin violation summary (blocked requests, policy hits)
- Gateway health overview
- Recent audit log entries with filtering
And I should be able to filter by:
- Time range
- Team / user
- Tool / agent
- Decision (allow / deny / violation)Technical Requirements:
- Observability dashboard page:
/contextforge/observability - Backend proxy to ContextForge metrics and log search APIs
- Chart components for usage trends (time series)
- Audit log table with pagination and filtering
- Export capability (CSV/JSON) for compliance reporting
π Architecture
Integration Overview
graph TB
subgraph "Developer Experience"
IDE[IDE / AI Assistant]
BS_UI[Backstage Frontend]
end
subgraph "Backstage"
BS_FE[Frontend Plugin<br/>@contextforge/backstage-plugin]
BS_BE[Backend Plugin<br/>@contextforge/backstage-plugin-backend]
BS_CAT[Catalog Entity Provider<br/>@contextforge/backstage-plugin-catalog-module]
BS_ACT[MCP Actions Bridge<br/>registers CF tools as actions]
BS_MCP[MCP Actions Backend<br/>@backstage/plugin-mcp-actions-backend]
CATALOG[(Backstage Catalog)]
end
subgraph "ContextForge"
CF_API[ContextForge API<br/>REST + MCP + A2A]
CF_PLUG[Plugin Chain<br/>PII, Rate Limit, RBAC]
CF_FED[Federation Layer]
CF_REG[(Service Registry<br/>Tools, Resources,<br/>Prompts, Agents)]
end
subgraph "Upstream Services"
MCP1[MCP Server 1<br/>SSE]
MCP2[MCP Server 2<br/>Streamable HTTP]
A2A1[A2A Agent<br/>Claude]
A2A2[A2A Agent<br/>Custom]
REST1[REST API<br/>via Reverse Proxy]
end
IDE -->|MCP Protocol| BS_MCP
BS_UI --> BS_FE
BS_FE -->|REST| BS_BE
BS_BE -->|REST| CF_API
BS_CAT -->|Periodic Sync| CF_API
BS_ACT -->|Register Actions| BS_MCP
BS_CAT -->|Write Entities| CATALOG
BS_MCP -->|tools/call| BS_ACT
BS_ACT -->|Proxy Invoke| CF_API
CF_API --> CF_PLUG
CF_PLUG --> CF_FED
CF_FED --> CF_REG
CF_FED --> MCP1
CF_FED --> MCP2
CF_API --> A2A1
CF_API --> A2A2
CF_API --> REST1
Entity Mapping
graph LR
subgraph "ContextForge Entities"
CF_T[Tool]
CF_R[Resource]
CF_P[Prompt]
CF_S[Virtual Server]
CF_G[Gateway]
CF_A[A2A Agent]
CF_TM[Team]
end
subgraph "Backstage Catalog Entities"
BS_API_T["kind: API<br/>spec.type: mcp-tool"]
BS_API_R["kind: API<br/>spec.type: mcp-resource"]
BS_API_P["kind: API<br/>spec.type: mcp-prompt"]
BS_COMP_S["kind: Component<br/>spec.type: mcp-server"]
BS_COMP_G["kind: Component<br/>spec.type: mcp-gateway"]
BS_COMP_A["kind: Component<br/>spec.type: a2a-agent"]
BS_GRP["kind: Group"]
end
CF_T --> BS_API_T
CF_R --> BS_API_R
CF_P --> BS_API_P
CF_S --> BS_COMP_S
CF_G --> BS_COMP_G
CF_A --> BS_COMP_A
CF_TM --> BS_GRP
Sync Flow
sequenceDiagram
participant Scheduler as Backstage Scheduler
participant Provider as Catalog Entity Provider
participant CF as ContextForge API
participant Catalog as Backstage Catalog
Scheduler->>Provider: Trigger sync (every N seconds)
Provider->>CF: GET /tools?visibility=public,team
CF-->>Provider: Tool list (paginated)
Provider->>CF: GET /a2a-agents?visibility=public,team
CF-->>Provider: Agent list (paginated)
Provider->>CF: GET /gateways
CF-->>Provider: Gateway list
Provider->>CF: GET /servers
CF-->>Provider: Virtual server list
Provider->>Provider: Transform CF entities β Backstage entities
Provider->>Provider: Compute delta (added, updated, removed)
Provider->>Catalog: Apply delta mutations
Catalog-->>Provider: Mutation result
Provider->>Provider: Log sync summary
Note over Provider,Catalog: Next sync in N seconds...
Tool Invocation Flow
sequenceDiagram
participant Dev as Developer
participant BS_FE as Backstage Frontend
participant BS_BE as Backstage Backend Plugin
participant CF as ContextForge API
participant Plugins as CF Plugin Chain
participant GW as CF Gateway Service
participant Upstream as Upstream MCP Server
Dev->>BS_FE: Click "Invoke Tool" on catalog page
BS_FE->>BS_FE: Render form from input schema
Dev->>BS_FE: Fill parameters and submit
BS_FE->>BS_BE: POST /api/contextforge/tools/{id}/invoke
Note over BS_FE,BS_BE: Backstage auth token included
BS_BE->>BS_BE: Map Backstage identity β CF JWT claims
BS_BE->>CF: POST /tools/{id}/invoke (CF bearer token)
CF->>Plugins: tool_pre_invoke hooks
Note over Plugins: RBAC check, rate limit,<br/>PII filter, clearance check
alt Plugin violation
Plugins-->>CF: Blocked (violation)
CF-->>BS_BE: 403 / 429 with violation details
BS_BE-->>BS_FE: Error with user-friendly message
BS_FE-->>Dev: Display error
else Allowed
Plugins-->>CF: Continue
CF->>GW: Route to source gateway
GW->>Upstream: Forward invocation
Upstream-->>GW: Tool result
GW-->>CF: Result
CF->>Plugins: tool_post_invoke hooks
Plugins-->>CF: Result (possibly modified)
CF-->>BS_BE: Tool result
BS_BE-->>BS_FE: Formatted result
BS_FE-->>Dev: Display output
end
π Implementation Tasks
Phase 1: Backstage Backend Plugin β Core
-
Project Scaffolding
- Create
@contextforge/backstage-plugin-backendpackage - Set up TypeScript project with Backstage backend plugin dependencies
- Implement
createBackendPlugin()with core services (Config, Logger, Database, HTTP Router, Discovery, Auth) - Add configuration schema for
app-config.yaml(contextforge.baseUrl,contextforge.auth,contextforge.sync) - Implement ContextForge API client class with authentication, retry, and error handling
- Create
-
ContextForge API Client
- Typed client for ContextForge REST endpoints
- Methods:
listTools(),listResources(),listPrompts(),listServers(),listGateways(),listA2AAgents() - Methods:
invokeTool(),invokeAgent(),refreshGateway() - Methods:
getMetrics(),searchAuditLogs() - Pagination handling (ContextForge uses offset/limit)
- Authentication: bearer token, basic auth, OAuth 2.0 client credentials
- Connection pooling and timeout configuration
- Circuit breaker for ContextForge unavailability
-
Backend API Routes
-
GET /api/contextforge/healthβ Connection and sync status -
GET /api/contextforge/toolsβ Proxied tool listing -
POST /api/contextforge/tools/:id/invokeβ Proxied tool invocation -
GET /api/contextforge/agentsβ Proxied A2A agent listing -
POST /api/contextforge/agents/:id/invokeβ Proxied agent invocation -
GET /api/contextforge/gatewaysβ Proxied gateway listing -
POST /api/contextforge/gateways/:id/refreshβ Proxied gateway refresh -
GET /api/contextforge/metricsβ Proxied metrics/observability -
GET /api/contextforge/auditβ Proxied audit log search
-
Phase 2: Catalog Entity Provider
-
Entity Provider Implementation
- Implement
EntityProviderinterface for Backstage catalog - Periodic sync with configurable interval (default 300s)
- Delta detection: compare current catalog state vs ContextForge state
- Entity mapping: ContextForge tools β
kind: API, spec.type: mcp-tool - Entity mapping: ContextForge resources β
kind: API, spec.type: mcp-resource - Entity mapping: ContextForge prompts β
kind: API, spec.type: mcp-prompt - Entity mapping: ContextForge servers β
kind: Component, spec.type: mcp-server - Entity mapping: ContextForge gateways β
kind: Component, spec.type: mcp-gateway - Entity mapping: ContextForge A2A agents β
kind: Component, spec.type: a2a-agent - Emit
providesApi/dependsOnrelations between servers and their tools - Emit
ownedByrelations to Backstage groups based on ContextForge team IDs
- Implement
-
Catalog Backend Module
- Create
@contextforge/backstage-plugin-catalog-modulepackage - Register entity provider as a catalog backend module via
createBackendModule() - Wire into catalog's extension point for entity providers
- Support entity removal when ContextForge entities are deleted or disabled
- Create
-
Team β Group Mapping
- Configurable team-to-group mapping in
app-config.yaml - Default: match by name (ContextForge team name = Backstage group name)
- Override: explicit mapping table for mismatched names
- Fallback: assign to a default group when no mapping found
- Configurable team-to-group mapping in
Phase 3: MCP Actions Bridge
-
Action Registration
- Register ContextForge tools as Backstage Actions via
ActionsRegistryService - Convert ContextForge tool input schemas (JSON Schema) to Zod schemas
- Generate action IDs:
contextforge:tool:<tool-name> - Include tool description and metadata in action registration
- Handle schema updates on re-sync (unregister stale, register new)
- Register ContextForge tools as Backstage Actions via
-
Action Execution
- Implement action handler that proxies to ContextForge
/tools/{id}/invoke - Map Backstage user identity to ContextForge auth context
- Return structured results compatible with MCP tool result format
- Handle errors and timeouts gracefully
- Implement action handler that proxies to ContextForge
-
MCP Client Compatibility
- Verify tools appear in
tools/listfor MCP clients connecting to Backstage - Verify
tools/callcorrectly proxies through ContextForge - Test with Claude Desktop, Cursor, and ChatGPT as MCP clients
- Verify ContextForge plugin chain executes (PII filter, rate limiting, etc.)
- Verify tools appear in
Phase 4: Backstage Frontend Plugin
-
Plugin Scaffolding
- Create
@contextforge/backstage-pluginfrontend package - Set up React components with Backstage frontend plugin API
- Register routes:
/contextforge,/contextforge/agents,/contextforge/gateways,/contextforge/observability - Add navigation sidebar item with ContextForge icon
- Create
-
Tool Invocation Card
- Entity page card component for
spec.type: mcp-toolentities - JSON Schema-driven form renderer for tool input parameters
- Execute button with loading state
- Result display panel with syntax-highlighted JSON/text/markdown output
- Error display with ContextForge violation details
- Invocation history (last 10 calls) stored in browser
- Entity page card component for
-
A2A Agent Page
- Agent list page with cards showing name, type, team, health, metrics
- Agent detail page with capabilities, configuration, and invocation history
- Conversational chat interface for agent interaction
- Streaming response support for long-running agent tasks
- Agent metrics charts (invocations over time, success rate, response time)
-
Gateway Management Page
- Gateway list with health status indicators (green/yellow/red)
- Gateway detail: configuration, transport type, auth method, provided tools/resources
- Refresh button with progress indication
- Gateway β tool dependency visualization (simple tree or graph)
- Register new gateway form (for admin users)
-
Observability Dashboard
- Tool invocation counts (bar chart by tool, line chart over time)
- Agent usage metrics (invocations, success rate)
- Plugin violation summary (blocked requests by plugin, violation type)
- Gateway health overview (uptime percentages)
- Audit log table with pagination, search, and time range filtering
- Export to CSV/JSON
-
Entity Page Enhancements
- For
mcp-toolentities: invocation card, metrics card, gateway info card - For
mcp-gatewayentities: health card, provided tools list, refresh button - For
a2a-agententities: chat card, metrics card, capabilities card - For
mcp-serverentities: associated tools/resources list, status card
- For
Phase 5: Identity and RBAC Bridge
-
Identity Mapping
- Map Backstage
userEntityRefto ContextForge user email - Map Backstage group membership to ContextForge
token_teamsJWT claims - Generate scoped ContextForge JWT tokens for proxied requests
- Configurable claim mapping for non-standard identity providers
- Map Backstage
-
Permission Integration
- Define Backstage permissions:
contextforge.tool.invoke,contextforge.agent.invoke,contextforge.gateway.manage,contextforge.audit.view - Integrate with Backstage permission framework (
@backstage/plugin-permission-backend) - Map Backstage permissions to ContextForge RBAC roles (viewer, developer, team_admin, platform_admin)
- Conditional permissions based on entity ownership (team-scoped)
- Define Backstage permissions:
-
Team Sync Service
- Backstage group β ContextForge team sync (configurable direction)
- Member email resolution from Backstage user entities
- Sync on schedule and on-demand via API
- Dry-run mode for validation
- Conflict logging and resolution strategy
Phase 6: ContextForge-Side Extensions
-
Backstage Webhook Notifications
- New ContextForge API endpoint:
POST /webhooksfor registering notification targets - Emit events on: tool created/updated/deleted, gateway health change, agent status change
- Backstage plugin subscribes to webhooks for real-time catalog updates
- Reduces polling frequency and improves sync latency
- New ContextForge API endpoint:
-
Catalog Metadata Endpoint
- New ContextForge API endpoint:
GET /catalog/backstagereturning pre-formatted Backstage entity descriptors - Eliminates client-side entity transformation
- Includes relations, annotations, and ownership pre-computed
- Supports
If-Modified-Sincefor efficient delta sync
- New ContextForge API endpoint:
-
Identity Federation Endpoint
- New ContextForge API endpoint:
POST /auth/backstage/token-exchange - Accept Backstage service-to-service token
- Return ContextForge JWT with mapped claims (email, teams, roles)
- Eliminates need for shared static tokens
- New ContextForge API endpoint:
Phase 7: Testing
-
Backend Plugin Unit Tests
- ContextForge API client: authentication, pagination, error handling
- Entity provider: mapping correctness for all 6 entity types
- Delta sync: additions, updates, removals
- Team mapping: name-based, explicit, fallback
- API routes: request validation, proxy behavior, error propagation
-
Frontend Plugin Tests
- Component rendering: tool invocation card, agent chat, gateway list
- Form generation from JSON Schema
- API call mocking and error states
- Permission-based UI element visibility
-
Integration Tests
- Full sync cycle: ContextForge β entity provider β Backstage catalog
- Tool invocation end-to-end: Backstage UI β backend β ContextForge β upstream
- MCP client via Backstage: connect, list tools, call tool
- A2A agent invocation via Backstage proxy
- Team sync: create group in Backstage, verify team in ContextForge
- RBAC: verify team-scoped tools only visible to correct groups
-
Compatibility Tests
- Backstage versions: v1.40+, latest
- ContextForge versions: current release, previous release
- MCP clients: Claude Desktop, Cursor, VS Code Copilot
- Browsers: Chrome, Firefox, Safari
Phase 8: Documentation
-
Installation Guide
- Prerequisites (Backstage version, ContextForge version, Node.js)
- Package installation (
yarn add) - Backend plugin registration in
packages/backend/src/index.ts - Frontend plugin registration in
packages/app/src/App.tsx -
app-config.yamlconfiguration reference - Authentication setup (bearer token, OAuth)
-
User Guide
- Browsing MCP tools in the catalog
- Invoking tools from entity pages
- Interacting with A2A agents
- Viewing gateway health and metrics
- Understanding team-scoped visibility
-
Administrator Guide
- Sync configuration and tuning
- Team-to-group mapping
- Permission setup
- Troubleshooting connectivity and sync issues
- Monitoring plugin health
-
Architecture Decision Record
- Entity kind mapping rationale (
APIvsComponent) - Sync strategy (polling vs webhook)
- Identity mapping approach
- Why catalog entity provider over static location
- Entity kind mapping rationale (
Phase 9: Quality and Polish
-
Code Quality
- ESLint + Prettier for TypeScript packages
- Backstage CLI
lintandtestpass - No
anytypes in TypeScript - Comprehensive JSDoc for public APIs
-
Performance
- Sync completes in <30s for 500 entities
- Tool invocation adds <100ms overhead vs direct ContextForge call
- Frontend renders tool list in <2s for 200 tools
- Catalog entity provider uses incremental delta (not full replace)
-
Security Review
- No secrets in configuration (use environment variable references)
- Token exchange does not leak ContextForge credentials to frontend
- Proxy routes validate input before forwarding to ContextForge
- CORS configuration for frontend-to-backend communication
-
Packaging and Release
- Publish to npm:
@contextforge/backstage-plugin,@contextforge/backstage-plugin-backend,@contextforge/backstage-plugin-catalog-module - Version aligned with Backstage release compatibility
- Changeset entries for all packages
- README with badges (npm version, Backstage compatibility, license)
- Publish to npm:
βοΈ Configuration Example
app-config.yaml
contextforge:
# ContextForge gateway connection
baseUrl: https://contextforge.internal.example.com
# Authentication to ContextForge API
auth:
method: bearer # bearer | basic | oauth
token: ${CONTEXTFORGE_BEARER_TOKEN}
# For OAuth:
# method: oauth
# clientId: ${CF_CLIENT_ID}
# clientSecret: ${CF_CLIENT_SECRET}
# tokenUrl: https://contextforge.internal.example.com/oauth/token
# Catalog sync configuration
sync:
enabled: true
intervalSeconds: 300 # Sync every 5 minutes
entityKinds: # Which CF entities to sync
- tools
- resources
- prompts
- servers
- gateways
- a2a-agents
teamMapping:
strategy: name # name | explicit
# For explicit mapping:
# strategy: explicit
# map:
# cf-engineering: group:engineering-team
# cf-security: group:infosec
defaultGroup: group:default
# Proxy settings
proxy:
timeout: 30000 # 30s timeout for proxied requests
retries: 2 # Retry failed requests
# Feature flags
features:
toolInvocation: true # Enable tool invocation from UI
agentChat: true # Enable A2A agent chat interface
gatewayManagement: true # Enable gateway management UI
observabilityDashboard: true # Enable observability page
mcpActionsBridge: true # Register CF tools as Backstage MCP Actions
# Register the entity provider
catalog:
providers:
contextforge:
# Uses settings from contextforge.baseUrl and contextforge.auth above
schedule:
frequency:
minutes: 5
timeout:
minutes: 3Backend Registration
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
// ... other plugins ...
// ContextForge integration
backend.add(import('@contextforge/backstage-plugin-backend'));
backend.add(import('@contextforge/backstage-plugin-catalog-module'));
backend.start();Frontend Registration
// packages/app/src/App.tsx
import { contextforgePlugin, ContextForgePage } from '@contextforge/backstage-plugin';
// In routes:
<Route path="/contextforge" element={<ContextForgePage />} />
// Entity page cards (in EntityPage.tsx):
import {
ContextForgeToolInvocationCard,
ContextForgeAgentCard,
ContextForgeGatewayHealthCard,
} from '@contextforge/backstage-plugin';
// On API entity pages (for mcp-tool type):
<EntitySwitch.Case if={isContextForgeTool}>
<ContextForgeToolInvocationCard />
</EntitySwitch.Case>β Success Criteria
- Catalog Sync: ContextForge tools, resources, prompts, servers, gateways, and A2A agents appear in Backstage catalog within configured sync interval
- Entity Mapping: All 6 entity types correctly mapped with annotations, tags, ownership, and relations
- Tool Invocation: Developers can invoke MCP tools from Backstage entity pages with schema-driven forms and formatted results
- A2A Agents: Developers can discover and interact with A2A agents via conversational interface in Backstage
- MCP Bridge: AI assistants connected to Backstage's MCP endpoint can discover and invoke ContextForge tools
- Gateway Management: Platform engineers can view gateway health, refresh capabilities, and register new gateways
- Team Scoping: ContextForge team visibility is respected through Backstage group ownership mapping
- RBAC: Backstage permissions correctly gate access to ContextForge operations
- Observability: Audit logs, metrics, and plugin violation data visible from Backstage dashboard
- Performance: Sync <30s for 500 entities; invocation overhead <100ms
- Testing: Unit, integration, and compatibility tests pass across supported Backstage versions
- Documentation: Installation guide, user guide, administrator guide, and ADR complete
π Definition of Done
- Three npm packages published:
@contextforge/backstage-plugin,@contextforge/backstage-plugin-backend,@contextforge/backstage-plugin-catalog-module - Catalog entity provider syncs all 6 entity types with delta detection
- Backend proxy routes handle tool invocation, agent invocation, gateway management, and audit queries
- MCP Actions bridge registers ContextForge tools as Backstage actions
- Frontend plugin provides: tool invocation card, agent chat, gateway management, observability dashboard
- Identity mapping bridges Backstage users/groups to ContextForge users/teams
- Backstage permission integration gates ContextForge operations
- ContextForge-side endpoints for webhook notifications and pre-formatted catalog export
- Token exchange endpoint eliminates static shared secrets
- Unit tests for backend and frontend with >80% coverage
- Integration tests for full sync cycle, tool invocation, and MCP client compatibility
- Tested against Backstage v1.40+ and current ContextForge release
- Installation, user, and administrator documentation complete
- Architecture Decision Record documented
- Code passes lint, format, and type checks for all packages
- Security review completed (no credential leakage, input validation, CORS)
- Published to npm with Backstage compatibility badges
π Additional Notes
πΉ Backstage MCP Ecosystem Context:
- Backstage v1.40+ ships
@backstage/plugin-mcp-actions-backendβ exposes Backstage actions as MCP tools via Streamable HTTP/SSE - Spotify Portal (commercial) registers MCP servers as
kind: APIwithspec.type: mcp-server - Community MCP Registry proposal (#4034) is open but inactive
- Red Hat Developer Hub has shipped basic MCP integration
- No A2A protocol support exists anywhere in the Backstage ecosystem
πΉ Why Not Just Use Backstage's Built-In MCP Plugin?:
- Backstage's MCP plugin exposes Backstage actions as tools β it does not federate external MCP servers
- It has no concept of upstream gateways, multi-transport proxying, or tool governance
- It cannot discover or aggregate tools from multiple MCP server instances
- It has no plugin chain (PII filtering, rate limiting, content moderation) for tool invocations
- It has no A2A agent support
- ContextForge fills these gaps while Backstage provides the developer portal experience
πΉ Entity Mapping Rationale:
- Tools, resources, and prompts map to
kind: APIbecause they are interfaces that components consume β consistent with Backstage's system model where APIs are "boundaries between components" - Servers, gateways, and A2A agents map to
kind: Componentbecause they are running software that provides APIs spec.typeusesmcp-tool,mcp-resource,mcp-prompt,mcp-server,mcp-gateway,a2a-agentβ prefixed for namespace clarity
πΉ Sync Strategy:
- Phase 1 uses polling (configurable interval, default 5 minutes) for simplicity
- Phase 6 adds webhook-driven sync for real-time updates
- Delta detection prevents catalog churn (entities only updated when changed)
- Tombstone handling: disabled or deleted ContextForge entities are removed from catalog
πΉ Security Considerations:
- ContextForge bearer tokens must be stored as environment variable references, never inline
- Backend plugin proxies all requests β frontend never contacts ContextForge directly
- Token exchange (Phase 6) eliminates long-lived shared secrets
- Tool invocation audit trail maintained in ContextForge regardless of entry point (direct API, Backstage, MCP client)
πΉ Future Enhancements:
- Backstage Scaffolder Integration: Generate
catalog-info.yamlwith ContextForge annotations from software templates - TechDocs Integration: Auto-generate tool/agent documentation pages from ContextForge metadata
- Cost Attribution: Surface ContextForge tool invocation costs alongside cloud spend in Backstage cost dashboards
- Backstage Search Integration: Index ContextForge tools and agents in Backstage's federated search
- Event-Driven Architecture: Replace polling with CloudEvents for sub-second sync
- Multi-Instance Support: Connect multiple ContextForge gateways from a single Backstage instance
- ContextForge Plugin for Backstage Catalog: A ContextForge plugin that reads Backstage catalog and auto-registers Backstage components as ContextForge resources
π Related Issues
- [EPIC][SECURITY]: Security clearance levels plugin - Bell-LaPadula MAC implementationΒ #1245 - Security clearance levels plugin (RBAC governance applicable to Backstage-proxied requests)
- #XXX - ContextForge Admin UI (parallel developer experience to Backstage frontend)
- #XXX - Webhook/event notification system (enables real-time Backstage sync)
- #XXX - Token exchange and identity federation
- #XXX - A2A agent metrics and observability
π References
- Backstage Official MCP Plugin β
@backstage/plugin-mcp-actions-backend - Backstage MCP Actions RFC #30218 β Distributed Actions architecture
- Backstage Community MCP Registry Proposal #4034
- Spotify Portal MCP Server Registration
- Red Hat Developer Hub MCP Integration
- Backstage Backend System Architecture
- Backstage Software Catalog System Model
- Backstage Entity Descriptor Format
- Backstage as the Ultimate MCP Server (vrabbi.cloud)
- MCP Protocol Specification
- A2A Protocol Specification