MCP server for the ExploitIQ/Agent Morpheus vulnerability analysis platform. Enables AI coding assistants (Claude Code, Cursor, Windsurf, etc.) to submit analyses, manage reports, and view results.
Also available as a Claude Code plugin with workflow skills for guided analysis, report management, and product management.
git clone --recurse-submodules https://github.com/RHEcosystemAppEng/exploitiq-mcp-server.git
cd exploitiq-mcp-server
npm install
npm run buildInstall as a Claude Code plugin to get both the MCP server connection and workflow skills:
# 1. Add the marketplace
/plugin marketplace add https://github.com/RHEcosystemAppEng/exploitiq-mcp-server.git
# 2. Install the plugin
/plugin install exploitiq-plugin@exploitiq-marketplaceThis registers:
- The MCP server (connects to
$EXPLOITIQ_MCP_URLorhttp://localhost:3000/mcpby default) - Three workflow skills:
/exploitiq-plugin:exploitiq-analyze,/exploitiq-plugin:exploitiq-reports,/exploitiq-plugin:exploitiq-products
The plugin is defined in .claude-plugin/plugin.json and the marketplace entry in .claude-plugin/marketplace.json. Skills are located in skills/ with one SKILL.md per workflow.
Set the EXPLOITIQ_MCP_URL environment variable to point to your MCP server instance:
export EXPLOITIQ_MCP_URL=https://exploitiq-mcp-server-<namespace>.apps.<cluster-domain>/mcpUse this approach when you don't need the plugin skills, or when connecting from clients other than Claude Code.
Add to ~/.claude/settings.json:
{
"mcpServers": {
"exploitiq": {
"command": "node",
"args": ["/path/to/exploitiq-mcp-server/dist/index.js"],
"env": {
"EXPLOITIQ_CLIENT_URL": "http://localhost:8080"
}
}
}
}Or via CLI:
claude mcp add exploitiq -- node /path/to/exploitiq-mcp-server/dist/index.jsStart the server:
EXPLOITIQ_CLIENT_URL=http://localhost:8080 node dist/http.jsWith TLS:
EXPLOITIQ_CLIENT_URL=http://localhost:8080 \
EXPLOITIQ_MCP_SERVER_TLS_CERT=/path/to/cert.pem \
EXPLOITIQ_MCP_SERVER_TLS_KEY=/path/to/key.pem \
node dist/http.jsConnect from Claude Code:
claude mcp add --transport http exploitiq http://localhost:3000/mcpWith TLS:
claude mcp add --transport http exploitiq https://localhost:3000/mcpDeploy to OpenShift using the manifest in deploy/exploitiq_mcp_server.yaml (or via the kustomize overlay in vulnerability-analysis/kustomize). The MCP server is exposed via an edge-TLS Route. Backend API auth uses the auto-detected ServiceAccount token.
Connect from Claude Code using the Route URL:
claude mcp add --transport http exploitiq \
https://exploitiq-mcp-server-<namespace>.apps.<cluster-domain>/mcpFor example:
claude mcp add --transport http exploitiq \
https://exploitiq-mcp-server-exploit-iq-testings.apps.ai-dev03.kni.syseng.devcluster.openshift.com/mcpOr add to ~/.claude/settings.json:
{
"mcpServers": {
"exploitiq": {
"type": "streamable-http",
"url": "https://exploitiq-mcp-server-exploit-iq-testings.apps.ai-dev03.kni.syseng.devcluster.openshift.com/mcp"
}
}
}The MCP server acts as an OAuth intermediary: MCP clients (Claude Code, Cursor, etc.) register with the server via Dynamic Client Registration, and the server proxies authorization to the upstream OIDC provider using its own pre-registered credentials.
With OAuth enabled (after creating the OAuthClient CR), the same connection configuration works -- Claude Code will open a browser for OpenShift login on first use and refresh tokens automatically.
Verified with Claude Code. Cursor should also work but has not been tested. Other MCP clients (ChatGPT, Windsurf, GitHub Copilot, Gemini CLI) may work but are untested.
-
Register a client with your OIDC provider:
OpenShift -- create an OAuthClient CR:
export OAUTH_CLIENT_SECRET=$(oc get oauthclient exploit-iq-client -o jsonpath='{..secret}') # Or generate a new secret: export OAUTH_CLIENT_SECRET=$(openssl rand -base64 32) export MCP_ROUTE=$(oc get route exploitiq-mcp-server -o jsonpath='{.spec.host}') oc create -f - <<EOF apiVersion: oauth.openshift.io/v1 kind: OAuthClient metadata: name: exploitiq-mcp-server grantMethod: prompt secret: $OAUTH_CLIENT_SECRET redirectURIs: - "https://${MCP_ROUTE}/oauth/callback" EOF
Keycloak -- create a client in your realm with:
- Client ID:
exploitiq-mcp-server - Valid Redirect URI:
https://<your-mcp-server>/oauth/callback - Client Authentication: enabled (confidential)
- If using
EXPLOITIQ_ALLOWED_GROUPS: add a "Group Membership" protocol mapper (Client Scopes -> Add mapper -> "Group Membership") with token claim namegroups. Without this mapper, JWTs won't contain group claims and group authorization will deny all users.
- Client ID:
-
Set the OAuth environment variables in the deployment:
EXPLOITIQ_CLIENT_URL=https://exploit-iq-client.<namespace>.svc:8443 EXPLOITIQ_OAUTH_ISSUER_URL=https://oauth-openshift.apps.<cluster-domain> EXPLOITIQ_OAUTH_CLIENT_ID=exploitiq-mcp-server EXPLOITIQ_OAUTH_CLIENT_SECRET=<your-client-secret> EXPLOITIQ_MCP_PUBLIC_URL=https://exploitiq-mcp-server-<namespace>.apps.<cluster-domain>
The server auto-discovers endpoints via .well-known/openid-configuration (standard OIDC), .well-known/oauth-authorization-server (OAuth 2.0), or falls back to standard OpenShift OAuth endpoint paths. Discovery requests have a 10-second timeout and network errors are handled gracefully (falling through to the next discovery level). The server exposes standard OAuth endpoints:
/.well-known/oauth-protected-resource-- resource metadata (RFC 9728)/.well-known/oauth-authorization-server-- authorization server metadata (RFC 8414)/authorize-- redirects to upstream OIDC provider/token-- exchanges local authorization codes for upstream tokens/register-- Dynamic Client Registration (RFC 7591)/oauth/callback-- receives upstream authorization codes
When OAuth is enabled, you can restrict access to users belonging to specific OpenShift groups by setting EXPLOITIQ_ALLOWED_GROUPS:
EXPLOITIQ_ALLOWED_GROUPS=exploitiq-users,security-teamWhen set, group membership is verified at two levels:
- During OAuth callback — before issuing a local authorization code. Unauthorized users see a 403 error in the browser during login, instead of a misleading "Authentication successful" followed by a silent connection failure. If the identity provider is unreachable during the group check, a 502 error is returned.
- On every
/mcprequest — as Express middleware (defense-in-depth).
When unset or empty, any authenticated user has access (default behavior).
This has no effect when OAuth is disabled (stdio mode or HTTP without OAuth).
| Variable | Required | Default | Description |
|---|---|---|---|
EXPLOITIQ_CLIENT_URL |
Yes | http://localhost:8080 |
ExploitIQ Client API URL |
EXPLOITIQ_READ_ONLY |
No | true |
When true, only read-only tools are registered. Set to false to enable write tools (analyze, delete, retry). |
EXPLOITIQ_REDACT_RESPONSES |
No | true |
When true, sensitive keys (secretValue, userName, fileContent) are redacted from tool responses. |
EXPLOITIQ_OAUTH_ISSUER_URL |
No | - | OIDC issuer URL (enables OAuth authentication) |
EXPLOITIQ_OAUTH_CLIENT_ID |
When OAuth | - | Client ID registered with the OIDC provider |
EXPLOITIQ_OAUTH_CLIENT_SECRET |
When OAuth | - | Client secret from the OIDC provider |
EXPLOITIQ_OAUTH_AUDIENCE |
No | - | Expected JWT aud claim for token validation (supported by Keycloak, Auth0, Azure AD; not used by OpenShift) |
EXPLOITIQ_MCP_PUBLIC_URL |
No | http://localhost:<port> |
Public URL for OAuth callback |
EXPLOITIQ_MCP_PORT |
No | 3000 |
HTTP port (remote mode). Falls back to 3000 if the value is not a valid number. |
EXPLOITIQ_MCP_SERVER_TLS_CERT |
No | - | Path to TLS certificate for serving HTTPS directly (without a reverse proxy) |
EXPLOITIQ_MCP_SERVER_TLS_KEY |
No | - | Path to TLS private key for serving HTTPS directly (without a reverse proxy) |
EXPLOITIQ_ALLOWED_GROUPS |
No | - | Comma-separated list of OpenShift groups allowed to access the MCP server. When unset, any authenticated user has access. |
On Kubernetes, the backend API token is auto-detected from the ServiceAccount token at /var/run/secrets/kubernetes.io/serviceaccount/token.
By default (EXPLOITIQ_READ_ONLY=true), the server only exposes read-only tools and prompts:
| Always available | Requires EXPLOITIQ_READ_ONLY=false |
|---|---|
health_check |
analyze_cve |
list_cve_reports |
analyze_rpm |
get_cve_report |
analyze_spdx_sbom |
get_cve_report_by_scan_id |
analyze_cyclonedx_sbom |
list_products |
delete_cve_report |
get_product |
retry_cve_analysis |
delete_product |
Prompts corresponding to write tools are also hidden in read-only mode. To enable all tools:
EXPLOITIQ_READ_ONLY=false node dist/http.jsBy default (EXPLOITIQ_REDACT_RESPONSES=true), sensitive keys in API responses are replaced with [REDACTED] before being returned to the MCP client. The redacted keys are the same ones redacted in request logs: secretValue, userName, fileContent. This applies recursively to nested objects and arrays. If the backend API introduces new fields containing sensitive data, update REDACTED_KEYS in src/tools/logging.ts and src/utils/format.ts accordingly.
To disable response redaction:
EXPLOITIQ_REDACT_RESPONSES=false node dist/http.js- stdio (
node dist/index.js): Single-client mode for local AI assistants. The MCP server communicates over stdin/stdout. - streamable-http (
node dist/http.js): Multi-client mode via HTTP. Each POST to/mcpcreates a stateless MCP server instance (no session persistence). Supports optional TLS and OAuth authentication. ExposesGET /healthz(liveness — returns 200 when the process is running) andGET /readyz(readiness — proxies the backend health check, returns 503 when the backend is unreachable). Used by Kubernetes liveness and readiness probes respectively.
When OAuth is enabled, the server acts as an intermediary between MCP clients and the upstream OIDC provider:
- MCP client registers via DCR -> gets local
client_id - MCP client calls
/authorize-> server redirects to upstream with its ownclient_id - User authenticates at upstream -> upstream redirects to
/oauth/callback - Server exchanges upstream code for tokens, verifies group membership if
EXPLOITIQ_ALLOWED_GROUPSis set (rejects with 403 before issuing a code), then issues local code to MCP client - MCP client exchanges local code at
/token-> gets upstream tokens - MCP client uses upstream
access_tokenfor/mcprequests -> verified via JWKS or OpenShift user API
Token verification uses JWT/JWKS when the OIDC provider supplies a jwks_uri (Keycloak, Auth0), or falls back to OpenShift opaque token verification via the Kubernetes user API (/apis/user.openshift.io/v1/users/~).
Client registrations are persisted via the backend API (POST/GET /api/v1/mcp-clients), which stores them in MongoDB with a 30-day TTL for automatic cleanup. The MCP server has no direct database dependency. Pending auth entries and issued codes are always in-memory with a 5-minute TTL, purged every 60 seconds. DCR is rate-limited to 10 registrations per minute, and concurrent pending auth flows are capped at 50. OAuth state parameters are HMAC-signed to prevent forgery.
All HTTP requests are logged with method, URL, status code, and duration. Authorization presence is logged as auth=present or auth=none (tokens are never logged, even partially). Tool calls are logged with client identity (authInfo.clientId), sanitized parameters, and duration — secretValue, userName, and fileContent are redacted.
The generated TypeScript client (src/generated/) communicates with the ExploitIQ Client API. On Kubernetes, the ServiceAccount token at /var/run/secrets/kubernetes.io/serviceaccount/token is auto-detected and used as a Bearer token for backend requests.
Tools marked with * require EXPLOITIQ_READ_ONLY=false.
| Tool | Description |
|---|---|
health_check |
Check service health |
analyze_cve * |
Analyze a CVE vulnerability against a source code repository (http/https URLs only) |
analyze_rpm * |
Analyze a CVE vulnerability against a specific RPM package to determine exploitability (uses the RPM package checker pipeline) |
analyze_spdx_sbom * |
Analyze an SPDX SBOM for CVE exploitability (accepts base64-encoded file content) |
analyze_cyclonedx_sbom * |
Analyze a CycloneDX SBOM for CVE exploitability (accepts base64-encoded file content) |
list_cve_reports |
List CVE analysis reports with filtering (by CVE ID, image name/tag, status, ExploitIQ status, product ID, report ID) |
get_cve_report |
Get CVE analysis report by MongoDB ObjectId (validated: 24-character hex) |
get_cve_report_by_scan_id |
Get CVE analysis report by scan ID |
delete_cve_report * |
Delete a CVE analysis report by MongoDB ObjectId (validated: 24-character hex) |
retry_cve_analysis * |
Retry failed CVE analysis by MongoDB ObjectId (validated: 24-character hex) |
list_products |
List products with filtering and sorting |
get_product |
Get product details including report summaries |
delete_product * |
Delete a product and all associated reports |
The server also registers 13 MCP prompts that generate pre-filled user messages for common workflows:
analyze-cve, analyze-rpm, analyze-spdx-sbom, analyze-cyclonedx-sbom, get-cve-report, get-cve-report-by-scan-id, list-cve-reports, delete-cve-report, retry-cve-analysis, list-products, get-product, delete-product, health-check
When installed as a Claude Code plugin, three skills provide guided workflows:
| Skill | Description |
|---|---|
/exploitiq-plugin:exploitiq-analyze |
Submit CVE or SBOM analyses, poll for results, present detailed findings |
/exploitiq-plugin:exploitiq-reports |
List, filter, inspect, retry, or delete CVE analysis reports |
/exploitiq-plugin:exploitiq-products |
List, inspect, or delete products and their associated reports |
Skills handle parameter collection, result formatting, polling, and retry logic automatically. Type the slash command in Claude Code — the skill loads and Claude follows the guided workflow, asking for any missing parameters interactively.
Analyzes CVEs against source repos or SBOM files. Automatically detects analysis type, submits the request, and offers to poll every 30 seconds until completion. Results include verdict, justification, checklist, and agent investigation trail.
CVE + source repo:
/exploitiq-plugin:exploitiq-analyze Analyze CVE-2024-51744 against https://github.com/openshift/assisted-installer at commit ab9e2ade
If the repo is private, include credentials or the skill will ask:
/exploitiq-plugin:exploitiq-analyze Analyze CVE-2024-29025 on https://github.com/my-org/my-app at 3f7a1b2c with username myuser and PAT ghp_xxxx
SBOM file (format auto-detected from file content or extension):
/exploitiq-plugin:exploitiq-analyze Analyze the SBOM at /home/user/sbom.spdx.json
/exploitiq-plugin:exploitiq-analyze Analyze /tmp/app-sbom.cdx.json for CVE-2023-44487
The skill reads the file, base64-encodes it, and submits it to the appropriate analyzer (SPDX or CycloneDX).
Manages CVE analysis reports. Results are presented as tables with an offer to inspect individual reports in detail.
/exploitiq-plugin:exploitiq-reports List completed reports
/exploitiq-plugin:exploitiq-reports Show reports for CVE-2024-51744
/exploitiq-plugin:exploitiq-reports List reports with ExploitIQ status TRUE
/exploitiq-plugin:exploitiq-reports List reports for image quay.io/my-org/my-app tag v1.2.3
/exploitiq-plugin:exploitiq-reports Show report with scan ID a1b2c3d4-e5f6-7890-abcd-ef1234567890
/exploitiq-plugin:exploitiq-reports Retry report 507f1f77bcf86cd799439011
/exploitiq-plugin:exploitiq-reports Delete report 507f1f77bcf86cd799439011
Confirms before destructive operations and offers to poll after retries.
Manages products that group related CVE analysis reports for a software component.
/exploitiq-plugin:exploitiq-products List all products
/exploitiq-plugin:exploitiq-products List products named my-application sorted by name DESC
/exploitiq-plugin:exploitiq-products Show product 680b7c3e9a1f2d4e5b6c7d8e
/exploitiq-plugin:exploitiq-products Delete product 680b7c3e9a1f2d4e5b6c7d8e
Warns that deleting a product also deletes all associated reports, and confirms before proceeding.
Below are example prompts you can use with an AI coding assistant (Claude Code, Cursor, etc.) connected to the ExploitIQ MCP server. Each example maps to one of the available tools.
Is ExploitIQ up?
Check the health of the ExploitIQ service
Analyze a CVE against a public repository:
Analyze CVE-2024-51744 against https://github.com/openshift/assisted-installer at commit ab9e2ade
Analyze a CVE against a private repository using a PAT:
Analyze CVE-2024-29025 on repo https://github.com/my-org/my-app at commit 3f7a1b2c with username myuser and PAT ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Analyze a CVE against a specific RPM package:
Analyze CVE-2024-29025 against RPM package openssl version 1.1.1k release 8.el9_9
Analyze with a specific architecture:
Analyze CVE-2023-44487 against RPM package curl version 7.76.1 release 26.el9_4 arch aarch64
Analyze an SPDX SBOM file:
Read the file at /home/user/sbom.spdx.json, base64-encode its content, and analyze it for vulnerabilities using SPDX
Analyze an SPDX SBOM file for a specific CVE:
Read /tmp/my-image-sbom.spdx.json, base64-encode it, and analyze it with the SPDX analyzer for CVE-2024-29025
Analyze a CycloneDX SBOM file:
Read the file at /home/user/sbom.cdx.json, base64-encode its content, and analyze it for vulnerabilities using CycloneDX
Analyze a CycloneDX SBOM for a specific CVE from a private repo:
Read /tmp/app-sbom.cdx.json, base64-encode it, and analyze it with the CycloneDX analyzer for CVE-2023-44487 with username myuser and secret ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
List all completed reports:
List the latest CVE reports filtered by status completed
List reports for a specific CVE with pagination:
List CVE reports filtered by CVE-2024-51744 and status completed, page 0 with 5 items per page
List reports that were assessed as exploitable:
Show me all reports with ExploitIQ status TRUE
List reports for a specific image:
List CVE reports filtered by image name quay.io/my-org/my-app and image tag v1.2.3
List reports without a product assignment:
List CVE reports that have no product assigned
Get a report by its ID:
Get report 507f1f77bcf86cd799439011
Get a report by scan ID:
Get the CVE report with scan ID a1b2c3d4-e5f6-7890-abcd-ef1234567890
Delete a report:
Delete report 507f1f77bcf86cd799439011
Retry a failed or expired analysis:
Retry the analysis for report 507f1f77bcf86cd799439011
List all products:
List all products
List products with filtering and sorting:
List products filtered by name my-application sorted by name DESC, page 0 with 10 items per page
List products affected by a specific CVE:
List products filtered by CVE CVE-2024-51744
Get product details:
Get product 680b7c3e9a1f2d4e5b6c7d8e
Delete a product and its reports:
Delete product 680b7c3e9a1f2d4e5b6c7d8e
Before connecting the ExploitIQ MCP server to production AI hosts, the following prerequisites must be completed:
-
AI Assessment (AIA): All proposed MCP hosts and AI solutions that utilize MCP servers must complete the AI Assessment process to document the new data source and connection. AIAs are not required for proof-of-concept use in Models.corp and MOSAIC sandboxes unless relying on data outside the approved dataverse dataset.
-
GRC Security Review: MCP hosts introduce new security risks and must be vetted by GRC (grc@redhat.com) before production use. The review covers authentication configuration, data sensitivity classification, allowed scopes, and monitoring.
-
ESS Compliance: The MCP server deployment must comply with the Red Hat Enterprise Security Standard (ESS). Refer to the Security Guidance for MCP deployments within Red Hat.
OAuth/OIDC authentication is required for production deployments. Running without OAuth (no EXPLOITIQ_OAUTH_ISSUER_URL set) disables all authentication and is for local development only. Never expose an unauthenticated MCP server endpoint to a network.
When OAuth is enabled:
- All MCP clients must register via Dynamic Client Registration (RFC 7591)
- Access tokens are verified on every
/mcprequest via JWT/JWKS or OpenShift user API - Group-based authorization can restrict access to specific teams (
EXPLOITIQ_ALLOWED_GROUPS)
Consuming hosts should validate tool-call parameters before forwarding them to the MCP server:
- Sanitize user-supplied inputs (CVE IDs, repository URLs, file content) before passing to analysis tools
- Enforce rate limits on analysis submissions to prevent abuse
- Review tool-call results before presenting to end users, especially for write operations (analyze, delete, retry)
- Do not expose write tools (
EXPLOITIQ_READ_ONLY=false) unless the host has been specifically authorized
The MCP server is a passthrough proxy to the ExploitIQ backend API. It does not store or cache vulnerability data. Response redaction (EXPLOITIQ_REDACT_RESPONSES=true, enabled by default) removes sensitive fields (secretValue, userName, fileContent) before responses reach the MCP client. The backend is the authoritative source for data accuracy and currency.
npm test # Run all tests
npm run test:watch # Watch modeThe eval/ directory contains an automated evaluation suite that validates the MCP server against a live deployment. It has two parts:
- Part A — Direct MCP protocol checks (tool listing, prompt listing, health, report/product queries) using a Python HTTP client. No LLM cost.
- Part B — Agent workflow evaluation using mcpchecker, which drives an LLM through end-to-end tool-calling scenarios.
Quick start:
# Part A only (no LLM cost)
export MCP_URL=<your-mcp-server-url>/mcp
python3 eval/run_eval.py --skip-mcpchecker
# Full eval including Part B (requires LLM endpoint)
export OPENAI_BASE_URL=<litellm-or-cluster-llm-url>
python3 eval/run_eval.pySee eval/README.md for prerequisites, CLI options, environment variables, and output format.
When the backend API changes, update the submodule and regenerate:
git submodule update --remote agent-morpheus-client
npm run generate-client
npm run buildBuild the container image using the multi-stage Dockerfile (UBI 9 nodejs-22-minimal):
podman build -t exploitiq-mcp-server .
podman run -p 3000:3000 -e EXPLOITIQ_CLIENT_URL=http://host:8080 exploitiq-mcp-serverThe image is automatically built and pushed to quay.io/exploit-iq/exploitiq-mcp-server:latest by the Tekton CI pipeline on pushes to main.
Tekton Pipelines-as-Code definitions are in .tekton/:
| Pipeline | Trigger | Description |
|---|---|---|
on-push.yaml |
Push to main |
Builds and pushes container image |
on-pull-request.yaml |
Pull request | Validates the PR (build + tests) |
on-tag.yaml |
Git tag | Builds and pushes tagged release image |
src/
index.ts # stdio entry point
http.ts # streamable-http entry point with Express
server.ts # MCP server creation (tool + prompt registration)
config.ts # Environment variable loading
auth.ts # OAuth/OIDC discovery, token verification, provider
agent-client-backend-clients-store.ts # Backend API client registration store (HTTP mode)
tools/
logging.ts # Tool call logging with sensitive param redaction
health.ts # health_check tool
reports.ts # list/get/delete/retry report tools
products.ts # list/get/delete product tools
analysis.ts # analyze_cve, analyze_rpm, analyze_spdx_sbom, analyze_cyclonedx_sbom
utils/
format.ts # Shared formatResult/formatError helpers
auth-headers.ts # Shared auth header resolution from OpenAPI.TOKEN
prompts/
prompts.ts # MCP prompt definitions
generated/ # Auto-generated API client (do not edit)
__tests__/ # Test files
skills/
exploitiq-analyze/ # CVE and SBOM analysis workflow skill
exploitiq-reports/ # Report management workflow skill
exploitiq-products/ # Product management workflow skill
eval/
run_eval.py # Automated evaluation runner (Part A + B)
mcp_http.py # MCP HTTP client for Part A checks
tasks/ # mcpchecker agent task definitions (Part B)
deploy/
exploitiq_mcp_server.yaml # Kubernetes/OpenShift manifest (Deployment, Service, Route)
.tekton/ # Tekton CI/CD pipeline definitions
.claude-plugin/ # Claude Code plugin configuration
plugin.json # Plugin metadata
marketplace.json # Marketplace configuration
.mcp.json # MCP server connection config (used by plugin)
Dockerfile # Multi-stage container build (UBI 9 nodejs-22-minimal)
agent-morpheus-client/ # Git submodule — backend OpenAPI spec for client generation