Complete guide to using the PatternFly MCP Server for development including CLI and programmatic API usage.
Development:
- CLI usage
- Programmatic usage
- Experimental settings
- MCP tool plugins
- Initial troubleshooting
- Project development maintenance
- In-progress and future work
| Flag | Description | Default |
|---|---|---|
--http |
Enable HTTP transport mode | false (stdio mode) |
--port <num> |
Port for HTTP transport | 8080 |
--host <string> |
Host to bind to | 127.0.0.1 |
--allowed-origins <origins> |
Comma-separated list of allowed CORS origins | none |
--allowed-hosts <hosts> |
Comma-separated list of allowed host headers | none |
--tool <path> |
Path to external Tool Plugin (repeatable) | none |
--plugin-isolation <none | strict> |
Isolation preset for external tools-as-plugins | strict |
--log-stderr |
Enable terminal logging | false |
--log-protocol |
Forward logs to MCP clients | false |
--log-level <level> |
Set log level (debug, info, warn, error) |
info |
--mode <mode> |
Operational mode (cli, programmatic, test) |
cli |
--mode-test-url <url> |
Base URL for fixture/mock servers in test mode |
none |
--verbose |
Shortcut for --log-level debug |
false |
- HTTP transport mode - By default, the server uses
stdio. Use the--httpflag to enable HTTP transport. Sub-flags like--port,--host, etc. only apply when--httpis set. - Logging - The server uses a
diagnostics_channel-based logger that keeps stdout pure by default. - Programmatic API - The server can also be used programmatically with options. See Programmatic usage for more details.
- Tool plugins - The server can load external tool plugins at startup. See MCP tool plugins for more details.
- Test Mode - When
--mode testis used, the server redirects resource requests to the URL provided by--mode-test-url, enabling E2E testing without local filesystem access. A missing--mode-test-urlwill result in a logger warning and a non-fatal error on resource requests. - Experimental options - Opt-in flags use
--experimental-<name>on the CLI andexperimental<Name>programmatically. See Experimental settings for the current list, examples, and lifecycle notes.
stdio mode (default):
npx -y @patternfly/patternfly-mcp@lateststdio mode with terminal logging:
npx -y @patternfly/patternfly-mcp@latest --log-stderrHTTP mode:
npx -y @patternfly/patternfly-mcp@latest --http --port 8080HTTP mode with custom security:
npx -y @patternfly/patternfly-mcp@latest --http --port 3000 --allowed-origins "https://app.com"Loading external tool plugins:
npx -y @patternfly/patternfly-mcp@latest --tool ./first-tool.js --tool ./second-tool.tsTesting with a fixture server:
npx -y @patternfly/patternfly-mcp@latest --mode test --mode-test-url "http://localhost:3000"The @modelcontextprotocol/inspector is the recommended way to visualize the server's interface.
- Build the PatternFly MCP:
npm install npm run build
- Start the Inspector:
npx -y @modelcontextprotocol/inspector node dist/cli.js
- Interact: The inspector opens a web interface (typically at
http://localhost:5173) where you can list tools, resources, and prompts, then execute and view their responses.
If you use @modelcontextprotocol/inspector-cli with an MCP client config file, set --server to the server key in that file. For example, use patternfly-mcp when it matches mcp-config-example.json.
npx -y @modelcontextprotocol/inspector-cli \
--config ./mcp-config-example.json \
--server patternfly-mcp \
--cli \
--method tools/call \
--tool-name usePatternFlyDocs \
--tool-arg name="Button"The start() function accepts an optional PfMcpOptions object for programmatic configuration. Use these options to customize behavior, transport, and logging for embedded instances.
| Option | Type | Description | Default |
|---|---|---|---|
toolModules |
ToolModule | ToolModule[] |
Array of tool modules or paths to external tool plugins to be loaded. | [] |
isHttp |
boolean |
Enable HTTP transport mode. | false |
http.port |
number |
Port for HTTP transport. | 8080 |
http.host |
string |
Host to bind to. | 127.0.0.1 |
http.allowedOrigins |
string[] |
List of allowed CORS origins. | [] |
http.allowedHosts |
string[] |
List of allowed host headers. | [] |
pluginIsolation |
'none' | 'strict' |
Isolation preset for external tools-as-plugins. | 'strict' |
logging.level |
'debug' | 'info' | 'warn' | 'error' |
Set the logging level. | 'info' |
logging.stderr |
boolean |
Enable terminal logging to stderr. | false |
logging.protocol |
boolean |
Forward logs to MCP clients. | false |
mode |
'cli' | 'programmatic' | 'test' |
Specifies the operation mode. | 'programmatic' |
modeOptions.test.baseUrl |
string |
Base URL for fixture/mock servers in test mode. |
undefined |
docsPaths |
string[] |
Whitelist of local documentation directories resolved by documentation: slug. When empty (default), the slug is dormant. |
[] |
- Test Mode - When
mode = 'test'is used, the server redirects resource requests to the URL provided bymodeOptions.test.baseUrl, enabling E2E testing without local filesystem access. A missingmodeOptions.test.baseUrlwill result in a logger warning and a non-fatal error on resource requests. - Experimental options - Opt-in flags use
experimental<Name>programmatically and--experimental-<name>on the CLI. See Experimental settings for the current list and configuration examples.
import { start, type PfMcpInstance, type PfMcpOptions } from '@patternfly/patternfly-mcp';
const options: PfMcpOptions = {
isHttp: true,
http: {
port: 3000,
allowedOrigins: ['https://your-app.com']
},
logging: {
level: 'debug',
stderr: true
}
};
const server: PfMcpInstance = await start(options);Tools-as-plugins
- Internally (maintained and built into the server), the MCP tool schemas require Zod. Failure to use Zod, or raw Zod shapes, will result in the MCP tool being logged and skipped during registration.
- Externally (CLI and embedding), MCP tools-as-plugins can be
JSON, Zod, or raw Zod shapes.The server attempts to normalize external tools-as-plugins plain JSON schemas to facilitate consumer flexibility.
Not sure what "tools-as-plugins" and "raw Zod" mean? See terminology for full definitions.
The documentation collection src/docs.json pins remote resources to specific commit SHAs (or explicit refs) for stability and reproducibility. This avoids unexpected upstream changes from breaking results. The searchPatternFlyDocs tool handles these lookups transparently for the user.
- Node.js 22+: Required to run the MCP server, load external tool plugins (
--tool), and use advanced process isolation features.
Example: Programmatic test mode
import { start, type PfMcpInstance } from '@patternfly/patternfly-mcp';
const server: PfMcpInstance = await start({
mode: 'test',
modeOptions: {
test: {
baseUrl: 'http://my-fixture-server:3000'
}
}
});This package exposes a curated public API through package.json exports:
| Entry | Import | Purpose |
|---|---|---|
| Root | @patternfly/patternfly-mcp |
start(), server instance types, programmatic options |
| Tools | @patternfly/patternfly-mcp/tools |
createMcpTool and tool-authoring types for plugins and inline tools |
import { start, type PfMcpInstance } from '@patternfly/patternfly-mcp';
import { createMcpTool, type ToolModule } from '@patternfly/patternfly-mcp/tools';Deep imports are not supported. Accessing internal modules (e.g., @patternfly/patternfly-mcp/dist/server) is restricted by our package configuration. This export strategy allows us to refactor internal code without impacting supported integrations, as long as documented entry points remain stable.
If you require access to a type or utility that is not currently exported from a supported entry, please open an issue to discuss your use case.
Deprecated APIs remain available through minor releases. Removal is targeted for major releases (semver). See CONTRIBUTING.md.
Current consumer deprecations:
| Deprecated | Replacement (Use instead) | Removal |
|---|---|---|
createMcpTool from the root entry |
@patternfly/patternfly-mcp/tools |
Planned 3.0 |
CliOptions type alias |
PfMcpCliOptions |
Planned 3.0 |
The server instance exposes the following methods:
isRunning()- Returns aboolean,trueif the server is running.onLog(callback)- Registers a callback for server logs, returns aPfMcpLogEventobject.stop()- Stops the server.getStats()- Returns aPfMcpStatsobject containing server metrics and diagnostic channel IDs.
Checks if the server is running, returns a boolean, true if the server is running.
import { start, type PfMcpInstance } from '@patternfly/patternfly-mcp';
const server: PfMcpInstance = await start({ /* options */ });
if (server.isRunning()) {
// Server is running
}Registers a callback for server logs. The callback receives a PfMcpLogEvent object.
import { start, type PfMcpInstance, type PfMcpLogEvent } from '@patternfly/patternfly-mcp';
const server: PfMcpInstance = await start({ /* options */ });
server.onLog((event: PfMcpLogEvent) => {
if (event.level !== 'debug') {
console.warn(`[${event.level}] ${event.msg || ''}`);
}
});Stops the server.
import { start, type PfMcpInstance } from '@patternfly/patternfly-mcp';
const server: PfMcpInstance = await start({ /* options */ });
process.on('SIGINT', async () => {
await server.stop();
process.exit(0);
});Returns a PfMcpStats object containing server metrics and diagnostic channel IDs for listening to server activity.
import { channel, unsubscribe, subscribe } from 'node:diagnostics_channel';
import { start, type PfMcpInstance, type PfMcpStats, type PfMcpStatReport } from '@patternfly/patternfly-mcp';
const server: PfMcpInstance = await start({ /* options */ });
const stats: PfMcpStats = server.getStats();
const logChannel = channel(stats.health.channelId);
const logHandler = (event: PfMcpStatReport) => {
/* Handle log events, on MCP server close unsubscribe */
};
const logSubscription = subscribe(logChannel, logHandler);Reference typings are exported from the package. The full listing can be found in src/index.ts.
You can embed the MCP server inside your application using the start() function and provide Tool Modules directly.
import { start, type PfMcpInstance } from '@patternfly/patternfly-mcp';
import { createMcpTool, type ToolModule } from '@patternfly/patternfly-mcp/tools';
const echoTool: ToolModule = createMcpTool({
name: 'echoAMessage',
description: 'Echo back the provided user message.',
inputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
required: ['message']
},
handler: async (args: { message: string }) => ({
content: [{ type: 'text', text: `You said: ${args.message}` }]
})
});
const main = async () => {
const server: PfMcpInstance = await start({
toolModules: [
echoTool
]
});
// Optional: observe refined server logs in-process.
// We recommend getting in the habit of avoiding use of console.log and info since they pollute stdout.
server.onLog((event) => {
if (event.level !== 'debug') {
console.warn(`[${event.level}] ${event.msg || ''}`);
}
});
// Graceful shutdown
process.on('SIGINT', async () => {
await server.stop();
process.exit(0);
});
}
main();See examples/ for more programmatic usage examples.
You can extend the server's capabilities by loading Tool Plugins at startup. These plugins run out-of-process in an isolated Tools Host to ensure security and stability.
While we recommend using
createMcpToolfor automatic normalization, external plugins are purposefully flexible. They can use plain JSON schemas forinputSchema, and the server will handle the conversion to Zod automatically during the loading process.
- Node.js >= 22: Loading external tool plugins (
--tool) requires Node.js version 22 or higher due to the use of advanced process isolation and ESM module loading features. - ESM: Plugins MUST be authored as ECMAScript Modules.
- Dependency Resolution: Plugins importing from
@patternfly/patternfly-mcp/toolsrequire the package to be resolvable in the execution environment. This may require a localnpm installin the plugin's directory or project root if the package is not available globally.
The server provides two isolation modes for external plugins via the --plugin-isolation flag:
strict(Default): The plugin runs in a restricted environment with limited access to the system. This is the recommended mode for most tools.none: The plugin has full access to the system environment, including the filesystem and network, inherited from the host process. Use this mode ONLY if your tool requires specific system access (e.g., executing Git commands or accessing local files outside the sandbox) and you trust the plugin code.
Warning: Disabling isolation (
--plugin-isolation none) increases the security risk. Always document the reason for requiring this mode in your tool's documentation.
We recommend using the createMcpTool helper to define tools. It ensures your tools are properly normalized for the server.
import { createMcpTool } from '@patternfly/patternfly-mcp/tools';
export default createMcpTool({
name: 'hello',
description: 'Say hello',
inputSchema: {
type: 'object',
properties: { name: { type: 'string' } },
required: ['name']
},
async handler({ name }) {
return {
content: [{ type: 'text', text: `Hello, ${name}!` }]
};
}
});import { createMcpTool } from '@patternfly/patternfly-mcp/tools';
export default createMcpTool([
{ name: 'hi', description: 'Greets', inputSchema: {}, handler: () => ({ content: [{ type: 'text', text: 'hi' }] }) },
{ name: 'bye', description: 'Farewell', inputSchema: {}, handler: () => ({ content: [{ type: 'text', text: 'bye' }] }) }
]);The inputSchema property accepts either plain JSON Schema objects or Zod schemas. Both formats are automatically converted to the format required by the MCP SDK.
JSON Schema (recommended):
const inputSchema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' }
},
required: ['name']
};Zod Schema:
import { z } from 'zod';
const inputSchema = z.object({
name: z.string(),
age: z.number().optional()
});See examples/toolPluginHelloWorld.js for a basic example.
These terms describe how tools and their related properties are represented in code and configuration.
Tool: The low-level tuple format[name, schema, handler].Tool Config: The authoring object format{ name, description, inputSchema, handler }.Tool Factory: A function wrapper(options) => Tool(internal).Tool Module: The programmatic result ofcreateMcpTool, representing a collection of tools.JSON Schema(plain object): A plain object intended as JSON Schema (for exampletype,properties,required). Converted toward Zod where possible viajsonSchemaToZod/fromJSONSchema.Zod schema: A Zod schema instance. Loosely detected withisZodSchema(Zod 4_zod/ public.def, Zod 3_def).Raw Zod shape(ZodRawShapeCompat): A non-empty plain object whose values are Zod schemas; keys are field names. An empty{}is not a raw Zod shape. Detected withisZodRawShape.
Internal and custom collections implement a McpCollection tuple structure:
type McpCollection = [
name: string,
config: { title?: string },
handler: (arg?: unknown) => McpCollectionResult | Promise<McpCollectionResult>,
_config?: {
initial?: McpCollectionResult | (() => McpCollectionResult | Promise<McpCollectionResult>);
runParallel?: `#${string}`;
runSchedule?: { intervalMs?: number; cancelMs?: number; delayStartMs?: number; continueOnError?: boolean; repeat?: number; };
retainLastViable?: boolean | ((context) => boolean | Promise<boolean>);
isRequired?: boolean;
}
];-
name(string): Unique identifier for the collection (e.g.,'patternfly-docs'). -
config(object): Plugin-visible metadata, such astitle. -
handler(function): Sync, or async, function returning anMcpCollectionResultobject containing{ records: [...] }. -
_config.initial: Synchronous or async initial data loader executed at server startup ($t=0$ ) before scheduled tasks or worker threads run. -
_config.runParallel: Subpath import specifier (#specifier) used to execute the collection handler in a background worker pool thread (server.workerPool). -
_config.runSchedule: Configuration for recurring background refresh intervals viadeferTask. -
_config.retainLastViable: Retains previously loaded valid records if an update attempt fails or returns an empty payload. -
_config.isRequired: Controls whether server startup requires this collection to be populated.
- Plugins don't appear: Verify the Node version (requires Node.js >= 22 for tool plugins) and check logs (enable
--log-stderr). - Startup warnings/errors: Startup
load:ackwarnings/errors from tool plugins are logged when stderr/protocol logging is enabled. - Schema errors: If
tools/callrejects with schema errors, ensureinputSchemais valid. See Authoring tools for details. - Network access issues: If the tool is having network access issues, you may need to configure
--plugin-isolation none. This is generally discouraged for security reasons but may be necessary in some cases.
- Connection issues: Ensure the port is not already in use and the host is correct.
- CORS errors: Configure
--allowed-originsif accessing from a web client. - DNS rebinding protection: If behind a proxy, ensure correct
Hostheader and configure--allowed-hosts.
- Server won't start: Check Node.js version (requires Node.js >= 22 to run the server).
- Missing tools/resources: Verify the server started successfully and check logs with
--log-stderr. - Type errors: Ensure TypeScript types are installed:
npm install --save-dev @types/node
For information on general build maintenance, refer to Maintenance in CONTRIBUTING.md.
Start on a fork of the repository, then:
- Rebase and align a Git branch to the current default branch state, currently the
mainbranch. - NPM install then bring local packages up to date.
- Run
npm run release. This brings thepackage.jsonrelated lockfile and CHANGELOG.md up to date and will automatically Git commit them.- If modifications to the CHANGELOG.md need to be made (e.g., breaking changes, etc.), make them. Your commits can be pre-squashed or squashed on merge through your pull request.
- Open a pull request from your fork to the default branch.
- The body of the pull request in GitHub should be the CHANGELOG.md modification being added for the release. This helps reviewers.
- A reviewer will review the CHANGELOG.md addition for consistent Git hashes that align to the default branch.
- If Git commits in the pull request CHANGELOG.md are determined to not be within the default branch, you will be asked to reapply the release process or a maintainer may add a modification to your pull request.
- After maintainer approval, the Git commit is squashed and merged to maintain the pull request number for tracking.
- A git release is then created mirroring previous git releases.
- Use tags that are prefixed with
v, (e.g.v1.0.0,v1.2.1, etc.) - Do not "auto-generate" the release notes, prefer linking to the CHANGELOG.md, this prevents note drift.
- Use tags that are prefixed with
- After a release is created and tagged,
CIwill run and publish the related NPM package. - Perform the Post-release review.
After each npm release, run a maintainer pass in addition to CI (integration, scheduled jobs in audit.yml / container.yml, publish workflow). CI is the automated gate; this is a smoke test to confirm everything is in working order.
When: Each GitHub Release. Ad hoc when major features are introduced, collections, allowlists, or experimental flags change materially.
- Version on npm matches tag and CHANGELOG.md.
- Collections/sources: any change to
docs.json, API seed/crawl, schema pin, or ai-handbook wiring? - Built-in tools are still read-only; experimental surface matches experimental.md.
- Confirm allowlist / HTTP docs are still accurate (
src/options.defaults.ts, usage.md). -
docs/usage.mdand architecture.md still match shipped behavior. - Optional smoke:
npx -y @patternfly/patternfly-mcp@<version> --log-stderror MCP Inspector.
Reuse the same themes with questions that fit your release (wording can change every time):
| Theme | Example questions |
|---|---|
| Features/Bugs | Did we add any major features or resolve any bugs? Are solutions working as-intended? |
| Sources | Did we add URLs or collections? Still RH-Public only? |
| Security | Allowlist drift? Plugin isolation default still strict? |
| CI | Any red scheduled runs since last release? |
| Docs | Anything user-visible we forgot to document? |
Important: Users or teams can retain a private copy of audit results. This application codebase does not require a filled form per release.
Negative audit findings should have a GitHub Issue opened. Link the release version and findings so an informed evaluation can take place.
Not every observation is a bug: link checks, upstream blips, and environment-specific behavior can be false positives. Use an issue for triage when unsure (“investigate whether X is real”) rather than silent fixes or a separate audit log.
The server maintains multiple record collections that provide documentation and schemas to a consuming LLM. Each collection source follows its own maintenance lifecycle.
When PatternFly releases new documentation or component features, reseed the embedded local collection data:
npm run build:collections: Runs reseeding for all collections and collection tests.npm run build:collections-api: Updatessrc/collection.patternFlyApi.jsonand outputs CSV diffs toreports/.npm run build:collections-docs: Updatessrc/docs.jsonwith latest repository hashes.
A large percentage of
docs.jsonrecords are being moved into the PatternFly API. In the near future,docs.jsonwill be renamed and incorporated into a support collection for one-off records.
The original curated Markdown collection. It pins remote repository URLs to specific Git commit SHAs to guarantee consistent documentation and remove upstream breaking changes.
- Update workflow: Follow the add-docs-links skill for manual additions/edits, or run the automated reseeding script:
# Reseed the Docs collection npm run build:collections-docs # Run collection test suites only npm run test:collections # Run collection test suites in watch mode npm run test:collections-dev
- Automated synchronization: The Docs reseeding pipeline (
tooling/collections/update.patternFlyDocs.ts) automatically resolves the latest commit SHAs across referenced GitHub repositories, recalculatesmeta.totalEntriesandmeta.totalDocs, and generates an audit diff report atreports/YYYYMMDD-collection.patternFlyDocs.report.csv. - Validation: Ensure all raw URLs are HTTPS, match the domain whitelist in
src/options.defaults.ts, and return 2xx responses. - Testing: Run
npm run test:collectionsornpm test, updatingbaseHashesand the Repository Breakdown table insrc/__tests__/docs.json.test.tswhen refs change.
The server packages pre-seeded API endpoints to enable instant server startup without network overhead.
- Update commands:
# Reseed the API collection npm run build:collections-api # Run collection test suites only npm run test:collections # Run collection test suites in watch mode npm run test:collections-dev
- Execution: Crawls live PatternFly API endpoints via
apiSpider, filters low-quality records, compresses content intosrc/collection.patternFlyApi.json, and outputs structured console diffs and timestamped CSV audit reports toreports/YYYYMMDD-collection.patternFlyApi.report.csv. - Configuration & Environment Overrides:
UPDATE_COLLECTIONS=true: Required environment flag to execute collection builds directly.
- When to run: When PatternFly publishes new releases, when updating metadata/quality filters, or as part of a general maintenance cycle.
A large percentage of Component schemas have been moved into the PatternFly API and are also being considered for incorporation into PatternFly React architecture and may be completely superseded in the future.
Component JSON schemas provide runtime prop definitions, default values, and type validations.
- Update workflow: Synchronized via standard npm package dependency updates (
package.json). - Validation: Verified through
src/collection.patternFlySchemas.tsand automated unit tests. - When to run: When PatternFly Component Schemas repo publishes a new release.
The AI Handbook is a support collection since its content goes beyond PatternFly towards AI-specific patterns at an organizational and enterprise level.
Collection of specialized guides and AI patterns that are fetched dynamically at runtime.
- Update workflow: Synchronized on runtime from the Red Hat AI Handbook repo.
- Validation: Verified through automated unit tests.
For more information on our development roadmap, including "in-progress" and "future" work, please refer to the Architecture & Roadmap documentation.