prepared last tool
This commit is contained in:
1 parent
8fa9d43530
commit
a65d39cea0
2 files changed
+116
No files matched your search
@@ -58,6 +58,7 @@ func main() {
|
|||||||
|
|
||||||
registerStoreFlashcard(mcpServer, store, searchEngine, logger)
|
registerStoreFlashcard(mcpServer, store, searchEngine, logger)
|
||||||
registerSearchFlashcard(mcpServer, searchEngine)
|
registerSearchFlashcard(mcpServer, searchEngine)
|
||||||
|
registerListRecentFlashcard(mcpServer, store, logger)
|
||||||
registerUpdateFlashcard(mcpServer, store, searchEngine, logger)
|
registerUpdateFlashcard(mcpServer, store, searchEngine, logger)
|
||||||
registerDeleteFlashcard(mcpServer, store, searchEngine, logger)
|
registerDeleteFlashcard(mcpServer, store, searchEngine, logger)
|
||||||
registerVoteFlashcard(mcpServer, store, logger)
|
registerVoteFlashcard(mcpServer, store, logger)
|
||||||
@@ -245,6 +246,65 @@ func registerSearchFlashcard(mcpServer *server.MCPServer, engine SearchEngine) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerListRecentFlashcard(mcpServer *server.MCPServer, sqlite *sqliteStore, logger *zap.Logger) {
|
||||||
|
mcpServer.AddTool(
|
||||||
|
mcp.NewTool("list_recent_flashcards",
|
||||||
|
mcp.WithDescription("List recently created flashcards, optionally filtered by tag, repo, or host. Use this at the start of a session to recall what was learned recently."),
|
||||||
|
mcp.WithNumber("limit",
|
||||||
|
mcp.Description("Maximum number of results to return (default: 20)"),
|
||||||
|
),
|
||||||
|
mcp.WithString("tag",
|
||||||
|
mcp.Description("Filter by tag (e.g. 'preference', 'convention')"),
|
||||||
|
),
|
||||||
|
mcp.WithString("repo",
|
||||||
|
mcp.Description("Filter by repository name (e.g. 'st-pierre', 'loopagent')"),
|
||||||
|
),
|
||||||
|
mcp.WithString("host",
|
||||||
|
mcp.Description("Filter by hostname (e.g. 'shulgi')"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
handleListRecentFlashcard(sqlite, logger),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleListRecentFlashcard(sqlite *sqliteStore, logger *zap.Logger) server.ToolHandlerFunc {
|
||||||
|
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
|
args, ok := request.Params.Arguments.(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return mcp.NewToolResultError("invalid arguments"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := parseOptionalString(args["tag"])
|
||||||
|
repo := parseOptionalString(args["repo"])
|
||||||
|
host := parseOptionalString(args["host"])
|
||||||
|
|
||||||
|
limit := uint64(20)
|
||||||
|
if rawLimit := args["limit"]; rawLimit != nil {
|
||||||
|
switch v := rawLimit.(type) {
|
||||||
|
case float64:
|
||||||
|
limit = uint64(v)
|
||||||
|
case int:
|
||||||
|
limit = uint64(v)
|
||||||
|
case int64:
|
||||||
|
limit = uint64(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := sqlite.listRecent(ctx, tag, repo, host, limit)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("list recent failed", zap.Error(err))
|
||||||
|
return mcp.NewToolResultError(fmt.Sprintf("list recent failed: %v", err)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := json.MarshalIndent(entries, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return mcp.NewToolResultError(fmt.Sprintf("failed to marshal results: %v", err)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return mcp.NewToolResultText(string(output)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func registerUpdateFlashcard(mcpServer *server.MCPServer, sqlite *sqliteStore, engine SearchEngine, logger *zap.Logger) {
|
func registerUpdateFlashcard(mcpServer *server.MCPServer, sqlite *sqliteStore, engine SearchEngine, logger *zap.Logger) {
|
||||||
mcpServer.AddTool(
|
mcpServer.AddTool(
|
||||||
mcp.NewTool("update_flashcard",
|
mcp.NewTool("update_flashcard",
|
||||||
|
|||||||
@@ -364,6 +364,62 @@ func (s *sqliteStore) searchFTS(ctx context.Context, query string, limit uint64)
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *sqliteStore) listRecent(ctx context.Context, tag, repo, host string, limit uint64) ([]flashcardSummary, error) {
|
||||||
|
if limit == 0 {
|
||||||
|
limit = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
q := `SELECT f.public_id, f.version, f.note, f.host, f.user, f.tags, f.repos, f.created
|
||||||
|
FROM flashcard f
|
||||||
|
WHERE f.version = (SELECT MAX(f2.version) FROM flashcard f2 WHERE f2.public_id = f.public_id)
|
||||||
|
AND f.delete_timestamp IS NULL
|
||||||
|
AND f.public_id != 0`
|
||||||
|
var args []any
|
||||||
|
|
||||||
|
if tag != "" {
|
||||||
|
q += ` AND f.tags LIKE ?`
|
||||||
|
args = append(args, `%"`+tag+`"%`)
|
||||||
|
}
|
||||||
|
if repo != "" {
|
||||||
|
q += ` AND f.repos LIKE ?`
|
||||||
|
args = append(args, `%"`+repo+`"%`)
|
||||||
|
}
|
||||||
|
if host != "" {
|
||||||
|
q += ` AND f.host = ?`
|
||||||
|
args = append(args, host)
|
||||||
|
}
|
||||||
|
|
||||||
|
q += ` ORDER BY f.created DESC LIMIT ?`
|
||||||
|
args = append(args, limit)
|
||||||
|
|
||||||
|
rows, err := s.db.QueryContext(ctx, q, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("list recent: %w", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var summaries []flashcardSummary
|
||||||
|
for rows.Next() {
|
||||||
|
var s flashcardSummary
|
||||||
|
var tagsJSON, reposJSON *string
|
||||||
|
if err := rows.Scan(&s.PublicID, &s.Version, &s.Note, &s.Host, &s.User, &tagsJSON, &reposJSON, &s.Created); err != nil {
|
||||||
|
return nil, fmt.Errorf("scan: %w", err)
|
||||||
|
}
|
||||||
|
if tagsJSON != nil {
|
||||||
|
json.Unmarshal([]byte(*tagsJSON), &s.Tags)
|
||||||
|
}
|
||||||
|
if reposJSON != nil {
|
||||||
|
json.Unmarshal([]byte(*reposJSON), &s.Repos)
|
||||||
|
}
|
||||||
|
s.URL = fmt.Sprintf("/api/v1/flashcards/%d", s.PublicID)
|
||||||
|
summaries = append(summaries, s)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("rows: %w", err)
|
||||||
|
}
|
||||||
|
return summaries, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *sqliteStore) close() error {
|
func (s *sqliteStore) close() error {
|
||||||
return s.db.Close()
|
return s.db.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user