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
2 changes: 1 addition & 1 deletion .mcp.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"mcpServers": {
"claude-plugins": {
"provectus-claude-plugins-finder": {
"command": "node",
"args": ["dist/index.js"]
}
Expand Down
148 changes: 86 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Claude Plugins

A shared repository of plugins for Claude Code. Each plugin packages reusable expertise — agents, skills, prompts, and MCP server configs — into a standard format that can be discovered and consumed through the built-in MCP server.
A shared repository of plugins for Claude Code. Each plugin packages reusable expertise — agents, skills, prompts, and MCP server configs — into a standard format that can be discovered and consumed through the built-in MCP server. Available as an [npm package](https://www.npmjs.com/package/@provectusinc/claude-plugins) for easy integration via `npx`.

## Philosophy

Expand All @@ -21,6 +21,53 @@ A few principles guide the design:
| `kotlin-expert` | Agent | Kotlin 2.0+, coroutines, Spring Boot, domain modeling |
| `react-expert` | Agent | React 19+, concurrent rendering, Tailwind, accessibility |

## Installation & Usage

### Add to Claude Code

Add it to your project's `.mcp.json` (project-level) or `~/.claude/claude_mcp_settings.json` (global):

```json
{
"mcpServers": {
"provectus-claude-plugins-finder": {
"command": "npx",
"args": ["-y", "@provectusinc/claude-plugins@latest"]
}
}
}
```

### Using the plugins

Once connected, three tools become available in your Claude Code sessions:

| Tool | What it does | Example prompt |
|------------------|-------------------------------------------|-----------------------------------------------|
| `list_plugins` | Browse all plugins, filter by type or tag | *"List all available plugins"* |
| `get_plugin` | Retrieve a plugin's full content | *"Get the python-expert agent prompt"* |
| `search_plugins` | Search plugins by keyword | *"Search for plugins related to code review"* |

You can ask Claude naturally and it will call the right tool:

- *"What plugins are available for Python?"*
- *"Show me the react-expert agent"*
- *"Find plugins tagged with 'git'"*

Claude will use the retrieved plugin content (agent prompts, skills, etc.) to enhance its responses with specialized expertise.

### Add to other MCP clients

Any MCP-compatible client can connect to the server via stdio. The server package is `@provectusinc/claude-plugins` (binary name: `claude-plugins`):

```bash
npx -y @provectusinc/claude-plugins
```

Configure your client to spawn this command and communicate over stdin/stdout using the [MCP protocol](https://modelcontextprotocol.io).

---

## Current Repo

This repository is both a collection of plugins and an MCP server. The server exposes tools that allow any MCP-compatible client — including other Claude Code sessions — to discover, search, and retrieve plugins programmatically.
Expand Down Expand Up @@ -63,95 +110,72 @@ Other commands:
```bash
pnpm run build # Compile TypeScript (only needed if modifying src/)
pnpm run start # Run the compiled MCP server (stdio)
pnpm run serve # Start HTTP server on port 3000
pnpm run test # Run the test suite
```

If you are only adding or editing plugins (not modifying the MCP server source in `src/`), you do not need to run `pnpm run build`.

### Claude Code Commands
### Testing Locally

These slash commands are available when working in this repo with Claude Code:
#### Run the test suite

| Command | Purpose |
|------------------|--------------------------------------------------------------------------|
| `/update-readme` | Regenerate the Current Plugins table in the README from plugin manifests |

### MCP Server

Any agentic tooling that supports the [Model Context Protocol](https://modelcontextprotocol.io) can connect to this server and programmatically list, search, and retrieve plugins — including their full markdown content.
```bash
pnpm run test
```

#### Available Tools
This runs integration tests that verify tool registration, plugin filtering, search, and error handling using an in-memory MCP transport.

| Tool | Description | Parameters |
|------------------|--------------------------------------------------------------|------------------------------------------------------------|
| `list_plugins` | List all plugins with optional filters | `type?` (`skill`, `agent`, `prompt`), `tag?` (string) |
| `get_plugin` | Get a plugin's full details or a single component's markdown | `name` (string), `component?` (`skill`, `agent`, `prompt`) |
| `search_plugins` | Full-text search across name, description, and tags | `query` (string), `type?` (`skill`, `agent`, `prompt`) |
#### Test the server manually

#### Connect from Claude Code Locally
You can test the stdio server by piping JSON-RPC messages directly:

Add the server to your project's `.mcp.json` (or `~/.claude/claude_mcp_settings.json` for global access):
```bash
# Build first (or use tsx for dev mode)
pnpm run build

```json
{
"mcpServers": {
"claude-plugins": {
"command": "node",
"args": ["/path/to/claude-plugins/dist/index.js"]
}
}
}
# Send an initialize + list_plugins request
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_plugins","arguments":{}}}' | node dist/index.js
```

Then in any Claude Code session the three tools above become available automatically.

#### Connect from other MCP clients
#### Test with Claude Code

The server supports both **stdio** and **HTTP** transports.
The local server is already configured in `.mcp.json`. Start a Claude Code session and the `list_plugins`, `get_plugin`, and `search_plugins` tools will be available. Try asking Claude to "list all available plugins" to verify the connection.

**stdio** (default) — for local MCP clients:
#### Test the npm package before publishing

```bash
node /path/to/claude-plugins/dist/index.js
```

Or in dev mode (no build step required):
# Simulate an npm install locally
pnpm pack

```bash
npx tsx /path/to/claude-plugins/src/index.ts
# Test the packed tarball works as a CLI
npx ./provectusinc-claude-plugins-0.0.0-develop.tgz
```

**HTTP** — for remote access (defaults to port 3000):

```bash
pnpm run serve # port 3000 (all platforms)
### Claude Code Commands

# Custom port:
# macOS/Linux (bash, zsh, etc.):
PORT=8080 pnpm run serve
These slash commands are available when working in this repo with Claude Code:

# Windows PowerShell:
$env:PORT=8080; pnpm run serve
| Command | Purpose |
|------------------|--------------------------------------------------------------------------|
| `/update-readme` | Regenerate the Current Plugins table in the README from plugin manifests |

# Windows cmd.exe:
set PORT=8080&& pnpm run serve
```
### MCP Server

This starts an HTTP server with the MCP Streamable HTTP transport at `POST /mcp`. Clients can connect using any MCP-compatible HTTP client:
Any agentic tooling that supports the [Model Context Protocol](https://modelcontextprotocol.io) can connect to this server and programmatically list, search, and retrieve plugins — including their full markdown content.

```bash
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'
```
#### Available Tools

#### Example workflow
| Tool | Description | Parameters |
|------------------|--------------------------------------------------------------|------------------------------------------------------------|
| `list_plugins` | List all plugins with optional filters | `type?` (`skill`, `agent`, `prompt`), `tag?` (string) |
| `get_plugin` | Get a plugin's full details or a single component's markdown | `name` (string), `component?` (`skill`, `agent`, `prompt`) |
| `search_plugins` | Full-text search across name, description, and tags | `query` (string), `type?` (`skill`, `agent`, `prompt`) |

A typical agentic integration pattern:
#### Connect from a local clone

1. Call `list_plugins` or `search_plugins` to discover relevant plugins
2. Call `get_plugin` with `component: "agent"` to retrieve the full markdown prompt
3. Use the returned markdown as a system prompt, agent instruction, or context injection
The repo includes a `.mcp.json` that configures the local MCP server automatically. Just clone, install, build, and start a Claude Code session.

### Contributing

Expand Down
31 changes: 25 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
{
"name": "claude-plugins",
"packageManager": "pnpm@10.6.2",
"version": "1.0.0",
"name": "@provectusinc/claude-plugins",
"version": "0.0.0-develop",
"description": "MCP server for discovering and serving Claude Code plugins",
"repository": {
"type": "git",
"url": "https://github.com/provectus/claude-plugins.git"
},
"type": "module",
"main": "dist/index.js",
"bin": {
"claude-plugins": "dist/index.js"
},
"files": [
"dist",
"plugins"
],
"keywords": [
"mcp",
"claude",
"plugins",
"model-context-protocol"
],
"license": "MIT",
Comment thread
Mgrdich marked this conversation as resolved.
"packageManager": "pnpm@10.6.2",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts",
"serve": "PORT=3000 node dist/index.js",
"test": "vitest run"
"test": "vitest run",
"prepublishOnly": "pnpm run build"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"@modelcontextprotocol/sdk": "^1.26.0",
"glob": "^11.0.1",
"zod": "^3.24.2"
},
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 9 additions & 75 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,17 @@
#!/usr/bin/env node

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { createServer as createHttpServer } from "http";
import { join } from "path";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { loadPlugins } from "./loader.js";
import { createServer } from "./server.js";

const pluginsDir = join(process.cwd(), "plugins");
const __dirname = dirname(fileURLToPath(import.meta.url));
const pluginsDir = join(__dirname, "..", "plugins");

const plugins = loadPlugins(pluginsDir);
console.error(`Loaded ${plugins.length} plugins`);

const MAX_BODY_SIZE = 1024 * 1024; // 1 MB

const portEnv = process.env.PORT;
let port: number | undefined;

if (portEnv !== undefined) {
const parsed = Number(portEnv);
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0) {
console.error(`Invalid PORT value "${portEnv}". Expected a non-negative integer.`);
process.exit(1);
}
port = parsed;
}

if (port !== undefined) {
const httpServer = createHttpServer(async (req, res) => {
if (req.url === "/mcp" && req.method === "POST") {
const server = createServer(plugins);
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});

try {
await server.connect(transport);

const body = await new Promise<string>((resolve, reject) => {
let data = "";
let size = 0;
req.on("data", (chunk: Buffer) => {
size += chunk.length;
if (size > MAX_BODY_SIZE) {
req.destroy();
reject(new Error("Request body too large"));
return;
}
data += chunk;
});
req.on("end", () => resolve(data));
req.on("error", reject);
});

await transport.handleRequest(req, res, JSON.parse(body));
} catch (err) {
if (!res.headersSent) {
const status = err instanceof Error && err.message === "Request body too large" ? 413 : 400;
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: status === 413 ? "Request body too large" : "Bad request" }));
}
} finally {
transport.close();
server.close();
}
} else {
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Not found" }));
}
});

httpServer.listen(port, () => {
console.error(`MCP HTTP server listening on port ${port}`);
});

process.on("SIGINT", () => {
httpServer.close();
process.exit(0);
});
} else {
const server = createServer(plugins);
const transport = new StdioServerTransport();
await server.connect(transport);
}
const server = createServer(plugins);
const transport = new StdioServerTransport();
await server.connect(transport);
Loading