agent-planner-mcp 1.5.1 → 1.5.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-planner-mcp",
3
- "version": "1.5.1",
3
+ "version": "1.5.4",
4
4
  "description": "MCP server for AgentPlanner — AI agent orchestration with planning, dependencies, knowledge graphs, and human oversight",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -463,8 +463,10 @@ async function listPlansHandler(args, apiClient) {
463
463
  const q = filter.query.toLowerCase();
464
464
  plans = plans.filter((p) => (p.title || '').toLowerCase().includes(q));
465
465
  }
466
- plans = plans.slice(0, filter.limit || 50);
467
466
 
467
+ // Summarize the FULL filtered set BEFORE paginating — otherwise `total` and
468
+ // the status counts only reflect the truncated page, making an agent think
469
+ // it has seen every plan when it hasn't.
468
470
  const summary = plans.reduce(
469
471
  (acc, p) => {
470
472
  acc[p.status] = (acc[p.status] || 0) + 1;
@@ -474,10 +476,15 @@ async function listPlansHandler(args, apiClient) {
474
476
  { total: 0 },
475
477
  );
476
478
 
479
+ const limit = filter.limit || 50;
480
+ const page = plans.slice(0, limit);
481
+ summary.returned = page.length;
482
+ summary.truncated = plans.length > page.length; // true → raise `filter.limit` to see the rest
483
+
477
484
  return formatResponse({
478
485
  as_of: asOf(),
479
486
  summary,
480
- plans: plans.map((p) => ({
487
+ plans: page.map((p) => ({
481
488
  id: p.id,
482
489
  title: p.title,
483
490
  status: p.status,
@@ -537,7 +544,16 @@ async function searchHandler(args, apiClient) {
537
544
  result = await apiClient.search.searchPlan(scope_id, query);
538
545
  } else {
539
546
  const global = await apiClient.search.globalSearch(query);
540
- const all = Array.isArray(global?.results) ? global.results : [];
547
+ // The backend returns `results` as a GROUPED object
548
+ // ({ plans, nodes, comments, logs }), not a flat array — so the old
549
+ // `Array.isArray(results) ? … : []` always fell to [] and global search
550
+ // returned nothing. Flatten both shapes.
551
+ const r = global?.results;
552
+ const all = Array.isArray(r)
553
+ ? r
554
+ : r && typeof r === 'object'
555
+ ? [...(r.plans || []), ...(r.nodes || []), ...(r.comments || []), ...(r.logs || [])]
556
+ : [];
541
557
  const matchScope = (r) => {
542
558
  if (scope === 'global') return true;
543
559
  if (scope === 'plans') return r.type === 'plan';
@@ -938,7 +938,10 @@ async function formIntentionHandler(args, apiClient) {
938
938
  continue;
939
939
  }
940
940
  try {
941
- await apiClient.axiosInstance.post('/dependencies', {
941
+ // Plan-scoped route — the bare /dependencies path is unmounted (only
942
+ // /dependencies/cross-plan + /external exist), so it 404s and silently
943
+ // dropped every inline edge. POST /plans/:id/dependencies is canonical.
944
+ await apiClient.axiosInstance.post(`/plans/${plan.id}/dependencies`, {
942
945
  source_node_id: sourceId,
943
946
  target_node_id: intent.targetId,
944
947
  dependency_type: 'blocks',
@@ -1133,7 +1136,9 @@ async function proposeResearchChainHandler(args, apiClient) {
1133
1136
  [created.plan.id, created.implement.id],
1134
1137
  ]) {
1135
1138
  try {
1136
- await apiClient.axiosInstance.post('/dependencies', {
1139
+ // Plan-scoped route — bare /dependencies 404s (unmounted), which silently
1140
+ // dropped both chain edges and left 3 orphan tasks.
1141
+ await apiClient.axiosInstance.post(`/plans/${plan_id}/dependencies`, {
1137
1142
  source_node_id: from,
1138
1143
  target_node_id: to,
1139
1144
  dependency_type: 'blocks',
@@ -1144,6 +1149,7 @@ async function proposeResearchChainHandler(args, apiClient) {
1144
1149
  }
1145
1150
  }
1146
1151
 
1152
+ const edgeFailures = failures.filter((f) => f.step === 'create_edge');
1147
1153
  return formatResponse({
1148
1154
  as_of: asOf(),
1149
1155
  plan_id,
@@ -1154,6 +1160,11 @@ async function proposeResearchChainHandler(args, apiClient) {
1154
1160
  implement: { id: created.implement.id, title: created.implement.title },
1155
1161
  edges,
1156
1162
  failures,
1163
+ // Fail loudly: don't let the caller believe the chain is wired when the
1164
+ // blocking edges didn't get created.
1165
+ ...(edgeFailures.length
1166
+ ? { warning: `Chain tasks created but ${edgeFailures.length} blocking edge(s) FAILED — the Research→Plan→Implement ordering is NOT wired: ${edgeFailures.map((f) => f.error).join('; ')}` }
1167
+ : {}),
1157
1168
  next_step: "Claim the Research task with claim_next_task({plan_id}) to begin investigation.",
1158
1169
  });
1159
1170
  }