feat: upgrade framework to v1.4.0-rc1 with installer script
This commit is contained in:
parent
7315f2658c
commit
647a03a10c
4 changed files with 299 additions and 1 deletions
14
README.md
14
README.md
|
|
@ -153,6 +153,20 @@ Pour l’update, la validation du manifeste accepte :
|
|||
|
||||
## Installation
|
||||
|
||||
### Installateur interactif
|
||||
|
||||
Le repo inclut un assistant interactif `install.sh` :
|
||||
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
Tu peux aussi l’exé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
2
go.mod
|
|
@ -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
2
go.sum
|
|
@ -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
282
install.sh
Executable 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 "$@"
|
||||
Loading…
Reference in a new issue