@reproapp/mcp 0.0.7 → 0.0.8
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/package.json +1 -1
- package/src/index.js +184 -40
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -16,7 +16,6 @@ const SERVER_INSTRUCTIONS = [
|
|
|
16
16
|
'For Repro-scoped questions about sessions, requests, traces, privacy policies, apps, or configuration, use the Repro MCP tools only.',
|
|
17
17
|
'Do not create local scripts, read cached Repro auth files, or call Repro HTTP APIs directly for Repro data or policy workflows.',
|
|
18
18
|
'For privacy policy writes, inspect first and then use exact statementSid(s) or blockerSetId. Broad natural-language policy update queries are read-only.',
|
|
19
|
-
'When a Repro tool returns valuePreview/valueLink for a large payload, return that preview and link to the user and stop there. Do not automatically follow the link or re-query for the full value unless the user explicitly asks for the full payload or raw value. Exact large-value expansion requires expandLargeValue=true and explicit user intent.',
|
|
20
19
|
].join(' ');
|
|
21
20
|
const DEFAULT_REPRO_AI_BASE_URL = 'https://repro-ai-u8lhw.ondigitalocean.app';
|
|
22
21
|
const DEFAULT_REPRO_API_BASE_URL = 'https://repro-api-d7288.ondigitalocean.app/api';
|
|
@@ -1193,9 +1192,10 @@ async function executeTool(params, config, client, getTools) {
|
|
|
1193
1192
|
throw rpcError(-32602, `Unknown tool: ${name}`);
|
|
1194
1193
|
}
|
|
1195
1194
|
|
|
1196
|
-
const response = await client.executeTool(name, input);
|
|
1195
|
+
const response = await client.executeTool(name, inputWithExactCapturedPayloads(name, input));
|
|
1196
|
+
const expandedResponse = await expandLinkedCapturedPayloads(name, response, client, input);
|
|
1197
1197
|
|
|
1198
|
-
const augmented = augmentPaths(
|
|
1198
|
+
const augmented = augmentPaths(expandedResponse, config.pathMappings);
|
|
1199
1199
|
const isError =
|
|
1200
1200
|
augmented &&
|
|
1201
1201
|
typeof augmented === 'object' &&
|
|
@@ -1214,58 +1214,202 @@ async function executeTool(params, config, client, getTools) {
|
|
|
1214
1214
|
};
|
|
1215
1215
|
}
|
|
1216
1216
|
|
|
1217
|
-
function
|
|
1218
|
-
if (name
|
|
1219
|
-
|
|
1220
|
-
if (text) return text;
|
|
1217
|
+
function inputWithExactCapturedPayloads(name, input) {
|
|
1218
|
+
if (name !== 'get_kafka_messages') {
|
|
1219
|
+
return input;
|
|
1221
1220
|
}
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1221
|
+
return {
|
|
1222
|
+
...input,
|
|
1223
|
+
includeLargeValues: true,
|
|
1224
|
+
expandLargeValue: true,
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
async function expandLinkedCapturedPayloads(name, response, client, originalInput = {}) {
|
|
1229
|
+
if (name !== 'get_kafka_messages') {
|
|
1230
|
+
return response;
|
|
1225
1231
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1232
|
+
|
|
1233
|
+
const root = cloneJson(response) ?? response;
|
|
1234
|
+
const visited = new Set();
|
|
1235
|
+
|
|
1236
|
+
while (true) {
|
|
1237
|
+
const links = collectCapturedPayloadLinks(root)
|
|
1238
|
+
.filter((entry) => !visited.has(capturedPayloadLinkKey(entry.link)));
|
|
1239
|
+
if (!links.length) {
|
|
1240
|
+
return root;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
for (const { link } of links) {
|
|
1244
|
+
const key = capturedPayloadLinkKey(link);
|
|
1245
|
+
visited.add(key);
|
|
1246
|
+
|
|
1247
|
+
const toolName = typeof link.tool === 'string' ? link.tool : '';
|
|
1248
|
+
if (toolName !== 'get_kafka_messages') {
|
|
1249
|
+
throw new Error(`Cannot expand captured payload through unsupported MCP tool: ${toolName || 'unknown'}`);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
const linkArgs = link.arguments && typeof link.arguments === 'object' && !Array.isArray(link.arguments)
|
|
1253
|
+
? link.arguments
|
|
1254
|
+
: {};
|
|
1255
|
+
const scopedLinkArgs = {
|
|
1256
|
+
...originalInput,
|
|
1257
|
+
...linkArgs,
|
|
1258
|
+
};
|
|
1259
|
+
const expanded = await client.executeTool(toolName, inputWithExactCapturedPayloads(toolName, scopedLinkArgs));
|
|
1260
|
+
const expandedLookup = lookupLinkedPayloadValue(expanded, link.path);
|
|
1261
|
+
if (!expandedLookup.found) {
|
|
1262
|
+
throw new Error(`Repro MCP could not expand captured payload at ${link.path || 'unknown path'}`);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
const applied = replaceLinkedPayloadValue(root, link.path, expandedLookup.value);
|
|
1266
|
+
if (!applied) {
|
|
1267
|
+
throw new Error(`Repro MCP could not replace captured payload at ${link.path || 'unknown path'}`);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1229
1270
|
}
|
|
1230
|
-
return JSON.stringify(value, null, 2);
|
|
1231
1271
|
}
|
|
1232
1272
|
|
|
1233
|
-
function
|
|
1273
|
+
function collectCapturedPayloadLinks(value, out = []) {
|
|
1234
1274
|
if (!value || typeof value !== 'object') {
|
|
1235
|
-
return
|
|
1275
|
+
return out;
|
|
1236
1276
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1277
|
+
if (Array.isArray(value)) {
|
|
1278
|
+
for (const item of value) {
|
|
1279
|
+
collectCapturedPayloadLinks(item, out);
|
|
1280
|
+
}
|
|
1281
|
+
return out;
|
|
1241
1282
|
}
|
|
1242
1283
|
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1284
|
+
const link = value.valueOmitted === true ? value.valueLink : value.rawValueLink;
|
|
1285
|
+
if (
|
|
1286
|
+
(value.valueOmitted === true || value.rawValueOmitted === true) &&
|
|
1287
|
+
link &&
|
|
1288
|
+
typeof link === 'object' &&
|
|
1289
|
+
link.kind === 'mcp-tool-call' &&
|
|
1290
|
+
typeof link.tool === 'string' &&
|
|
1291
|
+
typeof link.path === 'string'
|
|
1292
|
+
) {
|
|
1293
|
+
out.push({ holder: value, link });
|
|
1294
|
+
}
|
|
1245
1295
|
|
|
1246
|
-
for (const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1296
|
+
for (const nested of Object.values(value)) {
|
|
1297
|
+
collectCapturedPayloadLinks(nested, out);
|
|
1298
|
+
}
|
|
1299
|
+
return out;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
function capturedPayloadLinkKey(link) {
|
|
1303
|
+
return JSON.stringify({
|
|
1304
|
+
tool: link?.tool ?? null,
|
|
1305
|
+
path: link?.path ?? null,
|
|
1306
|
+
arguments: link?.arguments ?? null,
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
function lookupLinkedPayloadValue(root, pathExpression) {
|
|
1311
|
+
const segments = parseLinkedPayloadPath(pathExpression);
|
|
1312
|
+
if (!segments.length) {
|
|
1313
|
+
return { found: false };
|
|
1314
|
+
}
|
|
1315
|
+
return lookupPathCandidates(root, segments);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
function replaceLinkedPayloadValue(root, pathExpression, value) {
|
|
1319
|
+
const segments = parseLinkedPayloadPath(pathExpression);
|
|
1320
|
+
if (!segments.length) {
|
|
1321
|
+
return false;
|
|
1322
|
+
}
|
|
1323
|
+
const candidates = pathCandidateSegments(segments);
|
|
1324
|
+
for (const candidate of candidates) {
|
|
1325
|
+
const parentLookup = getAtPath(root, candidate.slice(0, -1));
|
|
1326
|
+
if (!parentLookup.found || !parentLookup.value || typeof parentLookup.value !== 'object') {
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
const leaf = candidate[candidate.length - 1];
|
|
1330
|
+
parentLookup.value[leaf] = value;
|
|
1331
|
+
if (leaf === 'value') {
|
|
1332
|
+
delete parentLookup.value.valueOmitted;
|
|
1333
|
+
delete parentLookup.value.valuePreview;
|
|
1334
|
+
delete parentLookup.value.valueLink;
|
|
1335
|
+
} else if (leaf === 'rawValue') {
|
|
1336
|
+
delete parentLookup.value.rawValueOmitted;
|
|
1337
|
+
delete parentLookup.value.rawValuePreview;
|
|
1338
|
+
delete parentLookup.value.rawValueLink;
|
|
1259
1339
|
}
|
|
1340
|
+
return true;
|
|
1260
1341
|
}
|
|
1342
|
+
return false;
|
|
1343
|
+
}
|
|
1261
1344
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
)
|
|
1345
|
+
function lookupPathCandidates(root, segments) {
|
|
1346
|
+
for (const candidate of pathCandidateSegments(segments)) {
|
|
1347
|
+
const lookup = getAtPath(root, candidate);
|
|
1348
|
+
if (lookup.found) {
|
|
1349
|
+
return lookup;
|
|
1350
|
+
}
|
|
1266
1351
|
}
|
|
1352
|
+
return { found: false };
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function pathCandidateSegments(segments) {
|
|
1356
|
+
return [
|
|
1357
|
+
['data', ...segments],
|
|
1358
|
+
segments,
|
|
1359
|
+
];
|
|
1360
|
+
}
|
|
1267
1361
|
|
|
1268
|
-
|
|
1362
|
+
function parseLinkedPayloadPath(pathExpression) {
|
|
1363
|
+
if (typeof pathExpression !== 'string' || !pathExpression.trim()) {
|
|
1364
|
+
return [];
|
|
1365
|
+
}
|
|
1366
|
+
const segments = [];
|
|
1367
|
+
const pattern = /([A-Za-z_$][\w$-]*)|\[(\d+)\]/g;
|
|
1368
|
+
let match;
|
|
1369
|
+
while ((match = pattern.exec(pathExpression)) !== null) {
|
|
1370
|
+
if (typeof match[1] === 'string') {
|
|
1371
|
+
segments.push(match[1]);
|
|
1372
|
+
} else if (typeof match[2] === 'string') {
|
|
1373
|
+
segments.push(Number.parseInt(match[2], 10));
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
return segments;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
function getAtPath(root, segments) {
|
|
1380
|
+
let current = root;
|
|
1381
|
+
for (const segment of segments) {
|
|
1382
|
+
if (current == null) {
|
|
1383
|
+
return { found: false };
|
|
1384
|
+
}
|
|
1385
|
+
if (typeof segment === 'number') {
|
|
1386
|
+
if (!Array.isArray(current) || segment < 0 || segment >= current.length) {
|
|
1387
|
+
return { found: false };
|
|
1388
|
+
}
|
|
1389
|
+
current = current[segment];
|
|
1390
|
+
continue;
|
|
1391
|
+
}
|
|
1392
|
+
if (typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
1393
|
+
return { found: false };
|
|
1394
|
+
}
|
|
1395
|
+
current = current[segment];
|
|
1396
|
+
}
|
|
1397
|
+
return { found: true, value: current };
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
function formatLocalToolContentText(name, value) {
|
|
1401
|
+
if (name === 'inspect_privacy_policy' || name === 'list_privacy_policy_blockers') {
|
|
1402
|
+
const text = renderPolicyInspectionText(value);
|
|
1403
|
+
if (text) return text;
|
|
1404
|
+
}
|
|
1405
|
+
if (name === 'check_privacy_coverage') {
|
|
1406
|
+
const text = renderPrivacyCoverageText(value);
|
|
1407
|
+
if (text) return text;
|
|
1408
|
+
}
|
|
1409
|
+
if (name === 'get_kafka_messages') {
|
|
1410
|
+
return JSON.stringify(value, null, 2);
|
|
1411
|
+
}
|
|
1412
|
+
return JSON.stringify(value, null, 2);
|
|
1269
1413
|
}
|
|
1270
1414
|
|
|
1271
1415
|
function mergeLocalTools(remoteTools) {
|