loopctl-mcp-server 2.43.0 → 2.45.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/index.js +121 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -188,6 +188,7 @@ autonomous agent) can self-remediate without a human. Full agent-tenant lifecycl
188
188
  | `get_cost_summary` | orch | Get cost/token usage summary for a project, optionally broken down by `agent`, `epic`, or `model`. |
189
189
  | `get_story_token_usage` | orch | Get all token usage records for a single story. |
190
190
  | `get_cost_anomalies` | orch | Get cost anomaly alerts — stories or agents exceeding expected budgets. Optionally filter by project. |
191
+ | `get_ingestion_anomalies` | orch | Get ingestion-health anomalies — capture-silence (a source_type stopped producing articles). Check whether knowledge capture is still landing. |
191
192
  | `set_token_budget` | orch | Set a token budget (in millicents) for a project, epic, story, or agent scope. Requires orchestrator role. |
192
193
 
193
194
  ### Knowledge Wiki Tools (agent key)
package/index.js CHANGED
@@ -413,6 +413,30 @@ async function createKbScope({ name, slug, repo_url, description, tech_stack })
413
413
  return toContent(result);
414
414
  }
415
415
 
416
+ async function archiveKbScope({ project_id }) {
417
+ // Reversible soft-delete of an agent-owned :kb scope on the AGENT key; frees its
418
+ // max_projects slot. The server rejects a :work project (422). Reverse with restore_kb_scope.
419
+ const result = await apiCall(
420
+ "DELETE",
421
+ `/api/v1/kb-scopes/${project_id}`,
422
+ null,
423
+ process.env.LOOPCTL_AGENT_KEY,
424
+ );
425
+ return toContent(result);
426
+ }
427
+
428
+ async function restoreKbScope({ project_id }) {
429
+ // Re-activate an archived :kb scope on the AGENT key (re-consumes a max_projects slot;
430
+ // 422 if at the cap). The server rejects a :work project (422).
431
+ const result = await apiCall(
432
+ "POST",
433
+ `/api/v1/kb-scopes/${project_id}/restore`,
434
+ {},
435
+ process.env.LOOPCTL_AGENT_KEY,
436
+ );
437
+ return toContent(result);
438
+ }
439
+
416
440
  async function deleteProject({ project_id }) {
417
441
  const result = await apiCall(
418
442
  "DELETE",
@@ -800,6 +824,35 @@ async function getCostAnomalies({ project_id, page, page_size }) {
800
824
  return toContent(result);
801
825
  }
802
826
 
827
+ async function getIngestionAnomalies({
828
+ source_type,
829
+ anomaly_type,
830
+ resolved,
831
+ include_archived,
832
+ page,
833
+ page_size,
834
+ }) {
835
+ const params = new URLSearchParams();
836
+ if (source_type) params.set("source_type", source_type);
837
+ if (anomaly_type) params.set("anomaly_type", anomaly_type);
838
+ if (resolved != null) params.set("resolved", String(resolved));
839
+ if (include_archived != null) params.set("include_archived", String(include_archived));
840
+ if (page != null) params.set("page", String(page));
841
+ if (page_size != null) params.set("page_size", String(page_size));
842
+
843
+ const query = params.toString() ? `?${params}` : "";
844
+ // Orchestrator-gated endpoint (RequireRole :orchestrator). Pass the ORCH key
845
+ // explicitly so a misconfigured single agent-role LOOPCTL_API_KEY fails loudly
846
+ // rather than drifting into an undiagnosable 403.
847
+ const result = await apiCall(
848
+ "GET",
849
+ `/api/v1/ingestion-anomalies${query}`,
850
+ undefined,
851
+ process.env.LOOPCTL_ORCH_KEY
852
+ );
853
+ return toContent(result);
854
+ }
855
+
803
856
  async function setTokenBudget({ scope_type, scope_id, budget_millicents, alert_threshold_pct }) {
804
857
  const body = { scope_type, scope_id, budget_millicents };
805
858
  if (alert_threshold_pct != null) body.alert_threshold_pct = alert_threshold_pct;
@@ -2130,6 +2183,30 @@ const TOOLS = [
2130
2183
  required: ["name", "slug"],
2131
2184
  },
2132
2185
  },
2186
+ {
2187
+ name: "archive_kb_scope",
2188
+ description:
2189
+ "Archive (reversible soft-delete) a knowledge-only project scope (kind: kb) you own, on the agent key. Frees the scope's slot in the tenant's max_projects budget so you can reclaim KB-scope capacity — the reverse of create_kb_scope. Its articles remain readable/writable; restore_kb_scope re-activates it. Rejects a kind: work project (422) — archiving a work project stays human-anchored. Idempotent on an already-archived scope.",
2190
+ inputSchema: {
2191
+ type: "object",
2192
+ properties: {
2193
+ project_id: { type: "string", description: "UUID of the :kb scope to archive." },
2194
+ },
2195
+ required: ["project_id"],
2196
+ },
2197
+ },
2198
+ {
2199
+ name: "restore_kb_scope",
2200
+ description:
2201
+ "Restore (re-activate) an archived knowledge-only project scope (kind: kb) you own, on the agent key — the reverse of archive_kb_scope. Re-activating consumes an active max_projects slot, so it is rejected (422) when the tenant is at its cap. Rejects a kind: work project (422).",
2202
+ inputSchema: {
2203
+ type: "object",
2204
+ properties: {
2205
+ project_id: { type: "string", description: "UUID of the archived :kb scope to restore." },
2206
+ },
2207
+ required: ["project_id"],
2208
+ },
2209
+ },
2133
2210
  {
2134
2211
  name: "delete_project",
2135
2212
  description:
@@ -2703,6 +2780,41 @@ const TOOLS = [
2703
2780
  required: [],
2704
2781
  },
2705
2782
  },
2783
+ {
2784
+ name: "get_ingestion_anomalies",
2785
+ description:
2786
+ "Get ingestion-health anomalies — capture-silence (a source_type that was producing " +
2787
+ "articles has gone silent). Use to check whether knowledge capture is still landing. " +
2788
+ "Paginated (page/page_size); advance `page` to enumerate all. Filter by source_type, " +
2789
+ "anomaly_type, resolved status, or include archived.",
2790
+ inputSchema: {
2791
+ type: "object",
2792
+ properties: {
2793
+ source_type: {
2794
+ type: "string",
2795
+ description: 'Optional: filter to one article source_type (e.g. "session_log").',
2796
+ },
2797
+ anomaly_type: {
2798
+ type: "string",
2799
+ enum: ["capture_silence"],
2800
+ description: 'Optional: filter by anomaly type (only "capture_silence" is currently produced).',
2801
+ },
2802
+ resolved: {
2803
+ type: "string",
2804
+ enum: ["false", "true", "all"],
2805
+ description:
2806
+ 'Which anomalies to return: "false" = unresolved only (default), "true" = resolved only, "all" = both.',
2807
+ },
2808
+ include_archived: {
2809
+ type: "boolean",
2810
+ description: "Optional: include archived (retired-source) anomalies (default false).",
2811
+ },
2812
+ page: { type: "integer", description: "Page number (default 1)." },
2813
+ page_size: { type: "integer", description: "Anomalies per page (default 20, max 100)." },
2814
+ },
2815
+ required: [],
2816
+ },
2817
+ },
2706
2818
  {
2707
2819
  name: "set_token_budget",
2708
2820
  description:
@@ -4893,6 +5005,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
4893
5005
  case "create_kb_scope":
4894
5006
  return await createKbScope(args);
4895
5007
 
5008
+ case "archive_kb_scope":
5009
+ return await archiveKbScope(args);
5010
+
5011
+ case "restore_kb_scope":
5012
+ return await restoreKbScope(args);
5013
+
4896
5014
  case "delete_project":
4897
5015
  return await deleteProject(args);
4898
5016
 
@@ -4965,6 +5083,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
4965
5083
  case "get_cost_anomalies":
4966
5084
  return await getCostAnomalies(args);
4967
5085
 
5086
+ case "get_ingestion_anomalies":
5087
+ return await getIngestionAnomalies(args);
5088
+
4968
5089
  case "set_token_budget":
4969
5090
  return await setTokenBudget(args);
4970
5091
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopctl-mcp-server",
3
- "version": "2.43.0",
3
+ "version": "2.45.0",
4
4
  "description": "MCP server for loopctl — structural trust for AI development loops",
5
5
  "type": "module",
6
6
  "main": "index.js",