@productbrain/mcp 0.0.1-beta.179 → 0.0.1-beta.180
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/{chunk-IOEZLNTK.js → chunk-XPFSARXP.js} +78 -56
- package/dist/chunk-XPFSARXP.js.map +1 -0
- package/dist/http.js +39 -16
- package/dist/http.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-IOEZLNTK.js.map +0 -1
|
@@ -49,7 +49,8 @@ function newKeyState() {
|
|
|
49
49
|
apiKeyScope: "readwrite",
|
|
50
50
|
sessionOriented: false,
|
|
51
51
|
sessionClosed: false,
|
|
52
|
-
lastAccess: Date.now()
|
|
52
|
+
lastAccess: Date.now(),
|
|
53
|
+
deploymentUrl: null
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
function getKeyState(apiKey) {
|
|
@@ -152,7 +153,8 @@ var _stdioState = {
|
|
|
152
153
|
apiKeyScope: "readwrite",
|
|
153
154
|
sessionOriented: false,
|
|
154
155
|
sessionClosed: false,
|
|
155
|
-
lastAccess: 0
|
|
156
|
+
lastAccess: 0,
|
|
157
|
+
deploymentUrl: null
|
|
156
158
|
};
|
|
157
159
|
function state() {
|
|
158
160
|
const reqKey = getRequestApiKey();
|
|
@@ -278,10 +280,44 @@ function bootstrap() {
|
|
|
278
280
|
function bootstrapHttp() {
|
|
279
281
|
process.env.CONVEX_SITE_URL ??= process.env.PRODUCTBRAIN_URL ?? DEFAULT_CLOUD_URL;
|
|
280
282
|
}
|
|
281
|
-
function
|
|
282
|
-
const
|
|
283
|
-
if (!
|
|
284
|
-
return
|
|
283
|
+
function parseFallbackUrls() {
|
|
284
|
+
const raw = process.env.CONVEX_FALLBACK_URLS;
|
|
285
|
+
if (!raw) return [];
|
|
286
|
+
return raw.split(",").map((u) => u.trim()).filter(Boolean);
|
|
287
|
+
}
|
|
288
|
+
async function resolveDeploymentUrl() {
|
|
289
|
+
const s = state();
|
|
290
|
+
if (s.deploymentUrl) return s.deploymentUrl;
|
|
291
|
+
const primaryUrl = (process.env.CONVEX_SITE_URL ?? DEFAULT_CLOUD_URL).replace(/\/$/, "");
|
|
292
|
+
const fallbacks = parseFallbackUrls();
|
|
293
|
+
if (fallbacks.length === 0) {
|
|
294
|
+
return primaryUrl;
|
|
295
|
+
}
|
|
296
|
+
const candidates = [primaryUrl, ...fallbacks.map((u) => u.replace(/\/$/, ""))];
|
|
297
|
+
let apiKey;
|
|
298
|
+
try {
|
|
299
|
+
apiKey = getActiveApiKey();
|
|
300
|
+
} catch {
|
|
301
|
+
return primaryUrl;
|
|
302
|
+
}
|
|
303
|
+
for (const candidate of candidates) {
|
|
304
|
+
try {
|
|
305
|
+
const probeRes = await fetch(`${candidate}/api/key-check`, {
|
|
306
|
+
method: "POST",
|
|
307
|
+
headers: { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
308
|
+
signal: AbortSignal.timeout(3e3)
|
|
309
|
+
});
|
|
310
|
+
if (probeRes.ok) {
|
|
311
|
+
const data = await probeRes.json();
|
|
312
|
+
if (data.ok) {
|
|
313
|
+
s.deploymentUrl = candidate;
|
|
314
|
+
return candidate;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return candidates[0];
|
|
285
321
|
}
|
|
286
322
|
function shouldLogAudit(status) {
|
|
287
323
|
return status === "error" || process.env.MCP_DEBUG === "1";
|
|
@@ -318,7 +354,7 @@ var TOUCH_EXCLUDED = /* @__PURE__ */ new Set([
|
|
|
318
354
|
"agent.closeSession"
|
|
319
355
|
]);
|
|
320
356
|
async function callGateway(fn, args) {
|
|
321
|
-
const siteUrl =
|
|
357
|
+
const siteUrl = await resolveDeploymentUrl();
|
|
322
358
|
const apiKey = getActiveApiKey();
|
|
323
359
|
const start = Date.now();
|
|
324
360
|
let res;
|
|
@@ -1878,7 +1914,7 @@ Reason: ${resolved.reasoning || "low signal"}
|
|
|
1878
1914
|
Choose one of these and retry with \`collection\`:
|
|
1879
1915
|
${suggestions}
|
|
1880
1916
|
|
|
1881
|
-
Correction path: rerun with your chosen \`collection\`, or capture and use \`
|
|
1917
|
+
Correction path: rerun with your chosen \`collection\`, or capture and use \`move-entry\` later.`;
|
|
1882
1918
|
return {
|
|
1883
1919
|
content: [{ type: "text", text: textBody }],
|
|
1884
1920
|
structuredContent: failure(
|
|
@@ -3334,7 +3370,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
|
|
|
3334
3370
|
lines.push(`- **${r.entryId}**: ${r.name} [${r.collection}] \u2014 \`${r.status}\` (${r.classifiedBy} ${r.confidence}%)${linkNote}`);
|
|
3335
3371
|
}
|
|
3336
3372
|
lines.push(`
|
|
3337
|
-
_Use \`
|
|
3373
|
+
_Use \`move-entry\` to correct any misclassified entries._`);
|
|
3338
3374
|
}
|
|
3339
3375
|
}
|
|
3340
3376
|
if (skippedLowConfidence.length > 0) {
|
|
@@ -4160,20 +4196,23 @@ function sanitizeEntryData(data) {
|
|
|
4160
4196
|
);
|
|
4161
4197
|
return Object.keys(filtered).length > 0 ? filtered : void 0;
|
|
4162
4198
|
}
|
|
4163
|
-
var ENTRIES_ACTIONS = ["list", "get", "batch", "search"
|
|
4199
|
+
var ENTRIES_ACTIONS = ["list", "get", "batch", "search"];
|
|
4164
4200
|
var entriesSchema = z4.object({
|
|
4165
4201
|
action: z4.enum(ENTRIES_ACTIONS).describe(
|
|
4166
|
-
"'list': browse entries with filters. 'get': fetch one entry by ID. 'batch': fetch multiple entries. 'search': full-text search.
|
|
4202
|
+
"'list': browse entries with filters. 'get': fetch one entry by ID. 'batch': fetch multiple entries. 'search': full-text search."
|
|
4167
4203
|
),
|
|
4168
|
-
entryId: z4.string().optional().describe("Entry ID for get
|
|
4204
|
+
entryId: z4.string().optional().describe("Entry ID for get action, e.g. 'DEC-42', 'BR-001'"),
|
|
4169
4205
|
entryIds: z4.array(z4.string()).min(1).max(20).optional().describe("Entry IDs for batch action, e.g. ['TYPE-strategy', 'STR-jljeg7']"),
|
|
4170
4206
|
collection: z4.string().optional().describe("Collection slug for list/search, e.g. 'glossary', 'tracking-events', 'business-rules'"),
|
|
4171
|
-
toCollection: z4.string().optional().describe("Target collection slug for move action, e.g. 'decisions', 'architecture'"),
|
|
4172
4207
|
status: z4.string().optional().describe("Filter: draft | active | deprecated | archived"),
|
|
4173
4208
|
tag: z4.string().optional().describe("Filter by internal tag for list"),
|
|
4174
4209
|
label: z4.string().optional().describe("Filter by label slug for list \u2014 matches entries across all collections"),
|
|
4175
4210
|
query: z4.string().optional().describe("Search text for search action (min 2 characters)")
|
|
4176
4211
|
});
|
|
4212
|
+
var moveEntrySchema = z4.object({
|
|
4213
|
+
entryId: z4.string().describe("Entry ID to move, e.g. 'DEC-42', 'BR-001'"),
|
|
4214
|
+
toCollection: z4.string().describe("Target collection slug, e.g. 'decisions', 'architecture'")
|
|
4215
|
+
});
|
|
4177
4216
|
var entriesGetOutputSchema = z4.object({
|
|
4178
4217
|
entryId: z4.string(),
|
|
4179
4218
|
name: z4.string(),
|
|
@@ -4235,14 +4274,14 @@ function registerEntriesTools(server) {
|
|
|
4235
4274
|
"entries",
|
|
4236
4275
|
{
|
|
4237
4276
|
title: "Entries",
|
|
4238
|
-
description: 'Read entries from the Chain. One tool for all entry reading.\n\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n
|
|
4277
|
+
description: 'Read entries from the Chain. One tool for all entry reading.\n\n- **list**: Browse entries with optional filters (collection, status, tag, label). Use collections action=list first to discover slugs.\n- **get**: Fetch a single entry by ID \u2014 full record with data, labels, relations, history.\n- **batch**: Fetch multiple entries (max 20) in one call. Same shape as get per entry.\n- **search**: Full-text search across entries. Scope by collection or filter by status.\n\nUse `entries action=get entryId="..."` to fetch one. Use `entries action=search query="..."` to discover. To reclassify, use `move-entry`.',
|
|
4239
4278
|
inputSchema: entriesSchema,
|
|
4240
|
-
annotations: { idempotentHint:
|
|
4279
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
4241
4280
|
},
|
|
4242
4281
|
thinWrapper(async (args) => {
|
|
4243
4282
|
const parsed = parseOrFail(entriesSchema, args);
|
|
4244
4283
|
if (!parsed.ok) return parsed.result;
|
|
4245
|
-
const { action, entryId, entryIds, collection,
|
|
4284
|
+
const { action, entryId, entryIds, collection, status, tag, label, query } = parsed.data;
|
|
4246
4285
|
return runWithToolContext({ tool: "entries", action }, async () => {
|
|
4247
4286
|
if (action === "get") {
|
|
4248
4287
|
if (!entryId) {
|
|
@@ -4265,15 +4304,27 @@ function registerEntriesTools(server) {
|
|
|
4265
4304
|
if (action === "list") {
|
|
4266
4305
|
return handleList(collection, status, tag, label);
|
|
4267
4306
|
}
|
|
4268
|
-
if (action === "move") {
|
|
4269
|
-
if (!entryId) return validationResult("entryId is required when action is 'move'.");
|
|
4270
|
-
if (!toCollection) return validationResult("toCollection is required when action is 'move'.");
|
|
4271
|
-
return handleMove(entryId, toCollection);
|
|
4272
|
-
}
|
|
4273
4307
|
return unknownAction(action, ENTRIES_ACTIONS);
|
|
4274
4308
|
});
|
|
4275
4309
|
})
|
|
4276
4310
|
);
|
|
4311
|
+
server.registerTool(
|
|
4312
|
+
"move-entry",
|
|
4313
|
+
{
|
|
4314
|
+
title: "Move Entry",
|
|
4315
|
+
description: 'Move an entry to a different collection. Use when the classifier misrouted or the user wants to reclassify.\n\nExample: `move-entry entryId="DEC-42" toCollection="tensions"` reclassifies DEC-42 into the tensions collection.',
|
|
4316
|
+
inputSchema: moveEntrySchema,
|
|
4317
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
4318
|
+
},
|
|
4319
|
+
thinWrapper(async (args) => {
|
|
4320
|
+
const parsed = parseOrFail(moveEntrySchema, args);
|
|
4321
|
+
if (!parsed.ok) return parsed.result;
|
|
4322
|
+
return runWithToolContext(
|
|
4323
|
+
{ tool: "move-entry", action: "move" },
|
|
4324
|
+
() => handleMove(parsed.data.entryId, parsed.data.toCollection)
|
|
4325
|
+
);
|
|
4326
|
+
})
|
|
4327
|
+
);
|
|
4277
4328
|
}
|
|
4278
4329
|
async function handleGet(entryId) {
|
|
4279
4330
|
const entry = await kernelQuery("chain.getEntry", { entryId });
|
|
@@ -4953,37 +5004,6 @@ async function handleCreate(from, to, type, score, preview) {
|
|
|
4953
5004
|
sessionId: agentSessionId ?? void 0,
|
|
4954
5005
|
...preview ? { preview: true } : {}
|
|
4955
5006
|
});
|
|
4956
|
-
if (result?.chainDebtPrevented) {
|
|
4957
|
-
const alts = result.suggestedAlternatives ?? [];
|
|
4958
|
-
const altList = alts.map((a) => ` \u2022 \`${a.type}\`: ${a.reason}`).join("\n");
|
|
4959
|
-
return {
|
|
4960
|
-
content: [{
|
|
4961
|
-
type: "text",
|
|
4962
|
-
text: `# Chain Debt Prevented
|
|
4963
|
-
|
|
4964
|
-
**"${result.originalType ?? type}"** was intercepted as a common misuse for this entry pair and converted to an agent sign-off proposal.
|
|
4965
|
-
|
|
4966
|
-
**Proposal ID:** \`${result.proposalId}\`
|
|
4967
|
-
|
|
4968
|
-
**Suggested alternatives:**
|
|
4969
|
-
${altList}
|
|
4970
|
-
|
|
4971
|
-
Review at /review in Cortex UI.`
|
|
4972
|
-
}],
|
|
4973
|
-
structuredContent: success(
|
|
4974
|
-
`Chain debt prevented: "${result.originalType ?? type}" was intercepted and converted to an agent sign-off proposal.`,
|
|
4975
|
-
{
|
|
4976
|
-
chainDebtPrevented: true,
|
|
4977
|
-
proposalId: result.proposalId,
|
|
4978
|
-
originalType: result.originalType ?? type,
|
|
4979
|
-
suggestedAlternatives: result.suggestedAlternatives
|
|
4980
|
-
},
|
|
4981
|
-
[
|
|
4982
|
-
{ tool: "relations", description: "Use correct type (e.g. informed_by)", parameters: { action: "create", from, to, type: alts[0]?.type ?? "informed_by" } }
|
|
4983
|
-
]
|
|
4984
|
-
)
|
|
4985
|
-
};
|
|
4986
|
-
}
|
|
4987
5007
|
if (result?.preview) {
|
|
4988
5008
|
const suggested2 = result.suggestedType;
|
|
4989
5009
|
const suggestedWithPosture2 = suggested2 ? { ...suggested2, governancePosture: suggested2.type === "governs" ? "requires_consent" : "direct" } : void 0;
|
|
@@ -9800,7 +9820,7 @@ var facilitateSchema = z14.object({
|
|
|
9800
9820
|
betEntryId: z14.string().optional().describe("Bet entry ID. Required for both actions."),
|
|
9801
9821
|
operationId: z14.string().optional().describe("Optional idempotency key for commit-constellation retries.")
|
|
9802
9822
|
});
|
|
9803
|
-
function
|
|
9823
|
+
function buildStudioUrl(workspaceSlug, entryId) {
|
|
9804
9824
|
const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://work.productbrain.io";
|
|
9805
9825
|
return `${appUrl}/${workspaceSlug}/legacy/entries/${entryId}`;
|
|
9806
9826
|
}
|
|
@@ -9851,7 +9871,7 @@ async function handleResume(args) {
|
|
|
9851
9871
|
});
|
|
9852
9872
|
const enrichedData = {
|
|
9853
9873
|
...envelope.data,
|
|
9854
|
-
|
|
9874
|
+
studioUrl: buildStudioUrl(workspaceSlug, betId)
|
|
9855
9875
|
};
|
|
9856
9876
|
const bet = enrichedData.betEntry;
|
|
9857
9877
|
const cx = enrichedData.constellation;
|
|
@@ -9867,7 +9887,7 @@ async function handleResume(args) {
|
|
|
9867
9887
|
`# ${bet.name}`,
|
|
9868
9888
|
"",
|
|
9869
9889
|
`**ID:** \`${bet.betEntryId}\` \xB7 **Status:** ${bet.status}`,
|
|
9870
|
-
enrichedData.
|
|
9890
|
+
enrichedData.studioUrl ? `**Cortex:** ${enrichedData.studioUrl}` : "",
|
|
9871
9891
|
"",
|
|
9872
9892
|
`**Constellation:** ${constellationSummary}`,
|
|
9873
9893
|
...draftLines.length > 0 ? ["", "**Session drafts:**", ...draftLines] : []
|
|
@@ -15670,6 +15690,8 @@ function initFeatureFlags(_posthogClient) {
|
|
|
15670
15690
|
export {
|
|
15671
15691
|
hashKey,
|
|
15672
15692
|
runWithAuth,
|
|
15693
|
+
getKeyState,
|
|
15694
|
+
DEFAULT_CLOUD_URL,
|
|
15673
15695
|
getAgentSessionId,
|
|
15674
15696
|
orphanAgentSession,
|
|
15675
15697
|
bootstrap,
|
|
@@ -15680,4 +15702,4 @@ export {
|
|
|
15680
15702
|
createProductBrainServer,
|
|
15681
15703
|
initFeatureFlags
|
|
15682
15704
|
};
|
|
15683
|
-
//# sourceMappingURL=chunk-
|
|
15705
|
+
//# sourceMappingURL=chunk-XPFSARXP.js.map
|