Expose tm mcp tools against the local daemon, document agent setup, and ignore workspace .tm_token files. Co-authored-by: Cursor <cursoragent@cursor.com>
80 lines
1.7 KiB
Go
80 lines
1.7 KiB
Go
package mcp
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
const tokenFileName = ".tm_token"
|
|
|
|
// TokenFile holds credentials from a workspace .tm_token file.
|
|
type TokenFile struct {
|
|
Project string
|
|
Token string
|
|
Path string
|
|
}
|
|
|
|
// FindTokenFile walks from start (usually cwd) upward looking for .tm_token.
|
|
func FindTokenFile(start string) (TokenFile, error) {
|
|
dir, err := filepath.Abs(start)
|
|
if err != nil {
|
|
return TokenFile{}, err
|
|
}
|
|
for {
|
|
path := filepath.Join(dir, tokenFileName)
|
|
if st, err := os.Stat(path); err == nil && !st.IsDir() {
|
|
tf, err := ParseTokenFile(path)
|
|
if err != nil {
|
|
return TokenFile{}, err
|
|
}
|
|
return tf, nil
|
|
}
|
|
parent := filepath.Dir(dir)
|
|
if parent == dir {
|
|
break
|
|
}
|
|
dir = parent
|
|
}
|
|
return TokenFile{}, fmt.Errorf("no %s found (create an MCP token in the TUI with g, then place project=… and token=… in %s)", tokenFileName, tokenFileName)
|
|
}
|
|
|
|
// ParseTokenFile reads project= and token= lines from path.
|
|
func ParseTokenFile(path string) (TokenFile, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return TokenFile{}, err
|
|
}
|
|
defer f.Close()
|
|
|
|
tf := TokenFile{Path: path}
|
|
sc := bufio.NewScanner(f)
|
|
for sc.Scan() {
|
|
line := strings.TrimSpace(sc.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
key, val, ok := strings.Cut(line, "=")
|
|
if !ok {
|
|
continue
|
|
}
|
|
key = strings.TrimSpace(strings.ToLower(key))
|
|
val = strings.TrimSpace(val)
|
|
switch key {
|
|
case "project":
|
|
tf.Project = val
|
|
case "token":
|
|
tf.Token = val
|
|
}
|
|
}
|
|
if err := sc.Err(); err != nil {
|
|
return TokenFile{}, err
|
|
}
|
|
if tf.Project == "" || tf.Token == "" {
|
|
return TokenFile{}, fmt.Errorf("%s must contain project= and token= lines", path)
|
|
}
|
|
return tf, nil
|
|
}
|