plugins/mcp-tooling/skills/mcp-proxy-daemoning/SKILL.md
Use this skill when working with mcp-proxy daemoning patterns — running a shared MCP proxy daemon that multiple Claude Code sessions can connect to simultaneously. Use when the user asks about sharing MCP servers across sessions, reducing MCP server overhead, running a single MCP proxy instance for multiple clients, configuring smart-mcp-proxy, or understanding the daemon lifecycle pattern from nsheaps/aitkit. Also use for the Serena de-duplication pattern — running project-level MCP servers at the user level to avoid duplicate instances across projects.
npx skillsauth add nsheaps/ai-mktpl mcp-proxy-daemoningInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Pattern for running a shared MCP proxy daemon that multiple Claude Code sessions connect to simultaneously, reducing resource overhead and enabling cross-session tool sharing.
When multiple Claude Code sessions each spawn their own MCP server processes:
A single daemon process runs the MCP proxy, and multiple sessions connect to it via HTTP:
Session A ──stdio──→ run-mcp-proxy.sh ──HTTP──→ mcp-proxy daemon (port 12476)
Session B ──stdio──→ run-mcp-proxy.sh ──HTTP──→ (same daemon)
Session C ──stdio──→ run-mcp-proxy.sh ──HTTP──→ (same daemon)
The run-mcp-proxy.sh script in nsheaps/aitkit implements a full daemon lifecycle:
MCPPROXY_TOP_K="10" # Tools to register per session
MCPPROXY_TOOLS_LIMIT="50" # Max tools in active pool
MCPPROXY_DATA_DIR="$AITKIT_ROOT/lib/mcpproxy" # Database/index location
MCPPROXY_CONFIG_PATH="$MCPPROXY_DATA_DIR/mcp_proxy_config.json"
MCPPROXY_PORT="12476" # Listen port
MCPPROXY_TRANSPORT="streamable-http" # Transport type
~/.aitkit/
├── run/ # PID files for daemon management
│ ├── mcp-proxy-<name>.pid # Daemon PID
│ └── mcp-servers/ # Per-session registration
│ ├── 12345 # Session A's PID
│ └── 12346 # Session B's PID
└── lib/mcpproxy/
├── mcp_proxy_config.json # MCP server definitions
├── mcp-proxy.log # Daemon log
└── (database/index files) # Smart proxy state
# Simplified lifecycle logic
start_or_reuse_daemon() {
if daemon_is_running; then
echo "Reusing existing daemon at PID $(daemon_pid)"
else
daemon --name "$DAEMON_NAME" --pidfile "$PID_FILE" \
--command "uvx smart-mcp-proxy \
--port $MCPPROXY_PORT \
--transport $MCPPROXY_TRANSPORT \
--config $MCPPROXY_CONFIG_PATH"
fi
# Register this session
echo $$ > "$MCP_PID_DIR/$$"
}
on_exit() {
rm -f "$MCP_PID_DIR/$$"
if [ "$(ls "$MCP_PID_DIR" | wc -l)" -eq 0 ]; then
kill_daemon
fi
}
trap on_exit EXIT
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"serena": {
"command": "uvx",
"args": ["serena", "--workspace", "/path/to/project"]
}
}
}
The smart-mcp-proxy (via uvx) provides:
Serena is a code-aware AI agent tool that stores project knowledge in .serena/memories/. When configured at the project level:
/Users/nheaps/.aitkit/upstreams/gathertown/.ai/bin/mcp/serena.sh) in per-project configs is fragile and non-portable.mcp.json.mcp.json declares Serena AND the user-level daemon already runs it, the daemon version takes precedence# Instead of this (per-project, fragile):
# project/.mcp.json → serena.sh → standalone serena process
# Do this (user-level, shared):
# ~/.aitkit/lib/mcpproxy/mcp_proxy_config.json includes serena
# All sessions connect to the shared daemon
# Serena runs once, with access to all registered projects
~/.aitkit/lib/mcpproxy/mcp_proxy_config.json.mcp.json filesIn your project's .mcp.json or user-level settings, point to the daemon wrapper:
{
"mcpServers": {
"shared-proxy": {
"type": "stdio",
"command": "/path/to/aitkit/bin/run-mcp-proxy.sh",
"args": ["mcp-user"]
}
}
}
The wrapper script:
| Issue | Resolution |
| ------------------------------- | ------------------------------------------------------------------------ |
| Daemon not starting | Check ~/.aitkit/lib/mcpproxy/mcp-proxy.log |
| Stale PID files | Remove ~/.aitkit/run/mcp-servers/* and ~/.aitkit/run/mcp-proxy-*.pid |
| Port conflict | Change MCPPROXY_PORT in the config |
| Tool not found | Verify mcp_proxy_config.json includes the server |
| Daemon crashes between sessions | Background health loop auto-recovers; check logs |
tools
Manually reproduce what the github-app plugin's SessionStart hook does to make a GitHub App installation token usable in the current session — materialize the PEM, generate the token, isolate GH_CONFIG_DIR, write the runtime env file, and wire CLAUDE_ENV_FILE so every Bash call sees GH_TOKEN/GITHUB_TOKEN. Use when the hook did not run, the token is missing from the environment, or a shell/teammate needs the token wired up by hand. <example>GH_TOKEN isn't set even though github-app is configured</example> <example>the github-app SessionStart hook didn't run, set up the token manually</example> <example>wire the github app token into CLAUDE_ENV_FILE</example> <example>gh keeps falling back to the wrong account, isolate GH_CONFIG_DIR</example>
tools
Manually configure the GitHub App bot git identity the way the github-app plugin's SessionStart hook does — resolve the app slug and bot user ID, build the <slug>[bot] name and noreply email, set GIT_AUTHOR_*/GIT_COMMITTER_* env vars, and write an isolated GIT_CONFIG_GLOBAL with the gh auth git-credential helper. Use when commits are attributed to the wrong account, "Author identity unknown" appears, or git identity must be set up by hand. <example>my commits are showing up as the handler, not the bot</example> <example>git says Author identity unknown after the github-app hook ran</example> <example>configure the github app bot git identity manually</example> <example>set up the gh credential helper for git push</example>
tools
Manages spec files for requirements capture and validation
tools
# Bash Chaining Alternatives This skill teaches you how to work around the bash command chaining restriction enforced by this plugin. ## Why Chaining is Blocked The `bash-command-rejection` plugin blocks these operators: | Operator | Name | Why Blocked | | -------- | ---------- | ----------------------------------------------------------------------------------- | | `&&` | AND chain | Runs cmd2 only if cmd1 su