tana-mcp-codemode 0.2.3 → 0.3.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 +71 -259
- package/dist/entry-node.js +1364 -0
- package/package.json +28 -26
- package/src/compat/bun.ts +39 -0
- package/src/compat/index.ts +29 -0
- package/src/compat/node.ts +62 -0
- package/src/compat/types.ts +15 -0
- package/src/debug-server.ts +232 -0
- package/src/entry-bun.ts +11 -0
- package/src/entry-node.ts +11 -0
- package/src/index.ts +5 -162
- package/src/main.ts +146 -0
- package/src/sandbox/executor.ts +2 -2
- package/src/sandbox/workflow.ts +4 -4
- package/src/storage/history.ts +11 -11
package/README.md
CHANGED
|
@@ -1,314 +1,126 @@
|
|
|
1
|
-
#
|
|
1
|
+
# tana-mcp-codemode
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Codemode MCP server for [Tana](https://tana.inc). Instead of structured API calls, your AI writes TypeScript that executes directly against the Tana Local API.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Tana Local API** — Workspaces, nodes, tags, fields, calendar, import
|
|
9
|
-
- **Top-level Await** — `await tana.workspaces.list()` works directly
|
|
10
|
-
- **Timeout Protection** — 10s max execution prevents infinite loops
|
|
11
|
-
- **Script History** — SQLite persistence for debugging and replay
|
|
12
|
-
- **Retry Logic** — Exponential backoff for transient failures
|
|
13
|
-
- **Debug UI** — WebSocket-based dashboard for testing scripts
|
|
7
|
+
### Binary (no runtime required)
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
Download from [GitHub Releases](https://github.com/fabiogaliano/tana-mcp-codemode/releases) for your platform:
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
| Platform | File |
|
|
12
|
+
|----------|------|
|
|
13
|
+
| macOS ARM | `tana-mcp-codemode-darwin-arm64` |
|
|
14
|
+
| macOS Intel | `tana-mcp-codemode-darwin-x64` |
|
|
15
|
+
| Linux x64 | `tana-mcp-codemode-linux-x64` |
|
|
16
|
+
| Linux ARM | `tana-mcp-codemode-linux-arm64` |
|
|
17
|
+
| Windows | `tana-mcp-codemode-windows-x64.exe` |
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
```bash
|
|
20
|
+
chmod +x tana-mcp-codemode-darwin-arm64
|
|
21
|
+
./tana-mcp-codemode-darwin-arm64
|
|
22
|
+
```
|
|
22
23
|
|
|
23
|
-
###
|
|
24
|
+
### npm (requires Node.js ≥ 20)
|
|
24
25
|
|
|
25
26
|
```bash
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
npm install -g tana-mcp-codemode
|
|
28
|
+
# or run without installing:
|
|
29
|
+
npx tana-mcp-codemode
|
|
28
30
|
```
|
|
29
31
|
|
|
30
|
-
###
|
|
32
|
+
### From source (requires Bun)
|
|
31
33
|
|
|
32
34
|
```bash
|
|
33
35
|
git clone https://github.com/fabiogaliano/tana-mcp-codemode
|
|
34
36
|
cd tana-mcp-codemode
|
|
35
37
|
bun install
|
|
38
|
+
bun run src/entry-bun.ts
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
##
|
|
41
|
+
## Prerequisites
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| `TANA_API_TOKEN` | (required) | Bearer token from Tana Desktop |
|
|
43
|
-
| `TANA_API_URL` | `http://127.0.0.1:8262` | Tana Local API URL |
|
|
44
|
-
| `TANA_TIMEOUT` | `10000` | Request timeout in ms |
|
|
45
|
-
| `TANA_HISTORY_PATH` | (platform default) | Custom path for SQLite history database |
|
|
46
|
-
| `MAIN_TANA_WORKSPACE` | (none) | Default workspace name or ID, resolved at startup |
|
|
47
|
-
| `TANA_SEARCH_WORKSPACES`| (none) | Comma-separated workspace names or IDs for default search scoping |
|
|
43
|
+
- [Tana Desktop](https://tana.inc) with **Local API enabled** (Settings → Local API → Enable)
|
|
44
|
+
- An API token from Tana (Settings → API → Generate Token)
|
|
48
45
|
|
|
49
|
-
## MCP
|
|
46
|
+
## MCP Configuration
|
|
50
47
|
|
|
51
|
-
Add to your MCP client
|
|
48
|
+
Add to your MCP client config (e.g. `claude_desktop_config.json`):
|
|
52
49
|
|
|
53
50
|
```json
|
|
54
51
|
{
|
|
55
52
|
"mcpServers": {
|
|
56
53
|
"tana": {
|
|
57
|
-
"command": "tana-mcp-codemode",
|
|
54
|
+
"command": "/path/to/tana-mcp-codemode-darwin-arm64",
|
|
58
55
|
"env": {
|
|
59
|
-
"TANA_API_TOKEN": "
|
|
60
|
-
|
|
61
|
-
"MAIN_TANA_WORKSPACE": "My Workspace",
|
|
62
|
-
"TANA_SEARCH_WORKSPACES": "My Workspace",
|
|
63
|
-
// Optional: customize where the SQLite history database is stored
|
|
64
|
-
"TANA_HISTORY_PATH": "/path/to/history.db"
|
|
56
|
+
"TANA_API_TOKEN": "your-token-here",
|
|
57
|
+
"MAIN_TANA_WORKSPACE": "My Workspace"
|
|
65
58
|
}
|
|
66
59
|
}
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
```
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
| ----------------- | ----------------------------------------------------------- |
|
|
73
|
-
| Claude Desktop | `claude_desktop_config.json` |
|
|
74
|
-
| Claude Code | `.mcp.json` (project) or `~/.claude/settings.json` (global) |
|
|
75
|
-
| Cursor / Windsurf | IDE MCP settings |
|
|
64
|
+
For npm install, use `"command": "tana-mcp-codemode"`. For source, use `"command": "bun"` with `"args": ["run", "/path/to/src/entry-bun.ts"]`.
|
|
76
65
|
|
|
77
|
-
|
|
66
|
+
## Environment Variables
|
|
78
67
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// Optional
|
|
88
|
-
"MAIN_TANA_WORKSPACE": "My Workspace",
|
|
89
|
-
"TANA_SEARCH_WORKSPACES": "My Workspace",
|
|
90
|
-
// Optional: customize where the SQLite history database is stored
|
|
91
|
-
"TANA_HISTORY_PATH": "/path/to/history.db"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Examples
|
|
99
|
-
|
|
100
|
-
### Search for nodes
|
|
68
|
+
| Variable | Default | Description |
|
|
69
|
+
|----------|---------|-------------|
|
|
70
|
+
| `TANA_API_TOKEN` | (required) | Bearer token from Tana Desktop |
|
|
71
|
+
| `TANA_API_URL` | `http://127.0.0.1:8262` | Tana Local API URL |
|
|
72
|
+
| `MAIN_TANA_WORKSPACE` | (none) | Default workspace name or ID |
|
|
73
|
+
| `TANA_SEARCH_WORKSPACES` | (none) | Comma-separated workspaces for search scope |
|
|
74
|
+
| `TANA_TIMEOUT` | `10000` | Request timeout in ms |
|
|
75
|
+
| `TANA_HISTORY_PATH` | (platform default) | Custom SQLite history path |
|
|
101
76
|
|
|
102
|
-
|
|
103
|
-
const results = await tana.nodes.search({
|
|
104
|
-
textContains: "meeting notes"
|
|
105
|
-
});
|
|
106
|
-
console.log("Found:", results.length, "nodes");
|
|
107
|
-
```
|
|
77
|
+
## Usage Examples
|
|
108
78
|
|
|
109
|
-
|
|
79
|
+
Search for nodes:
|
|
110
80
|
|
|
111
81
|
```typescript
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
{ hasType: "taskTagId" },
|
|
115
|
-
{ is: "todo" },
|
|
116
|
-
{ created: { last: 7 } }
|
|
117
|
-
]
|
|
82
|
+
const results = await tana.nodes.search("project ideas", {
|
|
83
|
+
workspaceIds: [tana.workspace.id]
|
|
118
84
|
});
|
|
119
|
-
console.log(
|
|
85
|
+
console.log(results.map(n => n.name));
|
|
120
86
|
```
|
|
121
87
|
|
|
122
|
-
|
|
88
|
+
Import content with tags and fields:
|
|
123
89
|
|
|
124
90
|
```typescript
|
|
125
|
-
await tana.import(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
-
|
|
91
|
+
await tana.import(tana.workspace.id, `
|
|
92
|
+
%%tana%%
|
|
93
|
+
- Meeting notes #meeting
|
|
94
|
+
- Date:: [[2024-01-15]]
|
|
95
|
+
- Attendees:: Alice, Bob
|
|
96
|
+
- Summary:: Discussed Q1 roadmap
|
|
129
97
|
`);
|
|
130
98
|
```
|
|
131
99
|
|
|
132
|
-
##
|
|
133
|
-
|
|
134
|
-
A WebSocket-based dashboard for testing scripts:
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
# Start debug server
|
|
138
|
-
bun run src/debug-server.ts
|
|
139
|
-
|
|
140
|
-
# Open http://localhost:3333
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**Routes:**
|
|
144
|
-
- `http://localhost:3333/#debug` — Script execution console
|
|
145
|
-
- `http://localhost:3333/#benchmark` — Codemode vs tana-local performance comparison
|
|
146
|
-
|
|
147
|
-
**Features:**
|
|
148
|
-
- Real-time script execution
|
|
149
|
-
- Workflow event timeline
|
|
150
|
-
- Error display with suggestions
|
|
151
|
-
- Benchmark results visualization (cost, speed, token usage)
|
|
152
|
-
|
|
153
|
-
### workflow Helper (Debug UI only)
|
|
154
|
-
|
|
155
|
-
Track multi-step operations with a timeline view:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
workflow.start("Processing nodes");
|
|
159
|
-
workflow.step("Fetching workspaces");
|
|
160
|
-
workflow.progress(5, 100, "Processing");
|
|
161
|
-
workflow.complete("Done!");
|
|
162
|
-
// Or: workflow.abort("Error message");
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
> **Note**: `workflow` is only available in the Debug UI. It's not exposed in the production MCP prompt.
|
|
166
|
-
|
|
167
|
-
### Building the React UI (optional)
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
cd ui
|
|
171
|
-
bun install
|
|
172
|
-
bun run build
|
|
173
|
-
cd ..
|
|
174
|
-
bun run src/debug-server.ts
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Architecture
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
src/
|
|
181
|
-
├── index.ts # MCP server entry
|
|
182
|
-
├── prompts.ts # Tool description
|
|
183
|
-
├── types.ts # TypeScript interfaces
|
|
184
|
-
├── debug-server.ts # WebSocket debug UI
|
|
185
|
-
├── api/
|
|
186
|
-
│ ├── client.ts # HTTP client (auth, retry, timeouts)
|
|
187
|
-
│ ├── tana.ts # API wrapper → `tana` object
|
|
188
|
-
│ └── types.ts # API type definitions
|
|
189
|
-
├── sandbox/
|
|
190
|
-
│ ├── executor.ts # Code execution engine
|
|
191
|
-
│ └── workflow.ts # Progress tracking
|
|
192
|
-
├── storage/
|
|
193
|
-
│ └── history.ts # SQLite script history
|
|
194
|
-
└── generated/
|
|
195
|
-
└── api.d.ts # Generated OpenAPI types
|
|
196
|
-
|
|
197
|
-
ui/ # React debug dashboard
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### How It Works
|
|
201
|
-
|
|
202
|
-
1. AI sends TypeScript code to the `execute` tool
|
|
203
|
-
2. `executor.ts` creates an AsyncFunction for top-level await
|
|
204
|
-
3. Code runs with injected `tana` and `console` objects
|
|
205
|
-
4. 10s timeout via Promise.race prevents hangs
|
|
206
|
-
5. `console.log()` output is captured and returned
|
|
207
|
-
6. Script run is saved to SQLite history
|
|
208
|
-
|
|
209
|
-
## Script History
|
|
210
|
-
|
|
211
|
-
Runs are persisted to SQLite:
|
|
212
|
-
|
|
213
|
-
| Platform | Location |
|
|
214
|
-
| -------- | --------------------------------------------------- |
|
|
215
|
-
| macOS | `~/Library/Application Support/tana-mcp/history.db` |
|
|
216
|
-
| Windows | `%APPDATA%/tana-mcp/history.db` |
|
|
217
|
-
| Linux | `~/.local/share/tana-mcp/history.db` |
|
|
218
|
-
|
|
219
|
-
Old runs (>30 days) are automatically cleaned up on startup.
|
|
220
|
-
|
|
221
|
-
### What Gets Saved
|
|
222
|
-
|
|
223
|
-
Each script run records:
|
|
100
|
+
## API Reference
|
|
224
101
|
|
|
225
|
-
|
|
|
226
|
-
|
|
227
|
-
| `
|
|
228
|
-
| `
|
|
229
|
-
| `
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `
|
|
233
|
-
| `
|
|
102
|
+
| Namespace | Methods |
|
|
103
|
+
|-----------|---------|
|
|
104
|
+
| `tana.workspace` | Pre-resolved default workspace |
|
|
105
|
+
| `tana.workspaces` | `list()` |
|
|
106
|
+
| `tana.nodes` | `search()`, `read()`, `getChildren()`, `edit()`, `move()`, `trash()`, `check()`, `uncheck()`, `open()` |
|
|
107
|
+
| `tana.tags` | `listAll()`, `getSchema()`, `create()`, `modify()`, `addField()`, `setCheckbox()` |
|
|
108
|
+
| `tana.fields` | `setOption()`, `setContent()`, `getFieldOptions()` |
|
|
109
|
+
| `tana.calendar` | `getOrCreate()` |
|
|
110
|
+
| `tana.import()` | Import Tana Paste content |
|
|
111
|
+
| `tana.health()` | API health check |
|
|
234
112
|
|
|
235
113
|
## Development
|
|
236
114
|
|
|
237
115
|
```bash
|
|
238
|
-
#
|
|
239
|
-
bun run
|
|
240
|
-
|
|
241
|
-
#
|
|
242
|
-
bun run typecheck
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
bun run
|
|
246
|
-
|
|
247
|
-
# Run debug server
|
|
248
|
-
bun run debug
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## API Reference
|
|
252
|
-
|
|
253
|
-
The server exposes a single `execute` tool. AI writes TypeScript code with access to the `tana` object:
|
|
254
|
-
|
|
255
|
-
### Workspaces
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
const workspaces = await tana.workspaces.list();
|
|
259
|
-
// → Workspace[] (id, name, homeNodeId)
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Nodes
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
await tana.nodes.search(query, options?) // → SearchResult[]
|
|
266
|
-
await tana.nodes.read(nodeId, maxDepth?) // → string (markdown)
|
|
267
|
-
await tana.nodes.getChildren(nodeId, opts?) // → { children, total, hasMore }
|
|
268
|
-
await tana.nodes.edit({ nodeId, name?, description? })
|
|
269
|
-
await tana.nodes.trash(nodeId)
|
|
270
|
-
await tana.nodes.check(nodeId) // mark done
|
|
271
|
-
await tana.nodes.uncheck(nodeId) // mark undone
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Tags (Supertags)
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
await tana.tags.listAll(workspaceId) // All workspace supertags (paginated)
|
|
278
|
-
await tana.tags.getSchema(tagId, opts?) // opts: { includeInheritedFields? }
|
|
279
|
-
await tana.tags.modify(nodeId, action, tagIds) // action: "add" | "remove"
|
|
280
|
-
await tana.tags.create({ workspaceId, name, description?, extendsTagIds?, showCheckbox? })
|
|
281
|
-
await tana.tags.addField({ tagId, name, dataType, ... })
|
|
282
|
-
await tana.tags.setCheckbox({ tagId, showCheckbox, doneStateMapping? })
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Fields
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
await tana.fields.setOption(nodeId, attributeId, optionId) // dropdown fields
|
|
289
|
-
await tana.fields.setContent(nodeId, attributeId, content) // text/date/url fields
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Calendar
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
await tana.calendar.getOrCreate(workspaceId, granularity, date?)
|
|
296
|
-
// granularity: "day" | "week" | "month" | "year"
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Import (Tana Paste)
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
await tana.import(parentNodeId, tanaPasteContent)
|
|
303
|
-
// → { success, nodeIds?, error? }
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Utility
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
tana.workspace // Pre-resolved default workspace (from MAIN_TANA_WORKSPACE) or null
|
|
310
|
-
tana.format(data) // Compact display of any API response
|
|
311
|
-
await tana.health() // → { status: "ok" }
|
|
116
|
+
bun install # Install deps
|
|
117
|
+
bun run start # Start MCP server
|
|
118
|
+
bun run dev # Dev mode with watch
|
|
119
|
+
bun run test # Run tests
|
|
120
|
+
bun run typecheck # Type check
|
|
121
|
+
bun run build # Build Node.js dist (tsup)
|
|
122
|
+
bun run build:binary # Build self-contained binary
|
|
123
|
+
bun run debug # Debug UI at localhost:3333
|
|
312
124
|
```
|
|
313
125
|
|
|
314
126
|
## License
|