@kynver-app/mcp-agent-os 0.3.63 → 0.3.65
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.
|
@@ -49,8 +49,13 @@ function getHeaders() {
|
|
|
49
49
|
const userId = ctx?.userId;
|
|
50
50
|
const serviceSecret = process.env.KYNVER_SERVICE_SECRET;
|
|
51
51
|
if (userId) {
|
|
52
|
+
const runnerToken = process.env.KYNVER_RUNNER_TOKEN?.trim();
|
|
53
|
+
if (runnerToken) {
|
|
54
|
+
headers["X-Kynver-Runner-Token"] = runnerToken;
|
|
55
|
+
return headers;
|
|
56
|
+
}
|
|
52
57
|
if (!serviceSecret) {
|
|
53
|
-
throw new Error("
|
|
58
|
+
throw new Error("User context requires authentication: set KYNVER_RUNNER_TOKEN (preferred) or KYNVER_SERVICE_SECRET in the MCP server environment.");
|
|
54
59
|
}
|
|
55
60
|
headers["X-Kynver-User-Id"] = userId;
|
|
56
61
|
headers["X-Kynver-Service-Secret"] = serviceSecret;
|
|
@@ -5,6 +5,13 @@ 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
7
|
const FORBIDDEN_QUERY_KEYS = ["apiKey", "secret", "userId"];
|
|
8
|
+
const TRUTHY_ENV = new Set(["1", "true", "yes", "on"]);
|
|
9
|
+
function isServiceSecretImpersonationRejectedInProduction() {
|
|
10
|
+
const override = process.env.KYNVER_ALLOW_SERVICE_SECRET_IMPERSONATION?.trim().toLowerCase();
|
|
11
|
+
if (override !== undefined && TRUTHY_ENV.has(override))
|
|
12
|
+
return false;
|
|
13
|
+
return process.env.NODE_ENV === "production" || process.env.VERCEL_ENV === "production";
|
|
14
|
+
}
|
|
8
15
|
export function headerValue(req, name) {
|
|
9
16
|
const v = req.headers[name];
|
|
10
17
|
return typeof v === "string" ? v : Array.isArray(v) ? (v[0] ?? null) : null;
|
|
@@ -121,6 +128,8 @@ function resolveInternalAuth(req, serviceSecret) {
|
|
|
121
128
|
const internalSecret = headerValue(req, "x-kynver-service-secret");
|
|
122
129
|
if (!internalUserId || !serviceSecret || !internalSecret)
|
|
123
130
|
return null;
|
|
131
|
+
if (isServiceSecretImpersonationRejectedInProduction())
|
|
132
|
+
return null;
|
|
124
133
|
if (!timingSafeEqualString(internalSecret, serviceSecret))
|
|
125
134
|
return null;
|
|
126
135
|
return { userId: internalUserId, auth: { kind: "internal", userId: internalUserId } };
|
package/dist/tools/graph.js
CHANGED
|
@@ -125,10 +125,18 @@ export function registerGraphTools({ register, resolveToolSlug, jsonResult }) {
|
|
|
125
125
|
grantToken: z
|
|
126
126
|
.string()
|
|
127
127
|
.describe("Signed expansion grant (kve:g:…) bound to this graph handle and envelope."),
|
|
128
|
-
purpose: z
|
|
128
|
+
purpose: z
|
|
129
|
+
.string()
|
|
130
|
+
.describe("Informational only — the server enforces the graph-expansion purpose bound into the grant and ignores this value."),
|
|
129
131
|
envelopeId: z.string().describe("Active context envelope id binding this expansion."),
|
|
130
132
|
asOf: z.string().optional().describe("Optional UTC ISO as-of instant for temporal filtering."),
|
|
131
|
-
maxDepth: z
|
|
133
|
+
maxDepth: z
|
|
134
|
+
.number()
|
|
135
|
+
.int()
|
|
136
|
+
.min(1)
|
|
137
|
+
.max(1)
|
|
138
|
+
.optional()
|
|
139
|
+
.describe("Traversal depth; the server caps expansion depth at 1."),
|
|
132
140
|
maxNodes: z.number().int().min(1).max(36).optional(),
|
|
133
141
|
}, async (args) => {
|
|
134
142
|
const slug = await resolveToolSlug(args.slug);
|
package/dist/tools/workbench.js
CHANGED
|
@@ -19,6 +19,20 @@ const commandKind = z.enum([
|
|
|
19
19
|
"yield",
|
|
20
20
|
"take",
|
|
21
21
|
]);
|
|
22
|
+
/** Keep in sync with COMMAND_CENTER_VIEW_MODES in command-center-url-state.ts */
|
|
23
|
+
const workbenchView = z.enum([
|
|
24
|
+
"overview",
|
|
25
|
+
"flow",
|
|
26
|
+
"marketing",
|
|
27
|
+
"projects",
|
|
28
|
+
"tasks",
|
|
29
|
+
"goals",
|
|
30
|
+
"dq",
|
|
31
|
+
"web",
|
|
32
|
+
"review",
|
|
33
|
+
"system",
|
|
34
|
+
"health",
|
|
35
|
+
]);
|
|
22
36
|
export function registerWorkbenchTools({ register, resolveToolSlug, jsonResult, }) {
|
|
23
37
|
register("agent_os_workbench_query", [
|
|
24
38
|
"Read the operator's current workbench focus (view mode, drilldown stack, focused entity)",
|
|
@@ -37,7 +51,7 @@ export function registerWorkbenchTools({ register, resolveToolSlug, jsonResult,
|
|
|
37
51
|
].join(" "), {
|
|
38
52
|
slug: z.string().optional(),
|
|
39
53
|
kind: commandKind,
|
|
40
|
-
view:
|
|
54
|
+
view: workbenchView.optional(),
|
|
41
55
|
target: z.string().optional().describe("EntityRef e.g. task:<id>, plan:<id>"),
|
|
42
56
|
push: z.boolean().optional().describe("For drill: push onto stack (default true)"),
|
|
43
57
|
panel: z.string().optional(),
|
package/package.json
CHANGED