
Advanced Features 2025
- 139 installs
- 50 repo stars
- Updated June 18, 2026
- josiahsiegel/claude-plugin-marketplace
Adopt 2025 advanced Claude plugin and agent capabilities—hooks, MCP, subagents, and marketplace patterns—when extending coding workflows beyond basic chat prompts.
About
Skill summarizing 2025 advanced Claude plugin marketplace features for agent builders. Helps teams wire MCP servers, hooks, subagents, and marketplace extensions into coding workflows with current patterns instead of legacy prompt-only setups.
- 2025 Claude plugin capability map
- MCP and tool-integration patterns
- Subagent and hook configuration
- Marketplace extension best practices
- Workflow automation beyond base prompts
Advanced Features 2025 by the numbers
- 139 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #3,527 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill advanced-features-2025Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 139 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 18, 2026 |
| Repository | josiahsiegel/claude-plugin-marketplace ↗ |
What it does
Adopt 2025 advanced Claude plugin and agent capabilities—hooks, MCP, subagents, and marketplace patterns—when extending coding workflows beyond basic chat prompts.
Files
Advanced Plugin Features (2025)
Quick Reference
| Feature | Location | Purpose |
|---|---|---|
| Agent Skills | skills/*/SKILL.md | Dynamic knowledge loading |
| Hooks | hooks/hooks.json | Event automation |
| MCP Servers | .mcp.json | External integrations |
| Team Config | .claude/settings.json | Repository plugins |
| Hook Event | When Fired | Use Case |
|---|---|---|
| PreToolUse | Before tool | Validation |
| PostToolUse | After tool | Testing, linting |
| SessionStart | Session begins | Logging, setup |
| SessionEnd | Session ends | Cleanup |
| UserPromptSubmit | Prompt submitted | Preprocessing |
| PreCompact | Before compact | State save |
| Notification | Notification shown | Custom alerts |
| Stop | User stops | Cleanup |
| SubagentStop | Subagent ends | Logging |
| Variable | Purpose |
|---|---|
${CLAUDE_PLUGIN_ROOT} | Plugin installation path |
${TOOL_INPUT_*} | Tool input parameters |
Agent Skills
Concept
Skills are dynamically loaded based on task context, enabling:
- Unbounded capacity: Knowledge split across files
- Context efficiency: Only load what's needed
- Progressive disclosure: Three-tier loading
Three-Tier Loading
1. Frontmatter: Loaded at startup (triggers) 2. SKILL.md body: Loaded on activation 3. references/: Loaded when detail needed
Structure
skills/
└── skill-name/
├── SKILL.md # Core content
├── references/ # Detailed docs
│ └── deep-dive.md
├── examples/ # Working code
│ └── example.md
└── scripts/ # Utilities
└── tool.shSKILL.md Format
---
name: skill-name
description: |
When to activate this skill. Include:
(1) Use case 1
(2) Use case 2
Provides: what it offers
---
# Skill Title
## Quick Reference
[Tables, key points]
## Core Content
[Essential information - keep lean]
## Additional Resources
See `references/` for detailed guidance.Hooks
Configuration
Inline in plugin.json:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/lint.sh"
}]
}]
}
}Separate hooks.json:
{
"PostToolUse": [{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 5000
}]
}]
}Matchers
Write- File writesEdit- File editsBash- Shell commandsWrite|Edit- Multiple tools.*- Any tool (use sparingly)
Common Patterns
Auto-test after changes:
{
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/run-tests.sh"
}]
}]
}Validate before Bash:
{
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-cmd.sh"
}]
}]
}MCP Server Integration
Configuration
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.js"],
"env": {
"API_KEY": "${API_KEY}"
}
}
}
}External Services
{
"mcpServers": {
"stripe": {
"command": "npx",
"args": ["-y", "@stripe/mcp-server"],
"env": {
"STRIPE_API_KEY": "${STRIPE_API_KEY}"
}
}
}
}Repository Configuration
Team Distribution
Create .claude/settings.json at repo root:
{
"extraKnownMarketplaces": [
"company/internal-plugins"
],
"plugins": {
"enabled": [
"deployment-helper@company",
"code-standards@company"
]
}
}Workflow
1. Maintainer creates .claude/settings.json 2. Team members clone repo 3. Trust folder when prompted 4. Plugins install automatically
Best Practices
Progressive Disclosure
- Keep SKILL.md under 500 lines
- Move details to
references/ - Use
examples/for working code - Reference files with relative paths
Hooks
- Use specific matchers (avoid
.*) - Set reasonable timeouts
- Use
${CLAUDE_PLUGIN_ROOT}for paths - Test scripts independently
MCP
- Document required env vars
- Provide setup instructions
- Use environment variables for secrets
- Test connection before distribution
Additional Resources
For detailed patterns, see:
- `references/hooks-advanced.md` - Complete hook patterns
- `references/mcp-patterns.md` - MCP integration examples
- `references/team-distribution.md` - Repository configuration
- `examples/hook-scripts.md` - Working hook scripts
Hook Script Examples
Working hook scripts for common automation tasks.
Auto-Format on Write
hooks.json
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh ${TOOL_INPUT_FILE_PATH}",
"timeout": 10000
}
]
}
]
}scripts/format.sh
#!/bin/bash
# Auto-format written files
FILE_PATH="$1"
# Skip if no file path
[[ -z "$FILE_PATH" ]] && exit 0
# Get file extension
EXT="${FILE_PATH##*.}"
case "$EXT" in
js|jsx|ts|tsx|json|md)
npx prettier --write "$FILE_PATH" 2>/dev/null
;;
py)
black "$FILE_PATH" 2>/dev/null || python -m black "$FILE_PATH" 2>/dev/null
;;
go)
gofmt -w "$FILE_PATH" 2>/dev/null
;;
rs)
rustfmt "$FILE_PATH" 2>/dev/null
;;
esac
exit 0Auto-Test After Changes
hooks.json
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/run-tests.sh",
"timeout": 120000
}
]
}
]
}scripts/run-tests.sh
#!/bin/bash
# Run tests after code changes
# Detect test framework and run tests
if [[ -f "package.json" ]]; then
# Node.js project
if grep -q "jest" package.json; then
npm test -- --bail --passWithNoTests 2>&1 | tail -20
elif grep -q "vitest" package.json; then
npx vitest run --bail 2>&1 | tail -20
elif grep -q "mocha" package.json; then
npm test 2>&1 | tail -20
fi
elif [[ -f "pytest.ini" ]] || [[ -f "pyproject.toml" ]]; then
# Python project
pytest --tb=short -q 2>&1 | tail -20
elif [[ -f "Cargo.toml" ]]; then
# Rust project
cargo test --quiet 2>&1 | tail -20
elif [[ -f "go.mod" ]]; then
# Go project
go test ./... -short 2>&1 | tail -20
fi
exit 0Block Dangerous Commands
hooks.json
{
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-command.sh",
"timeout": 5000
}
]
}
]
}scripts/validate-command.sh
#!/bin/bash
# Block dangerous bash commands
COMMAND="${TOOL_INPUT_COMMAND}"
# Patterns to block
BLOCKED_PATTERNS=(
"rm -rf /"
"rm -rf /*"
"rm -rf ~"
"> /dev/sda"
"mkfs."
":(){:|:&};:"
"dd if=/dev/zero of=/dev"
"chmod -R 777 /"
"chown -R.*:.*/"
)
for pattern in "${BLOCKED_PATTERNS[@]}"; do
if [[ "$COMMAND" == *"$pattern"* ]]; then
echo "BLOCKED: Dangerous command pattern detected: $pattern" >&2
exit 1
fi
done
# Block force push to protected branches
if [[ "$COMMAND" == *"git push"*"--force"* ]]; then
if [[ "$COMMAND" == *"main"* ]] || [[ "$COMMAND" == *"master"* ]]; then
echo "BLOCKED: Force push to protected branch" >&2
exit 1
fi
fi
exit 0Lint on File Write
hooks.json
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/lint.sh ${TOOL_INPUT_FILE_PATH}",
"timeout": 30000
}
]
}
]
}scripts/lint.sh
#!/bin/bash
# Lint written files
FILE_PATH="$1"
[[ -z "$FILE_PATH" ]] && exit 0
[[ ! -f "$FILE_PATH" ]] && exit 0
EXT="${FILE_PATH##*.}"
case "$EXT" in
js|jsx)
npx eslint "$FILE_PATH" --fix 2>&1 | grep -E "error|warning" | head -10
;;
ts|tsx)
npx eslint "$FILE_PATH" --fix 2>&1 | grep -E "error|warning" | head -10
npx tsc --noEmit "$FILE_PATH" 2>&1 | head -10
;;
py)
flake8 "$FILE_PATH" 2>&1 | head -10
mypy "$FILE_PATH" 2>&1 | head -10
;;
go)
go vet "$FILE_PATH" 2>&1
;;
sh|bash)
shellcheck "$FILE_PATH" 2>&1 | head -10
;;
esac
exit 0Session Logging
hooks.json
{
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/log-session.sh start"
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/log-session.sh end"
}
]
}
]
}scripts/log-session.sh
#!/bin/bash
# Log session start/end
ACTION="$1"
LOG_DIR="${CLAUDE_PLUGIN_ROOT}/logs"
LOG_FILE="$LOG_DIR/sessions.log"
# Create log directory if needed
mkdir -p "$LOG_DIR"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
PROJECT=$(basename "$PWD")
case "$ACTION" in
start)
echo "[$TIMESTAMP] SESSION_START project=$PROJECT" >> "$LOG_FILE"
;;
end)
echo "[$TIMESTAMP] SESSION_END project=$PROJECT" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
;;
esac
exit 0Dockerfile Validation
hooks.json
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-dockerfile.sh ${TOOL_INPUT_FILE_PATH}"
}
]
}
]
}scripts/validate-dockerfile.sh
#!/bin/bash
# Validate Dockerfile best practices
FILE_PATH="$1"
# Only validate Dockerfiles
[[ ! "$FILE_PATH" =~ Dockerfile ]] && exit 0
[[ ! -f "$FILE_PATH" ]] && exit 0
echo "Validating Dockerfile: $FILE_PATH"
WARNINGS=0
# Check for latest tag
if grep -q ":latest" "$FILE_PATH"; then
echo "Warning: Using ':latest' tag - consider pinning to specific version"
((WARNINGS++))
fi
# Check for ADD instead of COPY
if grep -q "^ADD " "$FILE_PATH"; then
echo "Warning: Using ADD instead of COPY - COPY is preferred for local files"
((WARNINGS++))
fi
# Check for root user
if ! grep -q "^USER " "$FILE_PATH"; then
echo "Warning: No USER instruction - container will run as root"
((WARNINGS++))
fi
# Check for .dockerignore
DIR=$(dirname "$FILE_PATH")
if [[ ! -f "$DIR/.dockerignore" ]]; then
echo "Warning: No .dockerignore file found"
((WARNINGS++))
fi
if [[ $WARNINGS -eq 0 ]]; then
echo "Dockerfile validation passed"
else
echo "Found $WARNINGS warning(s)"
fi
exit 0Git Pre-Commit Check
hooks.json
{
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/pre-commit-check.sh"
}
]
}
]
}scripts/pre-commit-check.sh
#!/bin/bash
# Check before git commit operations
COMMAND="${TOOL_INPUT_COMMAND}"
# Only check git commit commands
[[ ! "$COMMAND" =~ "git commit" ]] && exit 0
# Check for staged changes
STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l)
if [[ $STAGED -eq 0 ]]; then
echo "Warning: No files staged for commit"
fi
# Check for large files
LARGE_FILES=$(git diff --cached --name-only | xargs -I {} du -k {} 2>/dev/null | awk '$1 > 1024 {print $2}')
if [[ -n "$LARGE_FILES" ]]; then
echo "Warning: Large files staged (>1MB):"
echo "$LARGE_FILES"
fi
# Check for sensitive files
SENSITIVE=$(git diff --cached --name-only | grep -E '\.(env|pem|key|secrets)$')
if [[ -n "$SENSITIVE" ]]; then
echo "Warning: Potentially sensitive files staged:"
echo "$SENSITIVE"
fi
exit 0Making Scripts Executable
After creating hook scripts, make them executable:
chmod +x scripts/*.shOr in the plugin setup:
find "${CLAUDE_PLUGIN_ROOT}/scripts" -name "*.sh" -exec chmod +x {} \;Advanced Hook Patterns
Comprehensive guide to Claude Code hook development.
Hook Architecture
Event Flow
User Action → Event Triggered → Matchers Evaluated → Hooks Execute → Result ReturnedHook Types
1. Command hooks: Execute shell commands 2. Prompt hooks: Provide instructions to Claude
Complete Hook Schema
{
"EventName": [
{
"matcher": "ToolName|OtherTool",
"hooks": [
{
"type": "command",
"command": "shell-command",
"timeout": 30000,
"description": "What this hook does",
"env": {
"VAR_NAME": "value"
}
}
]
}
]
}Event Reference
PreToolUse
Fires BEFORE a tool executes. Use for validation, preparation.
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/check-lint.sh",
"description": "Validate code before writing"
}
]
}
]
}Return codes:
- 0: Allow tool execution
- Non-zero: Block execution (with error message)
PostToolUse
Fires AFTER a tool executes. Use for testing, formatting, notifications.
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm test -- --bail",
"timeout": 60000,
"description": "Run tests after code changes"
}
]
}
]
}SessionStart
Fires when Claude Code session begins.
{
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo 'Session: '$(date) >> ${CLAUDE_PLUGIN_ROOT}/logs/sessions.log"
}
]
}
]
}SessionEnd
Fires when session terminates.
{
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup.sh"
}
]
}
]
}UserPromptSubmit
Fires after user submits a prompt.
{
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "echo \"Prompt received: $(date)\" >> prompts.log"
}
]
}
]
}PreCompact
Fires before context compaction (when context gets too long).
{
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/save-state.sh"
}
]
}
]
}Matcher Patterns
Exact Match
"matcher": "Write"Multiple Tools
"matcher": "Write|Edit|Bash"Regex Pattern
"matcher": "Write.*"All Tools
"matcher": ".*"Warning: Avoid .* unless necessary - causes hook to run on every tool.
Environment Variables
Built-in Variables
| Variable | Description |
|---|---|
${CLAUDE_PLUGIN_ROOT} | Plugin installation directory |
${TOOL_INPUT_FILE_PATH} | File path (Write/Edit tools) |
${TOOL_INPUT_COMMAND} | Command (Bash tool) |
${TOOL_INPUT_*} | Any tool input parameter |
Custom Variables
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/process.sh",
"env": {
"ENVIRONMENT": "production",
"DEBUG": "true",
"API_KEY": "${API_KEY}"
}
}
]
}Advanced Patterns
Conditional Execution
Script that checks conditions:
#!/bin/bash
# Only run for certain file types
FILE_PATH="${TOOL_INPUT_FILE_PATH}"
if [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
npm run lint "$FILE_PATH"
fiChained Hooks
Multiple hooks run in sequence:
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "prettier --write ${TOOL_INPUT_FILE_PATH}",
"description": "Format code"
},
{
"type": "command",
"command": "eslint ${TOOL_INPUT_FILE_PATH}",
"description": "Lint code"
},
{
"type": "command",
"command": "npm test",
"description": "Run tests"
}
]
}
]
}Blocking Hook
PreToolUse hook that can block execution:
#!/bin/bash
# Block dangerous commands
COMMAND="${TOOL_INPUT_COMMAND}"
# Block rm -rf /
if [[ "$COMMAND" == *"rm -rf /"* ]]; then
echo "ERROR: Blocked dangerous command: $COMMAND" >&2
exit 1
fi
# Block force push to main
if [[ "$COMMAND" == *"git push"*"--force"*"main"* ]]; then
echo "ERROR: Force push to main is not allowed" >&2
exit 1
fi
exit 0Notification Hook
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"File saved: ${TOOL_INPUT_FILE_PATH}\" with title \"Claude Code\"'"
}
]
}
]
}Prompt-Based Hooks
Instead of shell commands, provide instructions to Claude:
{
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "prompt",
"prompt": "After writing this file, run the related tests and report any failures."
}
]
}
]
}Debugging Hooks
Enable Debug Mode
claude --debugShows hook registration, matching, and execution.
Test Hook Scripts
# Test script independently
TOOL_INPUT_FILE_PATH="/path/to/file.ts" ./scripts/lint.shLog Hook Execution
{
"hooks": [
{
"type": "command",
"command": "echo \"Hook triggered: $(date)\" >> ${CLAUDE_PLUGIN_ROOT}/logs/hooks.log && original-command"
}
]
}Best Practices
Performance
- Set reasonable timeouts (default 30s)
- Avoid blocking on long operations
- Use async operations when possible
Security
- Validate inputs in scripts
- Don't execute arbitrary user content
- Use
${CLAUDE_PLUGIN_ROOT}for paths
Reliability
- Handle errors gracefully
- Provide meaningful error messages
- Test on all target platforms
Organization
- Document each hook's purpose
- Use descriptive script names
- Keep scripts in
scripts/directory
MCP Integration Patterns
Model Context Protocol server integration for Claude Code plugins.
Overview
MCP (Model Context Protocol) enables Claude to interact with external tools, APIs, and services through standardized server interfaces.
Server Types
stdio Server
Most common type - communicates via stdin/stdout.
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.js"]
}
}
}SSE Server
Server-sent events for real-time communication.
{
"mcpServers": {
"streaming-server": {
"type": "sse",
"url": "https://api.example.com/mcp"
}
}
}HTTP Server
Standard HTTP request/response.
{
"mcpServers": {
"http-server": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}
}Configuration Locations
Inline in plugin.json
{
"name": "my-plugin",
"mcpServers": {
"server-name": {
"command": "...",
"args": ["..."]
}
}
}Separate .mcp.json
{
"mcpServers": {
"server-name": {
"command": "...",
"args": ["..."]
}
}
}Common Patterns
NPM Package Server
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}
}
}Python Server
{
"mcpServers": {
"python-tools": {
"command": "python",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.py"]
}
}
}Docker Container
{
"mcpServers": {
"containerized-server": {
"command": "docker",
"args": ["run", "-i", "--rm", "my-mcp-server:latest"]
}
}
}API Integrations
Stripe
{
"mcpServers": {
"stripe": {
"command": "npx",
"args": ["-y", "@stripe/mcp-server"],
"env": {
"STRIPE_API_KEY": "${STRIPE_API_KEY}"
}
}
}
}GitHub
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}Database
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
}Slack
{
"mcpServers": {
"slack": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}"
}
}
}
}Environment Variables
Using Plugin Variables
{
"mcpServers": {
"server": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.js"],
"env": {
"CONFIG_PATH": "${CLAUDE_PLUGIN_ROOT}/config.json"
}
}
}
}Using System Variables
{
"mcpServers": {
"server": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/server.js"],
"env": {
"HOME_DIR": "${HOME}",
"API_KEY": "${MY_API_KEY}"
}
}
}
}Creating Custom Servers
Basic Node.js Server
// mcp/server.js
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server({
name: 'my-server',
version: '1.0.0'
}, {
capabilities: {
tools: {}
}
});
// Register tools
server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'my-tool',
description: 'Does something useful',
inputSchema: {
type: 'object',
properties: {
input: { type: 'string' }
},
required: ['input']
}
}]
}));
server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
if (name === 'my-tool') {
// Implement tool logic
return {
content: [{
type: 'text',
text: `Result: ${args.input}`
}]
};
}
throw new Error(`Unknown tool: ${name}`);
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);Basic Python Server
# mcp/server.py
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
app = Server("my-server")
@app.list_tools()
async def list_tools():
return [{
"name": "my-tool",
"description": "Does something useful",
"inputSchema": {
"type": "object",
"properties": {
"input": {"type": "string"}
},
"required": ["input"]
}
}]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "my-tool":
return f"Result: {arguments['input']}"
raise ValueError(f"Unknown tool: {name}")
if __name__ == "__main__":
asyncio.run(stdio_server(app))Best Practices
Security
- Never hardcode API keys
- Use environment variables for secrets
- Document required credentials
- Validate all inputs
Reliability
- Handle connection failures gracefully
- Implement retry logic
- Set appropriate timeouts
- Log errors for debugging
Documentation
- List all required environment variables
- Provide setup instructions
- Document available tools
- Include usage examples
Testing
- Test server independently first
- Verify environment variables are set
- Check MCP server logs for errors
- Use
/mcpcommand to verify registration
Troubleshooting
Server not starting
- Check command path is correct
- Verify dependencies are installed
- Test command manually in terminal
- Check for missing environment variables
Tools not appearing
- Verify server starts without errors
- Check tool registration in server code
- Use
claude --debugto see MCP logs - Restart Claude Code after changes
Connection errors
- Check network connectivity
- Verify URLs and ports
- Check authentication credentials
- Review server logs
Timeout issues
- Increase timeout in configuration
- Optimize server response time
- Consider async operations
- Add progress indicators
Team Plugin Distribution
Repository-level configuration for automatic plugin installation.
Overview
Teams can configure repositories to automatically install plugins when developers trust the folder. This ensures consistent tooling across all team members.
Configuration File
Create .claude/settings.json at repository root:
repo-root/
├── .claude/
│ └── settings.json # Plugin configuration
├── src/
└── README.mdSettings Format
Basic Configuration
{
"extraKnownMarketplaces": [
"company/internal-plugins"
],
"plugins": {
"enabled": [
"code-standards@company",
"deployment-helper@company"
]
}
}Multiple Marketplaces
{
"extraKnownMarketplaces": [
"company/internal-plugins",
"JosiahSiegel/claude-plugin-marketplace",
"team/specialized-tools"
],
"plugins": {
"enabled": [
"code-standards@company",
"docker-master@JosiahSiegel",
"custom-tool@team"
]
}
}Plugin Specification
Format
plugin-name@marketplace-ownerExamples
{
"plugins": {
"enabled": [
"docker-master@JosiahSiegel", // From JosiahSiegel marketplace
"test-helper@company", // From company marketplace
"code-review-helper" // From default marketplace
]
}
}Setup Workflow
For Repository Maintainers
1. Create configuration directory:
mkdir -p .claude2. Create settings.json:
{
"extraKnownMarketplaces": [
"your-org/plugins"
],
"plugins": {
"enabled": [
"required-plugin@your-org"
]
}
}3. Commit to version control:
git add .claude/settings.json
git commit -m "Add Claude Code plugin configuration"4. Document in README:
## Development Setup
This repository uses Claude Code plugins for standardized workflows.
### First Time Setup
1. Install Claude Code
2. Clone this repository
3. Open folder in Claude Code
4. Trust this folder when prompted
5. Plugins will install automaticallyFor Team Members
1. Clone repository 2. Open in Claude Code 3. Trust folder when prompted 4. Plugins install automatically 5. Start working with shared tooling
Advanced Patterns
Environment-Specific Plugins
{
"extraKnownMarketplaces": [
"company/plugins"
],
"plugins": {
"enabled": [
"core-tools@company"
]
}
}Create different configs per environment using branches or separate files (though only one .claude/settings.json is read).
Minimal vs Full Setup
Minimal (essential only):
{
"extraKnownMarketplaces": ["company/core"],
"plugins": {
"enabled": ["standards@company"]
}
}Full (all team tools):
{
"extraKnownMarketplaces": [
"company/core",
"company/optional",
"JosiahSiegel/claude-plugin-marketplace"
],
"plugins": {
"enabled": [
"standards@company",
"testing@company",
"docs-helper@company",
"docker-master@JosiahSiegel"
]
}
}Security Considerations
Trust Model
- Users must explicitly trust folders
- Trust is granted per-folder, not globally
- Review settings.json before trusting unknown repos
Marketplace Security
- Only trust verified marketplaces
- Use organization-owned marketplaces for internal tools
- Review plugin code before adding to marketplace
Best Practices
1. Document requirements:
## Required Plugins
This repo requires the following plugins:
- `code-standards` - Enforces coding standards
- `test-helper` - Runs tests automatically
Review plugin source at: https://github.com/company/plugins2. Explain why:
These plugins ensure:
- Consistent code formatting
- Automatic test execution
- Standard commit messages3. Provide opt-out:
To skip plugin installation:
- Remove `.claude/settings.json` locally
- Or: Don't trust the folderMaintenance
Updating Plugins
1. Update version in marketplace 2. Team members get updates on next session
Adding New Plugins
1. Add to marketplace if new 2. Add to settings.json 3. Commit change 4. Team members get on pull
Removing Plugins
1. Remove from settings.json 2. Commit change 3. Team members manually uninstall
Troubleshooting
Plugins not installing
- Verify settings.json syntax is valid JSON
- Check marketplace names are correct
- Ensure repo is trusted
- Verify marketplace is public
Wrong marketplace
- Check spelling of marketplace owner
- Verify plugin exists in specified marketplace
- Try full format:
plugin@owner
Conflicts
- Ensure plugin names are unique
- Check for version conflicts
- Review error messages in Claude Code
Testing Configuration
# Validate JSON syntax
cat .claude/settings.json | python -m json.tool
# Check file exists
ls -la .claude/
# Verify git status
git status .claude/Example Configurations
Frontend Team
{
"extraKnownMarketplaces": [
"company/frontend-tools"
],
"plugins": {
"enabled": [
"react-patterns@company",
"typescript-helper@company",
"style-guide@company"
]
}
}Backend Team
{
"extraKnownMarketplaces": [
"company/backend-tools"
],
"plugins": {
"enabled": [
"api-design@company",
"database-helper@company",
"security-scanner@company"
]
}
}DevOps Team
{
"extraKnownMarketplaces": [
"company/devops-tools",
"JosiahSiegel/claude-plugin-marketplace"
],
"plugins": {
"enabled": [
"terraform-master@JosiahSiegel",
"docker-master@JosiahSiegel",
"ci-helper@company"
]
}
}