agent-planner-mcp 1.5.14 → 1.5.17

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/SKILL.md CHANGED
@@ -42,6 +42,9 @@ AgentPlanner exposes a **BDI-aligned** surface — Beliefs (state queries), Desi
42
42
  - `update_goal` — atomic goal update; subsumes link/unlink + achiever changes
43
43
  - `create_goal` — create a new top-level goal (no parent). Agents create goals directly when asked — no UI step. Defaults to `status='active'`.
44
44
  - `derive_subgoal` *(v1.0)* — create a sub-goal under an existing parent (use `create_goal` for top-level).
45
+ - `record_criterion_progress` — set the `current` value of a measurable success criterion (by `criterion_id` or 0-based `index`, both shown in `goal_state`). The write that drives goal attainment, e.g. "p99 latency: current 140 → 100".
46
+
47
+ **Success criteria** (`success_criteria` on create/derive/update) accept either plain strings (qualitative) or structured measurable objects: `{ statement, metric?, target?, current?, unit?, direction: 'increase'|'decrease'|'boolean' }`. A criterion with **metric + target + direction** is *measurable* and counts toward goal attainment (`increase`: current ≥ target, `decrease`: current ≤ target, `boolean`: current truthy). Prefer measurable criteria — "p99 latency < 100ms" beats "make it fast".
45
48
 
46
49
  ### Intentions — what am I committing to?
47
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-planner-mcp",
3
- "version": "1.5.14",
3
+ "version": "1.5.17",
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": {
package/src/api-client.js CHANGED
@@ -592,6 +592,11 @@ const goals = {
592
592
  return response.data;
593
593
  },
594
594
 
595
+ recordCriterionProgress: async (goalId, body) => {
596
+ const response = await apiClient.post(`/goals/${goalId}/criteria/progress`, body);
597
+ return response.data;
598
+ },
599
+
595
600
  // v2 goal-dependency endpoints
596
601
  getPath: async (goalId, maxDepth) => {
597
602
  const params = maxDepth ? `?max_depth=${maxDepth}` : '';
@@ -1087,6 +1092,12 @@ function createApiClient(token, options = {}) {
1087
1092
  // Export the axios instance for direct use
1088
1093
  const axiosInstance = apiClient;
1089
1094
 
1095
+ // ─── System ───────────────────────────────────────────────────
1096
+ // Operational metadata about the backend the MCP is talking to.
1097
+ const system = {
1098
+ version: () => apiClient.get('/version').then(r => r.data),
1099
+ };
1100
+
1090
1101
  // ─── Coherence ────────────────────────────────────────────────
1091
1102
  const coherence = {
1092
1103
  getPending: () => apiClient.get('/coherence/pending').then(r => r.data),
@@ -1112,6 +1123,7 @@ module.exports = {
1112
1123
  coherence,
1113
1124
  users,
1114
1125
  agentLoop,
1126
+ system,
1115
1127
  v1,
1116
1128
  axiosInstance, // Export for direct API calls
1117
1129
  createApiClient // Factory for per-session clients (HTTP mode)
@@ -9,6 +9,35 @@
9
9
 
10
10
  const { asOf, formatResponse, errorResponse, safeArray, apiErrorMessage } = require('./_shared');
11
11
 
12
+ // Success criteria accept plain strings (qualitative) or structured measurable
13
+ // units. A criterion with metric+target+direction becomes "measurable" and
14
+ // drives goal attainment (see the backend's goalCriteria.normalizeCriteria,
15
+ // which also maps legacy string[] / {criteria:[]} shapes onto this).
16
+ const SUCCESS_CRITERIA_SCHEMA = {
17
+ type: 'array',
18
+ description:
19
+ "Each entry is a plain string (qualitative) OR a structured object " +
20
+ "{ statement, metric?, target?, current?, unit?, direction: 'increase'|'decrease'|'boolean' }. " +
21
+ "Give a criterion metric+target+direction to make it measurable so it counts toward goal attainment.",
22
+ items: {
23
+ oneOf: [
24
+ { type: 'string' },
25
+ {
26
+ type: 'object',
27
+ required: ['statement'],
28
+ properties: {
29
+ statement: { type: 'string', description: 'Human-readable condition.' },
30
+ metric: { type: 'string', description: 'What is measured, e.g. "p99 latency".' },
31
+ target: { description: 'Goal value (number or string).' },
32
+ current: { description: 'Latest observed value (number or string).' },
33
+ unit: { type: 'string', description: 'e.g. "ms", "%", "customers".' },
34
+ direction: { type: 'string', enum: ['increase', 'decrease', 'boolean'] },
35
+ },
36
+ },
37
+ ],
38
+ },
39
+ };
40
+
12
41
  const listGoalsDefinition = {
13
42
  name: 'list_goals',
14
43
  description:
@@ -93,7 +122,7 @@ const updateGoalDefinition = {
93
122
  // Commitment: true once the goal is promoted to active execution
94
123
  // (replaces the old desire/intention goal_type vocabulary).
95
124
  committed: { type: 'boolean' },
96
- success_criteria: {},
125
+ success_criteria: SUCCESS_CRITERIA_SCHEMA,
97
126
  add_linked_plans: { type: 'array', items: { type: 'string' } },
98
127
  remove_linked_plans: { type: 'array', items: { type: 'string' } },
99
128
  add_achievers: { type: 'array', items: { type: 'string' } },
@@ -210,11 +239,7 @@ const deriveSubgoalDefinition = {
210
239
  default: 'active',
211
240
  description: "Default 'active' for human-directed creation. Pass 'draft' when acting autonomously without explicit user direction.",
212
241
  },
213
- success_criteria: {
214
- type: 'array',
215
- items: { type: 'string' },
216
- description: "Concrete, observable conditions that mark this sub-goal achieved.",
217
- },
242
+ success_criteria: SUCCESS_CRITERIA_SCHEMA,
218
243
  priority: { type: 'integer', default: 0 },
219
244
  },
220
245
  required: ['parent_goal_id', 'title', 'rationale'],
@@ -301,11 +326,7 @@ const createGoalDefinition = {
301
326
  default: 'active',
302
327
  description: "Default 'active' (live). Pass 'draft' to propose without activating.",
303
328
  },
304
- success_criteria: {
305
- type: 'array',
306
- items: { type: 'string' },
307
- description: "Concrete, observable conditions that mark this goal achieved.",
308
- },
329
+ success_criteria: SUCCESS_CRITERIA_SCHEMA,
309
330
  priority: { type: 'integer', minimum: 0, maximum: 10, default: 0 },
310
331
  workspace_id: { type: 'string', description: "Optional. Target workspace; defaults to the active org's default workspace." },
311
332
  },
@@ -342,12 +363,66 @@ async function createGoalHandler(args, apiClient) {
342
363
  });
343
364
  }
344
365
 
366
+ // ─────────────────────────────────────────────────────────────────────────
367
+ // record_criterion_progress — set the current value of a measurable criterion.
368
+ // This is the write that makes goal attainment real (metric moved 40→72).
369
+ // ─────────────────────────────────────────────────────────────────────────
370
+
371
+ const recordCriterionProgressDefinition = {
372
+ name: 'record_criterion_progress',
373
+ description:
374
+ "Record the latest observed value of one of a goal's success criteria " +
375
+ "(e.g. a metric moved 40→72). Identify the criterion by criterion_id " +
376
+ "(stable, like 'c0') or its 0-based index — both are visible in goal_state. " +
377
+ "Only measurable criteria (metric+target+direction) count toward attainment; " +
378
+ "this is the write that makes goal attainment real.",
379
+ inputSchema: {
380
+ type: 'object',
381
+ properties: {
382
+ goal_id: { type: 'string' },
383
+ criterion_id: { type: 'string', description: "Stable criterion id (e.g. 'c0'). Use this or index." },
384
+ index: { type: 'integer', description: '0-based position of the criterion. Alternative to criterion_id.' },
385
+ current: { description: 'Latest observed value (number or string). Required.' },
386
+ },
387
+ required: ['goal_id', 'current'],
388
+ },
389
+ };
390
+
391
+ async function recordCriterionProgressHandler(args, apiClient) {
392
+ const { goal_id, criterion_id, index, current } = args;
393
+ if (!goal_id) return errorResponse('invalid_arg', 'record_criterion_progress requires goal_id');
394
+ if (current === undefined) return errorResponse('invalid_arg', 'record_criterion_progress requires current');
395
+ if (!criterion_id && !Number.isInteger(index)) {
396
+ return errorResponse('invalid_arg', 'record_criterion_progress requires criterion_id or index');
397
+ }
398
+
399
+ const body = { current };
400
+ if (criterion_id) body.criterion_id = criterion_id;
401
+ if (Number.isInteger(index)) body.index = index;
402
+
403
+ try {
404
+ const result = await apiClient.goals.recordCriterionProgress(goal_id, body);
405
+ return formatResponse({ as_of: asOf(), goal_id, criterion: result.criterion, criteria: result.criteria });
406
+ } catch (err) {
407
+ const status = err.response?.status;
408
+ if (status === 404) return errorResponse('not_found', apiErrorMessage(err));
409
+ return errorResponse('upstream_unavailable', `record_criterion_progress failed: ${apiErrorMessage(err)}`);
410
+ }
411
+ }
412
+
345
413
  module.exports = {
346
- definitions: [listGoalsDefinition, updateGoalDefinition, createGoalDefinition, deriveSubgoalDefinition],
414
+ definitions: [
415
+ listGoalsDefinition,
416
+ updateGoalDefinition,
417
+ createGoalDefinition,
418
+ deriveSubgoalDefinition,
419
+ recordCriterionProgressDefinition,
420
+ ],
347
421
  handlers: {
348
422
  list_goals: listGoalsHandler,
349
423
  update_goal: updateGoalHandler,
350
424
  create_goal: createGoalHandler,
351
425
  derive_subgoal: deriveSubgoalHandler,
426
+ record_criterion_progress: recordCriterionProgressHandler,
352
427
  },
353
428
  };
@@ -19,19 +19,31 @@ const getStartedDefinition = {
19
19
  },
20
20
  };
21
21
 
22
- async function getStartedHandler(args) {
22
+ async function getStartedHandler(args, apiClient) {
23
+ // Best-effort backend version so one call shows which builds are in play
24
+ // (the MCP and the API it is actually talking to are deployed separately).
25
+ let api = { version: 'unavailable' };
26
+ try {
27
+ if (apiClient?.system?.version) api = await apiClient.system.version();
28
+ } catch {
29
+ api = { version: 'unavailable' };
30
+ }
31
+
23
32
  return formatResponse({
24
33
  as_of: asOf(),
25
34
  mcp_version: MCP_VERSION,
35
+ api_url: process.env.API_URL || 'http://localhost:3000',
36
+ api_version: api.version,
37
+ api_build: api.commit ? { commit: api.commit, started_at: api.started_at } : undefined,
26
38
  overview:
27
39
  "AgentPlanner exposes a BDI-aligned MCP surface. Tools are grouped by " +
28
40
  "Beliefs (state queries), Desires (goals), and Intentions (committed actions). " +
29
41
  "Each tool answers one whole agentic question and returns an `as_of` timestamp.",
30
42
  tools_by_namespace: {
31
43
  beliefs: ['briefing', 'list_plans', 'task_context', 'goal_state', 'recall_knowledge', 'search', 'plan_analysis'],
32
- desires: ['list_goals', 'create_goal', 'update_goal', 'derive_subgoal'],
44
+ desires: ['list_goals', 'create_goal', 'update_goal', 'derive_subgoal', 'record_criterion_progress'],
33
45
  intentions: ['form_intention', 'extend_intention', 'link_intentions', 'propose_research_chain', 'claim_next_task', 'update_task', 'update_node', 'release_task', 'queue_decision', 'resolve_decision', 'add_learning'],
34
- workspaces: ['list_workspaces', 'create_workspace', 'list_blueprints', 'fork_blueprint', 'save_as_blueprint'],
46
+ workspaces: ['list_workspaces', 'create_workspace', 'list_blueprints', 'fork_blueprint', 'save_as_blueprint', 'delete_blueprint'],
35
47
  },
36
48
  recommended_workflows: [
37
49
  {