@kynver-app/mcp-agent-os 0.3.46 → 0.3.49

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.
@@ -4,7 +4,7 @@ import { createServer } from "node:http";
4
4
  import { timingSafeEqual } from "node:crypto";
5
5
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
6
6
  export const MAX_SSE_BODY_BYTES = 1 * 1024 * 1024;
7
- const FORBIDDEN_QUERY_KEYS = ["secret", "userId"];
7
+ const FORBIDDEN_QUERY_KEYS = ["apiKey", "secret", "userId"];
8
8
  export function headerValue(req, name) {
9
9
  const v = req.headers[name];
10
10
  return typeof v === "string" ? v : Array.isArray(v) ? (v[0] ?? null) : null;
@@ -19,9 +19,6 @@ export function timingSafeEqualString(a, b) {
19
19
  export function hasForbiddenQueryAuth(url) {
20
20
  return FORBIDDEN_QUERY_KEYS.some((key) => url.searchParams.has(key));
21
21
  }
22
- function queryApiKey(url) {
23
- return url.searchParams.get("apiKey")?.trim() ?? "";
24
- }
25
22
  export function resolveListenHost() {
26
23
  const configured = process.env.MCP_SSE_HOST?.trim();
27
24
  return configured || "127.0.0.1";
@@ -130,7 +127,7 @@ function resolveInternalAuth(req, serviceSecret) {
130
127
  }
131
128
  function verifyPostAuth(req, url, sessionAuth, serviceSecret) {
132
129
  if (sessionAuth.kind === "apiKey") {
133
- const token = bearerToken(req) || queryApiKey(url);
130
+ const token = bearerToken(req);
134
131
  return token.length > 0 && timingSafeEqualString(token, sessionAuth.apiKey);
135
132
  }
136
133
  const internal = resolveInternalAuth(req, serviceSecret);
@@ -170,7 +167,6 @@ export function startKynverMcpSseServer(options) {
170
167
  const maxSessionsPerUser = intFromEnv("MCP_SSE_MAX_SESSIONS_PER_USER", 20);
171
168
  const idleTimeoutMs = intFromEnv("MCP_SSE_IDLE_TIMEOUT_MS", 5 * 60 * 1000);
172
169
  const rateLimitPerMin = intFromEnv("MCP_SSE_RATE_LIMIT_PER_MIN", 120);
173
- const rejectQueryApiKey = /^(1|true|yes)$/i.test(process.env.MCP_SSE_REJECT_QUERY_APIKEY ?? "");
174
170
  const rateLimiter = createFixedWindowRateLimiter(rateLimitPerMin, 60 * 1000);
175
171
  // Close idle SSE sessions so a flood of half-open connections can't pin memory.
176
172
  const idleSweep = setInterval(() => {
@@ -198,15 +194,6 @@ export function startKynverMcpSseServer(options) {
198
194
  });
199
195
  return;
200
196
  }
201
- if (url.searchParams.has("apiKey")) {
202
- if (rejectQueryApiKey) {
203
- json(res, 400, {
204
- error: "apiKey via query param is disabled. Use Authorization: Bearer <key>.",
205
- });
206
- return;
207
- }
208
- console.warn("[MCP SSE] WARNING: apiKey in query string may leak via logs. Prefer Authorization header when your client supports it.");
209
- }
210
197
  let userId = null;
211
198
  let auth = null;
212
199
  const internal = serviceSecret ? resolveInternalAuth(req, serviceSecret) : null;
@@ -215,7 +202,7 @@ export function startKynverMcpSseServer(options) {
215
202
  auth = internal.auth;
216
203
  }
217
204
  else {
218
- const apiKey = bearerToken(req) || queryApiKey(url);
205
+ const apiKey = bearerToken(req);
219
206
  if (apiKey) {
220
207
  userId = await resolveUserFromApiKey(baseUrl, apiKey);
221
208
  if (userId)
package/dist/server.js CHANGED
@@ -11,6 +11,7 @@ import { z } from "zod";
11
11
  import { get, post, patch } from "./lib/kynver-client.js";
12
12
  import { registerPlanTools } from "./tools/plans.js";
13
13
  import { registerPlanProgressTools } from "./tools/plan-progress.js";
14
+ import { registerPlanToFactoryTools } from "./tools/plan-to-factory.js";
14
15
  import { registerTaskTools } from "./tools/tasks.js";
15
16
  import { registerActionRequiredTools } from "./tools/action-required.js";
16
17
  import { registerGraphTools } from "./tools/graph.js";
@@ -26,6 +27,9 @@ import { registerSkillsTools } from "./tools/skills.js";
26
27
  import { registerMemoryLedgerTools } from "./tools/memory-ledger.js";
27
28
  import { registerMemoryVaultTools } from "./tools/memory-vault.js";
28
29
  import { registerMonitorTools } from "./tools/monitor.js";
30
+ import { registerMacroControlsTools } from "./tools/macro-controls.js";
31
+ import { registerKariAdMarketingLoopTools } from "./tools/kariad-marketing-loop.js";
32
+ import { registerKariAdOutcomeImportTools } from "./tools/kariad-outcome-import.js";
29
33
  import { readOwnPackageVersion } from "./lib/package-version.js";
30
34
  const PACKAGE_VERSION = readOwnPackageVersion(import.meta.url);
31
35
  function jsonResult(data) {
@@ -709,6 +713,7 @@ export function createAgentOsServer() {
709
713
  // First-class AgentOS plans (Phase 5A): versioned operational artifacts.
710
714
  registerPlanTools({ register, resolveToolSlug, jsonResult, compact });
711
715
  registerPlanProgressTools({ register, resolveToolSlug, jsonResult, compact });
716
+ registerPlanToFactoryTools({ register, resolveToolSlug, jsonResult, compact });
712
717
  // Action Required inbox: agent_os_ask_human + agent_os_await_action (slice 1).
713
718
  registerActionRequiredTools({ register, jsonResult, compact });
714
719
  // Operational graph insights — Agent SEE (agent_os_graph_query).
@@ -734,5 +739,9 @@ export function createAgentOsServer() {
734
739
  registerMemoryLedgerTools({ register, resolveToolSlug, jsonResult });
735
740
  registerMemoryVaultTools({ register, resolveToolSlug, jsonResult });
736
741
  registerMonitorTools({ register, resolveToolSlug, jsonResult });
742
+ registerMacroControlsTools({ register, resolveToolSlug, jsonResult });
743
+ registerKariAdMarketingLoopTools({ register, resolveToolSlug, jsonResult });
744
+ // KariAd marketing loop — M6 outcome import (analytics feedback + memory learning).
745
+ registerKariAdOutcomeImportTools({ register, resolveToolSlug, jsonResult });
737
746
  return server;
738
747
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * KariAd campaign brief MCP tool (M4).
3
+ *
4
+ * agent_os_kariad_campaign_brief_create — fuse macro trends, Kynver goals,
5
+ * and KariAd deep memory into a cited RuntimeCampaignBrief.
6
+ * Does not publish or spend.
7
+ */
8
+ type ToolResult = {
9
+ content: {
10
+ type: "text";
11
+ text: string;
12
+ }[];
13
+ structuredContent?: unknown;
14
+ };
15
+ export interface KariAdMarketingLoopToolDeps {
16
+ register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
17
+ resolveToolSlug: (explicitSlug?: string) => Promise<string>;
18
+ jsonResult: (data: unknown) => ToolResult;
19
+ }
20
+ export declare function registerKariAdMarketingLoopTools({ register, resolveToolSlug, jsonResult, }: KariAdMarketingLoopToolDeps): void;
21
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * KariAd campaign brief MCP tool (M4).
3
+ *
4
+ * agent_os_kariad_campaign_brief_create — fuse macro trends, Kynver goals,
5
+ * and KariAd deep memory into a cited RuntimeCampaignBrief.
6
+ * Does not publish or spend.
7
+ */
8
+ import { z } from "zod";
9
+ import { post } from "../lib/kynver-client.js";
10
+ const slugField = z
11
+ .string()
12
+ .optional()
13
+ .describe("AgentOS slug. Defaults to env/primary AgentOS.");
14
+ export function registerKariAdMarketingLoopTools({ register, resolveToolSlug, jsonResult, }) {
15
+ register("agent_os_kariad_campaign_brief_create", [
16
+ "Create a compact, cited RuntimeCampaignBrief by combining on-demand macro/social trend signals,",
17
+ "Kynver marketplace/runtime goals, and KariAd deep brand memory.",
18
+ "Returns content angles with source links, target audiences, selected brand/workspace, risk labels,",
19
+ "and recommended next KariAd actions.",
20
+ "Does NOT publish, schedule, or spend — approval is always required before KariAd execution tools (M5).",
21
+ "Call agent_os_macro_controls_get first when trend awareness matters for the marketing task.",
22
+ ].join(" "), {
23
+ slug: slugField,
24
+ workspaceId: z.string().describe("KariAd workspace id (from kari_whoami / connection preflight)."),
25
+ brandId: z.string().describe("KariAd brand id for voice, audience, and calendar context."),
26
+ brandName: z.string().optional().describe("Optional display name when brand id is known."),
27
+ goalStatement: z
28
+ .string()
29
+ .optional()
30
+ .describe("Campaign goal override. When omitted, inferred from active Kynver goals/projects."),
31
+ }, async (args) => {
32
+ const s = await resolveToolSlug(args.slug);
33
+ const payload = await post(`/agent-os/${encodeURIComponent(s)}/kariad-marketing-loop/briefs`, {
34
+ workspaceId: args.workspaceId,
35
+ brandId: args.brandId,
36
+ ...(args.brandName ? { brandName: args.brandName } : {}),
37
+ ...(args.goalStatement ? { goalStatement: args.goalStatement } : {}),
38
+ });
39
+ return jsonResult(payload);
40
+ });
41
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * M6 outcome import MCP tool — agent_os_kariad_outcome_import
3
+ */
4
+ type ToolResult = {
5
+ content: {
6
+ type: "text";
7
+ text: string;
8
+ }[];
9
+ structuredContent?: unknown;
10
+ };
11
+ export interface KariAdOutcomeImportToolDeps {
12
+ register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
13
+ resolveToolSlug: (explicitSlug?: string) => Promise<string>;
14
+ jsonResult: (data: unknown) => ToolResult;
15
+ }
16
+ export declare function registerKariAdOutcomeImportTools({ register, resolveToolSlug, jsonResult, }: KariAdOutcomeImportToolDeps): void;
17
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * M6 outcome import MCP tool — agent_os_kariad_outcome_import
3
+ */
4
+ import { z } from "zod";
5
+ import { post } from "../lib/kynver-client.js";
6
+ const slugField = z
7
+ .string()
8
+ .optional()
9
+ .describe("AgentOS slug. Defaults to env/primary AgentOS.");
10
+ export function registerKariAdOutcomeImportTools({ register, resolveToolSlug, jsonResult, }) {
11
+ register("agent_os_kariad_outcome_import", [
12
+ "Import KariAd campaign outcome summaries and produce separate KariAd vs Kynver memory proposals",
13
+ "with correct ownership, provider-quality metrics, and duplicate suppression.",
14
+ "Set writeback=true to route cleared proposals to KariAd submit_memory_proposal and Kynver MARM.",
15
+ "Requires planId + briefId from the marketing loop execution window.",
16
+ ].join(" "), {
17
+ slug: slugField,
18
+ workspaceId: z.string().describe("KariAd workspace id."),
19
+ brandId: z.string().describe("KariAd brand id."),
20
+ planId: z.string().describe("KariAd execution plan id for attribution."),
21
+ briefId: z.string().describe("Runtime campaign brief id for attribution."),
22
+ writeback: z
23
+ .boolean()
24
+ .optional()
25
+ .describe("When true, persist proposals to KariAd/Kynver. Default dry-run."),
26
+ }, async (args) => {
27
+ const s = await resolveToolSlug(args.slug);
28
+ const payload = await post(`/agent-os/${encodeURIComponent(s)}/kariad-marketing-loop/outcomes/import`, {
29
+ workspaceId: args.workspaceId,
30
+ brandId: args.brandId,
31
+ planId: args.planId,
32
+ briefId: args.briefId,
33
+ writeback: args.writeback === true,
34
+ });
35
+ return jsonResult(payload);
36
+ });
37
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Macro/social trend on-demand catch-up MCP tool.
3
+ *
4
+ * Runtime agents call agent_os_macro_controls_get before producing social media
5
+ * posts, ad copy, campaign briefs, launch announcements, or any trend-sensitive
6
+ * marketing content so they can adapt angle and tone to current signals.
7
+ *
8
+ * Read-only. Backed by GET /api/agent-os/{slug}/macro-controls.
9
+ */
10
+ type ToolResult = {
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ structuredContent?: unknown;
16
+ };
17
+ export interface MacroControlsToolDeps {
18
+ register: (name: string, description: string, inputSchema: Record<string, unknown>, cb: (args: any) => any) => void;
19
+ resolveToolSlug: (explicitSlug?: string) => Promise<string>;
20
+ jsonResult: (data: unknown) => ToolResult;
21
+ }
22
+ export declare function registerMacroControlsTools({ register, resolveToolSlug, jsonResult, }: MacroControlsToolDeps): void;
23
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Macro/social trend on-demand catch-up MCP tool.
3
+ *
4
+ * Runtime agents call agent_os_macro_controls_get before producing social media
5
+ * posts, ad copy, campaign briefs, launch announcements, or any trend-sensitive
6
+ * marketing content so they can adapt angle and tone to current signals.
7
+ *
8
+ * Read-only. Backed by GET /api/agent-os/{slug}/macro-controls.
9
+ */
10
+ import { z } from "zod";
11
+ import { get } from "../lib/kynver-client.js";
12
+ const slugField = z
13
+ .string()
14
+ .optional()
15
+ .describe("AgentOS slug. Defaults to env/primary AgentOS.");
16
+ export function registerMacroControlsTools({ register, resolveToolSlug, jsonResult, }) {
17
+ register("agent_os_macro_controls_get", [
18
+ "Fetch the current macro/social trend snapshot so you can adapt marketing content to active signals.",
19
+ "",
20
+ "WHEN TO CALL: before generating social media posts, ad copy, campaign briefs, launch announcements,",
21
+ "trend-reactive content, or any marketing material where current events could affect brand perception.",
22
+ "This is an on-demand catch-up step — call it at the START of social/content/marketing work, not on",
23
+ "every message.",
24
+ "",
25
+ "WHAT YOU GET: a compact MacroControlSnapshot with active MacroTrendSignals (topic, sensitivity,",
26
+ "summary, confidence, sourceLinks), a globalSensitivity aggregate ('safe'|'cautious'|'sensitive'|'blocked'),",
27
+ "isStale flag, and agentGuidance text you should incorporate into your content plan.",
28
+ "",
29
+ "GATING RULES:",
30
+ "- globalSensitivity='blocked': do NOT publish related content — surface the blocked topics to the",
31
+ " operator and wait for explicit approval before proceeding.",
32
+ "- globalSensitivity='sensitive': draft with extra care, avoid direct references to flagged topics,",
33
+ " prefer evergreen angles, and flag for human review before posting.",
34
+ "- globalSensitivity='cautious': note flagged topics in your plan; adjust tone but may proceed.",
35
+ "- globalSensitivity='safe' or isStale=true with no signals: proceed with standard brand voice.",
36
+ "",
37
+ "If isStale=true AND signals are present, treat the data as advisory only and note staleness in your",
38
+ "output so the operator knows to refresh. Read-only; safe for unattended invocation.",
39
+ ].join("\n"), {
40
+ slug: slugField,
41
+ includeSensitiveSignals: z
42
+ .boolean()
43
+ .optional()
44
+ .describe("When true, include 'sensitive' and 'blocked' signals in full detail. " +
45
+ "Default true — omit only when generating a safe-for-display summary."),
46
+ }, async ({ slug, includeSensitiveSignals = true, }) => {
47
+ const s = await resolveToolSlug(slug);
48
+ const snapshot = await get(`/agent-os/${encodeURIComponent(s)}/macro-controls`);
49
+ if (!includeSensitiveSignals && Array.isArray(snapshot.signals)) {
50
+ snapshot.signals = snapshot.signals.filter((sig) => sig.sensitivity === "safe" || sig.sensitivity === "cautious");
51
+ }
52
+ return jsonResult(snapshot);
53
+ });
54
+ }
@@ -0,0 +1,2 @@
1
+ import type { PlanToolDeps } from "./plans.js";
2
+ export declare function registerPlanToFactoryTools({ register, resolveToolSlug, jsonResult, }: PlanToolDeps): void;
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { post } from "../lib/kynver-client.js";
3
+ export function registerPlanToFactoryTools({ register, resolveToolSlug, jsonResult, }) {
4
+ const slugField = z
5
+ .string()
6
+ .optional()
7
+ .describe("AgentOS workspace slug. Omit to use env or the server-discovered primary.");
8
+ register("agent_os_plan_run_factory", "Run a plan through the factory: decompose progress rows, mint parent + child harness tasks, wire dependencies and owned paths, and return the next runnable slice.", {
9
+ planId: z.string(),
10
+ dryRun: z.boolean().optional(),
11
+ command: z
12
+ .string()
13
+ .optional()
14
+ .describe('Operator phrase; defaults to "run this plan through the factory".'),
15
+ slug: slugField,
16
+ }, async (args) => {
17
+ const s = await resolveToolSlug(args.slug);
18
+ return jsonResult(await post(`/agent-os/${s}/plans/${args.planId}/run-factory`, {
19
+ dryRun: args.dryRun,
20
+ command: args.command,
21
+ }));
22
+ });
23
+ }
@@ -147,7 +147,7 @@ export function registerTaskTools({ register, resolveToolSlug, jsonResult, compa
147
147
  scheduledFor,
148
148
  dependsOnTaskIds,
149
149
  lastSummary: z.string().optional().describe("Latest progress summary."),
150
- blocker: z.string().optional(),
150
+ blocker: z.string().nullable().optional().describe("Blocker text, or null to clear it."),
151
151
  branch: z.string().optional(),
152
152
  worktreePath: z.string().optional(),
153
153
  prUrl: z.string().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kynver-app/mcp-agent-os",
3
- "version": "0.3.46",
3
+ "version": "0.3.49",
4
4
  "description": "Kynver Agentic OS MCP server \u2014 slug-keyed agent identity, goals, projects, sessions, and long-term memory",
5
5
  "type": "module",
6
6
  "bin": {