@getmarrow/mcp 3.9.55 → 3.9.57
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 +31 -4
- package/dist/cli.js +326 -109
- package/dist/cli.js.map +1 -1
- package/dist/hook-context.d.ts +2 -1
- package/dist/hook-context.d.ts.map +1 -1
- package/dist/hook-context.js +2 -1
- package/dist/hook-context.js.map +1 -1
- package/dist/hook-contract.d.ts +6 -6
- package/dist/hook-contract.js +1 -1
- package/dist/hook-session.d.ts +1 -1
- package/dist/hook.d.ts +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +196 -15
- package/dist/index.js.map +1 -1
- package/dist/redact.js +1 -1
- package/dist/redact.js.map +1 -1
- package/dist/request-reliability.d.ts +27 -0
- package/dist/request-reliability.d.ts.map +1 -0
- package/dist/request-reliability.js +264 -0
- package/dist/request-reliability.js.map +1 -0
- package/dist/runtime-contract.d.ts +5 -0
- package/dist/runtime-contract.d.ts.map +1 -0
- package/dist/runtime-contract.js +107 -0
- package/dist/runtime-contract.js.map +1 -0
- package/package.json +7 -4
- package/scripts/control-path-canary.cjs +166 -0
- package/server.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -17,8 +17,12 @@ const hook_session_1 = require("./hook-session");
|
|
|
17
17
|
const hook_pre_action_1 = require("./hook-pre-action");
|
|
18
18
|
const env_1 = require("./env");
|
|
19
19
|
const lifecycle_spool_1 = require("./lifecycle-spool");
|
|
20
|
+
const guidance_cache_1 = require("./guidance-cache");
|
|
21
|
+
const request_reliability_1 = require("./request-reliability");
|
|
22
|
+
const hook_contract_1 = require("./hook-contract");
|
|
20
23
|
const ping_state_1 = require("./ping-state");
|
|
21
24
|
const redact_1 = require("./redact");
|
|
25
|
+
const runtime_contract_1 = require("./runtime-contract");
|
|
22
26
|
// Parse CLI args
|
|
23
27
|
function parseArgs() {
|
|
24
28
|
const args = process.argv.slice(2);
|
|
@@ -355,9 +359,12 @@ if (process.argv[2] !== 'keys') {
|
|
|
355
359
|
const rawBaseUrl = resolvedEnv.baseUrl || 'https://api.getmarrow.ai';
|
|
356
360
|
const BASE_URL = (0, index_1.validateBaseUrl)(rawBaseUrl);
|
|
357
361
|
const SESSION_ID = resolvedEnv.sessionId || undefined;
|
|
358
|
-
|
|
362
|
+
// One identity must bind headers, bodies, queries, cache, and lifecycle events.
|
|
363
|
+
// resolveMarrowEnv already gives MARROW_FLEET_AGENT_ID precedence over MARROW_AGENT_ID.
|
|
364
|
+
// When no identity is configured, omit it and let the API resolve the key's
|
|
365
|
+
// bound agent instead of inventing a process-local identity that changes on restart.
|
|
366
|
+
const FLEET_AGENT_ID = resolvedEnv.agentId || undefined;
|
|
359
367
|
const AUTO_ENROLL = process.env.MARROW_AUTO_ENROLL !== 'false'; // on by default
|
|
360
|
-
const AGENT_ID = process.env.MARROW_AGENT_ID || `${require('os').hostname()}-${Date.now().toString(36)}`;
|
|
361
368
|
if (!API_KEY) {
|
|
362
369
|
process.stderr.write('Error: MARROW_API_KEY environment variable is required\n');
|
|
363
370
|
process.stderr.write(`${resolvedEnv.exactFix}\n`);
|
|
@@ -389,12 +396,6 @@ if (process.argv[2] !== 'keys') {
|
|
|
389
396
|
process.stderr.write(`[marrow] Warning: failed to refresh orient warnings: ${msg}\n`);
|
|
390
397
|
}
|
|
391
398
|
}
|
|
392
|
-
// Initial orient
|
|
393
|
-
refreshOrientWarnings().then(() => {
|
|
394
|
-
if (cachedOrientWarnings.some((w) => w.failureRate > 0.4)) {
|
|
395
|
-
process.stderr.write(`[marrow] ⚠️ High failure rate detected on startup — call marrow_orient for details before acting\n`);
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
399
|
// Auto-commit tracking for session close
|
|
399
400
|
let lastDecisionId = null;
|
|
400
401
|
let lastCommitted = false;
|
|
@@ -432,6 +433,35 @@ if (process.argv[2] !== 'keys') {
|
|
|
432
433
|
function error(id, code, message) {
|
|
433
434
|
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
434
435
|
}
|
|
436
|
+
function toolSuccess(id, value, isError = false) {
|
|
437
|
+
success(id, {
|
|
438
|
+
content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
|
|
439
|
+
...(isError ? { isError: true } : {}),
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function toolFailure(toolName, failure) {
|
|
443
|
+
const result = (0, request_reliability_1.structuredRequestFailure)(failure);
|
|
444
|
+
const transient = failure.retryable && !['authentication_required', 'permission_denied'].includes(failure.code);
|
|
445
|
+
const supportsStale = ['marrow_agent_runtime', 'marrow_orient', 'marrow_ask', 'marrow_runtime_status', 'marrow_status'].includes(toolName || '');
|
|
446
|
+
if (transient && supportsStale) {
|
|
447
|
+
let cached = null;
|
|
448
|
+
try {
|
|
449
|
+
cached = (0, guidance_cache_1.readGuidanceCache)({ apiKey: API_KEY, baseUrl: BASE_URL, agentId: FLEET_AGENT_ID });
|
|
450
|
+
}
|
|
451
|
+
catch { /* owner-only cache is best effort */ }
|
|
452
|
+
if (cached) {
|
|
453
|
+
result.stale_brief = cached.context;
|
|
454
|
+
result.stale_ms = cached.stale_ms;
|
|
455
|
+
}
|
|
456
|
+
result.disposition = 'review_required';
|
|
457
|
+
result.allow = false;
|
|
458
|
+
result.stale_can_authorize_high_risk = false;
|
|
459
|
+
result.exact_next_action = cached
|
|
460
|
+
? 'Use this last-known brief for low-risk context only. Obtain a fresh Marrow runtime gate before high-risk work.'
|
|
461
|
+
: 'Retry once after retry_after_ms. Do not perform high-risk work without a fresh Marrow runtime gate.';
|
|
462
|
+
}
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
435
465
|
// [FIX #9] Runtime validation helper for required string params
|
|
436
466
|
function requireString(args, name) {
|
|
437
467
|
const val = args[name];
|
|
@@ -440,6 +470,51 @@ if (process.argv[2] !== 'keys') {
|
|
|
440
470
|
}
|
|
441
471
|
return val;
|
|
442
472
|
}
|
|
473
|
+
function requireBoolean(args, name) {
|
|
474
|
+
const value = args[name];
|
|
475
|
+
if (typeof value !== 'boolean')
|
|
476
|
+
throw new Error(`"${name}" is required and must be boolean`);
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
479
|
+
const HIGH_RISK_ACTION = /\b(?:billing|credential|database|delete|deploy|destructive|financial|key|merge|migrat(?:e|ion)|payment|production|publish|release|remove|rollback|secret|security|token|truncate|wipe)\b/i;
|
|
480
|
+
function isHighRiskAction(action, type) {
|
|
481
|
+
return HIGH_RISK_ACTION.test(`${String(type || '')} ${String(action || '')}`);
|
|
482
|
+
}
|
|
483
|
+
function cachedGuidance() {
|
|
484
|
+
try {
|
|
485
|
+
return (0, guidance_cache_1.readGuidanceCache)({ apiKey: API_KEY, baseUrl: BASE_URL, agentId: FLEET_AGENT_ID });
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
async function withControlDeadline(operation, options = {}) {
|
|
492
|
+
const hasCache = options.cacheAware !== false && Boolean(cachedGuidance());
|
|
493
|
+
const configuredCanaryMs = Number(process.env.MARROW_REQUEST_TIMEOUT_MS);
|
|
494
|
+
const timeoutMs = process.env.MARROW_CONTROL_PATH_CANARY === '1' && Number.isFinite(configuredCanaryMs)
|
|
495
|
+
? Math.min(5_000, Math.max(500, Math.floor(configuredCanaryMs)))
|
|
496
|
+
: options.highRisk ? 2_000 : hasCache ? 400 : 1_200;
|
|
497
|
+
const controller = new AbortController();
|
|
498
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
499
|
+
timer.unref?.();
|
|
500
|
+
try {
|
|
501
|
+
return await operation(controller.signal);
|
|
502
|
+
}
|
|
503
|
+
finally {
|
|
504
|
+
clearTimeout(timer);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function storeRuntimeGuidance(runtime) {
|
|
508
|
+
try {
|
|
509
|
+
(0, guidance_cache_1.writeGuidanceCache)({
|
|
510
|
+
apiKey: API_KEY,
|
|
511
|
+
baseUrl: BASE_URL,
|
|
512
|
+
agentId: FLEET_AGENT_ID,
|
|
513
|
+
context: (0, hook_context_1.compactRuntimeContext)(runtime),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
catch { /* owner-only cache is best effort */ }
|
|
517
|
+
}
|
|
443
518
|
// [FIX #6 & #7] Safe JSON response helper for memory API functions
|
|
444
519
|
async function safeMemoryResponse(res) {
|
|
445
520
|
if (!res.ok) {
|
|
@@ -726,8 +801,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
726
801
|
},
|
|
727
802
|
{
|
|
728
803
|
name: 'marrow_run',
|
|
729
|
-
description: '
|
|
730
|
-
'Use this instead of chaining marrow_think + marrow_commit when you want Marrow to just work without managing the loop yourself.',
|
|
804
|
+
description: 'One-call governed outcome capture. Records intent, obtains a gate for risky work, and closes only with an explicit measured result.',
|
|
731
805
|
inputSchema: {
|
|
732
806
|
type: 'object',
|
|
733
807
|
properties: {
|
|
@@ -739,27 +813,28 @@ if (process.argv[2] !== 'keys') {
|
|
|
739
813
|
enum: ['implementation', 'security', 'architecture', 'process', 'general'],
|
|
740
814
|
description: 'Type of action (default: general)',
|
|
741
815
|
},
|
|
816
|
+
proof: { type: 'object', description: 'Measured evidence required to close high-risk work.' },
|
|
817
|
+
gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
|
|
742
818
|
},
|
|
743
819
|
required: ['description', 'success', 'outcome'],
|
|
744
820
|
},
|
|
745
821
|
},
|
|
746
822
|
{
|
|
747
823
|
name: 'marrow_auto',
|
|
748
|
-
description: '
|
|
749
|
-
'Pass what you are about to do. Optionally pass outcome if already done. ' +
|
|
750
|
-
'Use for ANY action: deploys, file writes, API calls, external sends. ' +
|
|
751
|
-
'If you only have time for one call: pass action + outcome + success together — done in one shot.',
|
|
824
|
+
description: 'Durably capture low-risk activity without blocking. Outcomes remain pending unless success is explicit; risky completion still requires a fresh gate and measured proof.',
|
|
752
825
|
inputSchema: {
|
|
753
826
|
type: 'object',
|
|
754
827
|
properties: {
|
|
755
828
|
action: { type: 'string', description: 'What you are about to do or just did' },
|
|
756
829
|
outcome: { type: 'string', description: 'What happened (if already done). Omit to log intent only.' },
|
|
757
|
-
success: { type: 'boolean', description: '
|
|
830
|
+
success: { type: 'boolean', description: 'Measured result. Omit when the outcome is not yet proven.' },
|
|
758
831
|
type: {
|
|
759
832
|
type: 'string',
|
|
760
833
|
enum: ['implementation', 'security', 'architecture', 'process', 'general'],
|
|
761
834
|
description: 'Type of action (default: general)',
|
|
762
835
|
},
|
|
836
|
+
proof: { type: 'object', description: 'Measured completion evidence for gated work.' },
|
|
837
|
+
gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
|
|
763
838
|
},
|
|
764
839
|
required: ['action'],
|
|
765
840
|
},
|
|
@@ -1022,7 +1097,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1022
1097
|
type: 'object',
|
|
1023
1098
|
properties: {
|
|
1024
1099
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, or 30d' },
|
|
1025
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1100
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1026
1101
|
},
|
|
1027
1102
|
required: [],
|
|
1028
1103
|
},
|
|
@@ -1047,7 +1122,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1047
1122
|
type: 'object',
|
|
1048
1123
|
properties: {
|
|
1049
1124
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, 30d, or a day count up to 90.' },
|
|
1050
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1125
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1051
1126
|
},
|
|
1052
1127
|
required: [],
|
|
1053
1128
|
},
|
|
@@ -1063,7 +1138,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1063
1138
|
action: { type: 'string', description: 'What the agent is about to do.' },
|
|
1064
1139
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1065
1140
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1066
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1141
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1067
1142
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1068
1143
|
surfaces: {
|
|
1069
1144
|
type: 'array',
|
|
@@ -1085,7 +1160,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1085
1160
|
action: { type: 'string', description: 'Optional action to test. Defaults to a production deploy safety prompt.' },
|
|
1086
1161
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1087
1162
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1088
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1163
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1089
1164
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1090
1165
|
surfaces: { type: 'array', items: { type: 'string' }, description: 'Surfaces to test, e.g. production, deploy, github, npm.' },
|
|
1091
1166
|
context: { type: 'object', description: 'Optional non-sensitive metadata.' },
|
|
@@ -1105,7 +1180,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1105
1180
|
action: { type: 'string', description: 'What the agent is about to do.' },
|
|
1106
1181
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1107
1182
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1108
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1183
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1109
1184
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1110
1185
|
surfaces: {
|
|
1111
1186
|
type: 'array',
|
|
@@ -1165,7 +1240,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1165
1240
|
},
|
|
1166
1241
|
action: { type: 'string', description: 'Optional runtime action label.' },
|
|
1167
1242
|
type: { type: 'string', description: 'Optional runtime action type. Defaults to coordination.' },
|
|
1168
|
-
agentId: { type: 'string', description: 'Requesting agent id. Defaults to
|
|
1243
|
+
agentId: { type: 'string', description: 'Requesting agent id. Defaults to the canonical fleet-bound agent identity.' },
|
|
1169
1244
|
sessionId: { type: 'string', description: 'Optional workflow session id.' },
|
|
1170
1245
|
surfaces: { type: 'array', items: { type: 'string' } },
|
|
1171
1246
|
context: { type: 'object', description: 'Optional non-sensitive runtime metadata.' },
|
|
@@ -1174,6 +1249,75 @@ if (process.argv[2] !== 'keys') {
|
|
|
1174
1249
|
required: ['objective', 'proposals'],
|
|
1175
1250
|
},
|
|
1176
1251
|
},
|
|
1252
|
+
{
|
|
1253
|
+
name: 'marrow_coordinate',
|
|
1254
|
+
description: 'Coordinate tenant agents without sharing transcripts. Acquire or release a bounded resource lease, ' +
|
|
1255
|
+
'list current leases, or create/list compact evidence-backed child proof packets for a parent agent.',
|
|
1256
|
+
inputSchema: {
|
|
1257
|
+
type: 'object',
|
|
1258
|
+
properties: {
|
|
1259
|
+
action: {
|
|
1260
|
+
type: 'string',
|
|
1261
|
+
enum: ['list_leases', 'acquire_lease', 'release_lease', 'list_proof_packets', 'create_proof_packet'],
|
|
1262
|
+
},
|
|
1263
|
+
resource_type: { type: 'string', enum: ['file', 'directory', 'service', 'workflow', 'deployment', 'custom'] },
|
|
1264
|
+
resource: { type: 'string', maxLength: 160, description: 'Bounded tenant-visible resource label. Do not send secrets.' },
|
|
1265
|
+
workflow_id: { type: 'string' },
|
|
1266
|
+
ttl_seconds: { type: 'number', minimum: 30, maximum: 3600 },
|
|
1267
|
+
lease_id: { type: 'string' },
|
|
1268
|
+
lease_token: { type: 'string', description: 'One-time lease capability returned by acquire_lease.' },
|
|
1269
|
+
status: { type: 'string', enum: ['active', 'released', 'expired', 'incomplete', 'complete', 'failed'] },
|
|
1270
|
+
limit: { type: 'number', minimum: 1, maximum: 100 },
|
|
1271
|
+
decision_id: { type: 'string' },
|
|
1272
|
+
proof_pack_id: { type: 'string' },
|
|
1273
|
+
summary: { type: 'string', maxLength: 280, description: 'Compact result summary; no raw transcript.' },
|
|
1274
|
+
evidence_refs: {
|
|
1275
|
+
type: 'array', maxItems: 20, items: { type: 'string' },
|
|
1276
|
+
description: 'Opaque durable evidence identifiers only.',
|
|
1277
|
+
},
|
|
1278
|
+
},
|
|
1279
|
+
required: ['action'],
|
|
1280
|
+
},
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
name: 'marrow_replay_compare',
|
|
1284
|
+
description: 'Compare two already-recorded outcomes for the same tenant task using durable proof. ' +
|
|
1285
|
+
'This does not run a model or replay customer content; it returns complete or insufficient_evidence.',
|
|
1286
|
+
inputSchema: {
|
|
1287
|
+
type: 'object',
|
|
1288
|
+
properties: {
|
|
1289
|
+
comparison_id: { type: 'string', description: 'Fetch a prior replay comparison by id.' },
|
|
1290
|
+
source_decision_id: { type: 'string', description: 'Original task decision used to bind the comparison.' },
|
|
1291
|
+
workspace_binding_id: { type: 'string', description: 'Optional privacy-safe workspace binding from runtime.' },
|
|
1292
|
+
constraints: {
|
|
1293
|
+
type: 'object',
|
|
1294
|
+
additionalProperties: false,
|
|
1295
|
+
maxProperties: 7,
|
|
1296
|
+
description: 'Allowlisted comparison labels only; prompts, code, transcripts, credentials, and nested content are rejected.',
|
|
1297
|
+
properties: {
|
|
1298
|
+
environment: { type: 'string', maxLength: 80 },
|
|
1299
|
+
tests: { type: 'string', maxLength: 80 },
|
|
1300
|
+
policy_profile_id: { type: 'string', maxLength: 80 },
|
|
1301
|
+
workflow_type: { type: 'string', maxLength: 80 },
|
|
1302
|
+
task_type: { type: 'string', maxLength: 80 },
|
|
1303
|
+
required_proof: { type: 'boolean' },
|
|
1304
|
+
same_workspace: { type: 'boolean' },
|
|
1305
|
+
},
|
|
1306
|
+
},
|
|
1307
|
+
baseline: {
|
|
1308
|
+
type: 'object',
|
|
1309
|
+
properties: { label: { type: 'string' }, decision_id: { type: 'string' } },
|
|
1310
|
+
required: ['decision_id'],
|
|
1311
|
+
},
|
|
1312
|
+
candidate: {
|
|
1313
|
+
type: 'object',
|
|
1314
|
+
properties: { label: { type: 'string' }, decision_id: { type: 'string' } },
|
|
1315
|
+
required: ['decision_id'],
|
|
1316
|
+
},
|
|
1317
|
+
},
|
|
1318
|
+
required: [],
|
|
1319
|
+
},
|
|
1320
|
+
},
|
|
1177
1321
|
{
|
|
1178
1322
|
name: 'marrow_governance_control_plane',
|
|
1179
1323
|
description: 'Return Marrow control-plane proof: governance, runtime gates, proof packs, fleet intelligence, supported harnesses, and exact next action.',
|
|
@@ -1209,7 +1353,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1209
1353
|
inputSchema: {
|
|
1210
1354
|
type: 'object',
|
|
1211
1355
|
properties: {
|
|
1212
|
-
agentId: { type: 'string', description: 'Optional agent filter. Defaults to
|
|
1356
|
+
agentId: { type: 'string', description: 'Optional agent filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1213
1357
|
limit: { type: 'number', description: 'Max events to return, default 25, max 100.' },
|
|
1214
1358
|
},
|
|
1215
1359
|
required: [],
|
|
@@ -1232,7 +1376,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1232
1376
|
inputSchema: {
|
|
1233
1377
|
type: 'object',
|
|
1234
1378
|
properties: {
|
|
1235
|
-
agentId: { type: 'string', description: 'Optional agent filter. Defaults to
|
|
1379
|
+
agentId: { type: 'string', description: 'Optional agent filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1236
1380
|
periodDays: { type: 'number', description: 'Lookback period in days, default 30, max 90.' },
|
|
1237
1381
|
},
|
|
1238
1382
|
required: [],
|
|
@@ -1321,7 +1465,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1321
1465
|
type: 'object',
|
|
1322
1466
|
properties: {
|
|
1323
1467
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, 30d, or day count up to 90.' },
|
|
1324
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1468
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1325
1469
|
},
|
|
1326
1470
|
required: [],
|
|
1327
1471
|
},
|
|
@@ -1454,6 +1598,24 @@ if (process.argv[2] !== 'keys') {
|
|
|
1454
1598
|
},
|
|
1455
1599
|
},
|
|
1456
1600
|
];
|
|
1601
|
+
const CORE_TOOL_NAMES = new Set([
|
|
1602
|
+
'marrow_agent_runtime',
|
|
1603
|
+
'marrow_commit',
|
|
1604
|
+
'marrow_ask',
|
|
1605
|
+
'marrow_status',
|
|
1606
|
+
'marrow_auto',
|
|
1607
|
+
'marrow_handoff_status',
|
|
1608
|
+
]);
|
|
1609
|
+
function advertisedTools() {
|
|
1610
|
+
return process.env.MARROW_TOOL_PROFILE === 'full'
|
|
1611
|
+
? TOOLS
|
|
1612
|
+
: TOOLS.filter((tool) => CORE_TOOL_NAMES.has(tool.name));
|
|
1613
|
+
}
|
|
1614
|
+
function toolAllowedByActiveProfile(toolName) {
|
|
1615
|
+
return process.env.MARROW_TOOL_PROFILE === 'full'
|
|
1616
|
+
? Boolean(toolName && TOOLS.some((tool) => tool.name === toolName))
|
|
1617
|
+
: Boolean(toolName && CORE_TOOL_NAMES.has(toolName));
|
|
1618
|
+
}
|
|
1457
1619
|
// Request handler
|
|
1458
1620
|
async function handleRequest(req) {
|
|
1459
1621
|
const { id, method, params } = req;
|
|
@@ -1468,7 +1630,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1468
1630
|
success(id, {
|
|
1469
1631
|
protocolVersion: '2024-11-05',
|
|
1470
1632
|
capabilities: { tools: {}, prompts: {} },
|
|
1471
|
-
serverInfo: { name: 'marrow', version:
|
|
1633
|
+
serverInfo: { name: 'marrow', version: hook_contract_1.MCP_ADAPTER_VERSION },
|
|
1472
1634
|
});
|
|
1473
1635
|
// Auto-enroll: emit enrollment notification on connection
|
|
1474
1636
|
if (AUTO_ENROLL) {
|
|
@@ -1481,7 +1643,8 @@ if (process.argv[2] !== 'keys') {
|
|
|
1481
1643
|
data: {
|
|
1482
1644
|
type: 'auto_enroll',
|
|
1483
1645
|
message: 'Marrow auto-enroll active. Call marrow_orient FIRST, then marrow_think before acting, marrow_commit after. Or use marrow_auto / marrow_run for one-call logging.',
|
|
1484
|
-
agentId:
|
|
1646
|
+
agentId: FLEET_AGENT_ID,
|
|
1647
|
+
client_update: (0, request_reliability_1.localClientUpdate)(),
|
|
1485
1648
|
},
|
|
1486
1649
|
},
|
|
1487
1650
|
});
|
|
@@ -1554,29 +1717,21 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1554
1717
|
return;
|
|
1555
1718
|
}
|
|
1556
1719
|
if (method === 'tools/list') {
|
|
1557
|
-
success(id, { tools:
|
|
1720
|
+
success(id, { tools: advertisedTools() });
|
|
1558
1721
|
return;
|
|
1559
1722
|
}
|
|
1560
1723
|
if (method === 'tools/call') {
|
|
1561
1724
|
const toolName = params?.name;
|
|
1562
1725
|
const args = (params?.arguments || {});
|
|
1726
|
+
if (!toolAllowedByActiveProfile(toolName)) {
|
|
1727
|
+
error(id, -32601, 'Tool is not available in the active Marrow tool profile. Set MARROW_TOOL_PROFILE=full and restart MCP for advanced operator tools.');
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1563
1730
|
if (toolName === 'marrow_orient') {
|
|
1564
1731
|
orientCallCount++;
|
|
1565
|
-
let result;
|
|
1566
1732
|
const wantAutoWarn = args.autoWarn ?? true;
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
}
|
|
1570
|
-
catch (e) {
|
|
1571
|
-
// autoWarn endpoint may not be deployed yet — fall back to legacy orient
|
|
1572
|
-
if (wantAutoWarn) {
|
|
1573
|
-
process.stderr.write(`[marrow] autoWarn orient not available, falling back to legacy\n`);
|
|
1574
|
-
result = await (0, index_1.marrowOrient)(API_KEY, BASE_URL, { taskType: args.taskType, autoWarn: false }, SESSION_ID, FLEET_AGENT_ID);
|
|
1575
|
-
}
|
|
1576
|
-
else {
|
|
1577
|
-
throw e;
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1733
|
+
const taskType = args.taskType;
|
|
1734
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowOrient)(API_KEY, BASE_URL, { taskType, autoWarn: wantAutoWarn }, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: isHighRiskAction(`Orient before ${taskType || 'general'} work`, taskType) });
|
|
1580
1735
|
if (AUTO_ENROLL && orientCallCount === 1) {
|
|
1581
1736
|
const enrollmentText = `\n\n**Marrow control and proof active**\n\n` +
|
|
1582
1737
|
`Marrow applies relevant policy and prior lessons before consequential actions, then records evidence and the real outcome afterward.\n\n` +
|
|
@@ -1680,6 +1835,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1680
1835
|
// [FIX #9] Validate required params
|
|
1681
1836
|
const description = requireString(args, 'description');
|
|
1682
1837
|
const outcome = requireString(args, 'outcome');
|
|
1838
|
+
const measuredSuccess = requireBoolean(args, 'success');
|
|
1683
1839
|
// [FIX #16] Handle partial failures — return think result even if commit fails
|
|
1684
1840
|
let thinkResult = null;
|
|
1685
1841
|
try {
|
|
@@ -1697,18 +1853,12 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1697
1853
|
try {
|
|
1698
1854
|
commitResult = await (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
|
|
1699
1855
|
decision_id: thinkResult.decision_id,
|
|
1700
|
-
success:
|
|
1856
|
+
success: measuredSuccess,
|
|
1701
1857
|
outcome,
|
|
1702
|
-
proof:
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
blockers: (args.success ?? true) ? 'none' : 'see outcome',
|
|
1707
|
-
commits_prs_shas: 'not applicable',
|
|
1708
|
-
rollback_target: 'not applicable',
|
|
1709
|
-
handoff_result_file: 'not applicable',
|
|
1710
|
-
deployment_and_smoke: 'not applicable',
|
|
1711
|
-
},
|
|
1858
|
+
proof: args.proof && typeof args.proof === 'object' && !Array.isArray(args.proof)
|
|
1859
|
+
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
1860
|
+
: undefined,
|
|
1861
|
+
gate_receipt_id: typeof args.gate_receipt_id === 'string' ? args.gate_receipt_id : undefined,
|
|
1712
1862
|
action: description,
|
|
1713
1863
|
type: args.type || 'general',
|
|
1714
1864
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
@@ -1738,50 +1888,90 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1738
1888
|
return;
|
|
1739
1889
|
}
|
|
1740
1890
|
if (toolName === 'marrow_auto') {
|
|
1741
|
-
// [FIX #9] Validate required param
|
|
1742
1891
|
const action = requireString(args, 'action');
|
|
1743
1892
|
const outcome = args.outcome;
|
|
1744
|
-
const outcomeSuccess = args.success
|
|
1893
|
+
const outcomeSuccess = typeof args.success === 'boolean' ? args.success : undefined;
|
|
1745
1894
|
const type = args.type || 'general';
|
|
1746
|
-
|
|
1895
|
+
const highRisk = isHighRiskAction(action, type);
|
|
1896
|
+
const suppliedProof = args.proof && typeof args.proof === 'object' && !Array.isArray(args.proof)
|
|
1897
|
+
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
1898
|
+
: undefined;
|
|
1899
|
+
let runtimeGate = null;
|
|
1900
|
+
if (highRisk) {
|
|
1901
|
+
runtimeGate = await withControlDeadline((signal) => (0, index_1.marrowAgentRuntime)(API_KEY, BASE_URL, {
|
|
1902
|
+
action: (0, redact_1.redactSensitiveText)(action),
|
|
1903
|
+
type,
|
|
1904
|
+
agent_id: FLEET_AGENT_ID,
|
|
1905
|
+
session_id: SESSION_ID,
|
|
1906
|
+
proof: suppliedProof,
|
|
1907
|
+
context: { source: 'mcp_auto_risk_upgrade' },
|
|
1908
|
+
}, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: true });
|
|
1909
|
+
storeRuntimeGuidance(runtimeGate);
|
|
1910
|
+
}
|
|
1911
|
+
const proofCanClose = !highRisk || (0, runtime_contract_1.highRiskRuntimeCanClose)(runtimeGate, suppliedProof, args.gate_receipt_id);
|
|
1912
|
+
const acceptedSuccess = proofCanClose ? outcomeSuccess : undefined;
|
|
1913
|
+
const receipt = await (0, lifecycle_spool_1.recordLifecycleEvent)({
|
|
1914
|
+
apiKey: API_KEY,
|
|
1915
|
+
baseUrl: BASE_URL,
|
|
1916
|
+
deferDelivery: true,
|
|
1917
|
+
event: {
|
|
1918
|
+
event_type: !highRisk && acceptedSuccess === false ? 'tool_failed' : !highRisk && acceptedSuccess === true ? 'tool_completed' : 'goal_started',
|
|
1919
|
+
harness: process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || 'mcp',
|
|
1920
|
+
agent_id: FLEET_AGENT_ID,
|
|
1921
|
+
session_id: SESSION_ID,
|
|
1922
|
+
action,
|
|
1923
|
+
outcome_state: 'pending',
|
|
1924
|
+
success: highRisk ? undefined : acceptedSuccess,
|
|
1925
|
+
adapter_version: hook_contract_1.MCP_ADAPTER_VERSION,
|
|
1926
|
+
capability_level: 'mcp',
|
|
1927
|
+
},
|
|
1928
|
+
});
|
|
1747
1929
|
const response = {
|
|
1748
1930
|
action,
|
|
1749
1931
|
outcome: outcome || 'pending',
|
|
1750
1932
|
warnings: cachedOrientWarnings.map(formatWarningActionably),
|
|
1751
|
-
logging: '
|
|
1933
|
+
logging: 'durably_queued',
|
|
1934
|
+
receipt,
|
|
1935
|
+
completion_state: outcomeSuccess === undefined ? 'pending_evidence' : 'delivery_pending',
|
|
1936
|
+
client_update: (0, request_reliability_1.localClientUpdate)(),
|
|
1937
|
+
...(runtimeGate ? {
|
|
1938
|
+
runtime_gate: runtimeGate,
|
|
1939
|
+
completion_state: proofCanClose ? 'governed_delivery_pending' : 'pending_required_proof',
|
|
1940
|
+
} : {}),
|
|
1752
1941
|
};
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
handoff_result_file: 'not applicable',
|
|
1773
|
-
deployment_and_smoke: 'not applicable',
|
|
1774
|
-
},
|
|
1775
|
-
action,
|
|
1776
|
-
type,
|
|
1777
|
-
}, SESSION_ID, FLEET_AGENT_ID);
|
|
1778
|
-
}
|
|
1779
|
-
}
|
|
1780
|
-
catch (err) {
|
|
1781
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1782
|
-
process.stderr.write(`[marrow] marrow_auto background logging failed: ${msg}\n`);
|
|
1942
|
+
const delivery = () => (0, index_1.marrowAuto)(API_KEY, BASE_URL, {
|
|
1943
|
+
action,
|
|
1944
|
+
outcome,
|
|
1945
|
+
success: acceptedSuccess,
|
|
1946
|
+
type,
|
|
1947
|
+
proof: suppliedProof,
|
|
1948
|
+
gate_receipt_id: typeof args.gate_receipt_id === 'string'
|
|
1949
|
+
? args.gate_receipt_id
|
|
1950
|
+
: runtimeGate?.gate_receipt?.id,
|
|
1951
|
+
}, SESSION_ID, FLEET_AGENT_ID, 1_500);
|
|
1952
|
+
if (highRisk && acceptedSuccess !== undefined) {
|
|
1953
|
+
const delivered = await delivery();
|
|
1954
|
+
if (!delivered.committed) {
|
|
1955
|
+
throw new request_reliability_1.MarrowRequestError({
|
|
1956
|
+
code: 'invalid_response',
|
|
1957
|
+
message: 'Marrow did not confirm the governed outcome commit',
|
|
1958
|
+
retryable: true,
|
|
1959
|
+
exactFix: 'Keep the outcome pending and retry marrow_commit with the fresh gate receipt and required proof.',
|
|
1960
|
+
});
|
|
1783
1961
|
}
|
|
1784
|
-
|
|
1962
|
+
response.logging = 'governed_commit_confirmed';
|
|
1963
|
+
response.completion_state = 'closed_with_proof';
|
|
1964
|
+
response.decision_id = delivered.decision_id;
|
|
1965
|
+
}
|
|
1966
|
+
else if (!highRisk) {
|
|
1967
|
+
void delivery().catch((err) => {
|
|
1968
|
+
const failure = (0, request_reliability_1.structuredRequestFailure)(err);
|
|
1969
|
+
const errorCode = failure.error && typeof failure.error === 'object'
|
|
1970
|
+
? String(failure.error.code || 'request_failed')
|
|
1971
|
+
: 'request_failed';
|
|
1972
|
+
process.stderr.write(`[marrow] marrow_auto queued; live delivery unavailable (${errorCode})\n`);
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1785
1975
|
success(id, {
|
|
1786
1976
|
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
1787
1977
|
});
|
|
@@ -1789,17 +1979,25 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1789
1979
|
}
|
|
1790
1980
|
if (toolName === 'marrow_ask') {
|
|
1791
1981
|
const query = requireString(args, 'query');
|
|
1792
|
-
const result = await (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query }, SESSION_ID, FLEET_AGENT_ID);
|
|
1982
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query }, SESSION_ID, FLEET_AGENT_ID, signal));
|
|
1983
|
+
try {
|
|
1984
|
+
(0, guidance_cache_1.writeGuidanceCache)({
|
|
1985
|
+
apiKey: API_KEY,
|
|
1986
|
+
baseUrl: BASE_URL,
|
|
1987
|
+
agentId: FLEET_AGENT_ID,
|
|
1988
|
+
context: `## Marrow answer\n- ${String(result.answer || 'No relevant lesson found.').slice(0, 1200)}`,
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
catch { /* owner-only cache is best effort */ }
|
|
1793
1992
|
success(id, {
|
|
1794
1993
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
1795
1994
|
});
|
|
1796
1995
|
return;
|
|
1797
1996
|
}
|
|
1798
1997
|
if (toolName === 'marrow_status') {
|
|
1799
|
-
const result = await (0, index_1.marrowStatus)(API_KEY, BASE_URL, SESSION_ID, FLEET_AGENT_ID);
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
});
|
|
1998
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowStatus)(API_KEY, BASE_URL, SESSION_ID, FLEET_AGENT_ID, signal), { cacheAware: false });
|
|
1999
|
+
const statusRecord = result;
|
|
2000
|
+
toolSuccess(id, { ...statusRecord, client_update: statusRecord.client_update || (0, request_reliability_1.localClientUpdate)() });
|
|
1803
2001
|
return;
|
|
1804
2002
|
}
|
|
1805
2003
|
if (toolName === 'marrow_create_key') {
|
|
@@ -1932,17 +2130,17 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1932
2130
|
return;
|
|
1933
2131
|
}
|
|
1934
2132
|
if (toolName === 'marrow_agent_status') {
|
|
1935
|
-
const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2133
|
+
const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
1936
2134
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
1937
2135
|
return;
|
|
1938
2136
|
}
|
|
1939
2137
|
if (toolName === 'marrow_runtime_status') {
|
|
1940
|
-
const result = await (0, index_1.marrowRuntimeStatus)(API_KEY, BASE_URL, args.fast !== false, SESSION_ID, FLEET_AGENT_ID);
|
|
2138
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowRuntimeStatus)(API_KEY, BASE_URL, args.fast !== false, SESSION_ID, FLEET_AGENT_ID, signal), { cacheAware: false });
|
|
1941
2139
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
1942
2140
|
return;
|
|
1943
2141
|
}
|
|
1944
2142
|
if (toolName === 'marrow_value_report') {
|
|
1945
|
-
const result = await (0, index_1.marrowValueReport)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2143
|
+
const result = await (0, index_1.marrowValueReport)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
1946
2144
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
1947
2145
|
return;
|
|
1948
2146
|
}
|
|
@@ -1951,7 +2149,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1951
2149
|
action: args.action,
|
|
1952
2150
|
type: args.type,
|
|
1953
2151
|
role: args.role,
|
|
1954
|
-
agent_id: args.agentId ||
|
|
2152
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
1955
2153
|
session_id: args.sessionId || SESSION_ID,
|
|
1956
2154
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
1957
2155
|
period: args.period,
|
|
@@ -1964,7 +2162,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1964
2162
|
action: args.action ? (0, redact_1.redactSensitiveText)(args.action) : undefined,
|
|
1965
2163
|
type: args.type,
|
|
1966
2164
|
role: args.role,
|
|
1967
|
-
agent_id: args.agentId ||
|
|
2165
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
1968
2166
|
session_id: args.sessionId || SESSION_ID,
|
|
1969
2167
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
1970
2168
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -1978,11 +2176,11 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1978
2176
|
return;
|
|
1979
2177
|
}
|
|
1980
2178
|
if (toolName === 'marrow_agent_runtime') {
|
|
1981
|
-
const
|
|
2179
|
+
const runtimeInput = {
|
|
1982
2180
|
action: (0, redact_1.redactSensitiveText)(args.action),
|
|
1983
2181
|
type: args.type,
|
|
1984
2182
|
role: args.role,
|
|
1985
|
-
agent_id: args.agentId ||
|
|
2183
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
1986
2184
|
session_id: args.sessionId || SESSION_ID,
|
|
1987
2185
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
1988
2186
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -1992,7 +2190,9 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1992
2190
|
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
1993
2191
|
: undefined,
|
|
1994
2192
|
period: args.period,
|
|
1995
|
-
}
|
|
2193
|
+
};
|
|
2194
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowAgentRuntime)(API_KEY, BASE_URL, runtimeInput, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: isHighRiskAction(runtimeInput.action, runtimeInput.type) });
|
|
2195
|
+
storeRuntimeGuidance(result);
|
|
1996
2196
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
1997
2197
|
return;
|
|
1998
2198
|
}
|
|
@@ -2006,7 +2206,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2006
2206
|
: [],
|
|
2007
2207
|
action: typeof args.action === 'string' ? (0, redact_1.redactSensitiveText)(args.action) : undefined,
|
|
2008
2208
|
type: args.type,
|
|
2009
|
-
agent_id: args.agentId ||
|
|
2209
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
2010
2210
|
session_id: args.sessionId || SESSION_ID,
|
|
2011
2211
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
2012
2212
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -2019,6 +2219,19 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2019
2219
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2020
2220
|
return;
|
|
2021
2221
|
}
|
|
2222
|
+
if (toolName === 'marrow_coordinate') {
|
|
2223
|
+
const coordinationArgs = { ...args };
|
|
2224
|
+
delete coordinationArgs.agent_id;
|
|
2225
|
+
delete coordinationArgs.source_agent_id;
|
|
2226
|
+
const result = await (0, index_1.marrowCoordinate)(API_KEY, BASE_URL, coordinationArgs, SESSION_ID, FLEET_AGENT_ID);
|
|
2227
|
+
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
if (toolName === 'marrow_replay_compare') {
|
|
2231
|
+
const result = await (0, index_1.marrowReplayCompare)(API_KEY, BASE_URL, args, SESSION_ID, FLEET_AGENT_ID);
|
|
2232
|
+
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2022
2235
|
if (toolName === 'marrow_governance_control_plane') {
|
|
2023
2236
|
const result = await (0, index_1.marrowGovernanceControlPlane)(API_KEY, BASE_URL, SESSION_ID, FLEET_AGENT_ID);
|
|
2024
2237
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2049,7 +2262,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2049
2262
|
}
|
|
2050
2263
|
if (toolName === 'marrow_governance_timeline') {
|
|
2051
2264
|
const result = await (0, index_1.marrowGovernanceTimeline)(API_KEY, BASE_URL, {
|
|
2052
|
-
agentId: args.agentId ||
|
|
2265
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2053
2266
|
limit: args.limit,
|
|
2054
2267
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2055
2268
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2067,7 +2280,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2067
2280
|
}
|
|
2068
2281
|
if (toolName === 'marrow_buyer_proof') {
|
|
2069
2282
|
const result = await (0, index_1.marrowBuyerProof)(API_KEY, BASE_URL, {
|
|
2070
|
-
agentId: args.agentId ||
|
|
2283
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2071
2284
|
periodDays: args.periodDays,
|
|
2072
2285
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2073
2286
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2083,7 +2296,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2083
2296
|
: undefined,
|
|
2084
2297
|
agent: args.agent && typeof args.agent === 'object' && !Array.isArray(args.agent)
|
|
2085
2298
|
? (0, redact_1.redactSensitiveValue)(args.agent)
|
|
2086
|
-
: { id: FLEET_AGENT_ID
|
|
2299
|
+
: { id: FLEET_AGENT_ID },
|
|
2087
2300
|
selected_mode: args.selected_mode,
|
|
2088
2301
|
selection_source: args.selection_source,
|
|
2089
2302
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
@@ -2124,7 +2337,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2124
2337
|
: undefined,
|
|
2125
2338
|
agent: args.agent && typeof args.agent === 'object' && !Array.isArray(args.agent)
|
|
2126
2339
|
? (0, redact_1.redactSensitiveValue)(args.agent)
|
|
2127
|
-
: { id: FLEET_AGENT_ID
|
|
2340
|
+
: { id: FLEET_AGENT_ID },
|
|
2128
2341
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2129
2342
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2130
2343
|
return;
|
|
@@ -2143,7 +2356,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2143
2356
|
return;
|
|
2144
2357
|
}
|
|
2145
2358
|
if (toolName === 'marrow_agent_performance') {
|
|
2146
|
-
const result = await (0, index_1.marrowAgentPerformance)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2359
|
+
const result = await (0, index_1.marrowAgentPerformance)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
2147
2360
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2148
2361
|
return;
|
|
2149
2362
|
}
|
|
@@ -2151,7 +2364,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2151
2364
|
const result = await (0, index_1.marrowFleetLessons)(API_KEY, BASE_URL, {
|
|
2152
2365
|
query: args.query,
|
|
2153
2366
|
type: args.type,
|
|
2154
|
-
agentId: args.agentId ||
|
|
2367
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2155
2368
|
limit: args.limit,
|
|
2156
2369
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2157
2370
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2180,7 +2393,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2180
2393
|
if (toolName === 'marrow_handoff_status') {
|
|
2181
2394
|
const result = await (0, index_1.marrowHandoffStatus)(API_KEY, BASE_URL, {
|
|
2182
2395
|
status: args.status,
|
|
2183
|
-
agentId: args.agentId ||
|
|
2396
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2184
2397
|
limit: args.limit,
|
|
2185
2398
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2186
2399
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2226,8 +2439,12 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2226
2439
|
error(id, -32601, `Method not found: ${method}`);
|
|
2227
2440
|
}
|
|
2228
2441
|
catch (err) {
|
|
2442
|
+
if (err instanceof request_reliability_1.MarrowRequestError && method === 'tools/call') {
|
|
2443
|
+
toolSuccess(id, toolFailure(params?.name, err), true);
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2229
2446
|
const message = err instanceof Error ? err.message : String(err);
|
|
2230
|
-
error(id, -
|
|
2447
|
+
error(id, -32602, (0, redact_1.redactSensitiveText)(message).slice(0, 240));
|
|
2231
2448
|
}
|
|
2232
2449
|
}
|
|
2233
2450
|
// MCP stdio loop — raw stdin, no readline (readline writes prompts to stdout which breaks MCP)
|