docs: explain how to use the framework
This commit is contained in:
parent
867d761f5c
commit
2bda5459d6
1 changed files with 237 additions and 10 deletions
247
README.md
247
README.md
|
|
@ -8,19 +8,39 @@ Bibliotheque Go pour construire des binaires MCP avec :
|
|||
- lecture d'un manifeste `mcp.toml` a la racine du projet
|
||||
- pipeline d'auto-update via endpoint de release configurable
|
||||
|
||||
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 framework est volontairement petit. Il fournit des briques reutilisables,
|
||||
pas une application MCP complete.
|
||||
|
||||
Packages exposes :
|
||||
## Installation
|
||||
|
||||
- `cli`
|
||||
- `config`
|
||||
- `manifest`
|
||||
- `secretstore`
|
||||
- `update`
|
||||
```bash
|
||||
go get gitea.lclr.dev/AI/mcp-framework
|
||||
```
|
||||
|
||||
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
|
||||
[update]
|
||||
|
|
@ -30,3 +50,210 @@ latest_release_url = "https://gitea.example.com/api/v1/repos/org/repo/releases/l
|
|||
token_header = "Authorization"
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue