loopctl-mcp-server 2.25.0 → 2.26.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 (2) hide show
  1. package/index.js +54 -6
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1027,9 +1027,9 @@ async function knowledgeBulkDelete({
1027
1027
 
1028
1028
  async function knowledgeDrafts({ limit, offset, project_id }) {
1029
1029
  const params = new URLSearchParams();
1030
- // Pass `limit` through verbatim (like knowledge_list/index/search) so the
1031
- // server honors it up to its max page size and returns 400 above it rather
1032
- // than silently clamping client-side, which would truncate draft enumeration.
1030
+ // Pass `limit` through verbatim (like knowledge_list/index/search) so the server
1031
+ // honors it up to its max page size, clamping above it server-side rather than
1032
+ // silently clamping client-side (which would truncate draft enumeration).
1033
1033
  if (limit != null) params.set("limit", String(limit));
1034
1034
  if (offset != null) params.set("offset", String(offset));
1035
1035
  if (project_id) params.set("project_id", project_id);
@@ -1038,6 +1038,18 @@ async function knowledgeDrafts({ limit, offset, project_id }) {
1038
1038
  return toContent(result);
1039
1039
  }
1040
1040
 
1041
+ async function knowledgeConflicts({ limit, offset }) {
1042
+ const params = new URLSearchParams();
1043
+ if (limit != null) params.set("limit", String(limit));
1044
+ if (offset != null) params.set("offset", String(offset));
1045
+ const qs = params.toString();
1046
+ const path = qs
1047
+ ? `/api/v1/knowledge/conflicts?${qs}`
1048
+ : "/api/v1/knowledge/conflicts";
1049
+ const result = await apiCall("GET", path, null, process.env.LOOPCTL_AGENT_KEY);
1050
+ return toContent(result);
1051
+ }
1052
+
1041
1053
  async function knowledgeLint({ project_id, stale_days, min_coverage, max_per_category }) {
1042
1054
  const params = new URLSearchParams();
1043
1055
  if (stale_days != null) params.set("stale_days", String(stale_days));
@@ -2852,8 +2864,8 @@ const TOOLS = [
2852
2864
  description:
2853
2865
  "List draft (unpublished) knowledge articles. Requires orchestrator role. " +
2854
2866
  "Returns paginated drafts with total_count in meta. Paginate via offset/limit " +
2855
- "(limit honored up to 1000; a limit above the max is rejected with 400, not " +
2856
- "silently clamped).",
2867
+ "(limit honored up to 1000; a limit above the max is clamped to the maximum, " +
2868
+ "never rejected, so pagination stays complete).",
2857
2869
  inputSchema: {
2858
2870
  type: "object",
2859
2871
  properties: {
@@ -2861,7 +2873,7 @@ const TOOLS = [
2861
2873
  type: "integer",
2862
2874
  description:
2863
2875
  "Max drafts per page (default 20, max 1000). A limit above the max is " +
2864
- "rejected with 400not silently clamped — so offset pagination stays complete.",
2876
+ "clamped to the maximum never rejected — so offset pagination stays complete.",
2865
2877
  default: 20,
2866
2878
  minimum: 1,
2867
2879
  maximum: 1000,
@@ -2880,6 +2892,39 @@ const TOOLS = [
2880
2892
  required: [],
2881
2893
  },
2882
2894
  },
2895
+ {
2896
+ name: "knowledge_conflicts",
2897
+ description:
2898
+ "List potential-conflict article pairs — published articles flagged 'too similar " +
2899
+ "to comfortably coexist' by the auto-linker / nightly lint sweep, highest-overlap " +
2900
+ "first. The KB only FLAGS the pair (via a mechanical similarity threshold); it does " +
2901
+ "NOT decide whether it's a redundancy to merge or a real contradiction — that's your " +
2902
+ "call, with the live context. Each entry has the two articles (id/title/status/" +
2903
+ "category) and their similarity. Read both, then merge (supersede one, knowledge_create " +
2904
+ "the merged article, or PATCH) or, if they genuinely disagree, reconcile. Paginated " +
2905
+ "with total_count in meta. Agent role.",
2906
+ inputSchema: {
2907
+ type: "object",
2908
+ properties: {
2909
+ limit: {
2910
+ type: "integer",
2911
+ description:
2912
+ "Max pairs per page (default 50, max 1000). A limit above the max is clamped " +
2913
+ "to the maximum — never rejected — so offset pagination stays complete.",
2914
+ default: 50,
2915
+ minimum: 1,
2916
+ maximum: 1000,
2917
+ },
2918
+ offset: {
2919
+ type: "integer",
2920
+ description: "Pagination offset. Default 0.",
2921
+ default: 0,
2922
+ minimum: 0,
2923
+ },
2924
+ },
2925
+ required: [],
2926
+ },
2927
+ },
2883
2928
  {
2884
2929
  name: "knowledge_lint",
2885
2930
  description:
@@ -3500,6 +3545,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3500
3545
  case "knowledge_drafts":
3501
3546
  return await knowledgeDrafts(args);
3502
3547
 
3548
+ case "knowledge_conflicts":
3549
+ return await knowledgeConflicts(args);
3550
+
3503
3551
  case "knowledge_lint":
3504
3552
  return await knowledgeLint(args);
3505
3553
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopctl-mcp-server",
3
- "version": "2.25.0",
3
+ "version": "2.26.0",
4
4
  "description": "MCP server for loopctl — structural trust for AI development loops",
5
5
  "type": "module",
6
6
  "main": "index.js",