Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 51 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,37 +49,47 @@ npx @patternfly/patternfly-mcp

## Usage

The MCP server can communicate over **stdio** (default) or **HTTP** transport. It provides access to PatternFly documentation through built-in tools.
The MCP server tools are focused on being a resource library for PatternFly. Server tools are extensible by design and intended to be used in conjunction with the available MCP resources.

### Built-in Tools

All tools accept an argument named `urlList` (array of strings) or `componentName` (string).
#### Tool: searchPatternFlyDocs
Use this to search for PatternFly documentation URLs and component names. Accepts partial string matches or `*` to list all available components. From the content, you can select specific URLs and component names to use with `usePatternFlyDocs`

- **Parameters**: `searchQuery`: `string` (required)

#### Tool: usePatternFlyDocs
Use this to fetch high-level index content (for example, a local `README.md` that contains relevant links, or `llms.txt` files in docs-host mode). From that content, you can select specific URLs to pass to `fetchDocs`.
Fetch full documentation and component JSON schemas for specific PatternFly URLs or component names.

- **Parameters**: `urlList`: `string[]` (required)
> **Feature**: This tool automatically detects if a URL belongs to a component (or if a "name" is provided) and appends its machine-readable JSON schema (props, types, validation) to the response, providing a fused context of human-readable docs and technical specs.

#### Tool: fetchDocs
Use this to fetch one or more specific documentation pages (e.g., concrete design guidelines or accessibility pages) after you’ve identified them via `usePatternFlyDocs`.
- **Parameters**: _Parameters are mutually exclusive. Provide either `name` OR `urlList` not both._
- `name`: `string` (optional) - The name of the PatternFly component (e.g., "Button", "Modal"). **Recommended** for known component lookups.
- `urlList`: `string[]` (optional) - A list of specific documentation URLs discovered via `searchPatternFlyDocs`.

- **Parameters**: `urlList`: `string[]` (required)
#### Removed: ~~Tool: fetchDocs~~
> "fetchDocs" has been integrated into "usePatternFlyDocs."

#### Tool: componentSchemas
Use this to fetch the JSON Schema for a specific PatternFly component.
~~Use this to fetch one or more specific documentation pages (e.g., concrete design guidelines or accessibility pages) after you’ve identified them via `usePatternFlyDocs`.~~

- **Parameters**: `componentName`: `string` (required)
- ~~**Parameters**: `urlList`: `string[]` (required)~~

### Docs-host mode (local llms.txt mode)
#### Deprecated: ~~Tool: componentSchemas~~
> "componentSchemas" has been integrated into "usePatternFlyDocs."

If you run the server with `--docs-host`, local paths you pass in `urlList` are resolved relative to the `llms-files` folder at the repository root. This is useful when you have pre-curated `llms.txt` files locally.
~~Use this to fetch the JSON Schema for a specific PatternFly component.~~

Example:
```bash
npx @patternfly/patternfly-mcp --docs-host
```
- ~~**Parameters**: `componentName`: `string` (required)~~

### Built-in Resources

The server exposes a resource-centric architecture via the `patternfly://` URI scheme:

Then, passing a local path such as `react-core/6.0.0/llms.txt` in `urlList` will load from `llms-files/react-core/6.0.0/llms.txt`.
- **`patternfly://context`**: General PatternFly development context and high-level rules.
- **`patternfly://docs/index`**: Index of all available documentation pages.
- **`patternfly://docs/{name}`**: Documentation for a specific component (e.g., `patternfly://docs/Button`).
- **`patternfly://schemas/index`**: Index of all available component schemas.
- **`patternfly://schemas/{name}`**: JSON Schema for a specific component (e.g., `patternfly://schemas/Button`).

### MCP Client Configuration

Expand Down Expand Up @@ -111,19 +121,6 @@ Most MCP clients use a JSON configuration to specify how to start this server. B
}
```

#### Docs-host mode
```json
{
"mcpServers": {
"patternfly-docs": {
"command": "npx",
"args": ["-y", "@patternfly/patternfly-mcp@latest", "--docs-host"],
"description": "PatternFly docs (docs-host mode)"
}
}
}
```

#### Custom local tool

```json
Expand Down Expand Up @@ -173,6 +170,30 @@ Example:
npx @patternfly/patternfly-mcp --log-stderr --log-level debug
```

### Disabled: ~~Docs-host mode (local llms.txt mode)~~

> Docs-host mode will be removed or replaced in a future release.
>
> Docs-host mode was intended to be a more efficient way for accessing text file versions of PatternFly documentation and link
> resources. That effort was intended to help load times and token counts while attempting to account for future API work.
> Docs-host mode documentation and links have experienced drift with recent updates to PatternFly resources. That drift combined
> with the introduction of MCP server resources concludes in disabling Docs-host mode while we evaluate its removal or replacement.
>
> If you have been using Docs-host mode, there's a probability you've been leveraging model inference instead of PatternFly
> documentation. You can continue passing the `--docs-host` flag, it will not break the CLI, but it will no-longer affect how the
> PatternFly MCP server loads documentation and link resources.

~~If you run the server with `--docs-host`, local paths you pass in `urlList` are resolved relative to the `llms-files` folder at the repository root. This is useful when you have pre-curated `llms.txt` files locally.~~

- `--docs-host`: Running this flag produces no results. ~~Local paths you pass in `urlList` are resolved relative to the `llms-files` folder.~~

Example:
```bash
npx @patternfly/patternfly-mcp --docs-host
```

~~Then, passing a local path such as `react-core/6.0.0/llms.txt` in `urlList` will load from `llms-files/react-core/6.0.0/llms.txt`.~~

### MCP Tool Plugins

You can extend the server's capabilities by loading **Tool Plugins** at startup. These plugins run out‑of‑process in an isolated **Tools Host** (Node.js >= 22) to ensure security and stability.
Expand Down
9 changes: 6 additions & 3 deletions src/__tests__/__snapshots__/options.defaults.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ exports[`options defaults should return specific properties: defaults 1`] = `
"stderr": false,
"transport": "stdio",
},
"maxDocsToLoad": 500,
"name": "@patternfly/patternfly-mcp",
"nodeVersion": 22,
"pfExternal": "https://raw.githubusercontent.com/patternfly/patternfly-org/fb05713aba75998b5ecf5299ee3c1a259119bd74/packages/documentation-site/patternfly-docs/content",
Expand All @@ -38,6 +39,7 @@ exports[`options defaults should return specific properties: defaults 1`] = `
"loadTimeoutMs": 5000,
},
"pluginIsolation": "strict",
"recommendedMaxDocsToLoad": 15,
"repoName": "patternfly-mcp",
"resourceMemoOptions": {
"default": {
Expand All @@ -54,6 +56,7 @@ exports[`options defaults should return specific properties: defaults 1`] = `
"expire": 120000,
},
},
"resourceModules": [],
"separator": "

---
Expand All @@ -66,10 +69,10 @@ exports[`options defaults should return specific properties: defaults 1`] = `
},
},
"toolMemoOptions": {
"fetchDocs": {
"searchPatternFlyDocs": {
"cacheErrors": false,
"cacheLimit": 15,
"expire": 60000,
"cacheLimit": 10,
"expire": 600000,
},
"usePatternFlyDocs": {
"cacheErrors": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`patternFlyContextResource should have a consistent return structure: structure 1`] = `
{
"config": true,
"handler": [Function],
"name": "patternfly-context",
"uri": "patternfly://context",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`patternFlyDocsIndexResource should have a consistent return structure: structure 1`] = `
{
"config": true,
"handler": [Function],
"name": "patternfly-docs-index",
"uri": "patternfly://docs/index",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`patternFlyDocsTemplateResource should have a consistent return structure: structure 1`] = `
{
"config": true,
"handler": [Function],
"name": "patternfly-docs-template",
"uri": ResourceTemplate {
"_callbacks": {
"list": undefined,
},
"_uriTemplate": UriTemplate {
"parts": [
"patternfly://docs/",
{
"exploded": false,
"name": "name",
"names": [
"name",
],
"operator": "",
},
],
"template": "patternfly://docs/{name}",
},
},
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`patternFlySchemasIndexResource should have a consistent return structure: structure 1`] = `
{
"config": true,
"handler": [Function],
"name": "patternfly-schemas-index",
"uri": "patternfly://schemas/index",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`patternFlySchemasTemplateResource should have a consistent return structure: structure 1`] = `
{
"config": true,
"handler": [Function],
"name": "patternfly-schemas-template",
"uri": ResourceTemplate {
"_callbacks": {
"list": undefined,
},
"_uriTemplate": UriTemplate {
"parts": [
"patternfly://schemas/",
{
"exploded": false,
"name": "name",
"names": [
"name",
],
"operator": "",
},
],
"template": "patternfly://schemas/{name}",
},
},
}
`;
117 changes: 83 additions & 34 deletions src/__tests__/__snapshots__/server.getResources.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,51 +1,100 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`processDocsFunction should handle errors gracefully: errors 1`] = `
"# Documentation from good-file.md

success content

---

❌ Failed to load bad-file.md: Error: File not found"
[
{
"content": "success content",
"isSuccess": true,
"path": "good-file.md",
"resolvedPath": "/good-file.md",
},
{
"content": "❌ Failed to load bad-file.md: File not found",
"isSuccess": false,
"path": "bad-file.md",
"resolvedPath": undefined,
},
]
`;

exports[`processDocsFunction should process local and remote inputs, duplicate files and URLS 1`] = `
"# Documentation from file.md

local file content

---

# Documentation from https://example.com/remote.md

fetched content"
[
{
"content": "local file content",
"isSuccess": true,
"path": "file.md",
"resolvedPath": "/file.md",
},
{
"content": "fetched content",
"isSuccess": true,
"path": "https://example.com/remote.md",
"resolvedPath": "https://example.com/remote.md",
},
]
`;

exports[`processDocsFunction should process local and remote inputs, files and URLS 1`] = `
"# Documentation from local-file.md

local file content

---

# Documentation from https://example.com/remote.md

fetched content"
[
{
"content": "local file content",
"isSuccess": true,
"path": "local-file.md",
"resolvedPath": "/local-file.md",
},
{
"content": "fetched content",
"isSuccess": true,
"path": "https://example.com/remote.md",
"resolvedPath": "https://example.com/remote.md",
},
]
`;

exports[`processDocsFunction should process local and remote inputs, filter empty strings 1`] = `
"# Documentation from file.md

local file content
[
{
"content": "local file content",
"isSuccess": true,
"path": "file.md",
"resolvedPath": "/file.md",
},
{
"content": "local file content",
"isSuccess": true,
"path": "file2.md",
"resolvedPath": "/file2.md",
},
]
`;

---
exports[`promiseQueue should execute promises in order: allSettled 1`] = `
[
{
"status": "fulfilled",
"value": {
"content": "/dolor-sit.md",
"resolvedPath": "/dolor-sit.md",
},
},
{
"reason": "https://example.com/remote.md",
"status": "rejected",
},
{
"status": "fulfilled",
"value": {
"content": "/lorem-ipsum.md",
"resolvedPath": "/lorem-ipsum.md",
},
},
]
`;

# Documentation from file2.md
exports[`resolveLocalPathFunction should return a consistent path, basic 1`] = `"/lorem-ipsum.md"`;

local file content"
`;
exports[`resolveLocalPathFunction should return a consistent path, url, file 1`] = `"file://someDirectory/dolor-sit.md"`;

exports[`resolveLocalPathFunction should return a consistent path, with docsHost false 1`] = `"documentation/README.md"`;
exports[`resolveLocalPathFunction should return a consistent path, url, http 1`] = `"http://example.com/dolor-sit.md"`;

exports[`resolveLocalPathFunction should return a consistent path, with docsHost true 1`] = `"/llms-files/react-core/6.0.0/llms.txt"`;
exports[`resolveLocalPathFunction should return a consistent path, url, https 1`] = `"https://example.com/dolor-sit.md"`;
Loading
Loading