feat(mcp): mint-token CLI + get_card / delete_comment tools + executeToolAs(actor)
Net-new capacidades recuperadas del WIP stash que el merge notif no traia: - mint-token CLI subcommand: 'kanban mint-token --user <id> --name <pc>' genera token bearer para configurar Claude Code u otros clientes MCP HTTP sin tocar la UI. - executeToolAs(db, name, input, actor): variante actor-aware de executeTool. El dispatcher HTTP /mcp pasa el user_id resuelto del bearer token; tools per-user (add_comment, delete_comment) lo usan como autor sin que el llamante pueda forjarlo. - get_card tool: lookup por id o seq_num. Devuelve Card completa. - delete_comment tool: borra card_message; solo el autor original (validado en DB). executeTool() sigue siendo el wrapper legacy sin actor para chat WS.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -130,3 +131,44 @@ func generateMCPTokenPlaintext() (string, error) {
|
||||
}
|
||||
return mcpTokenPrefix + hex.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// runMintToken implements `kanban mint-token --user <id> --name <pc>`.
|
||||
// Generates a fresh token, persists its sha256 in mcp_tokens, and prints the
|
||||
// plaintext ONCE to stdout. The caller must save it — the server keeps only
|
||||
// the hash.
|
||||
func runMintToken(args []string) error {
|
||||
fs := flag.NewFlagSet("kanban mint-token", flag.ContinueOnError)
|
||||
dbPath := fs.String("db", "operations.db", "SQLite database path")
|
||||
userID := fs.String("user", "", "owner user_id (must exist in users table)")
|
||||
name := fs.String("name", "", "label for this token (e.g. PC name)")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
if *userID == "" || *name == "" {
|
||||
return fmt.Errorf("--user and --name required")
|
||||
}
|
||||
|
||||
db, err := openDB(*dbPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open db: %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
var exists int
|
||||
if err := db.conn.QueryRow(`SELECT COUNT(*) FROM users WHERE id=?`, *userID).Scan(&exists); err != nil {
|
||||
return fmt.Errorf("user lookup: %w", err)
|
||||
}
|
||||
if exists == 0 {
|
||||
return fmt.Errorf("user %q not found", *userID)
|
||||
}
|
||||
|
||||
plaintext, tok, err := db.MintMCPToken(*userID, *name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("mint: %w", err)
|
||||
}
|
||||
fmt.Printf("token id: %s\n", tok.ID)
|
||||
fmt.Printf("name: %s\n", tok.Name)
|
||||
fmt.Printf("created_at: %s\n", tok.CreatedAt)
|
||||
fmt.Printf("\ntoken (save now, will not be shown again):\n%s\n", plaintext)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user