Static MCP registry generator and GitHub Marketplace Action for producing host-agnostic registry artifacts.
- Repo: https://github.com/blackoutsecure/bos-mcp-engine-demo
- Branch:
registry-demo-cf - Site: https://demo.mcp.registry.blackoutsecure.dev/
- Repo: https://github.com/blackoutsecure/bos-mcp-engine-demo
- Branch:
registry-demo-gh - Site: https://demo-gh.mcp.registry.blackoutsecure.dev/
This project is built and maintained by Blackout Secure.
- Company website: https://blackoutsecure.app
- Organization profile: https://github.com/blackoutsecure
- Marketplace listing: https://github.com/marketplace/actions/blackout-secure-mcp-registry-engine
- Protocol baseline: MCP Specification 2025-11-25 (
https://modelcontextprotocol.io/specification/2025-11-25) - Protocol schema source of truth:
https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-11-25/schema.ts - Registry manifest schema reference:
https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json - This project keeps a split static manifest model (
server.json+versions/<semver>.json) and follows current registry field semantics. - Remote transports must use
remotes[].typewith current values (sse,streamable-http).
- Validates
servers/<name>/server.jsonandservers/<name>/versions/<semver>.json - Generates static registry output under
<output_directory>/<output> - Supports server-manifest lifecycle in MCP server repositories (generate/update + validate)
- Keeps generated public artifacts in the configured
outputfolder (default:public) - Produces versioned API-compatible artifacts for
v0.1 - Supports deployment profiles:
github(generates.nojekyll)cloudflare(generates_headersand_redirects)none(no host-specific profile files; suitable for local/static hosting like Apache/Nginx)
name: Build MCP Registry
on:
push:
branches: [main]
paths:
- 'servers/**'
- 'src/**'
jobs:
registry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate registry
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
# Required
# Supported values:
# generate_registry, validate_registry,
# generate_server_manifest, validate_server_manifest
action_type: 'generate_registry'
# Optional (default): info
# Suggested: debug, info, warn, error
log_level: 'info'
source: './servers'
# Optional (default): dist
output_directory: 'dist'
# Optional (default): public
# Generates to dist/public
output: 'public'
# Optional (default): github
deployment_environment: 'github'
# Optional
# config: './config/custom-registry-config.json'The table below is aligned with action.yml inputs.
| Input | Required | Default | Description |
|---|---|---|---|
action_type |
Yes | (none) | Operation mode |
log_level |
No | info |
Console logging level |
source |
No | ./servers |
Servers root path |
output_directory |
No | dist |
Base output directory path |
output |
No | public |
Registry public folder |
deployment_environment |
No | github |
Hosting profile |
cloudflare_lean_output |
No | true |
Cloudflare JSON-only lean output |
config |
No | (none) | Registry config file |
upload_artifacts |
No | true |
Upload generated registry as artifact |
artifact_name |
No | mcp-registry-files |
Artifact name when upload enabled |
artifact_retention_days |
No | 1 |
Retention days |
server_slug |
No | (none) | Server folder slug |
server_name |
No | (none) | Server manifest name |
server_description |
No | (none) | Server description |
server_title |
No | (none) | Server title |
server_website_url |
No | (none) | Server website URL |
repository_url |
No | (none) | Repository URL |
repository_source |
No | github |
Repository source |
repository_subfolder |
No | (none) | Repository subfolder |
server_version |
No | 1.0.0 |
Version manifest value |
release_date |
No | (none) | Release date |
package_registry_type |
No | npm |
Package registry type |
package_identifier |
No | (none) | Package identifier |
package_transport_type |
No | stdio |
Package transport type |
Input details:
action_type:generate_registry,validate_registry,generate_server_manifest,validate_server_manifest.log_level:debug,info,warn,error.output_directory,output,deployment_environment, andcloudflare_lean_outputapply to registry actions.cloudflare_lean_outputis only applied whendeployment_environment=cloudflare; defaulttrueemits JSON files and relies on_redirectsfor extensionless aliases.- If the configured
sourcedirectory does not exist,generate_registrycreates an empty source directory and generates an empty registry output (instead of crashing). upload_artifacts,artifact_name,artifact_retention_days,commit_generated_artifacts,artifact_committer_name, andartifact_committer_emailapply togenerate_registryonly.commit_generated_artifacts: defaults totrue; stages, commits, and pushes generated output from the checked-out repository workspace; requiresupload_artifacts=true.artifact_retention_days: must be an integer between1and400; invalid values fail the action during configuration.- GitHub retention defaults are controlled by your repository/organization policy (see GitHub artifact/log retention policy docs).
- This repository/action default for
artifact_retention_daysis1. artifact_committer_name: optional; defaults togithub-actions[bot]when localgit user.nameis unset.artifact_committer_email: optional; defaults to41898282+github-actions[bot]@users.noreply.github.comwhen localgit user.emailis unset.server_slugis required for server-manifest actions.server_nameandserver_descriptionare required forgenerate_server_manifest.configsupportsversionandexternalRepositories.
| Input Group | generate_registry | validate_registry | generate_server_manifest | validate_server_manifest |
|---|---|---|---|---|
source |
Required | Required | Required | Required |
log_level |
Optional | Optional | Optional | Optional |
output_directory |
Optional | Optional | N/A | N/A |
output |
Optional | Optional | N/A | N/A |
deployment_environment |
Optional | Optional | N/A | N/A |
cloudflare_lean_output |
Optional | Optional | N/A | N/A |
config |
Optional | Optional | N/A | N/A |
upload_artifacts |
Optional | N/A | N/A | N/A |
artifact_name |
Optional | N/A | N/A | N/A |
artifact_retention_days |
Optional | N/A | N/A | N/A |
server_slug |
N/A | N/A | Required | Required |
server_name |
N/A | N/A | Required | N/A |
server_description |
N/A | N/A | Required | N/A |
server_title |
N/A | N/A | Optional | N/A |
server_website_url |
N/A | N/A | Optional | N/A |
repository_* |
N/A | N/A | Optional | N/A |
server_version |
N/A | N/A | Optional | N/A |
release_date |
N/A | N/A | Optional | N/A |
package_* |
N/A | N/A | Optional | N/A |
Legend:
- Required = must be supplied for that action type.
- Optional = supported and not required.
- N/A = ignored for that action type.
| Value | Behavior | Generates files | Description |
|---|---|---|---|
| generate_registry | Validate + generate | Yes | Validates discovered manifests, then writes registry artifacts. |
| validate_registry | Validate only | No | Validates discovered manifests without writing output files. |
| generate_server_manifest | Generate/update files | Yes | Generates or updates one server manifest set, then validates. |
| validate_server_manifest | Validate one server | No | Validates manifests for a specific server_slug only. |
Notes:
- Use explicit values only; legacy aliases are not supported.
debug: troubleshooting.info: default operational logging.warn: warnings and errors.error: errors only.
generate_registry: validates all discovered manifests before writing registry artifacts.validate_registry: validates all discovered manifests and exits without writing output.generate_server_manifest: generates/updates files and then validates generated manifests before success.generate_server_manifest: updatesversions/latest.jsonto match the generatedserver_versionmanifest.validate_server_manifest: validates existing manifests forserver_slugand fails on schema/version errors.
If validation fails, the action exits non-zero and workflow steps fail.
For trusted ingestion (avoid blind adds), use this workflow pattern:
- Require PR-based changes for
servers/**(no direct pushes to protected branches). - Enforce CODEOWNERS review for
servers/**and registry config files. - Run
action_type: validate_registryin PR checks before merge. - Pin action versions in workflows (for example
@v1or full SHA in stricter environments). - Keep external sources explicit in
configand review config changes like code. - Optionally add policy checks (organization allowlists, signed commits, branch protections).
Trusted PR verification example:
name: Verify Registry Inputs
on:
pull_request:
paths:
- 'servers/**'
- 'config/**'
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate registry manifests
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'validate_registry'
log_level: 'info'
source: './servers'
config: './config/custom-registry-config.json'| Value | Intended host | Profile files generated | Notes |
|---|---|---|---|
github |
GitHub Pages | .nojekyll |
Prevents Jekyll processing on Pages |
cloudflare |
Cloudflare Pages / Workers static hosting | _headers, _redirects |
Applies headers and redirect aliases |
none |
Generic static hosts | (none) | Host-agnostic output with no profile files |
- In GitHub Actions,
output_directorycontrols the base output path (defaultdist). - In GitHub Actions,
outputcontrols the public directory name under that base (defaultpublic). - Effective Action output path is
<output_directory>/<output>. - In local CLI usage,
--outputmeans base output directory (for example./dist) and--public-directorycontrols the public folder name.
- Action input
output_directorycontrols the base path. - Action input
outputcontrols the public directory under that base. - Effective Action output path is
<output_directory>/<output>.
Examples:
output_directory: distandoutput: public→dist/publicoutput_directory: buildandoutput: registry→build/registry
Use two jobs so generation only runs after successful validation.
name: Validate and Generate MCP Registry
on:
push:
branches: [main]
paths:
- 'servers/**'
- 'src/**'
- 'action.yml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate MCP manifests
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'validate_registry'
log_level: 'info'
source: './servers'
generate:
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v4
- name: Generate static registry artifacts
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'generate_registry'
log_level: 'info'
source: './servers'
output: 'public'
deployment_environment: 'github'
- name: Upload registry artifact
uses: actions/upload-artifact@v4
with:
name: mcp-registry-public
path: dist/publicYou can let this action upload the generated registry directory as a GitHub Actions artifact directly:
- name: Generate static registry artifacts
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'generate_registry'
source: './servers'
output: 'public'
upload_artifacts: 'true'
artifact_name: 'mcp-registry-public'
artifact_retention_days: '7'
commit_generated_artifacts: 'true'
artifact_committer_name: 'github-actions[bot]'
artifact_committer_email: '41898282+github-actions[bot]@users.noreply.github.com'commit_generated_artifacts stages, commits, and pushes generated files from the checked-out repository workspace.
name: Generate MCP Server Manifests
on:
workflow_dispatch:
jobs:
server-manifest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate or update server manifests
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'generate_server_manifest'
log_level: 'info'
source: './servers'
server_slug: 'github'
server_name: 'io.github.github/github'
server_description: 'Official GitHub MCP server.'
server_version: '1.0.0'
package_identifier: '@modelcontextprotocol/server-github'
- name: Validate generated server manifests
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'validate_server_manifest'
log_level: 'info'
source: './servers'
server_slug: 'github'
## Local usage
```bash
npm install
npm run validate
npm run generateOptional custom config file:
node src/index.js --config ./config/custom-registry-config.jsonor:
MCP_REGISTRY_CONFIG=./config/custom-registry-config.json npm run generateRun validation-only mode (no output generation):
node src/index.js --action-type validate_registryNo config file is required by default. Built-in defaults are:
version:0.1externalRepositories:[]
servers/
<name>/
server.json
versions/
<semver>.json
Create your own server manifests using this layout in your repository.
Minimum required fields:
namedescription
Recommended fields:
$schematitlewebsiteUrlrepository_meta
Example:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.github/github",
"title": "GitHub",
"description": "Official GitHub MCP server for repositories, pull requests, issues, and related workflows.",
"websiteUrl": "https://github.com/modelcontextprotocol/servers/tree/main/src/github",
"repository": {
"url": "https://github.com/modelcontextprotocol/servers",
"source": "github",
"subfolder": "src/github"
}
}Required fields:
version(must be valid semver and cannot belatest)- At least one of:
packagesremotes
Example:
{
"version": "1.0.0",
"releaseDate": "2024-11-20",
"packages": [
{
"registryType": "npm",
"identifier": "@modelcontextprotocol/server-github",
"version": "1.0.0",
"transport": {
"type": "stdio"
}
}
]
}If needed, provide a custom config file with:
versionexternalRepositories
Use a config file when you want to:
- Aggregate servers from additional local repositories
- Keep environment-specific source roots outside default
servers/ - Override registry version metadata for controlled publishing flows
Recommendation:
- Use
configto setversionand external repositories in one reusable checked-in file.
externalRepositories must be an array of local directory references. Each entry can be:
- A string path
- An object with
path - An object with
serversPath
Each resolved path must point to a servers-style directory containing:
<server-name>/server.json<server-name>/versions/<semver>.json
Example:
{
"version": "0.1",
"externalRepositories": [
"../another-repo/servers",
{ "path": "../team-repo/servers" },
{ "serversPath": "../shared/servers" }
]
}Notes:
- Paths are resolved from the workspace root.
- Invalid or missing paths are skipped with a warning.
- Duplicate server names are ignored after first load.
jobs:
registry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate registry with external repositories
uses: blackoutsecure/bos-mcp-registry-engine@v1
with:
action_type: 'generate_registry'
log_level: 'info'
source: './servers'
output: 'public'
deployment_environment: 'github'
config: './config/custom-registry-config.json'Core generated files (shown for Action defaults where output: public):
dist/public/index.htmldist/public/v0.1/index.htmldist/public/v0.1/servers.jsondist/public/v0.1/servers/index.jsondist/public/v0.1/servers/<url-encoded-serverName>/versions/<version>.jsondist/public/v0.1/servers/<url-encoded-serverName>/versions/latest.json
Deployment-specific:
github:dist/public/.nojekyllcloudflare:dist/public/_headers,dist/public/_redirectsnone: no platform-specific profile files are generated (output remains portable static files with root/versionindex.htmlredirects)
deployment_environment |
Recommended host | Generated profile files | Notes |
|---|---|---|---|
github |
GitHub Pages | .nojekyll |
Keeps Pages from running Jekyll processing. |
cloudflare |
Cloudflare Pages / Workers static files | _headers, _redirects |
Applies security/cache headers and redirect aliases. |
none |
Local preview, Apache, Nginx, generic static host | (none) | Host-agnostic static output only; root and version index.html files still provide navigation/redirect behavior. |
This repository is for static registry generation and Marketplace Action packaging only.
- No runtime MCP server
- No backend hosting logic
- No workflow orchestration files in this repo
- No direct publishing to third-party MCP marketplaces from this action
npm run checkThis runs lint, format check, validation, tests, build, and production audit gate.
Apache-2.0. See LICENSE.
- Issues: blackoutsecure/bos-mcp-registry-engine/issues
- Security: SECURITY.md