@tpsdev-ai/flair-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +118 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @tpsdev-ai/flair-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for [Flair](https://tps.dev/#flair) — persistent memory for Claude Code, Cursor, and any MCP client.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Claude Code
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Add to your project's .mcp.json
|
|
11
|
+
cat > .mcp.json << 'EOF'
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"flair": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["@tpsdev-ai/flair-mcp"],
|
|
17
|
+
"env": {
|
|
18
|
+
"FLAIR_AGENT_ID": "my-project"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
EOF
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or install globally and configure once in `~/.claude/settings.json`.
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
You need a running Flair instance:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install -g @tpsdev-ai/flair
|
|
34
|
+
flair init
|
|
35
|
+
flair agent add my-project
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Tools
|
|
39
|
+
|
|
40
|
+
Once configured, Claude Code (or any MCP client) gets these tools:
|
|
41
|
+
|
|
42
|
+
| Tool | Description |
|
|
43
|
+
|------|-------------|
|
|
44
|
+
| `memory_search` | Semantic search across memories. Understands "what happened today". |
|
|
45
|
+
| `memory_store` | Save a memory with type (lesson/decision/fact) and durability. |
|
|
46
|
+
| `memory_get` | Retrieve a specific memory by ID. |
|
|
47
|
+
| `memory_delete` | Delete a memory. |
|
|
48
|
+
| `bootstrap` | Cold-start context — soul + recent memories in one call. |
|
|
49
|
+
| `soul_set` | Set personality or project context (included in every bootstrap). |
|
|
50
|
+
| `soul_get` | Get a personality or project context entry. |
|
|
51
|
+
|
|
52
|
+
## Environment Variables
|
|
53
|
+
|
|
54
|
+
| Variable | Default | Description |
|
|
55
|
+
|----------|---------|-------------|
|
|
56
|
+
| `FLAIR_AGENT_ID` | *(required)* | Agent identity for memory scoping |
|
|
57
|
+
| `FLAIR_URL` | `http://localhost:9926` | Flair server URL |
|
|
58
|
+
| `FLAIR_KEY_PATH` | auto-resolved | Path to Ed25519 private key |
|
|
59
|
+
|
|
60
|
+
## How It Works
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Claude Code ↔ stdio ↔ flair-mcp ↔ HTTP ↔ Flair (Harper)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The MCP server is a thin wrapper around `@tpsdev-ai/flair-client`. All memory is stored in your local Flair instance with Ed25519 authentication. Nothing leaves your machine unless you point `FLAIR_URL` at a remote server.
|
|
67
|
+
|
|
68
|
+
## Remote Flair
|
|
69
|
+
|
|
70
|
+
Point to a remote Flair instance:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"flair": {
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["@tpsdev-ai/flair-mcp"],
|
|
78
|
+
"env": {
|
|
79
|
+
"FLAIR_AGENT_ID": "my-project",
|
|
80
|
+
"FLAIR_URL": "http://your-server:9926"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Copy your key from the server: `scp server:~/.flair/keys/my-project.key ~/.flair/keys/`
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
[Apache 2.0](../../LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Flair MCP Server — persistent memory for Claude Code and any MCP client.
|
|
4
|
+
*
|
|
5
|
+
* Tools:
|
|
6
|
+
* - memory_search — semantic search across memories
|
|
7
|
+
* - memory_store — save a memory with type + durability
|
|
8
|
+
* - memory_get — retrieve a specific memory by ID
|
|
9
|
+
* - memory_delete — delete a memory
|
|
10
|
+
* - bootstrap — cold-start context (soul + recent memories)
|
|
11
|
+
* - soul_set — set a personality/context entry
|
|
12
|
+
* - soul_get — get a personality/context entry
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* npx @tpsdev-ai/flair-mcp
|
|
16
|
+
*
|
|
17
|
+
* Claude Code .mcp.json:
|
|
18
|
+
* { "mcpServers": { "flair": { "command": "npx", "args": ["@tpsdev-ai/flair-mcp"] } } }
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Flair MCP Server — persistent memory for Claude Code and any MCP client.
|
|
4
|
+
*
|
|
5
|
+
* Tools:
|
|
6
|
+
* - memory_search — semantic search across memories
|
|
7
|
+
* - memory_store — save a memory with type + durability
|
|
8
|
+
* - memory_get — retrieve a specific memory by ID
|
|
9
|
+
* - memory_delete — delete a memory
|
|
10
|
+
* - bootstrap — cold-start context (soul + recent memories)
|
|
11
|
+
* - soul_set — set a personality/context entry
|
|
12
|
+
* - soul_get — get a personality/context entry
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* npx @tpsdev-ai/flair-mcp
|
|
16
|
+
*
|
|
17
|
+
* Claude Code .mcp.json:
|
|
18
|
+
* { "mcpServers": { "flair": { "command": "npx", "args": ["@tpsdev-ai/flair-mcp"] } } }
|
|
19
|
+
*/
|
|
20
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
22
|
+
import { FlairClient } from "@tpsdev-ai/flair-client";
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
// ─── Client setup ────────────────────────────────────────────────────────────
|
|
25
|
+
const agentId = process.env.FLAIR_AGENT_ID;
|
|
26
|
+
if (!agentId) {
|
|
27
|
+
console.error("FLAIR_AGENT_ID is required. Set it in your .mcp.json env or shell.");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const flair = new FlairClient({
|
|
31
|
+
agentId,
|
|
32
|
+
url: process.env.FLAIR_URL,
|
|
33
|
+
keyPath: process.env.FLAIR_KEY_PATH,
|
|
34
|
+
});
|
|
35
|
+
// ─── MCP Server ──────────────────────────────────────────────────────────────
|
|
36
|
+
const server = new McpServer({
|
|
37
|
+
name: "flair",
|
|
38
|
+
version: "0.1.0",
|
|
39
|
+
});
|
|
40
|
+
// ─── Tools ───────────────────────────────────────────────────────────────────
|
|
41
|
+
server.tool("memory_search", "Search memories by meaning. Understands temporal queries like 'what happened today'.", {
|
|
42
|
+
query: z.string().describe("Search query — natural language, semantic matching"),
|
|
43
|
+
limit: z.number().optional().default(5).describe("Max results (default 5)"),
|
|
44
|
+
}, async ({ query, limit }) => {
|
|
45
|
+
const results = await flair.memory.search(query, { limit });
|
|
46
|
+
if (results.length === 0) {
|
|
47
|
+
return { content: [{ type: "text", text: "No relevant memories found." }] };
|
|
48
|
+
}
|
|
49
|
+
const text = results
|
|
50
|
+
.map((r, i) => {
|
|
51
|
+
const date = r.createdAt ? r.createdAt.slice(0, 10) : "";
|
|
52
|
+
const meta = [date, r.type, r.durability].filter(Boolean).join(", ");
|
|
53
|
+
return `${i + 1}. ${r.content}${meta ? ` (${meta})` : ""}`;
|
|
54
|
+
})
|
|
55
|
+
.join("\n");
|
|
56
|
+
return { content: [{ type: "text", text }] };
|
|
57
|
+
});
|
|
58
|
+
server.tool("memory_store", "Save information to persistent memory. Use for lessons, decisions, preferences, facts.", {
|
|
59
|
+
content: z.string().describe("What to remember"),
|
|
60
|
+
type: z.enum(["session", "lesson", "decision", "preference", "fact", "goal"]).optional().default("session"),
|
|
61
|
+
durability: z.enum(["permanent", "persistent", "standard", "ephemeral"]).optional().default("standard")
|
|
62
|
+
.describe("permanent=inviolable, persistent=key decisions, standard=default, ephemeral=auto-expires 72h"),
|
|
63
|
+
tags: z.array(z.string()).optional().describe("Optional tags for categorization"),
|
|
64
|
+
}, async ({ content, type, durability, tags }) => {
|
|
65
|
+
const result = await flair.memory.write(content, {
|
|
66
|
+
type: type,
|
|
67
|
+
durability: durability,
|
|
68
|
+
tags,
|
|
69
|
+
dedup: true,
|
|
70
|
+
dedupThreshold: 0.7,
|
|
71
|
+
});
|
|
72
|
+
const wasDeduped = !result.id?.startsWith(`${agentId}-`);
|
|
73
|
+
if (wasDeduped) {
|
|
74
|
+
return { content: [{ type: "text", text: `Similar memory already exists (id: ${result.id}): ${result.content?.slice(0, 200)}` }] };
|
|
75
|
+
}
|
|
76
|
+
return { content: [{ type: "text", text: `Memory stored (id: ${result.id})` }] };
|
|
77
|
+
});
|
|
78
|
+
server.tool("memory_get", "Retrieve a specific memory by ID.", {
|
|
79
|
+
id: z.string().describe("Memory ID"),
|
|
80
|
+
}, async ({ id }) => {
|
|
81
|
+
const mem = await flair.memory.get(id);
|
|
82
|
+
if (!mem)
|
|
83
|
+
return { content: [{ type: "text", text: `Memory ${id} not found.` }] };
|
|
84
|
+
return { content: [{ type: "text", text: `${mem.content}\n\n(type: ${mem.type}, durability: ${mem.durability}, created: ${mem.createdAt})` }] };
|
|
85
|
+
});
|
|
86
|
+
server.tool("memory_delete", "Delete a memory by ID.", {
|
|
87
|
+
id: z.string().describe("Memory ID to delete"),
|
|
88
|
+
}, async ({ id }) => {
|
|
89
|
+
await flair.memory.delete(id);
|
|
90
|
+
return { content: [{ type: "text", text: `Memory ${id} deleted.` }] };
|
|
91
|
+
});
|
|
92
|
+
server.tool("bootstrap", "Get cold-start context: soul + recent memories. Run this at the start of every session.", {
|
|
93
|
+
maxTokens: z.number().optional().default(4000).describe("Max tokens in output"),
|
|
94
|
+
}, async ({ maxTokens }) => {
|
|
95
|
+
const result = await flair.bootstrap({ maxTokens });
|
|
96
|
+
if (!result.context) {
|
|
97
|
+
return { content: [{ type: "text", text: "No context available." }] };
|
|
98
|
+
}
|
|
99
|
+
return { content: [{ type: "text", text: result.context }] };
|
|
100
|
+
});
|
|
101
|
+
server.tool("soul_set", "Set a personality or project context entry. Included in every bootstrap.", {
|
|
102
|
+
key: z.string().describe("Entry key (e.g., 'role', 'standards', 'project')"),
|
|
103
|
+
value: z.string().describe("Entry value — personality trait, project context, coding standards, etc."),
|
|
104
|
+
}, async ({ key, value }) => {
|
|
105
|
+
await flair.soul.set(key, value);
|
|
106
|
+
return { content: [{ type: "text", text: `Soul entry '${key}' set.` }] };
|
|
107
|
+
});
|
|
108
|
+
server.tool("soul_get", "Get a personality or project context entry.", {
|
|
109
|
+
key: z.string().describe("Entry key"),
|
|
110
|
+
}, async ({ key }) => {
|
|
111
|
+
const entry = await flair.soul.get(key);
|
|
112
|
+
if (!entry)
|
|
113
|
+
return { content: [{ type: "text", text: `No soul entry for '${key}'.` }] };
|
|
114
|
+
return { content: [{ type: "text", text: entry.value }] };
|
|
115
|
+
});
|
|
116
|
+
// ─── Start ───────────────────────────────────────────────────────────────────
|
|
117
|
+
const transport = new StdioServerTransport();
|
|
118
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tpsdev-ai/flair-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Flair — persistent memory for Claude Code, Cursor, and any MCP client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"flair-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc --noCheck",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
27
|
+
"@tpsdev-ai/flair-client": "^0.2.0",
|
|
28
|
+
"zod": "^4.3.6"
|
|
29
|
+
},
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/tpsdev-ai/flair.git",
|
|
34
|
+
"directory": "packages/flair-mcp"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://tps.dev/#flair",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"flair",
|
|
39
|
+
"mcp",
|
|
40
|
+
"claude",
|
|
41
|
+
"claude-code",
|
|
42
|
+
"cursor",
|
|
43
|
+
"memory",
|
|
44
|
+
"ai",
|
|
45
|
+
"agent"
|
|
46
|
+
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^24.11.0"
|
|
49
|
+
}
|
|
50
|
+
}
|