@yugabytedb/meko-mcp 2.0.0 → 2.2.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 +183 -33
- package/assets/hooks-handlers/codex-session-end.sh +13 -0
- package/assets/hooks-handlers/cursor-session-start.sh +19 -1
- package/assets/hooks-handlers/lib/capture-notices.js +321 -0
- package/assets/hooks-handlers/lib/capture-state.js +2079 -0
- package/assets/hooks-handlers/lib/capture-status-cli.js +82 -0
- package/assets/hooks-handlers/lib/capture.js +1653 -225
- package/assets/hooks-handlers/lib/checkpoint-timer.js +455 -50
- package/assets/hooks-handlers/lib/kiro-handler.js +738 -0
- package/assets/hooks-handlers/lib/terminal-handoff.js +418 -0
- package/assets/hooks-handlers/session-end.sh +3 -24
- package/assets/hooks-handlers/session-start.sh +8 -1
- package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
- package/assets/scripts/meko-statusline.sh +41 -1
- package/assets/scripts/package-desktop-skill.sh +32 -1
- package/assets/skills/meko-mcp-tools/SKILL.md +90 -137
- package/assets/skills/meko-mcp-tools/references/_sections.md +3 -5
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +31 -28
- package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
- package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +69 -49
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -6
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -5
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +29 -92
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +42 -40
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +1 -2
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +18 -11
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +10 -9
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +51 -44
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +6 -6
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +34 -25
- package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +63 -37
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +19 -22
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +42 -40
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +1 -2
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -17
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +31 -21
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +1 -1
- package/bin/create-meko-setup.mjs +93 -16
- package/lib/capture-status.mjs +67 -0
- package/lib/clients/aliases.mjs +5 -0
- package/lib/clients/claude-code.mjs +8 -4
- package/lib/clients/claude-desktop.mjs +133 -4
- package/lib/clients/codex.mjs +29 -11
- package/lib/clients/common.mjs +2 -0
- package/lib/clients/cursor.mjs +7 -2
- package/lib/clients/index.mjs +2 -0
- package/lib/clients/kiro.mjs +705 -0
- package/lib/config.mjs +90 -0
- package/lib/detect.mjs +7 -2
- package/lib/installer.mjs +1 -0
- package/lib/migrate/adapters/codex.mjs +490 -0
- package/lib/migrate/id.mjs +28 -3
- package/lib/migrate/orchestrator.mjs +34 -7
- package/lib/migrate.mjs +4 -2
- package/lib/prompt.mjs +17 -2
- package/lib/url-selection.mjs +55 -0
- package/package.json +4 -4
- package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -71
- package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -71
|
@@ -17,6 +17,7 @@ import { seedFor } from "./id.mjs";
|
|
|
17
17
|
import { resolveDestinationDatapack } from "./datapack.mjs";
|
|
18
18
|
import * as claudeCodeAdapter from "./adapters/claude-code.mjs";
|
|
19
19
|
import * as cursorAdapter from "./adapters/cursor.mjs";
|
|
20
|
+
import * as codexAdapter from "./adapters/codex.mjs";
|
|
20
21
|
import * as memoryMdAdapter from "./adapters/memory-md.mjs";
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -46,7 +47,9 @@ import * as memoryMdAdapter from "./adapters/memory-md.mjs";
|
|
|
46
47
|
* @returns {Promise<{ok: boolean, summary: object, counts: object}>}
|
|
47
48
|
*/
|
|
48
49
|
export async function runMigration(opts) {
|
|
49
|
-
|
|
50
|
+
// A planning pass is intentionally read-only. In particular, don't create
|
|
51
|
+
// a run directory that `--migrate-status` can mistake for an active run.
|
|
52
|
+
if (!opts.dryRun) fs.mkdirSync(opts.runDir, { recursive: true });
|
|
50
53
|
|
|
51
54
|
const log = opts.dryRun
|
|
52
55
|
? nullLogger()
|
|
@@ -55,6 +58,7 @@ export async function runMigration(opts) {
|
|
|
55
58
|
const prog = progress.initial(opts.runId, opts.scope);
|
|
56
59
|
const progressPath = path.join(opts.runDir, "progress.json");
|
|
57
60
|
const writeProgress = () => {
|
|
61
|
+
if (opts.dryRun) return;
|
|
58
62
|
try { progress.write(progressPath, prog); } catch { /* best effort */ }
|
|
59
63
|
};
|
|
60
64
|
|
|
@@ -91,19 +95,26 @@ export async function runMigration(opts) {
|
|
|
91
95
|
projectCwd: opts.projectCwd,
|
|
92
96
|
home: opts.home,
|
|
93
97
|
});
|
|
98
|
+
const codexSessions = codexAdapter.listSessions({
|
|
99
|
+
scope: opts.scope,
|
|
100
|
+
projectCwd: opts.projectCwd,
|
|
101
|
+
home: opts.home,
|
|
102
|
+
});
|
|
94
103
|
const memoryItems = await memoryMdAdapter.enumerateMemoryItems({
|
|
95
104
|
scope: opts.scope,
|
|
96
105
|
projectCwd: opts.projectCwd,
|
|
97
106
|
home: opts.home,
|
|
98
107
|
});
|
|
99
108
|
|
|
100
|
-
prog.counts.sessionsPlanned =
|
|
109
|
+
prog.counts.sessionsPlanned =
|
|
110
|
+
claudeSessions.length + cursorSessions.length + codexSessions.length;
|
|
101
111
|
writeProgress();
|
|
102
112
|
|
|
103
113
|
log.info("plan", {
|
|
104
114
|
scope: opts.scope,
|
|
105
115
|
claudeSessions: claudeSessions.length,
|
|
106
116
|
cursorSessions: cursorSessions.length,
|
|
117
|
+
codexSessions: codexSessions.length,
|
|
107
118
|
memoryItems: memoryItems.length,
|
|
108
119
|
dryRun: !!opts.dryRun,
|
|
109
120
|
noExtract: !!opts.noExtract,
|
|
@@ -122,7 +133,12 @@ export async function runMigration(opts) {
|
|
|
122
133
|
const parsed = cursorAdapter.parseSession(ref.path);
|
|
123
134
|
pairedTurns += parsed.exchanges.length;
|
|
124
135
|
}
|
|
125
|
-
const
|
|
136
|
+
for (const ref of codexSessions) {
|
|
137
|
+
const parsed = codexAdapter.parseSession(ref.path);
|
|
138
|
+
pairedTurns += parsed.exchanges.length;
|
|
139
|
+
}
|
|
140
|
+
const plannedConversationCreates =
|
|
141
|
+
claudeSessions.length + cursorSessions.length + codexSessions.length
|
|
126
142
|
+ (memoryItems.length > 0 ? countDistinctMemoryAgents(memoryItems) : 0);
|
|
127
143
|
const plannedConversationAddMessage = pairedTurns;
|
|
128
144
|
const plannedMemoryAddExtract = opts.noExtract ? 0 : pairedTurns;
|
|
@@ -132,6 +148,7 @@ export async function runMigration(opts) {
|
|
|
132
148
|
scope: opts.scope,
|
|
133
149
|
claudeSessions: claudeSessions.length,
|
|
134
150
|
cursorSessions: cursorSessions.length,
|
|
151
|
+
codexSessions: codexSessions.length,
|
|
135
152
|
memoryItems: memoryItems.length,
|
|
136
153
|
pairedTurns,
|
|
137
154
|
plannedCalls: {
|
|
@@ -218,7 +235,15 @@ export async function runMigration(opts) {
|
|
|
218
235
|
const withDp = (args) => (datapackId ? { ...args, datapack_id: datapackId } : args);
|
|
219
236
|
|
|
220
237
|
// -- Conversations --
|
|
221
|
-
|
|
238
|
+
// Tag each ref with its source so the parse dispatch below is explicit.
|
|
239
|
+
// Claude Code and Codex both store rollouts as `.jsonl`, so an
|
|
240
|
+
// extension check alone can't tell them apart.
|
|
241
|
+
const taggedSessions = [
|
|
242
|
+
...claudeSessions.map((ref) => ({ ref, source: "claude-code" })),
|
|
243
|
+
...cursorSessions.map((ref) => ({ ref, source: "cursor" })),
|
|
244
|
+
...codexSessions.map((ref) => ({ ref, source: "codex" })),
|
|
245
|
+
];
|
|
246
|
+
for (const { ref, source } of taggedSessions) {
|
|
222
247
|
let existing = state.getSession(st, ref.agentId, ref.sessionUuid);
|
|
223
248
|
if (existing?.status === "done" && !opts.force) {
|
|
224
249
|
log.info("session_skip_done", { agentId: ref.agentId, sessionUuid: ref.sessionUuid });
|
|
@@ -243,9 +268,11 @@ export async function runMigration(opts) {
|
|
|
243
268
|
prog.currentSession = ref.sessionUuid;
|
|
244
269
|
writeProgress();
|
|
245
270
|
|
|
246
|
-
const parsed =
|
|
271
|
+
const parsed = source === "claude-code"
|
|
247
272
|
? await claudeCodeAdapter.parseSession(ref.path)
|
|
248
|
-
:
|
|
273
|
+
: source === "codex"
|
|
274
|
+
? codexAdapter.parseSession(ref.path)
|
|
275
|
+
: cursorAdapter.parseSession(ref.path);
|
|
249
276
|
|
|
250
277
|
if (parsed.partial) {
|
|
251
278
|
log.warn("session_partial", { path: ref.path });
|
|
@@ -260,7 +287,7 @@ export async function runMigration(opts) {
|
|
|
260
287
|
session_id: ref.sessionUuid,
|
|
261
288
|
title: (parsed.firstUserText || ref.sessionUuid).slice(0, 120),
|
|
262
289
|
metadata: JSON.stringify({
|
|
263
|
-
source
|
|
290
|
+
source,
|
|
264
291
|
cwd: ref.cwd || null,
|
|
265
292
|
gitBranch: ref.slug ? (parsed.gitBranch || null) : null,
|
|
266
293
|
startedAt: parsed.startedAt || null,
|
package/lib/migrate.mjs
CHANGED
|
@@ -212,10 +212,10 @@ export async function startMigration(opts) {
|
|
|
212
212
|
// don't move when the state key changes.
|
|
213
213
|
const urlDatapackKey = datapackKeyFromUrl(opts.url);
|
|
214
214
|
let P = paths({ datapackKey: urlDatapackKey });
|
|
215
|
-
fs.mkdirSync(P.root, { recursive: true });
|
|
216
215
|
|
|
217
216
|
// Dry-run is a local-only planning pass: no HTTP, no lock, no fork.
|
|
218
|
-
// Don't gate it on URL/apiKey
|
|
217
|
+
// Don't gate it on URL/apiKey, and don't create the migration root: a
|
|
218
|
+
// planning pass must not appear as a phantom active run in --migrate-status.
|
|
219
219
|
if (opts.dryRun) {
|
|
220
220
|
const runId = generateRunId();
|
|
221
221
|
const runDir = P.runDir(runId);
|
|
@@ -260,6 +260,8 @@ export async function startMigration(opts) {
|
|
|
260
260
|
};
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
fs.mkdirSync(P.root, { recursive: true });
|
|
264
|
+
|
|
263
265
|
// Real run — now URL/apiKey are required (dry-run branch already returned).
|
|
264
266
|
if (!opts.url) {
|
|
265
267
|
return { ok: false, message: "--url (or MEKO_MCP_URL) is required for --migrate." };
|
package/lib/prompt.mjs
CHANGED
|
@@ -37,6 +37,21 @@ function question(query) {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Apply terminal erase bytes that survive readline's muted-output path.
|
|
42
|
+
* Some PTYs leave DEL/BS in the answer when readline is attached to a
|
|
43
|
+
* non-TTY Writable, even with terminal mode enabled. Treat them exactly as
|
|
44
|
+
* interactive backspace so a corrected secret never persists control bytes.
|
|
45
|
+
*/
|
|
46
|
+
function applyEraseCharacters(value) {
|
|
47
|
+
const chars = [];
|
|
48
|
+
for (const char of value) {
|
|
49
|
+
if (char === "\x7f" || char === "\b") chars.pop();
|
|
50
|
+
else chars.push(char);
|
|
51
|
+
}
|
|
52
|
+
return chars.join("");
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
// ---------------------------------------------------------------------------
|
|
41
56
|
// askChoice
|
|
42
57
|
// ---------------------------------------------------------------------------
|
|
@@ -50,7 +65,7 @@ function question(query) {
|
|
|
50
65
|
*
|
|
51
66
|
* @example
|
|
52
67
|
* const choice = await askChoice('Connection type:', [
|
|
53
|
-
* { label: 'Cloud Meko', description: 'Hosted at
|
|
68
|
+
* { label: 'Cloud Meko', description: 'Hosted at mekodata.ai' },
|
|
54
69
|
* { label: 'Local Meko', description: 'docker-compose stack' },
|
|
55
70
|
* ]);
|
|
56
71
|
*/
|
|
@@ -218,7 +233,7 @@ export async function askSecret(questionText) {
|
|
|
218
233
|
|
|
219
234
|
secretRL.question("", (answer) => {
|
|
220
235
|
finish();
|
|
221
|
-
resolve(answer);
|
|
236
|
+
resolve(applyEraseCharacters(answer));
|
|
222
237
|
});
|
|
223
238
|
});
|
|
224
239
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { MEKO_PRODUCTION_MCP_URL } from "./clients/common.mjs";
|
|
2
|
+
|
|
3
|
+
function validHttpUrl(value) {
|
|
4
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
5
|
+
const candidate = value.trim();
|
|
6
|
+
try {
|
|
7
|
+
const parsed = new URL(candidate);
|
|
8
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
9
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "") || "/";
|
|
10
|
+
return { value: candidate, comparisonKey: parsed.toString() };
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Select the URL offered by interactive/non-interactive setup.
|
|
18
|
+
* Explicit CLI URLs are resolved before this helper is called.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveSuggestedMcpUrl({
|
|
21
|
+
adapters,
|
|
22
|
+
clients,
|
|
23
|
+
name = "meko",
|
|
24
|
+
scope = "user",
|
|
25
|
+
projectRoot = process.cwd(),
|
|
26
|
+
}) {
|
|
27
|
+
const existingUrlsByKey = new Map();
|
|
28
|
+
for (const client of clients) {
|
|
29
|
+
const adapter = adapters[client];
|
|
30
|
+
if (!adapter?.detectExisting) continue;
|
|
31
|
+
try {
|
|
32
|
+
const existing = adapter.detectExisting(name, { scope, projectRoot });
|
|
33
|
+
const url = existing?.found ? validHttpUrl(existing.url) : null;
|
|
34
|
+
if (url && !existingUrlsByKey.has(url.comparisonKey)) {
|
|
35
|
+
existingUrlsByKey.set(url.comparisonKey, url.value);
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// Existing-config discovery is advisory. Installation performs its own
|
|
39
|
+
// prerequisite and config checks later with actionable errors.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const uniqueUrls = [...existingUrlsByKey.values()];
|
|
44
|
+
if (uniqueUrls.length === 1) {
|
|
45
|
+
return { url: uniqueUrls[0], source: "existing", existingUrls: uniqueUrls };
|
|
46
|
+
}
|
|
47
|
+
if (uniqueUrls.length > 1) {
|
|
48
|
+
return { url: null, source: "conflict", existingUrls: uniqueUrls };
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
url: MEKO_PRODUCTION_MCP_URL,
|
|
52
|
+
source: "production-default",
|
|
53
|
+
existingUrls: [],
|
|
54
|
+
};
|
|
55
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yugabytedb/meko-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Installer for Meko across Claude, Cursor, Codex, and Kiro clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-meko-setup": "bin/create-meko-setup.mjs",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"prepack": "node scripts/bundle-assets.mjs",
|
|
19
19
|
"postpack": "node scripts/bundle-assets.mjs --clean",
|
|
20
20
|
"bundle-assets": "node scripts/bundle-assets.mjs",
|
|
21
|
-
"test": "node --test \"test/*.mjs\"",
|
|
21
|
+
"test": "node --test \"test/*.mjs\" && node --test \"test/serial/*.mjs\"",
|
|
22
22
|
"smoke": "./scripts/prepublish-smoke.sh",
|
|
23
23
|
"test:unit": "node --test test/config.test.mjs test/validate.test.mjs test/clients.test.mjs",
|
|
24
24
|
"test:integration": "RUN_INSTALLER_INTEGRATION=1 node --test test/installer.test.mjs",
|
|
25
25
|
"test:integration:cloud": "RUN_INSTALLER_INTEGRATION=1 node --test test/installer.test.mjs"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": ">=18.
|
|
28
|
+
"node": ">=20.18.1"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [
|
|
31
31
|
"meko",
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Scope Permission Hierarchy and Per-Tool Requirements
|
|
2
|
-
|
|
3
|
-
**WRONG:** `memory_add(scope="read", ...)` → PermissionError: requires 'write' or higher.
|
|
4
|
-
**WRONG:** `memory_delete_all(scope="write", ...)` → PermissionError: requires 'admin'.
|
|
5
|
-
|
|
6
|
-
## Scope Hierarchy
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
admin (level 2) -- can do everything
|
|
10
|
-
↓
|
|
11
|
-
write (level 1) -- can read + write, not admin-only
|
|
12
|
-
↓
|
|
13
|
-
read (level 0) -- can only read
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Higher scopes include lower scopes. An unrecognized scope string always fails.
|
|
17
|
-
|
|
18
|
-
## Per-Tool Requirements
|
|
19
|
-
|
|
20
|
-
### read scope (9 tools)
|
|
21
|
-
|
|
22
|
-
| Tool | Group |
|
|
23
|
-
|------|-------|
|
|
24
|
-
| `knowledgebase_search` | RAG |
|
|
25
|
-
| `memory_search` | Memory |
|
|
26
|
-
| `memory_get_by_id` | Memory |
|
|
27
|
-
| `memory_get_all` | Memory |
|
|
28
|
-
| `flush_pending_memory_candidates` | Memory |
|
|
29
|
-
| `conversation_get` | Conversation |
|
|
30
|
-
| `conversation_list` | Conversation |
|
|
31
|
-
| `datapack_list` | Datapack |
|
|
32
|
-
| `datapack_describe` | Datapack |
|
|
33
|
-
|
|
34
|
-
### write scope (9 tools)
|
|
35
|
-
|
|
36
|
-
| Tool | Group |
|
|
37
|
-
|------|-------|
|
|
38
|
-
| `memory_add` | Memory |
|
|
39
|
-
| `memory_update` | Memory |
|
|
40
|
-
| `memory_delete_by_id` | Memory |
|
|
41
|
-
| `conversation_create` | Conversation |
|
|
42
|
-
| `conversation_add_message` | Conversation |
|
|
43
|
-
| `conversation_update` | Conversation |
|
|
44
|
-
| `datapack_create` | Datapack |
|
|
45
|
-
| `datapack_update` | Datapack |
|
|
46
|
-
| `track_token_usage` | Observability |
|
|
47
|
-
|
|
48
|
-
### admin scope (3 tools — destructive, irreversible)
|
|
49
|
-
|
|
50
|
-
| Tool | Group |
|
|
51
|
-
|------|-------|
|
|
52
|
-
| `memory_delete_all` | Memory |
|
|
53
|
-
| `conversation_delete` | Conversation |
|
|
54
|
-
| `datapack_delete` | Datapack |
|
|
55
|
-
|
|
56
|
-
Agent and knowledge-base lifecycle tools are not MCP-exposed — see "Platform capabilities NOT exposed via MCP" in `tools-overview.md`.
|
|
57
|
-
|
|
58
|
-
## Best Practices
|
|
59
|
-
|
|
60
|
-
1. **Use the minimum scope needed.** `scope="read"` for reads documents intent and prevents accidental writes.
|
|
61
|
-
2. **The scope is a parameter, not an auth token.** When OAuth is enabled, the actual permission check happens against the OAuth token's claims. Both `scope` parameter and OAuth permissions must be satisfied.
|
|
62
|
-
|
|
63
|
-
## Common Mistakes
|
|
64
|
-
|
|
65
|
-
**WRONG:** `scope="all"` — there is no "all" scope. Valid values are exactly: `"read"`, `"write"`, `"admin"`. Nothing else.
|
|
66
|
-
|
|
67
|
-
Other invalid values that will fail: `"readwrite"`, `"rw"`, `"full"`, `"any"`.
|
|
68
|
-
|
|
69
|
-
The error `Insufficient scope: 'all'. This tool requires 'read' or higher.` means the scope string was not recognized as a valid value. Always use one of the three valid strings.
|
|
70
|
-
|
|
71
|
-
**Default choice:** Start with `scope="read"` unless you specifically need to write or delete.
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Scope Permission Hierarchy and Per-Tool Requirements
|
|
2
|
-
|
|
3
|
-
**WRONG:** `memory_add(scope="read", ...)` → PermissionError: requires 'write' or higher.
|
|
4
|
-
**WRONG:** `memory_delete_all(scope="write", ...)` → PermissionError: requires 'admin'.
|
|
5
|
-
|
|
6
|
-
## Scope Hierarchy
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
admin (level 2) -- can do everything
|
|
10
|
-
↓
|
|
11
|
-
write (level 1) -- can read + write, not admin-only
|
|
12
|
-
↓
|
|
13
|
-
read (level 0) -- can only read
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Higher scopes include lower scopes. An unrecognized scope string always fails.
|
|
17
|
-
|
|
18
|
-
## Per-Tool Requirements
|
|
19
|
-
|
|
20
|
-
### read scope (9 tools)
|
|
21
|
-
|
|
22
|
-
| Tool | Group |
|
|
23
|
-
|------|-------|
|
|
24
|
-
| `knowledgebase_search` | RAG |
|
|
25
|
-
| `memory_search` | Memory |
|
|
26
|
-
| `memory_get_by_id` | Memory |
|
|
27
|
-
| `memory_get_all` | Memory |
|
|
28
|
-
| `flush_pending_memory_candidates` | Memory |
|
|
29
|
-
| `conversation_get` | Conversation |
|
|
30
|
-
| `conversation_list` | Conversation |
|
|
31
|
-
| `datapack_list` | Datapack |
|
|
32
|
-
| `datapack_describe` | Datapack |
|
|
33
|
-
|
|
34
|
-
### write scope (9 tools)
|
|
35
|
-
|
|
36
|
-
| Tool | Group |
|
|
37
|
-
|------|-------|
|
|
38
|
-
| `memory_add` | Memory |
|
|
39
|
-
| `memory_update` | Memory |
|
|
40
|
-
| `memory_delete_by_id` | Memory |
|
|
41
|
-
| `conversation_create` | Conversation |
|
|
42
|
-
| `conversation_add_message` | Conversation |
|
|
43
|
-
| `conversation_update` | Conversation |
|
|
44
|
-
| `datapack_create` | Datapack |
|
|
45
|
-
| `datapack_update` | Datapack |
|
|
46
|
-
| `track_token_usage` | Observability |
|
|
47
|
-
|
|
48
|
-
### admin scope (3 tools — destructive, irreversible)
|
|
49
|
-
|
|
50
|
-
| Tool | Group |
|
|
51
|
-
|------|-------|
|
|
52
|
-
| `memory_delete_all` | Memory |
|
|
53
|
-
| `conversation_delete` | Conversation |
|
|
54
|
-
| `datapack_delete` | Datapack |
|
|
55
|
-
|
|
56
|
-
Agent and knowledge-base lifecycle tools are not MCP-exposed — see "Platform capabilities NOT exposed via MCP" in `tools-overview.md`.
|
|
57
|
-
|
|
58
|
-
## Best Practices
|
|
59
|
-
|
|
60
|
-
1. **Use the minimum scope needed.** `scope="read"` for reads documents intent and prevents accidental writes.
|
|
61
|
-
2. **The scope is a parameter, not an auth token.** When OAuth is enabled, the actual permission check happens against the OAuth token's claims. Both `scope` parameter and OAuth permissions must be satisfied.
|
|
62
|
-
|
|
63
|
-
## Common Mistakes
|
|
64
|
-
|
|
65
|
-
**WRONG:** `scope="all"` — there is no "all" scope. Valid values are exactly: `"read"`, `"write"`, `"admin"`. Nothing else.
|
|
66
|
-
|
|
67
|
-
Other invalid values that will fail: `"readwrite"`, `"rw"`, `"full"`, `"any"`.
|
|
68
|
-
|
|
69
|
-
The error `Insufficient scope: 'all'. This tool requires 'read' or higher.` means the scope string was not recognized as a valid value. Always use one of the three valid strings.
|
|
70
|
-
|
|
71
|
-
**Default choice:** Start with `scope="read"` unless you specifically need to write or delete.
|