Skip to content
Draft
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
14 changes: 13 additions & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,17 @@
"author": { "name": "Pipefy", "url": "https://github.com/pipefy" },
"homepage": "https://github.com/pipefy/ai-toolkit",
"repository": "https://github.com/pipefy/ai-toolkit",
"license": "Apache-2.0"
"license": "Apache-2.0",
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "sh \"${CLAUDE_PLUGIN_ROOT}/hooks/check-server-version.sh\""
}
]
}
]
}
}
51 changes: 51 additions & 0 deletions hooks/check-server-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
# SessionStart nudge: when install.sh has registered a user-scope `pipefy`
# server (the persistent pipefy-mcp-server binary, which shadows the plugin's
# bundled uvx entry), plugin auto-updates no longer reach that running server.
# This compares the installed binary's version against the plugin's declared
# version and, on drift, tells the user to re-run install.sh (the path that
# actually reinstalls the binary and re-registers the user-scope server;
# /pipefy:install only installs the CLI).
#
# No-op unless that user-scope override is registered: users on the pure
# plugin/uvx path have no installed binary, and users who installed the binary
# only for another client (e.g. --client cursor) still run the plugin's uvx
# server here, so there is nothing shadowing the plugin to nudge about.
set -eu

# Cheap pre-filter: no installed binary means nothing could shadow the plugin.
command -v pipefy-mcp-server >/dev/null 2>&1 || exit 0
Comment thread
gbrlcustodio marked this conversation as resolved.

# The precise trigger is a user-scope `pipefy` server whose command is that
# binary. `command -v` alone is not enough: --client cursor also puts the
# binary on PATH without registering a Claude Code override, so the plugin's
# uvx server still runs here and there is nothing to sync. Fall through to no
# nudge if python3 is missing or the config cannot be read.
python3 - <<'PY' || exit 0
import json
import os
import sys

try:
servers = json.load(open(os.path.expanduser("~/.claude.json"))).get("mcpServers", {})
except (OSError, ValueError):
sys.exit(1)
entry = servers.get("pipefy") if isinstance(servers, dict) else None
command = entry.get("command") if isinstance(entry, dict) else None
sys.exit(0 if command == "pipefy-mcp-server" else 1)
PY

# Cheap checks first; only spawn the binary (Python cold start) once we have a
# plugin version to compare against.
manifest="${CLAUDE_PLUGIN_ROOT:-}/.claude-plugin/plugin.json"
[ -f "$manifest" ] || exit 0
plugin=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$manifest" | head -n1)
[ -n "$plugin" ] || exit 0

installed=$(pipefy-mcp-server --version 2>/dev/null | tr -d '[:space:]')
[ -n "$installed" ] || exit 0

if [ "$installed" != "$plugin" ]; then
echo "Pipefy: the installed MCP server ($installed) differs from this plugin ($plugin). Re-run the installer to sync: curl -fsSL https://raw.githubusercontent.com/pipefy/ai-toolkit/main/install.sh | sh -s -- --client claude-code"
fi
exit 0
45 changes: 38 additions & 7 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Resolves the latest GitHub Release tag (or a tag passed via --version),
# discovers its wheel assets, installs the CLI and MCP server via
# `uv tool install`, optionally installs skills via `npx skills add`, and
# writes the MCP server registration into the chosen client's config.
# registers the MCP server with the chosen client (a config-file write for
# most clients; `claude mcp add` at user scope for Claude Code).

set -eu

Expand Down Expand Up @@ -71,8 +72,11 @@ and register the MCP server with an MCP client.
Options:
--yes, -y Skip all confirmation prompts.
--no-skills Skip the skills installation step.
--client <id> Register MCP server in this client's config.
--client <id> Register the MCP server for this client.
One of: claude-code, claude-desktop, cursor, codex, none.
claude-code registers via 'claude mcp add' at user scope
(overrides the plugin's bundled server); the others write
the client's own config file.
Defaults to 'none' (prints snippet to paste).
--version <tag> Install a specific GitHub Release tag (e.g. v0.2.0-beta.2).
Defaults to the most recent release (incl. prereleases).
Expand Down Expand Up @@ -314,6 +318,28 @@ require_python3() {
fi
}

require_claude() {
if ! command -v claude >/dev/null 2>&1; then
err "the 'claude' CLI is required to register the MCP server in Claude Code, but was not found. Install Claude Code (https://claude.com/claude-code), or re-run with --client none and paste the snippet manually."
fi
}

claude_code_register_pipefy() {
# Register at USER scope: Claude Code resolves same-named servers
# local > project > user > plugin, so a user-scope `pipefy` shadows the
# plugin's bundled entry and only the binary installed above spawns. The
# bare binary (not a uvx command) keeps the server on the system Python it
# was installed with, without baking an interpreter path into user config.
if [ "$DRY_RUN" -eq 0 ]; then
require_claude
# `claude mcp add` errors on a duplicate name; drop any prior user-scope
# entry first to keep re-runs idempotent.
claude mcp remove pipefy --scope user >/dev/null 2>&1 || true
fi
run claude mcp add pipefy --scope user -- pipefy-mcp-server
[ "$DRY_RUN" -eq 1 ] || say "Registered 'pipefy' at user scope (overrides the plugin's bundled server)."
}

json_merge_pipefy() {
path="$1"
if [ "$DRY_RUN" -eq 1 ]; then
Expand Down Expand Up @@ -404,6 +430,8 @@ EOF
}

write_client_config() {
# cursor/claude-desktop/codex write the client's own config file; claude-code
# instead registers via `claude mcp add` (user scope) to override the plugin.
case "$CLIENT" in
cursor)
json_merge_pipefy "$HOME/.cursor/mcp.json"
Expand All @@ -415,11 +443,7 @@ write_client_config() {
codex_append_pipefy "$HOME/.codex/config.toml"
;;
claude-code)
cat <<EOF
To install in Claude Code, run these slash commands:
/plugin marketplace add $REPO
/plugin install pipefy@pipefy
EOF
claude_code_register_pipefy
;;
""|none)
print_manual_snippet
Expand Down Expand Up @@ -450,6 +474,13 @@ print_next_steps() {
say " ~/.zshrc, ~/.config/fish/conf.d/uv.fish). If a new terminal still"
say " can't find 'pipefy', add \$HOME/.local/bin to PATH manually."
fi
if [ "$CLIENT" = "claude-code" ]; then
say ""
say "==> Pipefy MCP server registered at user scope (overrides the plugin's"
say " bundled server). Reload or restart Claude Code for it to take effect."
say " For skills and slash commands, also install the plugin:"
say " /plugin marketplace add $REPO && /plugin install pipefy@pipefy"
fi
say ""
say "Next: authenticate with Pipefy."
say " Default (browser): pipefy auth login"
Expand Down