docs: explain how to use the framework

This commit is contained in:
thibaud-leclere 2026-04-13 15:53:53 +02:00
parent 867d761f5c
commit 2bda5459d6

247
README.md
View file

@ -8,19 +8,39 @@ Bibliotheque Go pour construire des binaires MCP avec :
- lecture d'un manifeste `mcp.toml` a la racine du projet - lecture d'un manifeste `mcp.toml` a la racine du projet
- pipeline d'auto-update via endpoint de release configurable - pipeline d'auto-update via endpoint de release configurable
Le package `update` ne deduit pas la forge ni l'authentification. Le framework est volontairement petit. Il fournit des briques reutilisables,
L'application cliente fournit l'URL de release, le header d'auth eventuel et, pas une application MCP complete.
si besoin, les variables d'environnement a consulter.
Packages exposes : ## Installation
- `cli` ```bash
- `config` go get gitea.lclr.dev/AI/mcp-framework
- `manifest` ```
- `secretstore`
- `update`
Exemple minimal de `mcp.toml` : ## Packages
- `cli` : helpers pour resoudre un profil, valider une URL et demander des valeurs a l'utilisateur.
- `config` : lecture/ecriture atomique d'une config JSON versionnee dans `os.UserConfigDir()`.
- `manifest` : lecture de `mcp.toml` a la racine du projet et conversion vers `update.ReleaseSource`.
- `secretstore` : lecture/ecriture de secrets dans le wallet natif.
- `update` : telechargement et remplacement du binaire courant depuis un endpoint de release.
## Usage Type
Le flux typique cote application est :
1. Resoudre le profil actif avec `cli`.
2. Charger la config versionnee avec `config`.
3. Lire les secrets avec `secretstore`.
4. Charger `mcp.toml` avec `manifest`.
5. Executer l'auto-update avec `update` si necessaire.
## Manifeste `mcp.toml`
Le package `manifest` cherche automatiquement `mcp.toml` dans le repertoire
courant puis remonte les repertoires parents jusqu'a trouver le fichier.
Exemple minimal :
```toml ```toml
[update] [update]
@ -30,3 +50,210 @@ latest_release_url = "https://gitea.example.com/api/v1/repos/org/repo/releases/l
token_header = "Authorization" token_header = "Authorization"
token_env_names = ["GITEA_TOKEN"] token_env_names = ["GITEA_TOKEN"]
``` ```
Champs supportes dans `[update]` :
- `source_name` : nom humain de la source de release, utilise dans certains messages d'erreur.
- `base_url` : base de la forge ou du service de release.
- `latest_release_url` : URL complete qui retourne la release la plus recente.
- `token_header` : header HTTP a utiliser pour l'authentification.
- `token_env_names` : liste de variables d'environnement candidates pour retrouver le token.
Exemple de chargement :
```go
file, path, err := manifest.LoadDefault(".")
if err != nil {
return err
}
fmt.Printf("manifest loaded from %s\n", path)
source := file.Update.ReleaseSource()
```
## Config JSON
Le package `config` stocke une structure generique par profil dans un JSON prive
pour l'utilisateur courant.
Exemple :
```go
type Profile struct {
BaseURL string `json:"base_url"`
APIKey string `json:"api_key"`
}
store := config.NewStore[Profile]("my-mcp")
cfg, path, err := store.LoadDefault()
if err != nil {
return err
}
profileName := cli.ResolveProfileName(flagProfile, os.Getenv("MY_MCP_PROFILE"), cfg.CurrentProfile)
profile := cfg.Profiles[profileName]
profile.BaseURL = "https://api.example.com"
cfg.CurrentProfile = profileName
cfg.Profiles[profileName] = profile
_, err = store.SaveDefault(cfg)
if err != nil {
return err
}
fmt.Printf("config saved to %s\n", path)
```
Notes :
- le fichier est cree avec des permissions `0600`
- le repertoire parent est force en `0700`
- l'ecriture est atomique via un fichier temporaire puis `rename`
- si le fichier n'existe pas, `Load` et `LoadDefault` retournent une config vide par defaut
## Secrets
Le package `secretstore` s'appuie sur le wallet natif du systeme :
- macOS : Keychain
- Linux : Secret Service ou KWallet selon l'environnement
- Windows : Credential Manager
Exemple :
```go
store, err := secretstore.Open(secretstore.Options{
ServiceName: "my-mcp",
})
if err != nil {
return err
}
if err := store.SetSecret("api-token", "My MCP API token", token); err != nil {
return err
}
token, err = store.GetSecret("api-token")
switch {
case err == nil:
// secret found
case errors.Is(err, secretstore.ErrNotFound):
// first run
default:
return err
}
```
## CLI Helpers
`cli` fournit des helpers simples pour les assistants interactifs :
```go
profileName := cli.ResolveProfileName(flagProfile, os.Getenv("MY_MCP_PROFILE"), cfg.CurrentProfile)
baseURL, err := cli.PromptLine(reader, os.Stdout, "Base URL", profile.BaseURL)
if err != nil {
return err
}
if err := cli.ValidateBaseURL(baseURL); err != nil {
return err
}
token, err := cli.PromptSecret(os.Stdin, os.Stdout, "API token", hasStoredSecret, storedToken)
if err != nil {
return err
}
```
## Auto-Update
Le package `update` ne deduit pas la forge ni l'authentification.
L'application cliente fournit l'URL de release, le header d'auth eventuel et,
si besoin, les variables d'environnement a consulter.
Le format attendu pour la reponse `latest release` est actuellement :
```json
{
"tag_name": "v1.2.3",
"assets": {
"links": [
{
"name": "my-mcp-linux-amd64",
"url": "https://example.com/downloads/my-mcp-linux-amd64"
}
]
}
}
```
Exemple :
```go
file, _, err := manifest.LoadDefault(".")
if err != nil {
return err
}
err = update.Run(ctx, update.Options{
CurrentVersion: version,
BinaryName: "my-mcp",
ReleaseSource: file.Update.ReleaseSource(),
Stdout: os.Stdout,
})
if err != nil {
return err
}
```
Contraintes actuelles :
- le `latest_release_url` doit etre renseigne explicitement
- les assets supportes sont `darwin/amd64`, `darwin/arm64`, `linux/amd64` et `windows/amd64`
- le remplacement du binaire n'est pas supporte sur Windows
- le nom de l'asset est derive de `BinaryName`, `GOOS` et `GOARCH`
## Exemple Minimal
```go
type Profile struct {
BaseURL string `json:"base_url"`
}
func run(ctx context.Context, flagProfile string) error {
cfgStore := config.NewStore[Profile]("my-mcp")
cfg, _, err := cfgStore.LoadDefault()
if err != nil {
return err
}
profileName := cli.ResolveProfileName(flagProfile, os.Getenv("MY_MCP_PROFILE"), cfg.CurrentProfile)
profile := cfg.Profiles[profileName]
manifestFile, _, err := manifest.LoadDefault(".")
if err != nil {
return err
}
err = update.Run(ctx, update.Options{
CurrentVersion: version,
BinaryName: "my-mcp",
ReleaseSource: manifestFile.Update.ReleaseSource(),
})
if err != nil {
return err
}
_ = profile
return nil
}
```
## Limites Actuelles
- le manifeste gere uniquement la section `[update]`
- le framework ne fournit pas encore d'interface unique de bootstrap
- l'auto-update reste volontairement simple et ne supporte pas encore de scripts externes