feat: upgrade framework to v1.4.0-rc1 with installer script

This commit is contained in:
thibaud-lclr 2026-04-15 10:19:42 +02:00
parent 7315f2658c
commit 647a03a10c
4 changed files with 299 additions and 1 deletions

View file

@ -153,6 +153,20 @@ Pour lupdate, la validation du manifeste accepte :
## Installation
### Installateur interactif
Le repo inclut un assistant interactif `install.sh` :
```sh
./install.sh
```
Tu peux aussi lexécuter directement depuis la branche `main` :
```sh
curl -fsSL https://gitea.lclr.dev/AI/email-mcp/raw/branch/main/install.sh | bash
```
### Claude Code CLI
Ajoute le serveur MCP en pointant vers le binaire et la sous-commande `mcp` :

2
go.mod
View file

@ -3,7 +3,7 @@ module email-mcp
go 1.25.0
require (
gitea.lclr.dev/AI/mcp-framework v1.3.2
gitea.lclr.dev/AI/mcp-framework v1.4.0-rc1
github.com/emersion/go-imap/v2 v2.0.0-beta.8
github.com/emersion/go-message v0.18.2
github.com/godbus/dbus/v5 v5.2.2

2
go.sum
View file

@ -2,6 +2,8 @@ gitea.lclr.dev/AI/mcp-framework v1.3.1 h1:GxT5bV22+hbLLUz2IMCscb3qLdkqX5u9d1dbHn
gitea.lclr.dev/AI/mcp-framework v1.3.1/go.mod h1:kUVMrL3/UBYgjOsW7sJCs3V0pO0qoJJMpIpueoTsoA4=
gitea.lclr.dev/AI/mcp-framework v1.3.2 h1:BCfr77B9cmbSytC4ORPfCGjtgldUotbmzvdBQhKHF9o=
gitea.lclr.dev/AI/mcp-framework v1.3.2/go.mod h1:kUVMrL3/UBYgjOsW7sJCs3V0pO0qoJJMpIpueoTsoA4=
gitea.lclr.dev/AI/mcp-framework v1.4.0-rc1 h1:zwggfzUBlhgQEh999YUfEe3pk8VXoL+8Ht+8tIoVfNY=
gitea.lclr.dev/AI/mcp-framework v1.4.0-rc1/go.mod h1:kUVMrL3/UBYgjOsW7sJCs3V0pO0qoJJMpIpueoTsoA4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=

282
install.sh Executable file
View file

@ -0,0 +1,282 @@
#!/usr/bin/env bash
set -euo pipefail
BINARY_NAME="email-mcp"
DEFAULT_PROFILE="default"
PROFILE_ENV="EMAIL_MCP_PROFILE"
RELEASE_BASE_URL="https://gitea.lclr.dev"
RELEASE_REPOSITORY="AI/email-mcp"
prompt() {
local label="$1"
local default_value="$2"
local answer=""
if [ -n "$default_value" ]; then
printf "%s [%s]: " "$label" "$default_value"
else
printf "%s: " "$label"
fi
if [ -r /dev/tty ]; then
IFS= read -r answer < /dev/tty || answer=""
else
IFS= read -r answer || answer=""
fi
if [ -z "$answer" ]; then
printf "%s" "$default_value"
return
fi
printf "%s" "$answer"
}
detect_os() {
case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
linux) printf "linux" ;;
darwin) printf "darwin" ;;
*)
printf "OS non supporté: %s\n" "$(uname -s)" >&2
exit 1
;;
esac
}
detect_arch() {
case "$(uname -m)" in
x86_64|amd64) printf "amd64" ;;
aarch64|arm64) printf "arm64" ;;
*)
printf "Architecture non supportée: %s\n" "$(uname -m)" >&2
exit 1
;;
esac
}
release_api_url() {
printf "%s/api/v1/repos/%s/releases/latest\n" "${RELEASE_BASE_URL%/}" "$RELEASE_REPOSITORY"
}
extract_asset_url() {
local json="$1"
local asset_name="$2"
printf "%s\n" "$json" \
| grep -o '"browser_download_url":"[^"]*"' \
| sed 's/"browser_download_url":"//;s/"$//' \
| sed 's#\\/#/#g' \
| grep "/${asset_name}$" \
| head -n 1
}
go_bin_dir() {
local gobin
gobin="$(go env GOBIN 2>/dev/null || true)"
if [ -n "$gobin" ]; then
printf "%s\n" "$gobin"
return
fi
go env GOPATH 2>/dev/null | awk '{print $1 "/bin"}'
}
resolve_binary_path() {
if command -v "$BINARY_NAME" >/dev/null 2>&1; then
command -v "$BINARY_NAME"
return
fi
if command -v go >/dev/null 2>&1; then
local bin_dir
bin_dir="$(go_bin_dir)"
if [ -n "$bin_dir" ] && [ -x "$bin_dir/$BINARY_NAME" ]; then
printf "%s\n" "$bin_dir/$BINARY_NAME"
return
fi
fi
printf "%s\n" "$HOME/.local/bin/$BINARY_NAME"
}
verify_checksum() {
local binary_path="$1"
local checksum_path="$2"
if command -v sha256sum >/dev/null 2>&1; then
( cd "$(dirname "$binary_path")" && sha256sum -c "$(basename "$checksum_path")" )
return
fi
if command -v shasum >/dev/null 2>&1; then
local expected
local actual
expected="$(awk '{print $1}' "$checksum_path")"
actual="$(shasum -a 256 "$binary_path" | awk '{print $1}')"
if [ "$expected" != "$actual" ]; then
printf "Checksum invalide pour %s\n" "$binary_path" >&2
exit 1
fi
return
fi
printf "Aucun utilitaire de checksum trouvé (sha256sum/shasum), vérification ignorée.\n" >&2
}
download_latest_release_binary() {
if ! command -v curl >/dev/null 2>&1; then
printf "curl est requis pour télécharger la release.\n" >&2
exit 1
fi
local os_name
local arch_name
local ext=""
os_name="$(detect_os)"
arch_name="$(detect_arch)"
if [ "$os_name" = "windows" ]; then
ext=".exe"
fi
local asset_name
local checksum_name
asset_name="${BINARY_NAME}-${os_name}-${arch_name}${ext}"
checksum_name="${asset_name}.sha256"
printf "Récupération de la dernière release...\n"
local release_json
release_json="$(curl -fsSL "$(release_api_url)")"
local asset_url
asset_url="$(extract_asset_url "$release_json" "$asset_name")"
if [ -z "$asset_url" ]; then
printf "Asset introuvable dans la dernière release: %s\n" "$asset_name" >&2
exit 1
fi
local checksum_url
checksum_url="$(extract_asset_url "$release_json" "$checksum_name" || true)"
local tmp_dir
tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT INT TERM
curl -fsSL "$asset_url" -o "$tmp_dir/$asset_name"
chmod +x "$tmp_dir/$asset_name"
if [ -n "$checksum_url" ]; then
curl -fsSL "$checksum_url" -o "$tmp_dir/$checksum_name"
verify_checksum "$tmp_dir/$asset_name" "$tmp_dir/$checksum_name"
fi
local target_dir
target_dir="$(prompt "Répertoire d'installation" "$HOME/.local/bin")"
mkdir -p "$target_dir"
install -m 0755 "$tmp_dir/$asset_name" "$target_dir/$BINARY_NAME"
printf "Binaire installé: %s/%s\n" "$target_dir" "$BINARY_NAME"
printf "Ajoute ce dossier au PATH si nécessaire.\n"
}
install_binary() {
if command -v "$BINARY_NAME" >/dev/null 2>&1; then
printf "Binaire détecté: %s\n" "$(command -v "$BINARY_NAME")"
local reinstall
reinstall="$(prompt "Forcer une réinstallation depuis la dernière release ? (y/N)" "N")"
case "$reinstall" in
y|Y|yes|YES)
download_latest_release_binary
;;
*)
return
;;
esac
return
fi
download_latest_release_binary
}
run_setup_wizard() {
install_binary
local profile
profile="$(prompt "Profil à configurer (${PROFILE_ENV})" "$DEFAULT_PROFILE")"
local binary_path
binary_path="$(resolve_binary_path)"
printf "Lancement de %s setup...\n\n" "$BINARY_NAME"
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
env "${PROFILE_ENV}=${profile}" "$binary_path" setup < /dev/tty > /dev/tty
else
env "${PROFILE_ENV}=${profile}" "$binary_path" setup
fi
}
print_mcp_json() {
local profile
profile="$(prompt "Profil à exposer dans la config MCP (${PROFILE_ENV})" "$DEFAULT_PROFILE")"
local default_command
default_command="$(resolve_binary_path)"
local command_path
command_path="$(prompt "Commande du serveur MCP" "$default_command")"
cat <<JSON
{
"mcpServers": {
"${BINARY_NAME}": {
"command": "${command_path}",
"args": ["mcp"],
"env": {
"${PROFILE_ENV}": "${profile}"
}
}
}
}
JSON
}
print_header() {
cat <<TXT
===========================================================
Installateur MCP pour ${BINARY_NAME}
===========================================================
Choisis une action :
1) Installer le binaire + lancer le setup
2) Générer un JSON de config MCP (Codex)
3) Générer un JSON de config MCP (Claude Desktop)
4) Générer un JSON de config MCP (autre client)
5) Quitter
TXT
}
main() {
while true; do
print_header
local choice
choice="$(prompt "Choix" "1")"
printf "\n"
case "$choice" in
1)
run_setup_wizard
printf "\nInstallation terminée.\n"
return
;;
2|3|4)
printf "Copie ce JSON dans la config MCP du client ciblé.\n\n"
print_mcp_json
return
;;
5)
printf "Annulé.\n"
return
;;
*)
printf "Choix invalide: %s\n\n" "$choice" >&2
;;
esac
done
}
main "$@"