Use when setting up project-specific development tools or after analyzing a codebase - generates custom MCP server with semantic search, project-aware tools, and health monitoring capabilities. Do NOT use if generic popkit commands are sufficient or for small projects where MCP server overhead isn't justified - stick with built-in tools for simple workflows.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
checklists/mcp-checklist.jsonscripts/analyze_project.pyworkflows/mcp-workflow.jsonGenerate a custom MCP (Model Context Protocol) server tailored to the specific project's needs, including semantic search, project-specific tools, and contextual capabilities.
Core principle: Every project deserves tools that understand its unique architecture.
Trigger: /popkit:project mcp command after project analysis
This is a Pro tier feature. Free tier users receive a basic project analysis instead.
When a free tier user invokes this skill, provide valuable project insights without generating the MCP server:
## Project Analysis (Free Tier)
Since custom MCP server generation requires PopKit Pro, here's what I found about your project:
### Tech Stack Detected
- **Framework:** [detected framework]
- **Language:** [language]
- **Database:** [if detected]
- **Testing:** [test framework]
### Recommended Checks
Based on your stack, these health checks would be useful:
- [ ] [Service 1] on port [X]
- [ ] [Service 2] on port [Y]
- [ ] [Database] connectivity
### Project Structure
[directory tree overview]
### What MCP Server Would Provide
With PopKit Pro, you'd get a custom MCP server including:
- ⨠**Semantic tool search** - Find tools by description
- š **Project-specific health checks** - Monitor your services
- ā” **Custom quality tools** - Typecheck, lint, test commands
- š **Embeddings** - Vector search across tools
Run `/popkit:upgrade` to unlock custom MCP generation.
Before proceeding with MCP generation, check user entitlement:
import sys
sys.path.insert(0, "hooks/utils")
from premium_checker import check_entitlement
result = check_entitlement("pop-mcp-generator")
if not result.allowed:
# Execute fallback: basic project analysis
print("## Project Analysis (Free Tier)")
# ... show detection results without generating MCP
print("\nRun `/popkit:upgrade` to unlock custom MCP generation.")
return
Premium users call the cloud API for server-side generation:
import sys
sys.path.insert(0, "hooks/utils")
from premium_client import generate_mcp_server, is_premium
if not is_premium():
# Show free tier fallback
return
# Call cloud API for generation
result = generate_mcp_server(
project_name="my-project",
tech_stack=["nextjs", "typescript", "prisma"],
dev_port=3000,
db_port=5432,
include_embeddings=True,
include_routines=True
)
if result.success:
# Write generated files to disk
for file in result.files:
path = Path(f".claude/mcp-servers/{project_name}-dev/{file.path}")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(file.content)
print(result.instructions)
print(f"\nGenerated {len(result.tools)} tools: {', '.join(result.tools)}")
else:
print(f"Generation failed: {result.error}")
| Flag | Description |
|---|---|
--from-analysis | Use .claude/analysis.json for tool selection |
--no-embed | Skip auto-embedding of tools |
--no-semantic | Don't include semantic search capabilities |
--tools <list> | Comma-separated list of tools to generate |
.claude/mcp-servers/[project-name]-dev/
āāā package.json
āāā tsconfig.json
āāā src/
ā āāā index.ts # MCP server entry point
ā āāā tools/
ā ā āāā project-tools.ts # Project-specific tools
ā ā āāā health-check.ts # Service health checks
ā ā āāā search.ts # Semantic search
ā āāā resources/
ā āāā project-context.ts # Project documentation
āāā README.md
Gather project information:
# Detect tech stack
ls package.json Cargo.toml pyproject.toml go.mod 2>/dev/null
# Find main directories
ls -d src lib app components 2>/dev/null
# Detect test framework
grep -l "jest\|mocha\|vitest\|pytest" package.json pyproject.toml 2>/dev/null
# Find configuration files
ls .env* config/ *.config.* 2>/dev/null
Based on project type, select tools:
Node.js:
Python:
Rust:
Common:
{
"name": "[project]-dev-mcp",
"version": "1.0.0",
"description": "MCP server for [project] development",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "latest"
},
"devDependencies": {
"typescript": "^5.0.0",
"tsx": "^4.0.0"
}
}
For each tool, generate TypeScript implementation:
// Example: health check tool
export const checkService = {
name: "[project]__check_[service]",
description: "Check if [service] is running on port [port]",
inputSchema: {
type: "object",
properties: {},
required: []
},
async execute() {
const response = await fetch(`http://localhost:[port]/health`);
return {
running: response.ok,
url: `http://localhost:[port]`,
status: response.status
};
}
};
Create tool search with embeddings:
// Tool search with semantic matching
export const toolSearch = {
name: "[project]__tool_search",
description: "Search for tools by description",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Natural language query" },
top_k: { type: "number", default: 5 }
},
required: ["query"]
},
async execute({ query, top_k = 5 }) {
// Match against tool descriptions
const tools = getAllTools();
return rankByRelevance(tools, query, top_k);
}
};
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// Import all tools
import { projectTools } from "./tools/project-tools.js";
import { healthChecks } from "./tools/health-check.js";
import { searchTools } from "./tools/search.js";
const server = new Server({
name: "[project]-dev",
version: "1.0.0"
}, {
capabilities: {
tools: {}
}
});
// Register all tools
const allTools = [...projectTools, ...healthChecks, ...searchTools];
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: allTools.map(t => ({
name: t.name,
description: t.description,
inputSchema: t.inputSchema
}))
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const tool = allTools.find(t => t.name === request.params.name);
if (!tool) throw new Error(`Unknown tool: ${request.params.name}`);
return await tool.execute(request.params.arguments);
});
const transport = new StdioServerTransport();
await server.connect(transport);
Add to .claude/settings.json:
{
"mcpServers": {
"[project]-dev": {
"command": "node",
"args": [".claude/mcp-servers/[project]-dev/dist/index.js"]
}
}
}
After generating:
MCP server generated at .claude/mcp-servers/[project]-dev/
Tools created:
- [project]__check_[services]
- [project]__run_typecheck
- [project]__run_lint
- [project]__run_tests
- [project]__git_status
- [project]__tool_search
Next steps:
1. cd .claude/mcp-servers/[project]-dev
2. npm install
3. npm run build
4. Restart Claude Code to load MCP server
Would you like me to build and test it?
When .claude/analysis.json exists (from /popkit:project analyze --json), the generator uses structured data:
import json
from pathlib import Path
analysis_path = Path.cwd() / ".claude" / "analysis.json"
if analysis_path.exists():
analysis = json.loads(analysis_path.read_text())
frameworks = analysis.get("frameworks", [])
patterns = analysis.get("patterns", [])
commands = analysis.get("commands", {})
else:
# Fall back to manual detection
frameworks = []
patterns = []
commands = {}
| Framework | Generated Tools |
|---|---|
nextjs | check_dev_server, check_build, run_typecheck |
express | check_api_server, health_endpoints |
prisma | check_database, run_migrations, prisma_studio |
supabase | check_supabase, supabase_status |
redis | check_redis, redis_info |
docker-compose | docker_status, docker_logs |
Tool descriptions should be detailed enough for semantic matching:
{
name: "health:dev-server",
description: "Check dev server"
}
{
name: "health:dev-server",
description: "Check if the Next.js development server is running and responding on port 3000. Use this to verify the dev environment is working, troubleshoot startup issues, or confirm the app is accessible. Returns status, URL, and response time."
}
After generating the MCP server, automatically embed tool descriptions:
import sys
import json
from datetime import datetime
from pathlib import Path
sys.path.insert(0, "hooks/utils")
from voyage_client import VoyageClient
def export_tool_embeddings(tools: list, output_path: str):
"""Export embeddings for semantic search."""
client = VoyageClient()
if not client.is_available:
print("ā Voyage API not available, skipping embeddings")
return False
descriptions = [t["description"] for t in tools]
embeddings = client.embed(descriptions, input_type="document")
output = {
"generated_at": datetime.now().isoformat(),
"model": "voyage-3.5",
"dimension": len(embeddings[0]) if embeddings else 0,
"tools": [
{
"name": t["name"],
"description": t["description"],
"embedding": emb
}
for t, emb in zip(tools, embeddings)
]
}
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
Path(output_path).write_text(json.dumps(output, indent=2))
print(f"ā Exported {len(tools)} tool embeddings to {output_path}")
return True
# After generating MCP server
tools = [
{"name": "health:dev-server", "description": "Check if the Next.js..."},
{"name": "health:database", "description": "Check database connectivity..."},
# ... other tools
]
export_tool_embeddings(tools, ".claude/tool_embeddings.json")
Also store in the global embedding database for cross-project discovery:
from embedding_project import auto_embed_item
# After writing each tool file
for tool_file in tool_files:
success = auto_embed_item(tool_file, "mcp-tool")
if success:
print(f" āā Embedded: {tool_file}")
1. Check for .claude/analysis.json
2. If exists: Use recommended tools from analysis
3. If not: Fall back to project detection
4. Generate MCP server with detailed descriptions
5. Export tool_embeddings.json for semantic search
6. Register tools in embedding store
7. Update .claude/settings.json
8. Report status with embedding summary
After generating:
MCP server generated at .claude/mcp-servers/[project]-dev/
Tools created (8):
ā health:dev-server - Check Next.js dev server
āā Embedded for semantic search
ā health:database - Check PostgreSQL connectivity
āā Embedded for semantic search
ā quality:typecheck - Run TypeScript type checking
āā Embedded for semantic search
ā quality:lint - Run ESLint checks
āā Embedded for semantic search
ā quality:test - Run Jest test suite
āā Embedded for semantic search
ā git:status - Get git working tree status
āā Embedded for semantic search
ā git:diff - Show staged and unstaged changes
āā Embedded for semantic search
ā search:tools - Semantic tool search
āā Embedded for semantic search
Embedding Summary:
- Tool embeddings: .claude/tool_embeddings.json
- Total tools: 8
- Successfully embedded: 8
- Model: voyage-3.5
Next steps:
1. cd .claude/mcp-servers/[project]-dev
2. npm install
3. npm run build
4. Restart Claude Code to load MCP server
Would you like me to build and test it?
Requires:
Enables: