loopctl-mcp-server 2.37.0 → 2.39.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 +5 -3
- package/index.js +120 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ REST endpoint (`PATCH /api/v1/tenants/me/llm-config`), and the docs — so you (
|
|
|
121
121
|
autonomous agent) can self-remediate without a human. Full agent-tenant lifecycle:
|
|
122
122
|
[`docs/onboarding-agent-tenant.md`](../docs/onboarding-agent-tenant.md).
|
|
123
123
|
|
|
124
|
-
## Tools (
|
|
124
|
+
## Tools (84)
|
|
125
125
|
|
|
126
126
|
### Project Tools
|
|
127
127
|
|
|
@@ -214,6 +214,7 @@ autonomous agent) can self-remediate without a human. Full agent-tenant lifecycl
|
|
|
214
214
|
| `knowledge_conflicts` | List potential-conflict article pairs — published articles flagged "too similar to comfortably coexist" by the auto-linker / nightly lint sweep, highest-overlap first. The KB only FLAGS the pair; it does NOT decide redundancy-vs-contradiction — that's your call with live context. Each entry has both articles (id/title/status/category) + similarity. Then merge (supersede one, `knowledge_create` the merged article, or PATCH) or reconcile if they genuinely disagree. Paginated with `total_count` in meta. Agent role. Optional: `limit` (default 50, max 1000, clamped), `offset`. |
|
|
215
215
|
| `knowledge_resolve_conflict` | Record YOUR verdict on a potential-conflict pair (from `knowledge_conflicts`). Dispositions: `dismiss` (false positive, drops from queue), `supersede` (one wins — pass `authoritative_article_id`; nightly executor links + retires loser, only at `confidence:"high"`, reversible/audited), `merge` (at high confidence an LLM synthesizes both into ONE new DRAFT, sources preserved, never auto-published). Non-destructive at agent role — you record intent, the privileged nightly job executes. Last-write-wins per pair. Required: `source_article_id`, `target_article_id`, `disposition`. Optional: `authoritative_article_id`, `classification`, `evidence`, `confidence`. |
|
|
216
216
|
| `knowledge_create` | Create a new knowledge article. File findings, document patterns, or record decisions. **Published immediately by default** (visible per `metadata.visibility` — default `owner` for agent authors, only visible to that agent; `shared` for visibility to all agents) — the response `note` says which outcome occurred. Pass `draft: true` to stage it for later review instead (publish afterwards with `knowledge_publish`). Pass `metadata: {visibility: "shared"}` to make the article visible to other agents; higher roles can set visibility and agent_id explicitly. Pass `idempotency_key` for idempotent capture (re-creating with the same key is a no-op returning the existing article — no partial duplicates). Optional: `category`, `tags`, `project_id`, `draft`, `idempotency_key`, `source_type`, `source_id`, `metadata`. |
|
|
217
|
+
| `knowledge_update` | Edit an EXISTING article IN PLACE, **preserving its ID** (IDs are load-bearing — cited in project CLAUDE.mds and cross-links). Fold in a new fact, tidy a hub, retag, or reclassify without churning a new row. Send only the fields to change; `tags` REPLACES the whole array. A changed body/tags re-triggers embedding + auto-linking. Agent role — KB-content curation (reversible + audited); visibility-scoped, so another agent's private/owner memory 404s. Required: `article_id`. Optional: `title`, `body`, `category`, `tags`, `metadata`. |
|
|
217
218
|
| `knowledge_okf_export` | **Requires `LOOPCTL_USER_KEY`.** Export the wiki as a portable OKF (Open Knowledge Format) v0.1 bundle of markdown files. Writes to `out_dir`, or returns `{files, meta}` inline. |
|
|
218
219
|
| `knowledge_okf_import` | **Requires `LOOPCTL_USER_KEY`.** Import an OKF v0.1 bundle from a local directory. Creates or (with `merge`) updates articles; tolerates and preserves unknown frontmatter. |
|
|
219
220
|
|
|
@@ -233,6 +234,7 @@ it is enforced server-side and a no-op for a non-superadmin key — see below.)
|
|
|
233
234
|
| `memory_recall` | Semantically recall your own long-term memories most similar to `query`. When embedding generation is unavailable the response degrades to a recent-first text match with `meta.fallback: true` and a stable `meta.reason` (score is `null` on that path) — check `meta.fallback` before treating a short/empty result as a genuinely empty scope. `meta.total_count`/`meta.underfilled` are also returned. Optional: `limit`, `include_superseded`. |
|
|
234
235
|
| `memory_list` | List your own long-term memories, newest first, paginated with `meta.total_count/limit/offset` (the true scoped count, never silently capped by `limit`). Optional: `limit`, `offset`, `include_superseded`, `all_subjects` (superadmin only; ignored for non-superadmin keys). |
|
|
235
236
|
| `memory_forget` | Delete one of your own long-term memories by id. A foreign-subject, foreign-tenant, or unknown id returns 404 (no existence leak). Required: `id`. |
|
|
237
|
+
| `memory_promote` | Call at session end to compile this session's short-term (`session`-tier) memory into durable `long_term` memory — unlike `memory_remember` (a single explicit write), this compiles the whole session in one shot; fire it once at session end, not per turn. Returns 202 with `{job_id, session_id, status: "enqueued"}` — promotion runs asynchronously, so the resulting memory is recallable via `memory_recall` only after the worker drains. You can only promote your own sessions (scope resolved server-side from your key). Required: `session_id`. |
|
|
236
238
|
|
|
237
239
|
### Knowledge Management Tools (orchestrator key)
|
|
238
240
|
|
|
@@ -242,8 +244,8 @@ it is enforced server-side and a no-op for a non-superadmin key — see below.)
|
|
|
242
244
|
| `knowledge_bulk_publish` | **Requires `LOOPCTL_USER_KEY`.** Publish drafts, partial-success style: every valid draft publishes; others are reported per-id as `skipped` (already published — idempotent — or archived/superseded), `not_found`, or `errored`. No 100-id cap (auto-chunked); duplicates ignored; safe to retry. `meta.count` = published; `meta.counts`/`meta.results` give the breakdown. Required: `article_ids` (array). |
|
|
243
245
|
| `knowledge_unpublish` | **Requires `LOOPCTL_USER_KEY`.** Revert a published article back to draft (hidden from search/context, not deleted). Required: `article_id`. |
|
|
244
246
|
| `knowledge_bulk_unpublish` | **Requires `LOOPCTL_USER_KEY`.** Revert published articles to draft in bulk, partial-success style (mirror of `knowledge_bulk_publish`): per-id `unpublished`/`skipped` (already draft, or archived/superseded)/`not_found`/`errored`. No 100-id cap (auto-chunked, ≤5000); duplicates ignored; safe to retry. Not deleted (re-publish to restore; `knowledge_bulk_delete` to archive). `meta.count`/`meta.counts`/`meta.results` give the breakdown. Required: `article_ids` (array). |
|
|
245
|
-
| `knowledge_archive` |
|
|
246
|
-
| `knowledge_delete` |
|
|
247
|
+
| `knowledge_archive` | Soft-delete an article (draft or published). Row retained for audit; hidden from all reads (reversible — re-publish/edit it back). Agent role — KB-content curation, visibility-scoped (another agent's private/owner memory 404s). Required: `article_id`. |
|
|
248
|
+
| `knowledge_delete` | Alias for `knowledge_archive` — DELETE verb on the REST API archives under the hood (soft delete, reversible, audited). Agent role. (Irreversible HARD delete is `knowledge_bulk_delete hard:true`, which stays `LOOPCTL_USER_KEY`.) Required: `article_id`. |
|
|
247
249
|
| `knowledge_bulk_delete` | **Requires `LOOPCTL_USER_KEY`.** Bulk archive (default, reversible) or IRREVERSIBLE hard-delete by selector. Provide exactly one selector: `article_ids` (list), `source_type`+`source_id` (every active article from a source), or `tag`+`confirm:true` (every active article with the tag — high blast radius). Default = set-based soft archive (idempotent; `meta.count`=archived, `meta.counts`/`meta.results` give the breakdown; ≤5000). **Dry-run** (`dry_run:true`) mutates nothing, returns `meta.would_affect` (with `hard:true` also a single-use `meta.token`, or `meta.confirm_hash` for oversized selectors). **Hard delete** (irreversible): dry-run with `hard:true` for a token, then call again with `hard:true`+`token` to FK-correctly delete the frozen id-set (links first, access events cascade). |
|
|
248
250
|
| `knowledge_drafts` | List draft (unpublished) knowledge articles with pagination. Optional: `limit` (default 20, max 1000 — over-max → 400, no silent clamp), `offset` (default 0), `project_id`. Returns `meta.total_count`. |
|
|
249
251
|
| `knowledge_lint` | Run a lint check on the knowledge wiki to identify stale or low-coverage articles. Optional: `project_id`, `stale_days`, `min_coverage`, `max_per_category` (default 50, max 500). True totals returned in `summary.total_per_category`. |
|
package/index.js
CHANGED
|
@@ -1065,6 +1065,26 @@ async function knowledgeCreate({
|
|
|
1065
1065
|
return toContent(result);
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
1068
|
+
// In-place edit of an existing article (#331). PATCH preserves the ID; only the
|
|
1069
|
+
// provided fields change. Agent role — KB-content curation, visibility-scoped
|
|
1070
|
+
// server-side (another agent's private/owner memory 404s).
|
|
1071
|
+
async function knowledgeUpdate({ article_id, title, body, category, tags, metadata }) {
|
|
1072
|
+
const payload = {};
|
|
1073
|
+
if (title != null) payload.title = title;
|
|
1074
|
+
if (body != null) payload.body = body;
|
|
1075
|
+
if (category != null) payload.category = category;
|
|
1076
|
+
if (tags != null) payload.tags = tags;
|
|
1077
|
+
if (metadata != null) payload.metadata = metadata;
|
|
1078
|
+
|
|
1079
|
+
const result = await apiCall(
|
|
1080
|
+
"PATCH",
|
|
1081
|
+
`/api/v1/articles/${article_id}`,
|
|
1082
|
+
payload,
|
|
1083
|
+
process.env.LOOPCTL_AGENT_KEY,
|
|
1084
|
+
);
|
|
1085
|
+
return toContent(result);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1068
1088
|
// --- Agent Memory Tools (US-28.4) ---
|
|
1069
1089
|
//
|
|
1070
1090
|
// memory_* is YOUR own scoped, private, accumulated working state — recall
|
|
@@ -1159,6 +1179,17 @@ async function memoryForget({ id }) {
|
|
|
1159
1179
|
return toContent(result);
|
|
1160
1180
|
}
|
|
1161
1181
|
|
|
1182
|
+
async function memoryPromote({ session_id }) {
|
|
1183
|
+
const payload = { session_id };
|
|
1184
|
+
const result = await apiCall(
|
|
1185
|
+
"POST",
|
|
1186
|
+
"/api/v1/memory/promote",
|
|
1187
|
+
payload,
|
|
1188
|
+
process.env.LOOPCTL_AGENT_KEY,
|
|
1189
|
+
);
|
|
1190
|
+
return toContent(result);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1162
1193
|
// --- Knowledge Management Tools (orch key) ---
|
|
1163
1194
|
|
|
1164
1195
|
async function knowledgePublish({ article_id }) {
|
|
@@ -1226,22 +1257,25 @@ async function knowledgeUnpublish({ article_id }) {
|
|
|
1226
1257
|
return toContent(result);
|
|
1227
1258
|
}
|
|
1228
1259
|
|
|
1260
|
+
// #331: single-article archive is agent-role KB curation (reversible soft delete,
|
|
1261
|
+
// audited, visibility-scoped server-side).
|
|
1229
1262
|
async function knowledgeArchive({ article_id }) {
|
|
1230
1263
|
const result = await apiCall(
|
|
1231
1264
|
"POST",
|
|
1232
1265
|
`/api/v1/articles/${article_id}/archive`,
|
|
1233
1266
|
null,
|
|
1234
|
-
process.env.
|
|
1267
|
+
process.env.LOOPCTL_AGENT_KEY
|
|
1235
1268
|
);
|
|
1236
1269
|
return toContent(result);
|
|
1237
1270
|
}
|
|
1238
1271
|
|
|
1272
|
+
// #331: soft-delete (archive) is agent-role KB curation, same as knowledge_archive.
|
|
1239
1273
|
async function knowledgeDelete({ article_id }) {
|
|
1240
1274
|
const result = await apiCall(
|
|
1241
1275
|
"DELETE",
|
|
1242
1276
|
`/api/v1/articles/${article_id}`,
|
|
1243
1277
|
null,
|
|
1244
|
-
process.env.
|
|
1278
|
+
process.env.LOOPCTL_AGENT_KEY
|
|
1245
1279
|
);
|
|
1246
1280
|
return toContent(result);
|
|
1247
1281
|
}
|
|
@@ -3146,6 +3180,54 @@ const TOOLS = [
|
|
|
3146
3180
|
required: ["title", "body"],
|
|
3147
3181
|
},
|
|
3148
3182
|
},
|
|
3183
|
+
{
|
|
3184
|
+
name: "knowledge_update",
|
|
3185
|
+
description:
|
|
3186
|
+
"Edit an EXISTING knowledge article IN PLACE, preserving its ID. Use this to fold a " +
|
|
3187
|
+
"new fact into a canonical article, tidy a hub, retag, or reclassify — WITHOUT " +
|
|
3188
|
+
"creating a new row and churning the article ID (IDs are load-bearing: cited in " +
|
|
3189
|
+
"project CLAUDE.mds and cross-links). Send only the fields you want to change; every " +
|
|
3190
|
+
"field is optional except article_id. `tags` REPLACES the whole array (send the full " +
|
|
3191
|
+
"desired set, not a delta). A changed body/tags re-triggers embedding + auto-linking. " +
|
|
3192
|
+
"Agent role — this is KB-content curation (reversible + audited). Visibility-scoped: " +
|
|
3193
|
+
"you can only edit an article you can see, so another agent's private/owner memory " +
|
|
3194
|
+
"returns 404. `tenant_id` is never accepted. Returns the full updated article. To " +
|
|
3195
|
+
"instead retire/replace an article, use knowledge_archive or knowledge_resolve_conflict.",
|
|
3196
|
+
inputSchema: {
|
|
3197
|
+
type: "object",
|
|
3198
|
+
properties: {
|
|
3199
|
+
article_id: {
|
|
3200
|
+
type: "string",
|
|
3201
|
+
description: "The UUID of the article to edit (preserved across the update).",
|
|
3202
|
+
},
|
|
3203
|
+
title: {
|
|
3204
|
+
type: "string",
|
|
3205
|
+
description: "Optional: new title.",
|
|
3206
|
+
},
|
|
3207
|
+
body: {
|
|
3208
|
+
type: "string",
|
|
3209
|
+
description: "Optional: new body (Markdown). Re-triggers embedding + linking.",
|
|
3210
|
+
},
|
|
3211
|
+
category: {
|
|
3212
|
+
type: "string",
|
|
3213
|
+
description: "Optional: new category.",
|
|
3214
|
+
},
|
|
3215
|
+
tags: {
|
|
3216
|
+
type: "array",
|
|
3217
|
+
items: { type: "string" },
|
|
3218
|
+
description: "Optional: REPLACES the whole tags array (send the full desired set).",
|
|
3219
|
+
},
|
|
3220
|
+
metadata: {
|
|
3221
|
+
type: "object",
|
|
3222
|
+
description:
|
|
3223
|
+
"Optional: extensible JSONB (merged/replaced wholesale). For an agent key, an " +
|
|
3224
|
+
"agent-memory `agent_id` is stamped from your verified key identity — you cannot " +
|
|
3225
|
+
"re-attribute a memory to another agent.",
|
|
3226
|
+
},
|
|
3227
|
+
},
|
|
3228
|
+
required: ["article_id"],
|
|
3229
|
+
},
|
|
3230
|
+
},
|
|
3149
3231
|
|
|
3150
3232
|
// Agent Memory Tools (US-28.4)
|
|
3151
3233
|
{
|
|
@@ -3298,6 +3380,29 @@ const TOOLS = [
|
|
|
3298
3380
|
required: ["id"],
|
|
3299
3381
|
},
|
|
3300
3382
|
},
|
|
3383
|
+
{
|
|
3384
|
+
name: "memory_promote",
|
|
3385
|
+
description:
|
|
3386
|
+
"Call at session end to compile this session's short-term memory into durable long-term memory" +
|
|
3387
|
+
" — private, scoped working state, NOT the shared knowledge wiki. Unlike " +
|
|
3388
|
+
"memory_remember, which writes a single explicit fact, this compiles the WHOLE session's " +
|
|
3389
|
+
"session-tier memory in one shot — fire it once at session end, not per turn. Scope " +
|
|
3390
|
+
"(tenant_id/subject_id) is resolved server-side from your API key: you can only promote " +
|
|
3391
|
+
"your OWN sessions. Returns 202 Accepted with `{job_id, session_id, status: \"enqueued\"}` " +
|
|
3392
|
+
"— promotion runs asynchronously via a background worker, so the resulting long-term " +
|
|
3393
|
+
"memory becomes recallable via memory_recall only after that worker drains, not " +
|
|
3394
|
+
"immediately.",
|
|
3395
|
+
inputSchema: {
|
|
3396
|
+
type: "object",
|
|
3397
|
+
properties: {
|
|
3398
|
+
session_id: {
|
|
3399
|
+
type: "string",
|
|
3400
|
+
description: "The session whose short-term memory to compile into long-term memory.",
|
|
3401
|
+
},
|
|
3402
|
+
},
|
|
3403
|
+
required: ["session_id"],
|
|
3404
|
+
},
|
|
3405
|
+
},
|
|
3301
3406
|
|
|
3302
3407
|
// Knowledge Management Tools (orchestrator key)
|
|
3303
3408
|
{
|
|
@@ -3387,9 +3492,10 @@ const TOOLS = [
|
|
|
3387
3492
|
name: "knowledge_archive",
|
|
3388
3493
|
description:
|
|
3389
3494
|
"Archive an article (soft delete). The article is hidden from search, context, " +
|
|
3390
|
-
"and the index but the row is retained for audit/history
|
|
3391
|
-
"
|
|
3392
|
-
"
|
|
3495
|
+
"and the index but the row is retained for audit/history (reversible — re-publish " +
|
|
3496
|
+
"or edit it back). Works for drafts and published articles. Agent role — KB-content " +
|
|
3497
|
+
"curation. Visibility-scoped: you can only archive an article you can see, so " +
|
|
3498
|
+
"another agent's private/owner memory returns 404.",
|
|
3393
3499
|
inputSchema: {
|
|
3394
3500
|
type: "object",
|
|
3395
3501
|
properties: {
|
|
@@ -3406,8 +3512,9 @@ const TOOLS = [
|
|
|
3406
3512
|
description:
|
|
3407
3513
|
"Delete an article. Under the hood this performs the same soft-delete (archive) " +
|
|
3408
3514
|
"as knowledge_archive — use whichever name is clearer at the call site. The row " +
|
|
3409
|
-
"is retained for audit; there is no hard delete
|
|
3410
|
-
"
|
|
3515
|
+
"is retained for audit; there is no hard delete (that is knowledge_bulk_delete " +
|
|
3516
|
+
"hard:true, which stays user-gated). Agent role — KB-content curation, reversible + " +
|
|
3517
|
+
"audited, visibility-scoped (another agent's private/owner memory 404s).",
|
|
3411
3518
|
inputSchema: {
|
|
3412
3519
|
type: "object",
|
|
3413
3520
|
properties: {
|
|
@@ -4510,6 +4617,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
4510
4617
|
case "knowledge_create":
|
|
4511
4618
|
return await knowledgeCreate(args);
|
|
4512
4619
|
|
|
4620
|
+
case "knowledge_update":
|
|
4621
|
+
return await knowledgeUpdate(args);
|
|
4622
|
+
|
|
4513
4623
|
// Agent Memory Tools
|
|
4514
4624
|
case "memory_remember":
|
|
4515
4625
|
return await memoryRemember(args);
|
|
@@ -4523,6 +4633,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
4523
4633
|
case "memory_forget":
|
|
4524
4634
|
return await memoryForget(args);
|
|
4525
4635
|
|
|
4636
|
+
case "memory_promote":
|
|
4637
|
+
return await memoryPromote(args);
|
|
4638
|
+
|
|
4526
4639
|
// Knowledge Management Tools
|
|
4527
4640
|
case "knowledge_publish":
|
|
4528
4641
|
return await knowledgePublish(args);
|