@kynver-app/mcp-agent-os 0.3.6 → 0.3.7

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 CHANGED
@@ -51,6 +51,19 @@ AgentTask board (Phase 2 — batch 1 CRUD + batch 1.5 steering/lease):
51
51
  - `agent_os_task_claim`
52
52
  - `agent_os_task_renew_lease`
53
53
 
54
+ AgentPlan first-class plans (Phase 5A — versioned operational artifacts
55
+ separate from goals/projects/tasks):
56
+
57
+ - `agent_os_plan_create`
58
+ - `agent_os_plan_list`
59
+ - `agent_os_plan_get`
60
+ - `agent_os_plan_update`
61
+ - `agent_os_plan_add_version`
62
+ - `agent_os_plan_mark_current`
63
+ - `agent_os_plan_add_link`
64
+ - `agent_os_plan_list_links`
65
+ - `agent_os_plan_list_versions`
66
+
54
67
  Schemas are mirrored in `lib/mcp/tool-manifests/kynver-mcp-agent-os.json` in
55
68
  the Kynver repo (used as the static fallback when stdio spawn isn't available
56
69
  — e.g. on Vercel).
@@ -81,6 +94,18 @@ slug as `skillId`; user-authored skill memories use `AgentSkill.id`.
81
94
  summaries can then be synthesized from actual topics, actions, decisions, and
82
95
  follow-ups instead of generic lifecycle text.
83
96
 
97
+ AgentPlan tools manage first-class plans — versioned operational artifacts
98
+ distinct from goals/projects/tasks. Each `AgentPlan` owns a chain of immutable
99
+ `AgentPlanVersion` snapshots (one stamped current at a time) plus typed
100
+ `AgentPlanLink` rows pointing at goals/projects/tasks/memories/sessions/plans
101
+ or remote refs (repo/branch/commit/PR/URL/markdown). The plan body itself is
102
+ immutable — to record a new snapshot call `agent_os_plan_add_version`, which
103
+ appends a new version and (by default) advances `currentVersionId` atomically.
104
+ Use `planSlug` for the plan's own stable slug; the workspace `slug` argument
105
+ is reserved for the AgentOS workspace. Workspace-owned link targets are
106
+ re-validated server-side against the same AgentOS workspace; remote refs
107
+ carry metadata only.
108
+
84
109
  AgentTask tools expose the durable task board. `agent_os_task_create` is
85
110
  idempotent within an AgentOS — pass `idempotencyKey` (or `requestId`) from the
86
111
  foreground turn so a retry or restart returns the existing task instead of
package/dist/server.js CHANGED
@@ -9,7 +9,9 @@
9
9
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
10
  import { z } from "zod";
11
11
  import { get, post, patch } from "./lib/kynver-client.js";
12
+ import { registerPlanTools } from "./tools/plans.js";
12
13
  import { registerTaskTools } from "./tools/tasks.js";
14
+ import { registerActionRequiredTools } from "./tools/action-required.js";
13
15
  function jsonResult(data) {
14
16
  return {
15
17
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
@@ -119,6 +121,26 @@ export function createAgentOsServer() {
119
121
  const s = await resolveToolSlug(args.slug);
120
122
  return jsonResult(await get(`/agent-os/${s}/stats`));
121
123
  });
124
+ register("agent_os_context_envelope", "Build a compact context envelope for one anchor (plan | task | goal | project | session). Returns the resolved anchor, its goal + plan (with current version body) + most-relevant task + recent session + top related memories with deduplicated source refs. Use this instead of reading giant docs when picking up an in-flight piece of work — one round trip, scoped to your workspace.", {
125
+ anchorType: z.enum(["plan", "task", "goal", "project", "session"]).describe("Kind of anchor to load context around."),
126
+ anchorId: z.string().describe("Id of the anchor row within this workspace."),
127
+ memoryQuery: z.string().optional().describe("Override the memory search query. Defaults to a query derived from the anchor's title/summary."),
128
+ memoryLimit: z.number().optional().describe("Max memory hits (default 5, max 20). Set 0 to skip memory recall."),
129
+ sessionLimit: z.number().optional().describe("Max recent sessions (default 1, max 5). Set 0 to skip."),
130
+ slug: slugField,
131
+ }, async (args) => {
132
+ const s = await resolveToolSlug(args.slug);
133
+ const params = new URLSearchParams();
134
+ params.set("anchorType", args.anchorType);
135
+ params.set("anchorId", args.anchorId);
136
+ if (args.memoryQuery)
137
+ params.set("memoryQuery", args.memoryQuery);
138
+ if (args.memoryLimit !== undefined)
139
+ params.set("memoryLimit", String(args.memoryLimit));
140
+ if (args.sessionLimit !== undefined)
141
+ params.set("sessionLimit", String(args.sessionLimit));
142
+ return jsonResult(await get(`/agent-os/${s}/context-envelope?${params}`));
143
+ });
122
144
  register("agent_os_open_session", "Call this at the START of every session. Records channel, model, and opens a session record for continuity. Ghost calls this immediately after agent_os_get_context on startup.", {
123
145
  channel: z.string().describe("Runtime channel: 'webchat' | 'telegram' | 'discord' | …"),
124
146
  model: z.string().optional().describe("Model used for the session (default 'claude-sonnet-4-6')."),
@@ -586,5 +608,9 @@ export function createAgentOsServer() {
586
608
  });
587
609
  // AgentTask board — batch 1 (CRUD) + batch 1.5 (steering / lease) tools.
588
610
  registerTaskTools({ register, resolveToolSlug, jsonResult, compact });
611
+ // First-class AgentOS plans (Phase 5A): versioned operational artifacts.
612
+ registerPlanTools({ register, resolveToolSlug, jsonResult, compact });
613
+ // Action Required inbox: agent_os_ask_human + agent_os_await_action (slice 1).
614
+ registerActionRequiredTools({ register, jsonResult, compact });
589
615
  return server;
590
616
  }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Action Required inbox MCP tools.
3
+ *
4
+ * Slice 1 exposes two tools:
5
+ * - agent_os_ask_human : create one inbox item (one decision per call)
6
+ * - agent_os_await_action: poll an item until it resolves (or timeout)
7
+ *
8
+ * Each tool proxies to `/api/action-required/*`. The Kynver API enforces
9
+ * per-user ownership and the one-question lint server-side.
10
+ */
11
+ type ToolResult = {
12
+ content: {
13
+ type: "text";
14
+ text: string;
15
+ }[];
16
+ structuredContent?: unknown;
17
+ };
18
+ export interface ActionRequiredToolDeps {
19
+ register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
20
+ jsonResult: (data: unknown) => ToolResult;
21
+ compact: (source: Record<string, unknown>) => Record<string, unknown>;
22
+ }
23
+ export declare function registerActionRequiredTools({ register, jsonResult, compact, }: ActionRequiredToolDeps): void;
24
+ export {};
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Action Required inbox MCP tools.
3
+ *
4
+ * Slice 1 exposes two tools:
5
+ * - agent_os_ask_human : create one inbox item (one decision per call)
6
+ * - agent_os_await_action: poll an item until it resolves (or timeout)
7
+ *
8
+ * Each tool proxies to `/api/action-required/*`. The Kynver API enforces
9
+ * per-user ownership and the one-question lint server-side.
10
+ */
11
+ import { z } from "zod";
12
+ import { get, post } from "../lib/kynver-client.js";
13
+ const category = z.enum([
14
+ "decision",
15
+ "approval",
16
+ "question",
17
+ "blocker",
18
+ "clarification",
19
+ ]);
20
+ const priority = z.enum(["low", "normal", "high", "critical"]);
21
+ const blockerKind = z
22
+ .enum([
23
+ "none",
24
+ "deploy",
25
+ "env",
26
+ "db",
27
+ "npm",
28
+ "live_trade",
29
+ "content_publish",
30
+ "code_review",
31
+ "merge",
32
+ "other",
33
+ ])
34
+ .optional();
35
+ const askerKind = z.enum(["agent", "reviewer", "task", "system"]).default("agent");
36
+ const recommendation = z
37
+ .object({
38
+ value: z.string().describe("The recommended answer the user can accept with one tap."),
39
+ confidence: z.enum(["low", "medium", "high"]).optional(),
40
+ rationale: z.string().optional(),
41
+ source: z.enum(["agent", "policy", "history"]).optional(),
42
+ })
43
+ .strict();
44
+ const evidence = z
45
+ .array(z
46
+ .object({
47
+ kind: z.enum(["url", "memory", "task_event", "file", "text", "pr", "commit"]),
48
+ label: z.string().optional(),
49
+ ref: z.string(),
50
+ })
51
+ .strict())
52
+ .optional();
53
+ const options = z
54
+ .array(z
55
+ .object({
56
+ value: z.string(),
57
+ label: z.string().optional(),
58
+ isRecommended: z.boolean().optional(),
59
+ })
60
+ .strict())
61
+ .optional();
62
+ export function registerActionRequiredTools({ register, jsonResult, compact, }) {
63
+ register("agent_os_ask_human", [
64
+ "Surface one decision to the human via the Action Required inbox.",
65
+ "Each call MUST contain exactly one question the human can answer in one breath.",
66
+ "Compound asks ('Do X? Or Y?') are rejected server-side with multiple_questions_detected — split them into two calls.",
67
+ "Recommendation is required for category=decision|approval; supply the best-guess answer the user can one-tap accept.",
68
+ "Returns the created `item` (with id you can pass to agent_os_await_action) and a `created` flag (false = idempotent re-create).",
69
+ ].join(" "), {
70
+ title: z.string().describe("Short headline rendered as the card title."),
71
+ question: z
72
+ .string()
73
+ .describe("The single question (one '?'). The user sees this verbatim."),
74
+ body: z
75
+ .string()
76
+ .optional()
77
+ .describe("Expanded context / background. Collapsed in the UI; expand-on-tap."),
78
+ category: category.default("decision"),
79
+ priority: priority.default("normal"),
80
+ askerKind: askerKind.optional(),
81
+ askerRef: z.string().optional().describe("Free-form ref (e.g. agent slug, reviewer id)."),
82
+ blockerKind: blockerKind,
83
+ recommendation: recommendation.optional(),
84
+ evidence,
85
+ options,
86
+ taskId: z.string().optional().describe("Linked AgentTask id — unblocks on answer."),
87
+ planId: z.string().optional(),
88
+ planVersionId: z.string().optional(),
89
+ goalId: z.string().optional(),
90
+ projectId: z.string().optional(),
91
+ sessionId: z.string().optional(),
92
+ sourceEventId: z.number().int().optional(),
93
+ unblockTaskIds: z.array(z.string()).optional(),
94
+ expiresAt: z
95
+ .string()
96
+ .optional()
97
+ .describe("ISO-8601 timestamp for hard deadline. Defaults to 24h for approvals; null otherwise."),
98
+ agentOsId: z.string().optional(),
99
+ createdByAgentRef: z.string().optional(),
100
+ clientRequestId: z
101
+ .string()
102
+ .optional()
103
+ .describe("Dedupe key — repeating the same id within a user returns the existing item with created=false."),
104
+ }, async (args) => {
105
+ return jsonResult(await post("/action-required", compact(args)));
106
+ });
107
+ register("agent_os_await_action", [
108
+ "Poll one Action Required item until it resolves.",
109
+ "Returns immediately if the item is already terminal (answered / resolved_noop / expired / superseded / cancelled).",
110
+ "If still open/snoozed, waits up to `timeoutSeconds` (default 60, max 300) with `pollIntervalSeconds` between checks.",
111
+ "On answer, the answer text + acceptedRecommendation flag are returned so you can resume work without re-fetching.",
112
+ ].join(" "), {
113
+ itemId: z.string().describe("The Action Required item id returned by agent_os_ask_human."),
114
+ timeoutSeconds: z.number().int().min(0).max(300).optional(),
115
+ pollIntervalSeconds: z.number().int().min(2).max(60).optional(),
116
+ }, async (args) => {
117
+ const itemId = String(args.itemId);
118
+ const timeout = Math.min(300, Math.max(0, args.timeoutSeconds ?? 60));
119
+ const interval = Math.max(2, Math.min(60, args.pollIntervalSeconds ?? 5));
120
+ const start = Date.now();
121
+ let last = null;
122
+ while (true) {
123
+ const data = (await get(`/action-required/${encodeURIComponent(itemId)}/await`));
124
+ last = data;
125
+ if (data.status !== "open" && data.status !== "snoozed") {
126
+ return jsonResult({ ...data, waited: Math.round((Date.now() - start) / 1000) });
127
+ }
128
+ if (Date.now() - start >= timeout * 1000) {
129
+ return jsonResult({
130
+ ...data,
131
+ stillOpen: true,
132
+ waited: Math.round((Date.now() - start) / 1000),
133
+ });
134
+ }
135
+ await new Promise((r) => setTimeout(r, interval * 1000));
136
+ }
137
+ // eslint-disable-next-line no-unreachable
138
+ return jsonResult(last);
139
+ });
140
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * AgentOS plan MCP tools — Phase 5A of
3
+ * docs/superpowers/plans/2026-05-17-agent-os-memory-reliability.md. Each tool
4
+ * proxies to `/api/agent-os/{slug}/plans*` on Kynver. Workspace isolation is
5
+ * enforced server-side via slug-resolved AgentOS context plus service-layer
6
+ * scope checks — callers do NOT pass userId or agentOsId from here.
7
+ *
8
+ * Kept in its own module so server.ts stays small. server.ts calls
9
+ * `registerPlanTools` with the helpers it already has in scope.
10
+ */
11
+ type ToolResult = {
12
+ content: {
13
+ type: "text";
14
+ text: string;
15
+ }[];
16
+ structuredContent?: unknown;
17
+ };
18
+ export interface PlanToolDeps {
19
+ /** server.ts's thin wrapper over `server.registerTool`. */
20
+ register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
21
+ /** Resolve the effective AgentOS slug (explicit arg → env → discovered primary). */
22
+ resolveToolSlug: (explicitSlug?: string) => Promise<string>;
23
+ /** Wrap a value as an MCP text + structuredContent result. */
24
+ jsonResult: (data: unknown) => ToolResult;
25
+ /** Drop `undefined` entries from an object. */
26
+ compact: (source: Record<string, unknown>) => Record<string, unknown>;
27
+ }
28
+ export declare function registerPlanTools({ register, resolveToolSlug, jsonResult, compact, }: PlanToolDeps): void;
29
+ export {};
@@ -0,0 +1,201 @@
1
+ /**
2
+ * AgentOS plan MCP tools — Phase 5A of
3
+ * docs/superpowers/plans/2026-05-17-agent-os-memory-reliability.md. Each tool
4
+ * proxies to `/api/agent-os/{slug}/plans*` on Kynver. Workspace isolation is
5
+ * enforced server-side via slug-resolved AgentOS context plus service-layer
6
+ * scope checks — callers do NOT pass userId or agentOsId from here.
7
+ *
8
+ * Kept in its own module so server.ts stays small. server.ts calls
9
+ * `registerPlanTools` with the helpers it already has in scope.
10
+ */
11
+ import { z } from "zod";
12
+ import { get, post, patch } from "../lib/kynver-client.js";
13
+ const planStatus = z.enum([
14
+ "draft",
15
+ "active",
16
+ "blocked",
17
+ "complete",
18
+ "archived",
19
+ "superseded",
20
+ ]);
21
+ const planPriority = z.enum(["low", "normal", "high", "critical"]);
22
+ const planLinkTarget = z.enum([
23
+ "goal",
24
+ "project",
25
+ "task",
26
+ "memory",
27
+ "session",
28
+ "repo",
29
+ "branch",
30
+ "commit",
31
+ "pr",
32
+ "url",
33
+ "markdown",
34
+ "plan",
35
+ ]);
36
+ const initialVersionSchema = z
37
+ .object({
38
+ title: z.string().optional(),
39
+ body: z.string().describe("Full plan body (markdown)."),
40
+ summary: z.string().optional(),
41
+ changeSummary: z.string().optional(),
42
+ author: z.string().optional(),
43
+ sourceRefs: z.unknown().optional(),
44
+ metadata: z.record(z.string(), z.unknown()).optional(),
45
+ })
46
+ .passthrough();
47
+ export function registerPlanTools({ register, resolveToolSlug, jsonResult, compact, }) {
48
+ const slugField = z
49
+ .string()
50
+ .optional()
51
+ .describe("AgentOS workspace slug. Omit to use env or the server-discovered primary.");
52
+ register("agent_os_plan_create", "Create a first-class AgentOS plan with an initial version. Plans are versioned operational artifacts (separate from goals/projects/tasks). `initialVersion.body` is required and becomes the plan's current version. Use `planSlug` for the plan's own stable slug — the workspace `slug` argument is reserved for the AgentOS workspace.", {
53
+ title: z.string().describe("Human-readable plan title (required)."),
54
+ summary: z.string().optional(),
55
+ planSlug: z
56
+ .string()
57
+ .optional()
58
+ .describe("Stable slug for the plan within the AgentOS workspace."),
59
+ status: planStatus.optional(),
60
+ priority: planPriority.optional(),
61
+ owner: z.string().optional(),
62
+ projectId: z.string().optional(),
63
+ goalId: z.string().optional(),
64
+ canonicalKey: z.string().optional(),
65
+ metadata: z.record(z.string(), z.unknown()).optional(),
66
+ sourceRefs: z.unknown().optional(),
67
+ initialVersion: initialVersionSchema.describe("First version snapshot (required). Becomes the plan's current version."),
68
+ slug: slugField,
69
+ }, async (args) => {
70
+ const { slug, planSlug, ...rest } = args;
71
+ const s = await resolveToolSlug(slug);
72
+ const body = compact({
73
+ ...rest,
74
+ ...(planSlug !== undefined ? { slug: planSlug } : {}),
75
+ });
76
+ return jsonResult(await post(`/agent-os/${s}/plans`, body));
77
+ });
78
+ register("agent_os_plan_list", "List AgentOS plans, optionally filtered by status, projectId, goalId, or canonicalKey.", {
79
+ status: planStatus.optional(),
80
+ projectId: z.string().optional(),
81
+ goalId: z.string().optional(),
82
+ canonicalKey: z.string().optional(),
83
+ limit: z
84
+ .number()
85
+ .optional()
86
+ .describe("Max rows (default 50, max 200)."),
87
+ slug: slugField,
88
+ }, async (args) => {
89
+ const params = new URLSearchParams();
90
+ if (args.status)
91
+ params.set("status", args.status);
92
+ if (args.projectId)
93
+ params.set("projectId", args.projectId);
94
+ if (args.goalId)
95
+ params.set("goalId", args.goalId);
96
+ if (args.canonicalKey)
97
+ params.set("canonicalKey", args.canonicalKey);
98
+ if (args.limit)
99
+ params.set("limit", String(args.limit));
100
+ const qs = params.toString();
101
+ const s = await resolveToolSlug(args.slug);
102
+ return jsonResult(await get(`/agent-os/${s}/plans${qs ? `?${qs}` : ""}`));
103
+ });
104
+ register("agent_os_plan_get", "Fetch one AgentOS plan with its full version history, current version pointer, and typed links.", { planId: z.string(), slug: slugField }, async (args) => {
105
+ const s = await resolveToolSlug(args.slug);
106
+ return jsonResult(await get(`/agent-os/${s}/plans/${args.planId}`));
107
+ });
108
+ register("agent_os_plan_update", "Patch an AgentOS plan's metadata (title, summary, status, priority, owner, project/goal links, canonicalKey). The plan body itself is immutable — use agent_os_plan_add_version to record a new snapshot. Use `planSlug` for the plan's own stable slug.", {
109
+ planId: z.string(),
110
+ title: z.string().optional(),
111
+ summary: z.string().optional(),
112
+ planSlug: z
113
+ .string()
114
+ .optional()
115
+ .describe("Stable slug for the plan within the AgentOS workspace."),
116
+ status: planStatus.optional(),
117
+ priority: planPriority.optional(),
118
+ owner: z.string().optional(),
119
+ projectId: z.string().optional(),
120
+ goalId: z.string().optional(),
121
+ canonicalKey: z.string().optional(),
122
+ metadata: z.record(z.string(), z.unknown()).optional(),
123
+ sourceRefs: z.unknown().optional(),
124
+ slug: slugField,
125
+ }, async (args) => {
126
+ const { slug, planId, planSlug, ...rest } = args;
127
+ const s = await resolveToolSlug(slug);
128
+ const body = compact({
129
+ ...rest,
130
+ ...(planSlug !== undefined ? { slug: planSlug } : {}),
131
+ });
132
+ return jsonResult(await patch(`/agent-os/${s}/plans/${planId}`, body));
133
+ });
134
+ register("agent_os_plan_add_version", "Append an immutable version snapshot to a plan. The new version's versionNumber is one greater than the latest, and (when markCurrent is true, the default) the plan's currentVersionId pointer advances atomically. Use this — not agent_os_plan_update — to record a new plan body.", {
135
+ planId: z.string(),
136
+ title: z.string().optional(),
137
+ body: z.string().describe("Full new version body (markdown)."),
138
+ summary: z.string().optional(),
139
+ changeSummary: z.string().optional(),
140
+ author: z.string().optional(),
141
+ sourceRefs: z.unknown().optional(),
142
+ metadata: z.record(z.string(), z.unknown()).optional(),
143
+ markCurrent: z
144
+ .boolean()
145
+ .optional()
146
+ .describe("When true (default), the new version becomes the plan's current version."),
147
+ slug: slugField,
148
+ }, async (args) => {
149
+ const { slug, planId, ...rest } = args;
150
+ const s = await resolveToolSlug(slug);
151
+ return jsonResult(await post(`/agent-os/${s}/plans/${planId}/versions`, compact(rest)));
152
+ });
153
+ register("agent_os_plan_mark_current", "Promote an existing version of a plan to be the current version. The version must already belong to the plan.", {
154
+ planId: z.string(),
155
+ versionId: z
156
+ .string()
157
+ .describe("Existing version id to promote to current."),
158
+ slug: slugField,
159
+ }, async (args) => {
160
+ const s = await resolveToolSlug(args.slug);
161
+ return jsonResult(await post(`/agent-os/${s}/plans/${args.planId}/versions`, {
162
+ action: "mark_current",
163
+ versionId: args.versionId,
164
+ }));
165
+ });
166
+ register("agent_os_plan_add_link", "Add a typed link from a plan (and optionally a specific version) to a related goal, project, task, memory, session, repo, branch, commit, PR, URL, markdown file, or other plan. Workspace-owned targets (goal/project/task/memory/session/plan) are validated against the same AgentOS workspace server-side; remote refs (url/repo/branch/commit/pr/markdown) carry metadata only.", {
167
+ planId: z.string(),
168
+ planVersionId: z
169
+ .string()
170
+ .optional()
171
+ .describe("Optional version id when the link applies to a specific snapshot."),
172
+ targetType: planLinkTarget,
173
+ targetId: z
174
+ .string()
175
+ .optional()
176
+ .describe("AgentOS-owned target id. Required for workspace-owned link types."),
177
+ targetUrl: z
178
+ .string()
179
+ .optional()
180
+ .describe("URL for remote refs. Either targetId or targetUrl is required."),
181
+ label: z.string().optional(),
182
+ relation: z
183
+ .string()
184
+ .optional()
185
+ .describe("Optional free-form relation label (e.g. 'derived_from', 'supersedes')."),
186
+ metadata: z.record(z.string(), z.unknown()).optional(),
187
+ slug: slugField,
188
+ }, async (args) => {
189
+ const { slug, planId, ...rest } = args;
190
+ const s = await resolveToolSlug(slug);
191
+ return jsonResult(await post(`/agent-os/${s}/plans/${planId}/links`, compact(rest)));
192
+ });
193
+ register("agent_os_plan_list_links", "List the typed links attached to a plan.", { planId: z.string(), slug: slugField }, async (args) => {
194
+ const s = await resolveToolSlug(args.slug);
195
+ return jsonResult(await get(`/agent-os/${s}/plans/${args.planId}/links`));
196
+ });
197
+ register("agent_os_plan_list_versions", "List the version history of a plan in ascending order by versionNumber. agent_os_plan_get already returns versions; use this when you only need the version list.", { planId: z.string(), slug: slugField }, async (args) => {
198
+ const s = await resolveToolSlug(args.slug);
199
+ return jsonResult(await get(`/agent-os/${s}/plans/${args.planId}/versions`));
200
+ });
201
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kynver-app/mcp-agent-os",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Kynver Agentic OS MCP server — slug-keyed agent identity, goals, projects, sessions, and long-term memory",
5
5
  "type": "module",
6
6
  "bin": {