@kynver-app/mcp-agent-os 0.3.17 → 0.3.19
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/dist/lib/mcp-sse-server.d.ts +29 -0
- package/dist/lib/mcp-sse-server.js +191 -0
- package/dist/server.js +44 -3
- package/dist/sse.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type IncomingMessage } from "node:http";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
export declare const MAX_SSE_BODY_BYTES: number;
|
|
4
|
+
export type SessionAuth = {
|
|
5
|
+
kind: "apiKey";
|
|
6
|
+
apiKey: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "internal";
|
|
9
|
+
userId: string;
|
|
10
|
+
};
|
|
11
|
+
type RequestContextStore = {
|
|
12
|
+
run: <T>(store: {
|
|
13
|
+
userId?: string;
|
|
14
|
+
}, fn: () => Promise<T>) => Promise<T>;
|
|
15
|
+
};
|
|
16
|
+
export type StartKynverMcpSseServerOptions = {
|
|
17
|
+
label: string;
|
|
18
|
+
defaultPort: number;
|
|
19
|
+
createMcpServer: () => McpServer | Promise<McpServer>;
|
|
20
|
+
requestContext: RequestContextStore;
|
|
21
|
+
};
|
|
22
|
+
export declare function headerValue(req: IncomingMessage, name: string): string | null;
|
|
23
|
+
export declare function timingSafeEqualString(a: string, b: string): boolean;
|
|
24
|
+
export declare function hasForbiddenQueryAuth(url: URL): boolean;
|
|
25
|
+
export declare function resolveListenHost(): string;
|
|
26
|
+
export declare function parseJsonBody(req: IncomingMessage, maxBytes?: number): Promise<unknown>;
|
|
27
|
+
export declare function validateMcporterServerName(name: string): string;
|
|
28
|
+
export declare function startKynverMcpSseServer(options: StartKynverMcpSseServerOptions): void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// @generated — synced from packages/kynver-mcp-sse-lib/src/index.ts via scripts/sync-mcp-sse-server.mjs
|
|
2
|
+
// Do not edit by hand; change the canonical file and re-run the sync script.
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { timingSafeEqual } from "node:crypto";
|
|
5
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
6
|
+
export const MAX_SSE_BODY_BYTES = 1 * 1024 * 1024;
|
|
7
|
+
const FORBIDDEN_QUERY_KEYS = ["secret", "userId"];
|
|
8
|
+
export function headerValue(req, name) {
|
|
9
|
+
const v = req.headers[name];
|
|
10
|
+
return typeof v === "string" ? v : Array.isArray(v) ? (v[0] ?? null) : null;
|
|
11
|
+
}
|
|
12
|
+
export function timingSafeEqualString(a, b) {
|
|
13
|
+
const left = Buffer.from(a);
|
|
14
|
+
const right = Buffer.from(b);
|
|
15
|
+
if (left.length !== right.length)
|
|
16
|
+
return false;
|
|
17
|
+
return timingSafeEqual(left, right);
|
|
18
|
+
}
|
|
19
|
+
export function hasForbiddenQueryAuth(url) {
|
|
20
|
+
return FORBIDDEN_QUERY_KEYS.some((key) => url.searchParams.has(key));
|
|
21
|
+
}
|
|
22
|
+
function queryApiKey(url) {
|
|
23
|
+
return url.searchParams.get("apiKey")?.trim() ?? "";
|
|
24
|
+
}
|
|
25
|
+
export function resolveListenHost() {
|
|
26
|
+
const configured = process.env.MCP_SSE_HOST?.trim();
|
|
27
|
+
return configured || "127.0.0.1";
|
|
28
|
+
}
|
|
29
|
+
export function parseJsonBody(req, maxBytes = MAX_SSE_BODY_BYTES) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const chunks = [];
|
|
32
|
+
let totalSize = 0;
|
|
33
|
+
req.on("data", (chunk) => {
|
|
34
|
+
totalSize += chunk.length;
|
|
35
|
+
if (totalSize > maxBytes) {
|
|
36
|
+
req.destroy();
|
|
37
|
+
reject(new Error("Request body too large"));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
chunks.push(chunk);
|
|
41
|
+
});
|
|
42
|
+
req.on("end", () => {
|
|
43
|
+
try {
|
|
44
|
+
resolve(JSON.parse(Buffer.concat(chunks).toString()));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
reject(error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
req.on("error", reject);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function validateMcporterServerName(name) {
|
|
54
|
+
const trimmed = name.trim();
|
|
55
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(trimmed)) {
|
|
56
|
+
throw new Error("Invalid mcporter server name.");
|
|
57
|
+
}
|
|
58
|
+
return trimmed;
|
|
59
|
+
}
|
|
60
|
+
function bearerToken(req) {
|
|
61
|
+
const auth = headerValue(req, "authorization");
|
|
62
|
+
if (!auth)
|
|
63
|
+
return "";
|
|
64
|
+
const match = /^Bearer\s+(.+)$/i.exec(auth);
|
|
65
|
+
return match?.[1]?.trim() ?? "";
|
|
66
|
+
}
|
|
67
|
+
function resolveInternalAuth(req, serviceSecret) {
|
|
68
|
+
const internalUserId = headerValue(req, "x-kynver-user-id");
|
|
69
|
+
const internalSecret = headerValue(req, "x-kynver-service-secret");
|
|
70
|
+
if (!internalUserId || !serviceSecret || !internalSecret)
|
|
71
|
+
return null;
|
|
72
|
+
if (!timingSafeEqualString(internalSecret, serviceSecret))
|
|
73
|
+
return null;
|
|
74
|
+
return { userId: internalUserId, auth: { kind: "internal", userId: internalUserId } };
|
|
75
|
+
}
|
|
76
|
+
function verifyPostAuth(req, url, sessionAuth, serviceSecret) {
|
|
77
|
+
if (sessionAuth.kind === "apiKey") {
|
|
78
|
+
const token = bearerToken(req) || queryApiKey(url);
|
|
79
|
+
return token.length > 0 && timingSafeEqualString(token, sessionAuth.apiKey);
|
|
80
|
+
}
|
|
81
|
+
const internal = resolveInternalAuth(req, serviceSecret);
|
|
82
|
+
return (internal !== null &&
|
|
83
|
+
internal.userId === sessionAuth.userId &&
|
|
84
|
+
internal.auth.kind === "internal");
|
|
85
|
+
}
|
|
86
|
+
async function resolveUserFromApiKey(baseUrl, apiKey) {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(`${baseUrl.replace(/\/$/, "")}/api/users/me`, {
|
|
89
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok)
|
|
92
|
+
return null;
|
|
93
|
+
const data = (await res.json());
|
|
94
|
+
return data.id ?? null;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function parseUrl(req, port) {
|
|
101
|
+
return new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
102
|
+
}
|
|
103
|
+
function json(res, status, body) {
|
|
104
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
105
|
+
res.end(JSON.stringify(body));
|
|
106
|
+
}
|
|
107
|
+
export function startKynverMcpSseServer(options) {
|
|
108
|
+
const port = parseInt(process.env.PORT ?? String(options.defaultPort), 10);
|
|
109
|
+
const baseUrl = process.env.KYNVER_API_URL ?? "https://kynver.com";
|
|
110
|
+
const serviceSecret = process.env.KYNVER_SERVICE_SECRET ?? "";
|
|
111
|
+
const host = resolveListenHost();
|
|
112
|
+
const sessions = {};
|
|
113
|
+
const httpServer = createServer(async (req, res) => {
|
|
114
|
+
const url = parseUrl(req, port);
|
|
115
|
+
const path = url.pathname;
|
|
116
|
+
if (req.method === "GET" && path === "/sse") {
|
|
117
|
+
if (hasForbiddenQueryAuth(url)) {
|
|
118
|
+
json(res, 400, {
|
|
119
|
+
error: "Internal auth via query params is not allowed. Use X-Kynver-User-Id and X-Kynver-Service-Secret headers.",
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (url.searchParams.has("apiKey")) {
|
|
124
|
+
console.warn("[MCP SSE] WARNING: apiKey in query string may leak via logs. Prefer Authorization header when your client supports it.");
|
|
125
|
+
}
|
|
126
|
+
let userId = null;
|
|
127
|
+
let auth = null;
|
|
128
|
+
const internal = serviceSecret ? resolveInternalAuth(req, serviceSecret) : null;
|
|
129
|
+
if (internal) {
|
|
130
|
+
userId = internal.userId;
|
|
131
|
+
auth = internal.auth;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const apiKey = bearerToken(req) || queryApiKey(url);
|
|
135
|
+
if (apiKey) {
|
|
136
|
+
userId = await resolveUserFromApiKey(baseUrl, apiKey);
|
|
137
|
+
if (userId)
|
|
138
|
+
auth = { kind: "apiKey", apiKey };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!userId || !auth) {
|
|
142
|
+
json(res, 401, {
|
|
143
|
+
error: "Unauthorized. Pass API key via Authorization: Bearer <key> or internal X-Kynver-User-Id + X-Kynver-Service-Secret headers.",
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(`[MCP SSE] New connection (${options.label}, user: ${userId.slice(0, 8)}...)`);
|
|
148
|
+
const transport = new SSEServerTransport("/messages", res);
|
|
149
|
+
sessions[transport.sessionId] = { transport, userId, auth };
|
|
150
|
+
res.on("close", () => {
|
|
151
|
+
delete sessions[transport.sessionId];
|
|
152
|
+
});
|
|
153
|
+
const server = await options.createMcpServer();
|
|
154
|
+
await server.connect(transport);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (req.method === "POST" && path === "/messages") {
|
|
158
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
159
|
+
const entry = sessionId ? sessions[sessionId] : undefined;
|
|
160
|
+
if (!entry) {
|
|
161
|
+
json(res, 400, { error: "No active SSE session for this sessionId" });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!verifyPostAuth(req, url, entry.auth, serviceSecret)) {
|
|
165
|
+
json(res, 401, { error: "Unauthorized. Re-send the same credentials used to open the SSE session." });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
const body = await parseJsonBody(req);
|
|
170
|
+
await options.requestContext.run({ userId: entry.userId }, async () => {
|
|
171
|
+
await entry.transport.handlePostMessage(req, res, body);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
json(res, 400, {
|
|
176
|
+
error: error instanceof Error ? error.message : "Invalid request body",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (req.method === "GET" && path === "/health") {
|
|
182
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
183
|
+
res.end("ok");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
json(res, 404, { error: "Not found" });
|
|
187
|
+
});
|
|
188
|
+
httpServer.listen(port, host, () => {
|
|
189
|
+
console.log(`[MCP SSE] ${options.label} listening on ${host}:${port}`);
|
|
190
|
+
});
|
|
191
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -69,6 +69,10 @@ export function createAgentOsServer() {
|
|
|
69
69
|
return MCP_LEGACY_SLUG_FALLBACK;
|
|
70
70
|
}
|
|
71
71
|
const slugField = z.string().optional().describe("AgentOS slug within your account. Omit to use env or server-discovered primary (GET /api/agent-os). Legacy: `ghost`.");
|
|
72
|
+
const memorySurfaceField = z
|
|
73
|
+
.enum(["operator", "customer"])
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Response shape for memory reads. Owners/env admins may pass operator for full diagnostics or customer to preview grantee-safe JSON. Grantees always receive customer-safe fields regardless of this flag.");
|
|
72
76
|
const sourceRefSchema = z
|
|
73
77
|
.object({
|
|
74
78
|
type: z
|
|
@@ -130,6 +134,7 @@ export function createAgentOsServer() {
|
|
|
130
134
|
memoryQuery: z.string().optional().describe("Override the memory search query. Defaults to a query derived from the anchor's title/summary."),
|
|
131
135
|
memoryLimit: z.number().optional().describe("Max memory hits (default 5, max 20). Set 0 to skip memory recall."),
|
|
132
136
|
sessionLimit: z.number().optional().describe("Max recent sessions (default 1, max 5). Set 0 to skip."),
|
|
137
|
+
surface: memorySurfaceField,
|
|
133
138
|
slug: slugField,
|
|
134
139
|
}, async (args) => {
|
|
135
140
|
const s = await resolveToolSlug(args.slug);
|
|
@@ -142,6 +147,8 @@ export function createAgentOsServer() {
|
|
|
142
147
|
params.set("memoryLimit", String(args.memoryLimit));
|
|
143
148
|
if (args.sessionLimit !== undefined)
|
|
144
149
|
params.set("sessionLimit", String(args.sessionLimit));
|
|
150
|
+
if (args.surface)
|
|
151
|
+
params.set("surface", args.surface);
|
|
145
152
|
return jsonResult(await get(`/agent-os/${s}/context-envelope?${params}`));
|
|
146
153
|
});
|
|
147
154
|
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.", {
|
|
@@ -269,7 +276,7 @@ export function createAgentOsServer() {
|
|
|
269
276
|
const s = await resolveToolSlug(slug);
|
|
270
277
|
return jsonResult(await patch(`/agent-os/${s}/projects/${projectId}`, body));
|
|
271
278
|
});
|
|
272
|
-
register("agent_os_search_memory", "Semantic + keyword hybrid search over the agent's long-term
|
|
279
|
+
register("agent_os_search_memory", "Semantic + keyword hybrid search over the agent's long-term memory (ownerType=agent). Use to recall specific decisions, project details, or lessons without loading full context. Replaces grep/reading MEMORY.md. Optionally restrict to one source namespace via sourceId, or several via sourceIds (sourceId takes precedence when both are set). Workspace owners and env admins receive operator diagnostics (rrfScore, lanes, hygiene) unless surface=customer; grantees always receive grantee-safe hits (content, trust, evidence links only).", {
|
|
273
280
|
query: z.string().describe("Natural language query to search memory."),
|
|
274
281
|
k: z.number().optional().describe("Number of results (default 10, max 50)."),
|
|
275
282
|
sourceId: z
|
|
@@ -282,6 +289,8 @@ export function createAgentOsServer() {
|
|
|
282
289
|
.describe("Restrict search to any of these source namespaces. Ignored when sourceId is also set."),
|
|
283
290
|
ticker: z.string().optional().describe("Trading desk: filter hits to this ticker symbol."),
|
|
284
291
|
debatePersona: z.enum(["bull", "bear"]).optional().describe("Trading desk: filter to bull or bear advocate memories."),
|
|
292
|
+
personaSlug: z.string().optional().describe("Layer in this persona's operating rules in Lane A alongside global rules."),
|
|
293
|
+
surface: memorySurfaceField,
|
|
285
294
|
slug: slugField,
|
|
286
295
|
}, async (args) => {
|
|
287
296
|
const params = new URLSearchParams({ q: args.query });
|
|
@@ -297,6 +306,10 @@ export function createAgentOsServer() {
|
|
|
297
306
|
params.set("ticker", args.ticker);
|
|
298
307
|
if (args.debatePersona)
|
|
299
308
|
params.set("debatePersona", args.debatePersona);
|
|
309
|
+
if (args.personaSlug)
|
|
310
|
+
params.set("personaSlug", args.personaSlug);
|
|
311
|
+
if (args.surface)
|
|
312
|
+
params.set("surface", args.surface);
|
|
300
313
|
const s = await resolveToolSlug(args.slug);
|
|
301
314
|
return jsonResult(await get(`/agent-os/${s}/memory?${params}`));
|
|
302
315
|
});
|
|
@@ -408,6 +421,14 @@ export function createAgentOsServer() {
|
|
|
408
421
|
goalId: z.string().optional().describe("AgentOS goal id this memory supports, when known."),
|
|
409
422
|
contactId: z.string().optional().describe("AgentOS contact id this memory concerns, when known."),
|
|
410
423
|
skillId: z.string().optional().describe("Skill identifier this memory belongs to. Built-ins use skill slug; user-authored skills use AgentSkill.id."),
|
|
424
|
+
correctionReason: z
|
|
425
|
+
.string()
|
|
426
|
+
.optional()
|
|
427
|
+
.describe("When this write encodes a user/operator correction (e.g. Telegram preference fix), explain why — triggers memory-quality negative feedback."),
|
|
428
|
+
correctionSource: z
|
|
429
|
+
.enum(["telegram", "manual", "api", "session"])
|
|
430
|
+
.optional()
|
|
431
|
+
.describe("Channel that supplied the correction; stored in metadata for audit, not memory body."),
|
|
411
432
|
slug: slugField,
|
|
412
433
|
}, async (args) => {
|
|
413
434
|
const categoryToSourceId = {
|
|
@@ -440,6 +461,10 @@ export function createAgentOsServer() {
|
|
|
440
461
|
body.contactId = args.contactId;
|
|
441
462
|
if (args.skillId)
|
|
442
463
|
body.skillId = args.skillId;
|
|
464
|
+
if (args.correctionReason)
|
|
465
|
+
body.correctionReason = args.correctionReason;
|
|
466
|
+
if (args.correctionSource)
|
|
467
|
+
body.correctionSource = args.correctionSource;
|
|
443
468
|
const s = await resolveToolSlug(args.slug);
|
|
444
469
|
return jsonResult(await post(`/agent-os/${s}/memory`, body));
|
|
445
470
|
});
|
|
@@ -536,9 +561,17 @@ export function createAgentOsServer() {
|
|
|
536
561
|
goalId: z.string().optional(),
|
|
537
562
|
contactId: z.string().optional(),
|
|
538
563
|
skillId: z.string().optional().describe("Skill identifier this memory belongs to. Built-ins use skill slug; user-authored skills use AgentSkill.id."),
|
|
564
|
+
correctionReason: z
|
|
565
|
+
.string()
|
|
566
|
+
.optional()
|
|
567
|
+
.describe("Why this update corrects prior memory — triggers memory-quality negative feedback when set."),
|
|
568
|
+
correctionSource: z
|
|
569
|
+
.enum(["telegram", "manual", "api", "session"])
|
|
570
|
+
.optional()
|
|
571
|
+
.describe("Channel that supplied the correction."),
|
|
539
572
|
slug: slugField,
|
|
540
573
|
}, async (args) => {
|
|
541
|
-
const { key, slug, content, sourceId, metadata, sourceRefs, memoryType, confidence, reviewStatus, projectId, goalId, contactId, skillId } = args;
|
|
574
|
+
const { key, slug, content, sourceId, metadata, sourceRefs, memoryType, confidence, reviewStatus, projectId, goalId, contactId, skillId, correctionReason, correctionSource } = args;
|
|
542
575
|
const body = { content, slug: key };
|
|
543
576
|
if (sourceId)
|
|
544
577
|
body.sourceId = sourceId;
|
|
@@ -560,6 +593,10 @@ export function createAgentOsServer() {
|
|
|
560
593
|
body.contactId = contactId;
|
|
561
594
|
if (skillId)
|
|
562
595
|
body.skillId = skillId;
|
|
596
|
+
if (correctionReason)
|
|
597
|
+
body.correctionReason = correctionReason;
|
|
598
|
+
if (correctionSource)
|
|
599
|
+
body.correctionSource = correctionSource;
|
|
563
600
|
const s = await resolveToolSlug(slug);
|
|
564
601
|
return jsonResult(await post(`/agent-os/${s}/memory`, body));
|
|
565
602
|
});
|
|
@@ -579,6 +616,7 @@ export function createAgentOsServer() {
|
|
|
579
616
|
goalId: z.string().optional(),
|
|
580
617
|
contactId: z.string().optional(),
|
|
581
618
|
skillId: z.string().optional(),
|
|
619
|
+
correctionSource: z.enum(["telegram", "manual", "api", "session"]).optional(),
|
|
582
620
|
slug: slugField,
|
|
583
621
|
}, async (args) => {
|
|
584
622
|
const { slug, ...body } = args;
|
|
@@ -607,9 +645,10 @@ export function createAgentOsServer() {
|
|
|
607
645
|
entityType: activeStateEntityTypeSchema.optional(),
|
|
608
646
|
projectId: z.string().optional(),
|
|
609
647
|
limit: z.number().optional(),
|
|
648
|
+
surface: memorySurfaceField,
|
|
610
649
|
slug: slugField,
|
|
611
650
|
}, async (args) => {
|
|
612
|
-
const { slug, entityKey, entityType, projectId, limit } = args;
|
|
651
|
+
const { slug, entityKey, entityType, projectId, limit, surface } = args;
|
|
613
652
|
const s = await resolveToolSlug(slug);
|
|
614
653
|
const qs = new URLSearchParams();
|
|
615
654
|
if (entityKey)
|
|
@@ -620,6 +659,8 @@ export function createAgentOsServer() {
|
|
|
620
659
|
qs.set("projectId", projectId);
|
|
621
660
|
if (limit !== undefined)
|
|
622
661
|
qs.set("limit", String(limit));
|
|
662
|
+
if (surface)
|
|
663
|
+
qs.set("surface", surface);
|
|
623
664
|
const suffix = qs.toString() ? "?" + qs.toString() : "";
|
|
624
665
|
return jsonResult(await get("/agent-os/" + s + "/memory/state" + suffix));
|
|
625
666
|
});
|
package/dist/sse.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { startKynverMcpSseServer } from "
|
|
1
|
+
import { startKynverMcpSseServer } from "./lib/mcp-sse-server.js";
|
|
2
2
|
import { createAgentOsServer } from "./server.js";
|
|
3
3
|
import { requestContext } from "./lib/kynver-client.js";
|
|
4
4
|
startKynverMcpSseServer({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kynver-app/mcp-agent-os",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.19",
|
|
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": {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"SECURITY.md"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"
|
|
15
|
+
"prebuild": "node ../../scripts/sync-mcp-sse-server.mjs",
|
|
16
|
+
"build": "node --max-old-space-size=8192 ../../node_modules/typescript/bin/tsc",
|
|
16
17
|
"dev": "node --max-old-space-size=8192 ../../node_modules/typescript/bin/tsc --watch",
|
|
17
18
|
"start": "node dist/index.js",
|
|
18
19
|
"start:sse": "node dist/sse.js"
|
|
@@ -21,7 +22,6 @@
|
|
|
21
22
|
"node": ">=18"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@kynver-app/mcp-sse-lib": "*",
|
|
25
25
|
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
26
26
|
"zod": "^3.23.0"
|
|
27
27
|
},
|