Skip to content

Commit e043420

Browse files
alanshurafaclaude
andcommitted
[integrations] Thought management — update and delete tools
Add update_thought and delete_thought MCP tools as a remote Edge Function. Moved from extensions/ to integrations/ per maintainer review — extensions are curated and require approval. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 107b736 commit e043420

3 files changed

Lines changed: 223 additions & 0 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Thought Management Tools
2+
3+
> Update and delete MCP tools for managing existing thoughts in Open Brain.
4+
5+
## Overview
6+
7+
The core MCP server provides `capture_thought` for writing and `search_thoughts` for reading, but there's no way for your AI client to edit or remove thoughts. This integration adds two tools:
8+
9+
- **`update_thought`** — Edit a thought's content and automatically re-embed and re-classify
10+
- **`delete_thought`** — Remove a thought by ID
11+
12+
These are separate from the core server to keep the base install minimal. Add them when you need your AI to manage thoughts, not just capture them.
13+
14+
## Why You'd Want This
15+
16+
- Fix typos or inaccuracies in captured thoughts
17+
- Reclassify thoughts after reviewing them ("this isn't an idea, it's a task")
18+
- Remove thoughts that are no longer relevant, sensitive, or were captured in error
19+
- Let your AI maintain your second brain over time, not just append to it
20+
21+
## Prerequisites
22+
23+
- Open Brain deployed with the core MCP server
24+
- `OPENROUTER_API_KEY` set in Edge Function secrets
25+
- `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` available
26+
27+
## Setup
28+
29+
### Option A: Add to existing MCP server
30+
31+
Add these two tool registrations to your `server/index.ts`, after the existing tools:
32+
33+
```typescript
34+
// --- update_thought tool ---
35+
mcpServer.tool(
36+
"update_thought",
37+
"Update an existing thought's content. Re-embeds and re-classifies automatically.",
38+
{ id: z.string().uuid(), content: z.string() },
39+
async ({ id, content }) => {
40+
const [embedding, metadata] = await Promise.all([
41+
getEmbedding(content),
42+
extractMetadata(content),
43+
]);
44+
const { data, error } = await supabase
45+
.from("thoughts")
46+
.update({
47+
content,
48+
embedding,
49+
metadata: { ...metadata, source: "mcp", updated: true },
50+
updated_at: new Date().toISOString(),
51+
})
52+
.eq("id", id)
53+
.select("id, content, metadata")
54+
.single();
55+
if (error) return { content: [{ type: "text", text: `Error: ${error.message}` }] };
56+
return { content: [{ type: "text", text: `Updated thought ${data.id}` }] };
57+
}
58+
);
59+
60+
// --- delete_thought tool ---
61+
mcpServer.tool(
62+
"delete_thought",
63+
"Permanently delete a thought by ID.",
64+
{ id: z.string().uuid() },
65+
async ({ id }) => {
66+
const { error } = await supabase
67+
.from("thoughts")
68+
.delete()
69+
.eq("id", id);
70+
if (error) return { content: [{ type: "text", text: `Error: ${error.message}` }] };
71+
return { content: [{ type: "text", text: `Deleted thought ${id}` }] };
72+
}
73+
);
74+
```
75+
76+
### Option B: Deploy as separate Edge Function
77+
78+
See [`index.ts`](./index.ts) for the full standalone implementation.
79+
80+
## Deployment
81+
82+
1. Create the Edge Function:
83+
```bash
84+
supabase functions new thought-management
85+
```
86+
2. Copy `index.ts` into `supabase/functions/thought-management/index.ts`
87+
3. Deploy:
88+
```bash
89+
supabase functions deploy thought-management --no-verify-jwt
90+
```
91+
4. Connect in Claude Desktop: Settings → Connectors → Add custom connector → paste your function URL
92+
93+
## Expected Outcome
94+
95+
After setup, your AI client can:
96+
- Search for a thought, realize it's outdated, and update it in place
97+
- Remove duplicate or irrelevant thoughts
98+
- Reclassify thoughts (the update re-runs extractMetadata automatically)
99+
100+
> **Tool hygiene:** This integration adds MCP tools to your AI's context window. As you add more integrations, the total tool count grows. See the [MCP Tool Audit & Optimization Guide](../../docs/05-tool-audit.md) for strategies on managing your tool surface area.
101+
102+
## Troubleshooting
103+
104+
**Issue: "No rows updated" when updating**
105+
The thought ID may not exist. Use `search_thoughts` first to find valid IDs.
106+
107+
**Issue: Concerned about accidental deletion**
108+
Consider adding a soft-delete pattern (set a `deleted_at` timestamp instead of removing the row). The hard delete shown here is simpler but irreversible.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// supabase/functions/thought-management/index.ts
2+
import { Hono } from "hono";
3+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4+
import { StreamableHTTPTransport } from "@hono/mcp";
5+
import { createClient } from "@supabase/supabase-js";
6+
import { z } from "zod";
7+
8+
const supabase = createClient(
9+
Deno.env.get("SUPABASE_URL")!,
10+
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
11+
);
12+
13+
async function getEmbedding(text: string): Promise<number[]> {
14+
const res = await fetch("https://openrouter.ai/api/v1/embeddings", {
15+
method: "POST",
16+
headers: {
17+
"Authorization": `Bearer ${Deno.env.get("OPENROUTER_API_KEY")}`,
18+
"Content-Type": "application/json",
19+
},
20+
body: JSON.stringify({ model: "openai/text-embedding-3-small", input: text }),
21+
});
22+
const json = await res.json();
23+
return json.data[0].embedding;
24+
}
25+
26+
async function extractMetadata(text: string) {
27+
const res = await fetch("https://openrouter.ai/api/v1/chat/completions", {
28+
method: "POST",
29+
headers: {
30+
"Authorization": `Bearer ${Deno.env.get("OPENROUTER_API_KEY")}`,
31+
"Content-Type": "application/json",
32+
},
33+
body: JSON.stringify({
34+
model: "openai/gpt-4o-mini",
35+
messages: [{
36+
role: "system",
37+
content: "Extract metadata from this thought. Return JSON with: people (array), action_items (array), dates_mentioned (array), topics (array), type (one of: observation, task, idea, reference, person_note)."
38+
}, { role: "user", content: text }],
39+
response_format: { type: "json_object" },
40+
}),
41+
});
42+
const json = await res.json();
43+
try { return JSON.parse(json.choices[0].message.content); }
44+
catch { return { topics: ["uncategorized"], type: "observation" }; }
45+
}
46+
47+
const mcpServer = new McpServer({ name: "thought-management", version: "1.0.0" });
48+
49+
mcpServer.tool(
50+
"update_thought",
51+
"Update an existing thought's content. Re-embeds and re-classifies automatically.",
52+
{ id: z.string().uuid(), content: z.string() },
53+
async ({ id, content }) => {
54+
const [embedding, metadata] = await Promise.all([
55+
getEmbedding(content),
56+
extractMetadata(content),
57+
]);
58+
const { data, error } = await supabase
59+
.from("thoughts")
60+
.update({
61+
content,
62+
embedding,
63+
metadata: { ...metadata, source: "mcp", updated: true },
64+
updated_at: new Date().toISOString(),
65+
})
66+
.eq("id", id)
67+
.select("id, content, metadata")
68+
.single();
69+
if (error) return { content: [{ type: "text", text: `Error: ${error.message}` }] };
70+
return { content: [{ type: "text", text: `Updated thought ${data.id}` }] };
71+
}
72+
);
73+
74+
mcpServer.tool(
75+
"delete_thought",
76+
"Permanently delete a thought by ID.",
77+
{ id: z.string().uuid() },
78+
async ({ id }) => {
79+
const { error } = await supabase.from("thoughts").delete().eq("id", id);
80+
if (error) return { content: [{ type: "text", text: `Error: ${error.message}` }] };
81+
return { content: [{ type: "text", text: `Deleted thought ${id}` }] };
82+
}
83+
);
84+
85+
const app = new Hono();
86+
const transport = new StreamableHTTPTransport();
87+
88+
app.all("/mcp", async (c) => {
89+
const key = c.req.header("x-brain-key") || new URL(c.req.url).searchParams.get("key");
90+
if (key !== Deno.env.get("MCP_ACCESS_KEY")) return c.text("Unauthorized", 401);
91+
return transport.handleRequest(c);
92+
});
93+
94+
transport.connectToServer(mcpServer);
95+
Deno.serve(app.fetch);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "Thought Management Tools",
3+
"description": "Update and delete MCP tools for managing existing thoughts — edit content, reclassify, or remove outdated thoughts.",
4+
"category": "integrations",
5+
"author": {
6+
"name": "Alan Shurafa",
7+
"github": "alanshurafa"
8+
},
9+
"version": "1.0.0",
10+
"requires": {
11+
"open_brain": true,
12+
"services": ["openrouter"],
13+
"tools": ["capture_thought", "search_thoughts"]
14+
},
15+
"tags": ["mcp", "update", "delete", "management", "crud"],
16+
"difficulty": "intermediate",
17+
"estimated_time": "15 minutes",
18+
"created": "2026-03-16",
19+
"updated": "2026-03-16"
20+
}

0 commit comments

Comments
 (0)