mcp-perforce-server 3.0.0 → 3.2.0
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 +109 -121
- package/dist/p4/parse.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +638 -53
- package/dist/server.js.map +1 -1
- package/dist/tools/advanced.d.ts +28 -0
- package/dist/tools/advanced.d.ts.map +1 -1
- package/dist/tools/advanced.js +223 -6
- package/dist/tools/advanced.js.map +1 -1
- package/dist/tools/arg-utils.d.ts +13 -0
- package/dist/tools/arg-utils.d.ts.map +1 -0
- package/dist/tools/arg-utils.js +57 -0
- package/dist/tools/arg-utils.js.map +1 -0
- package/dist/tools/basic.d.ts +58 -7
- package/dist/tools/basic.d.ts.map +1 -1
- package/dist/tools/basic.js +460 -70
- package/dist/tools/basic.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/utils.d.ts +2 -1
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +19 -3
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/workflows.d.ts +58 -0
- package/dist/tools/workflows.d.ts.map +1 -1
- package/dist/tools/workflows.js +547 -0
- package/dist/tools/workflows.js.map +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -84,6 +84,10 @@ const TOOL_HANDLERS = {
|
|
|
84
84
|
'p4.review.bundle': tools.p4ReviewBundle,
|
|
85
85
|
'p4.change.inspect': tools.p4ChangeInspect,
|
|
86
86
|
'p4.path.synccheck': tools.p4PathSyncCheck,
|
|
87
|
+
'p4.file.inspect': tools.p4FileInspect,
|
|
88
|
+
'p4.workspace.snapshot': tools.p4WorkspaceSnapshot,
|
|
89
|
+
'p4.search.inspect': tools.p4SearchInspect,
|
|
90
|
+
'p4.review.prepare': tools.p4ReviewPrepare,
|
|
87
91
|
'p4.blame': tools.p4Blame,
|
|
88
92
|
'p4.annotate': tools.p4Annotate,
|
|
89
93
|
'p4.copy': tools.p4Copy,
|
|
@@ -141,6 +145,10 @@ const LOW_LATENCY_CACHE_TTL_TOOLS = new Set([
|
|
|
141
145
|
'p4.review.bundle',
|
|
142
146
|
'p4.change.inspect',
|
|
143
147
|
'p4.path.synccheck',
|
|
148
|
+
'p4.file.inspect',
|
|
149
|
+
'p4.workspace.snapshot',
|
|
150
|
+
'p4.search.inspect',
|
|
151
|
+
'p4.review.prepare',
|
|
144
152
|
]);
|
|
145
153
|
const STABLE_CACHE_TTL_TOOLS = new Set([
|
|
146
154
|
'p4.info',
|
|
@@ -471,17 +479,21 @@ class MCPPerforceServer {
|
|
|
471
479
|
log.info('Performance snapshot:', topEntries);
|
|
472
480
|
}
|
|
473
481
|
async executeTool(name, args) {
|
|
474
|
-
|
|
482
|
+
// Normalize tool name: support both dot notation (p4.changes) and underscore (p4_changes)
|
|
483
|
+
const normalizedName = name.replace(/_/g, '.');
|
|
484
|
+
const handler = TOOL_HANDLERS[normalizedName];
|
|
475
485
|
if (!handler) {
|
|
476
486
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
477
487
|
}
|
|
478
488
|
return handler(this.context, args);
|
|
479
489
|
}
|
|
480
490
|
async executeToolWithCaching(name, args) {
|
|
481
|
-
|
|
491
|
+
// Normalize tool name for consistency in caching
|
|
492
|
+
const normalizedName = name.replace(/_/g, '.');
|
|
493
|
+
if (!this.responseCacheEnabled || !CACHEABLE_TOOLS.has(normalizedName)) {
|
|
482
494
|
return { result: await this.executeTool(name, args), cacheStatus: 'uncacheable' };
|
|
483
495
|
}
|
|
484
|
-
const cacheKey = this.buildCacheKey(
|
|
496
|
+
const cacheKey = this.buildCacheKey(normalizedName, args);
|
|
485
497
|
const cachedResult = this.getCachedResult(cacheKey);
|
|
486
498
|
if (cachedResult) {
|
|
487
499
|
return cachedResult;
|
|
@@ -496,7 +508,7 @@ class MCPPerforceServer {
|
|
|
496
508
|
try {
|
|
497
509
|
const result = await pending;
|
|
498
510
|
if (startedEpoch === this.cacheEpoch) {
|
|
499
|
-
const toolTtlMs = this.getToolCacheTtlMs(
|
|
511
|
+
const toolTtlMs = this.getToolCacheTtlMs(normalizedName);
|
|
500
512
|
if (result && typeof result === 'object' && result.ok === true) {
|
|
501
513
|
this.setCachedResult(cacheKey, result, toolTtlMs, false);
|
|
502
514
|
}
|
|
@@ -652,6 +664,11 @@ class MCPPerforceServer {
|
|
|
652
664
|
type: 'string',
|
|
653
665
|
description: 'Filespec to sync (optional, defaults to current directory)',
|
|
654
666
|
},
|
|
667
|
+
filespecs: {
|
|
668
|
+
type: 'array',
|
|
669
|
+
items: { type: 'string' },
|
|
670
|
+
description: 'Filespecs to sync in one command (optional)',
|
|
671
|
+
},
|
|
655
672
|
force: {
|
|
656
673
|
type: 'boolean',
|
|
657
674
|
description: 'Force sync (optional, defaults to false)',
|
|
@@ -660,6 +677,42 @@ class MCPPerforceServer {
|
|
|
660
677
|
type: 'boolean',
|
|
661
678
|
description: 'Preview sync without executing (optional, defaults to false)',
|
|
662
679
|
},
|
|
680
|
+
summaryPreview: {
|
|
681
|
+
type: 'boolean',
|
|
682
|
+
description: 'Preview only the sync summary using p4 sync -N (optional)',
|
|
683
|
+
},
|
|
684
|
+
quiet: {
|
|
685
|
+
type: 'boolean',
|
|
686
|
+
description: 'Suppress normal sync messages using -q (optional)',
|
|
687
|
+
},
|
|
688
|
+
metadataOnly: {
|
|
689
|
+
type: 'boolean',
|
|
690
|
+
description: 'Update have-list metadata only using -k (optional)',
|
|
691
|
+
},
|
|
692
|
+
safeSync: {
|
|
693
|
+
type: 'boolean',
|
|
694
|
+
description: 'Enable digest safety checks using -s (optional)',
|
|
695
|
+
},
|
|
696
|
+
populateOnly: {
|
|
697
|
+
type: 'boolean',
|
|
698
|
+
description: 'Populate without updating server state using -p (optional)',
|
|
699
|
+
},
|
|
700
|
+
reopenMoved: {
|
|
701
|
+
type: 'boolean',
|
|
702
|
+
description: 'Reopen moved files in new depot locations using -r (optional)',
|
|
703
|
+
},
|
|
704
|
+
useListOptimization: {
|
|
705
|
+
type: 'boolean',
|
|
706
|
+
description: 'Use the -L file list optimization for exact depot revisions (optional)',
|
|
707
|
+
},
|
|
708
|
+
max: {
|
|
709
|
+
type: 'number',
|
|
710
|
+
description: 'Limit sync to the first max files (optional)',
|
|
711
|
+
},
|
|
712
|
+
parallel: {
|
|
713
|
+
type: 'string',
|
|
714
|
+
description: 'Parallel sync specification, for example threads=4,batch=8 (optional)',
|
|
715
|
+
},
|
|
663
716
|
workspacePath: {
|
|
664
717
|
type: 'string',
|
|
665
718
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -678,6 +731,11 @@ class MCPPerforceServer {
|
|
|
678
731
|
type: 'string',
|
|
679
732
|
description: 'Changelist number (optional, shows all opened files if not specified)',
|
|
680
733
|
},
|
|
734
|
+
files: {
|
|
735
|
+
type: 'array',
|
|
736
|
+
items: { type: 'string' },
|
|
737
|
+
description: 'Optional files/filespecs to check for opened state',
|
|
738
|
+
},
|
|
681
739
|
workspacePath: {
|
|
682
740
|
type: 'string',
|
|
683
741
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -872,6 +930,11 @@ class MCPPerforceServer {
|
|
|
872
930
|
type: 'string',
|
|
873
931
|
description: 'Filespec to show history for (required)',
|
|
874
932
|
},
|
|
933
|
+
filespecs: {
|
|
934
|
+
type: 'array',
|
|
935
|
+
items: { type: 'string' },
|
|
936
|
+
description: 'Filespecs to show history for in one command (required if filespec is omitted)',
|
|
937
|
+
},
|
|
875
938
|
maxRevisions: {
|
|
876
939
|
type: 'number',
|
|
877
940
|
description: 'Maximum number of revisions to show (optional)',
|
|
@@ -881,7 +944,10 @@ class MCPPerforceServer {
|
|
|
881
944
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
882
945
|
},
|
|
883
946
|
},
|
|
884
|
-
|
|
947
|
+
anyOf: [
|
|
948
|
+
{ required: ['filespec'] },
|
|
949
|
+
{ required: ['filespecs'] },
|
|
950
|
+
],
|
|
885
951
|
additionalProperties: false,
|
|
886
952
|
},
|
|
887
953
|
},
|
|
@@ -895,6 +961,30 @@ class MCPPerforceServer {
|
|
|
895
961
|
type: 'string',
|
|
896
962
|
description: 'Filter by user (optional)',
|
|
897
963
|
},
|
|
964
|
+
stream: {
|
|
965
|
+
type: 'string',
|
|
966
|
+
description: 'Limit workspaces to a dedicated stream using -S (optional)',
|
|
967
|
+
},
|
|
968
|
+
nameFilter: {
|
|
969
|
+
type: 'string',
|
|
970
|
+
description: 'Workspace name filter using -e (optional)',
|
|
971
|
+
},
|
|
972
|
+
caseInsensitiveNameFilter: {
|
|
973
|
+
type: 'string',
|
|
974
|
+
description: 'Case-insensitive workspace name filter using -E (optional)',
|
|
975
|
+
},
|
|
976
|
+
unloaded: {
|
|
977
|
+
type: 'boolean',
|
|
978
|
+
description: 'List unloaded clients using -U (optional)',
|
|
979
|
+
},
|
|
980
|
+
allServers: {
|
|
981
|
+
type: 'boolean',
|
|
982
|
+
description: 'List clients across all servers using -a (optional)',
|
|
983
|
+
},
|
|
984
|
+
serverId: {
|
|
985
|
+
type: 'string',
|
|
986
|
+
description: 'Limit clients to a specific server using -s (optional)',
|
|
987
|
+
},
|
|
898
988
|
max: {
|
|
899
989
|
type: 'number',
|
|
900
990
|
description: 'Maximum number of results (optional)',
|
|
@@ -1033,6 +1123,11 @@ class MCPPerforceServer {
|
|
|
1033
1123
|
type: 'string',
|
|
1034
1124
|
description: 'Filter by filespec (optional)',
|
|
1035
1125
|
},
|
|
1126
|
+
filespecs: {
|
|
1127
|
+
type: 'array',
|
|
1128
|
+
items: { type: 'string' },
|
|
1129
|
+
description: 'Filter by multiple filespecs (optional)',
|
|
1130
|
+
},
|
|
1036
1131
|
workspacePath: {
|
|
1037
1132
|
type: 'string',
|
|
1038
1133
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1100,6 +1195,27 @@ class MCPPerforceServer {
|
|
|
1100
1195
|
type: 'string',
|
|
1101
1196
|
description: 'Target depot filespec/path (required)',
|
|
1102
1197
|
},
|
|
1198
|
+
targetPaths: {
|
|
1199
|
+
type: 'array',
|
|
1200
|
+
items: { type: 'string' },
|
|
1201
|
+
description: 'Additional target depot filespecs for branch or path modes (optional)',
|
|
1202
|
+
},
|
|
1203
|
+
branch: {
|
|
1204
|
+
type: 'string',
|
|
1205
|
+
description: 'Branch spec name for p4 interchanges -b mode (optional)',
|
|
1206
|
+
},
|
|
1207
|
+
stream: {
|
|
1208
|
+
type: 'string',
|
|
1209
|
+
description: 'Stream path for p4 interchanges -S mode (optional)',
|
|
1210
|
+
},
|
|
1211
|
+
parentStream: {
|
|
1212
|
+
type: 'string',
|
|
1213
|
+
description: 'Parent stream override for stream mode using -P (optional)',
|
|
1214
|
+
},
|
|
1215
|
+
useBranchSource: {
|
|
1216
|
+
type: 'boolean',
|
|
1217
|
+
description: 'Use branch -s mode where sourcePath becomes fromFile (optional)',
|
|
1218
|
+
},
|
|
1103
1219
|
max: {
|
|
1104
1220
|
type: 'number',
|
|
1105
1221
|
description: 'Maximum number of changelists to return (optional)',
|
|
@@ -1108,12 +1224,33 @@ class MCPPerforceServer {
|
|
|
1108
1224
|
type: 'boolean',
|
|
1109
1225
|
description: 'Include long descriptions (optional, equivalent to -l)',
|
|
1110
1226
|
},
|
|
1227
|
+
reverse: {
|
|
1228
|
+
type: 'boolean',
|
|
1229
|
+
description: 'Reverse branch or stream mapping direction using -r (optional)',
|
|
1230
|
+
},
|
|
1231
|
+
time: {
|
|
1232
|
+
type: 'boolean',
|
|
1233
|
+
description: 'Display the time as well as the date using -t (optional)',
|
|
1234
|
+
},
|
|
1235
|
+
user: {
|
|
1236
|
+
type: 'string',
|
|
1237
|
+
description: 'Limit results to changes submitted by a specific user (optional)',
|
|
1238
|
+
},
|
|
1239
|
+
forceStreamFlow: {
|
|
1240
|
+
type: 'boolean',
|
|
1241
|
+
description: 'Force stream-mode interchanges to ignore expected flow using -F (optional)',
|
|
1242
|
+
},
|
|
1111
1243
|
workspacePath: {
|
|
1112
1244
|
type: 'string',
|
|
1113
1245
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1114
1246
|
},
|
|
1115
1247
|
},
|
|
1116
|
-
|
|
1248
|
+
anyOf: [
|
|
1249
|
+
{ required: ['sourcePath', 'targetPath'] },
|
|
1250
|
+
{ required: ['sourcePath', 'targetPaths'] },
|
|
1251
|
+
{ required: ['branch'] },
|
|
1252
|
+
{ required: ['stream'] },
|
|
1253
|
+
],
|
|
1117
1254
|
additionalProperties: false,
|
|
1118
1255
|
},
|
|
1119
1256
|
},
|
|
@@ -1131,12 +1268,20 @@ class MCPPerforceServer {
|
|
|
1131
1268
|
type: 'string',
|
|
1132
1269
|
description: 'Optional target depot filespec/path',
|
|
1133
1270
|
},
|
|
1271
|
+
files: {
|
|
1272
|
+
type: 'array',
|
|
1273
|
+
items: { type: 'string' },
|
|
1274
|
+
description: 'Optional file/filespec list for native p4 integrated filtering',
|
|
1275
|
+
},
|
|
1134
1276
|
workspacePath: {
|
|
1135
1277
|
type: 'string',
|
|
1136
1278
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1137
1279
|
},
|
|
1138
1280
|
},
|
|
1139
|
-
|
|
1281
|
+
anyOf: [
|
|
1282
|
+
{ required: ['sourcePath'] },
|
|
1283
|
+
{ required: ['files'] },
|
|
1284
|
+
],
|
|
1140
1285
|
additionalProperties: false,
|
|
1141
1286
|
},
|
|
1142
1287
|
},
|
|
@@ -1249,6 +1394,209 @@ class MCPPerforceServer {
|
|
|
1249
1394
|
additionalProperties: false,
|
|
1250
1395
|
},
|
|
1251
1396
|
},
|
|
1397
|
+
{
|
|
1398
|
+
name: 'p4.file.inspect',
|
|
1399
|
+
description: 'Composite file inspection: fstat + filelog + optional print/blame in one call',
|
|
1400
|
+
inputSchema: {
|
|
1401
|
+
type: 'object',
|
|
1402
|
+
properties: {
|
|
1403
|
+
filespec: {
|
|
1404
|
+
type: 'string',
|
|
1405
|
+
description: 'Single filespec to inspect',
|
|
1406
|
+
},
|
|
1407
|
+
filespecs: {
|
|
1408
|
+
type: 'array',
|
|
1409
|
+
items: { type: 'string' },
|
|
1410
|
+
description: 'Multiple filespecs to inspect in one call',
|
|
1411
|
+
},
|
|
1412
|
+
includeFstat: {
|
|
1413
|
+
type: 'boolean',
|
|
1414
|
+
description: 'Include p4 fstat metadata (optional, default true)',
|
|
1415
|
+
},
|
|
1416
|
+
includeHistory: {
|
|
1417
|
+
type: 'boolean',
|
|
1418
|
+
description: 'Include p4 filelog history (optional, default true)',
|
|
1419
|
+
},
|
|
1420
|
+
includeContent: {
|
|
1421
|
+
type: 'boolean',
|
|
1422
|
+
description: 'Include p4 print content (optional, default false)',
|
|
1423
|
+
},
|
|
1424
|
+
includeBlame: {
|
|
1425
|
+
type: 'boolean',
|
|
1426
|
+
description: 'Include p4 annotate/blame output (optional, default false)',
|
|
1427
|
+
},
|
|
1428
|
+
maxFiles: {
|
|
1429
|
+
type: 'number',
|
|
1430
|
+
description: 'Maximum files to inspect in one call (optional, default requested count capped at 25)',
|
|
1431
|
+
},
|
|
1432
|
+
maxRevisions: {
|
|
1433
|
+
type: 'number',
|
|
1434
|
+
description: 'Maximum revisions per filelog call (optional, default 5)',
|
|
1435
|
+
},
|
|
1436
|
+
workspacePath: {
|
|
1437
|
+
type: 'string',
|
|
1438
|
+
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1439
|
+
},
|
|
1440
|
+
},
|
|
1441
|
+
anyOf: [
|
|
1442
|
+
{ required: ['filespec'] },
|
|
1443
|
+
{ required: ['filespecs'] },
|
|
1444
|
+
],
|
|
1445
|
+
additionalProperties: false,
|
|
1446
|
+
},
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
name: 'p4.workspace.snapshot',
|
|
1450
|
+
description: 'Composite workspace snapshot: info + status + optional config/opened/recent changes',
|
|
1451
|
+
inputSchema: {
|
|
1452
|
+
type: 'object',
|
|
1453
|
+
properties: {
|
|
1454
|
+
includeConfig: {
|
|
1455
|
+
type: 'boolean',
|
|
1456
|
+
description: 'Include p4.config.detect output (optional, default true)',
|
|
1457
|
+
},
|
|
1458
|
+
includeOpened: {
|
|
1459
|
+
type: 'boolean',
|
|
1460
|
+
description: 'Include full p4.opened output (optional, default false)',
|
|
1461
|
+
},
|
|
1462
|
+
includeRecentChanges: {
|
|
1463
|
+
type: 'boolean',
|
|
1464
|
+
description: 'Include recent changelists via p4.changes (optional, default false)',
|
|
1465
|
+
},
|
|
1466
|
+
recentChangesMax: {
|
|
1467
|
+
type: 'number',
|
|
1468
|
+
description: 'Maximum recent changelists to include (optional, default 10)',
|
|
1469
|
+
},
|
|
1470
|
+
workspacePath: {
|
|
1471
|
+
type: 'string',
|
|
1472
|
+
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1473
|
+
},
|
|
1474
|
+
},
|
|
1475
|
+
additionalProperties: false,
|
|
1476
|
+
},
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
name: 'p4.search.inspect',
|
|
1480
|
+
description: 'Composite search helper: grep + optional fstat + optional content previews',
|
|
1481
|
+
inputSchema: {
|
|
1482
|
+
type: 'object',
|
|
1483
|
+
properties: {
|
|
1484
|
+
pattern: {
|
|
1485
|
+
type: 'string',
|
|
1486
|
+
description: 'Search pattern for p4 grep (required)',
|
|
1487
|
+
},
|
|
1488
|
+
filespec: {
|
|
1489
|
+
type: 'string',
|
|
1490
|
+
description: 'Single filespec to search',
|
|
1491
|
+
},
|
|
1492
|
+
filespecs: {
|
|
1493
|
+
type: 'array',
|
|
1494
|
+
items: { type: 'string' },
|
|
1495
|
+
description: 'Multiple filespecs to search in one call',
|
|
1496
|
+
},
|
|
1497
|
+
caseInsensitive: {
|
|
1498
|
+
type: 'boolean',
|
|
1499
|
+
description: 'Case insensitive search (optional, default false)',
|
|
1500
|
+
},
|
|
1501
|
+
maxFiles: {
|
|
1502
|
+
type: 'number',
|
|
1503
|
+
description: 'Maximum matched files to include (optional, default 20)',
|
|
1504
|
+
},
|
|
1505
|
+
maxMatchesPerFile: {
|
|
1506
|
+
type: 'number',
|
|
1507
|
+
description: 'Maximum grep matches to retain per file (optional, default 20)',
|
|
1508
|
+
},
|
|
1509
|
+
includeFstat: {
|
|
1510
|
+
type: 'boolean',
|
|
1511
|
+
description: 'Include p4 fstat metadata for matched files (optional, default true)',
|
|
1512
|
+
},
|
|
1513
|
+
includeContentPreview: {
|
|
1514
|
+
type: 'boolean',
|
|
1515
|
+
description: 'Include p4 print context snippets for matched files (optional, default false)',
|
|
1516
|
+
},
|
|
1517
|
+
previewContextLines: {
|
|
1518
|
+
type: 'number',
|
|
1519
|
+
description: 'Context lines before and after each match when includeContentPreview=true (optional, default 2)',
|
|
1520
|
+
},
|
|
1521
|
+
workspacePath: {
|
|
1522
|
+
type: 'string',
|
|
1523
|
+
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1524
|
+
},
|
|
1525
|
+
},
|
|
1526
|
+
required: ['pattern'],
|
|
1527
|
+
additionalProperties: false,
|
|
1528
|
+
},
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
name: 'p4.review.prepare',
|
|
1532
|
+
description: 'Composite review preparation: discover or accept changelists, then build review-ready inspection bundles',
|
|
1533
|
+
inputSchema: {
|
|
1534
|
+
type: 'object',
|
|
1535
|
+
properties: {
|
|
1536
|
+
changelist: {
|
|
1537
|
+
type: 'string',
|
|
1538
|
+
description: 'Single changelist to inspect directly',
|
|
1539
|
+
},
|
|
1540
|
+
changelists: {
|
|
1541
|
+
type: 'array',
|
|
1542
|
+
items: { type: 'string' },
|
|
1543
|
+
description: 'Multiple changelists to inspect directly',
|
|
1544
|
+
},
|
|
1545
|
+
status: {
|
|
1546
|
+
type: 'string',
|
|
1547
|
+
enum: ['submitted', 'pending', 'shelved'],
|
|
1548
|
+
description: 'Status filter used when discovering changelists',
|
|
1549
|
+
},
|
|
1550
|
+
user: {
|
|
1551
|
+
type: 'string',
|
|
1552
|
+
description: 'User filter used when discovering changelists',
|
|
1553
|
+
},
|
|
1554
|
+
client: {
|
|
1555
|
+
type: 'string',
|
|
1556
|
+
description: 'Client/workspace filter used when discovering changelists',
|
|
1557
|
+
},
|
|
1558
|
+
filespec: {
|
|
1559
|
+
type: 'string',
|
|
1560
|
+
description: 'Single filespec filter used when discovering changelists',
|
|
1561
|
+
},
|
|
1562
|
+
filespecs: {
|
|
1563
|
+
type: 'array',
|
|
1564
|
+
items: { type: 'string' },
|
|
1565
|
+
description: 'Multiple filespec filters used when discovering changelists',
|
|
1566
|
+
},
|
|
1567
|
+
maxChanges: {
|
|
1568
|
+
type: 'number',
|
|
1569
|
+
description: 'Maximum changelists to inspect (optional, default 10)',
|
|
1570
|
+
},
|
|
1571
|
+
includeDiff: {
|
|
1572
|
+
type: 'boolean',
|
|
1573
|
+
description: 'Include changelist diff content in each inspection bundle (optional, default false)',
|
|
1574
|
+
},
|
|
1575
|
+
diffFormat: {
|
|
1576
|
+
type: 'string',
|
|
1577
|
+
enum: ['u', 'c', 'n', 's'],
|
|
1578
|
+
description: 'Diff format for inspection describe output when includeDiff=true',
|
|
1579
|
+
},
|
|
1580
|
+
includeFileHistory: {
|
|
1581
|
+
type: 'boolean',
|
|
1582
|
+
description: 'Include file history for files touched by each changelist (optional, default false)',
|
|
1583
|
+
},
|
|
1584
|
+
maxFilesWithHistory: {
|
|
1585
|
+
type: 'number',
|
|
1586
|
+
description: 'Maximum files per changelist to include history for (optional, default 5)',
|
|
1587
|
+
},
|
|
1588
|
+
maxRevisions: {
|
|
1589
|
+
type: 'number',
|
|
1590
|
+
description: 'Maximum revisions per file history call (optional, default 5)',
|
|
1591
|
+
},
|
|
1592
|
+
workspacePath: {
|
|
1593
|
+
type: 'string',
|
|
1594
|
+
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1595
|
+
},
|
|
1596
|
+
},
|
|
1597
|
+
additionalProperties: false,
|
|
1598
|
+
},
|
|
1599
|
+
},
|
|
1252
1600
|
{
|
|
1253
1601
|
name: 'p4.blame',
|
|
1254
1602
|
description: 'Show file annotations with change history (like git blame)',
|
|
@@ -1259,12 +1607,20 @@ class MCPPerforceServer {
|
|
|
1259
1607
|
type: 'string',
|
|
1260
1608
|
description: 'File to show blame for (required)',
|
|
1261
1609
|
},
|
|
1610
|
+
files: {
|
|
1611
|
+
type: 'array',
|
|
1612
|
+
items: { type: 'string' },
|
|
1613
|
+
description: 'Files to show blame for in one command (required if file is omitted)',
|
|
1614
|
+
},
|
|
1262
1615
|
workspacePath: {
|
|
1263
1616
|
type: 'string',
|
|
1264
1617
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1265
1618
|
},
|
|
1266
1619
|
},
|
|
1267
|
-
|
|
1620
|
+
anyOf: [
|
|
1621
|
+
{ required: ['file'] },
|
|
1622
|
+
{ required: ['files'] },
|
|
1623
|
+
],
|
|
1268
1624
|
additionalProperties: false,
|
|
1269
1625
|
},
|
|
1270
1626
|
},
|
|
@@ -1278,12 +1634,20 @@ class MCPPerforceServer {
|
|
|
1278
1634
|
type: 'string',
|
|
1279
1635
|
description: 'File to annotate (required)',
|
|
1280
1636
|
},
|
|
1637
|
+
files: {
|
|
1638
|
+
type: 'array',
|
|
1639
|
+
items: { type: 'string' },
|
|
1640
|
+
description: 'Files to annotate in one command (required if file is omitted)',
|
|
1641
|
+
},
|
|
1281
1642
|
workspacePath: {
|
|
1282
1643
|
type: 'string',
|
|
1283
1644
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1284
1645
|
},
|
|
1285
1646
|
},
|
|
1286
|
-
|
|
1647
|
+
anyOf: [
|
|
1648
|
+
{ required: ['file'] },
|
|
1649
|
+
{ required: ['files'] },
|
|
1650
|
+
],
|
|
1287
1651
|
additionalProperties: false,
|
|
1288
1652
|
},
|
|
1289
1653
|
},
|
|
@@ -1406,6 +1770,11 @@ class MCPPerforceServer {
|
|
|
1406
1770
|
type: 'string',
|
|
1407
1771
|
description: 'Depot filespec to print (required)',
|
|
1408
1772
|
},
|
|
1773
|
+
filespecs: {
|
|
1774
|
+
type: 'array',
|
|
1775
|
+
items: { type: 'string' },
|
|
1776
|
+
description: 'Depot filespecs to print in one command (required if filespec is omitted)',
|
|
1777
|
+
},
|
|
1409
1778
|
quiet: {
|
|
1410
1779
|
type: 'boolean',
|
|
1411
1780
|
description: 'Suppress file headers (optional, defaults to true)',
|
|
@@ -1415,7 +1784,10 @@ class MCPPerforceServer {
|
|
|
1415
1784
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1416
1785
|
},
|
|
1417
1786
|
},
|
|
1418
|
-
|
|
1787
|
+
anyOf: [
|
|
1788
|
+
{ required: ['filespec'] },
|
|
1789
|
+
{ required: ['filespecs'] },
|
|
1790
|
+
],
|
|
1419
1791
|
additionalProperties: false,
|
|
1420
1792
|
},
|
|
1421
1793
|
},
|
|
@@ -1429,16 +1801,64 @@ class MCPPerforceServer {
|
|
|
1429
1801
|
type: 'string',
|
|
1430
1802
|
description: 'Filespec to inspect (required)',
|
|
1431
1803
|
},
|
|
1804
|
+
filespecs: {
|
|
1805
|
+
type: 'array',
|
|
1806
|
+
items: { type: 'string' },
|
|
1807
|
+
description: 'Filespecs to inspect in one command (required if filespec is omitted)',
|
|
1808
|
+
},
|
|
1432
1809
|
max: {
|
|
1433
1810
|
type: 'number',
|
|
1434
1811
|
description: 'Maximum number of results (optional)',
|
|
1435
1812
|
},
|
|
1813
|
+
filter: {
|
|
1814
|
+
type: 'string',
|
|
1815
|
+
description: 'fstat filter expression for -F (optional)',
|
|
1816
|
+
},
|
|
1817
|
+
fields: {
|
|
1818
|
+
type: 'array',
|
|
1819
|
+
items: { type: 'string' },
|
|
1820
|
+
description: 'Specific tagged fields to return using -T (optional)',
|
|
1821
|
+
},
|
|
1822
|
+
reverseOrder: {
|
|
1823
|
+
type: 'boolean',
|
|
1824
|
+
description: 'Reverse the output sort order using -r (optional)',
|
|
1825
|
+
},
|
|
1826
|
+
attributePattern: {
|
|
1827
|
+
type: 'string',
|
|
1828
|
+
description: 'Restrict attributes using -A pattern (optional)',
|
|
1829
|
+
},
|
|
1830
|
+
changeAfter: {
|
|
1831
|
+
type: 'string',
|
|
1832
|
+
description: 'Show files modified by or after a submitted changelist using -c (optional)',
|
|
1833
|
+
},
|
|
1834
|
+
changelist: {
|
|
1835
|
+
type: 'string',
|
|
1836
|
+
description: 'Show files modified by a specific changelist using -e (optional)',
|
|
1837
|
+
},
|
|
1838
|
+
outputOptions: {
|
|
1839
|
+
type: 'array',
|
|
1840
|
+
items: { type: 'string' },
|
|
1841
|
+
description: 'Raw -O option suffixes such as l, p, r, s (optional)',
|
|
1842
|
+
},
|
|
1843
|
+
limitOptions: {
|
|
1844
|
+
type: 'array',
|
|
1845
|
+
items: { type: 'string' },
|
|
1846
|
+
description: 'Raw -R option suffixes such as c, h, o, u (optional)',
|
|
1847
|
+
},
|
|
1848
|
+
sortOptions: {
|
|
1849
|
+
type: 'array',
|
|
1850
|
+
items: { type: 'string' },
|
|
1851
|
+
description: 'Raw -S option suffixes such as d, h, r, s, t (optional)',
|
|
1852
|
+
},
|
|
1436
1853
|
workspacePath: {
|
|
1437
1854
|
type: 'string',
|
|
1438
1855
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
1439
1856
|
},
|
|
1440
1857
|
},
|
|
1441
|
-
|
|
1858
|
+
anyOf: [
|
|
1859
|
+
{ required: ['filespec'] },
|
|
1860
|
+
{ required: ['filespecs'] },
|
|
1861
|
+
],
|
|
1442
1862
|
additionalProperties: false,
|
|
1443
1863
|
},
|
|
1444
1864
|
},
|
|
@@ -1452,6 +1872,24 @@ class MCPPerforceServer {
|
|
|
1452
1872
|
type: 'string',
|
|
1453
1873
|
description: 'Optional stream path filter',
|
|
1454
1874
|
},
|
|
1875
|
+
streams: {
|
|
1876
|
+
type: 'array',
|
|
1877
|
+
items: { type: 'string' },
|
|
1878
|
+
description: 'Optional stream path filters to query in one command',
|
|
1879
|
+
},
|
|
1880
|
+
unloaded: {
|
|
1881
|
+
type: 'boolean',
|
|
1882
|
+
description: 'Include unloaded task streams using -U (optional)',
|
|
1883
|
+
},
|
|
1884
|
+
filter: {
|
|
1885
|
+
type: 'string',
|
|
1886
|
+
description: 'Stream filter expression for -F (optional)',
|
|
1887
|
+
},
|
|
1888
|
+
viewMatch: {
|
|
1889
|
+
type: 'array',
|
|
1890
|
+
items: { type: 'string' },
|
|
1891
|
+
description: 'One or more depot paths to pass with --viewmatch (optional)',
|
|
1892
|
+
},
|
|
1455
1893
|
max: {
|
|
1456
1894
|
type: 'number',
|
|
1457
1895
|
description: 'Maximum number of results (optional)',
|
|
@@ -1497,6 +1935,11 @@ class MCPPerforceServer {
|
|
|
1497
1935
|
type: 'string',
|
|
1498
1936
|
description: 'Filespec to search in (optional)',
|
|
1499
1937
|
},
|
|
1938
|
+
filespecs: {
|
|
1939
|
+
type: 'array',
|
|
1940
|
+
items: { type: 'string' },
|
|
1941
|
+
description: 'Filespecs to search in (optional)',
|
|
1942
|
+
},
|
|
1500
1943
|
caseInsensitive: {
|
|
1501
1944
|
type: 'boolean',
|
|
1502
1945
|
description: 'Case insensitive search (optional, defaults to false)',
|
|
@@ -1520,10 +1963,31 @@ class MCPPerforceServer {
|
|
|
1520
1963
|
type: 'string',
|
|
1521
1964
|
description: 'Filespec to list (optional, defaults to all files)',
|
|
1522
1965
|
},
|
|
1966
|
+
filespecs: {
|
|
1967
|
+
type: 'array',
|
|
1968
|
+
items: { type: 'string' },
|
|
1969
|
+
description: 'Filespecs to list in one command (optional)',
|
|
1970
|
+
},
|
|
1523
1971
|
max: {
|
|
1524
1972
|
type: 'number',
|
|
1525
1973
|
description: 'Maximum number of results (optional)',
|
|
1526
1974
|
},
|
|
1975
|
+
allRevisions: {
|
|
1976
|
+
type: 'boolean',
|
|
1977
|
+
description: 'Display all revisions in range using -a (optional)',
|
|
1978
|
+
},
|
|
1979
|
+
archiveDepot: {
|
|
1980
|
+
type: 'boolean',
|
|
1981
|
+
description: 'Include files in archive depots using -A (optional)',
|
|
1982
|
+
},
|
|
1983
|
+
existingOnly: {
|
|
1984
|
+
type: 'boolean',
|
|
1985
|
+
description: 'Show only revisions available for sync/integrate using -e (optional)',
|
|
1986
|
+
},
|
|
1987
|
+
ignoreCase: {
|
|
1988
|
+
type: 'boolean',
|
|
1989
|
+
description: 'Ignore case of the file argument using -i (optional)',
|
|
1990
|
+
},
|
|
1527
1991
|
workspacePath: {
|
|
1528
1992
|
type: 'string',
|
|
1529
1993
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1542,6 +2006,31 @@ class MCPPerforceServer {
|
|
|
1542
2006
|
type: 'string',
|
|
1543
2007
|
description: 'Filespec to list directories for (optional, defaults to all directories)',
|
|
1544
2008
|
},
|
|
2009
|
+
filespecs: {
|
|
2010
|
+
type: 'array',
|
|
2011
|
+
items: { type: 'string' },
|
|
2012
|
+
description: 'Filespecs to list directories for in one command (optional)',
|
|
2013
|
+
},
|
|
2014
|
+
ignoreCase: {
|
|
2015
|
+
type: 'boolean',
|
|
2016
|
+
description: 'Ignore case using -i (optional; incompatible with onlyClientMapped)',
|
|
2017
|
+
},
|
|
2018
|
+
onlyClientMapped: {
|
|
2019
|
+
type: 'boolean',
|
|
2020
|
+
description: 'List only directories in the current client view using -C (optional)',
|
|
2021
|
+
},
|
|
2022
|
+
includeDeleted: {
|
|
2023
|
+
type: 'boolean',
|
|
2024
|
+
description: 'Include directories containing only deleted files using -D (optional)',
|
|
2025
|
+
},
|
|
2026
|
+
onlyHave: {
|
|
2027
|
+
type: 'boolean',
|
|
2028
|
+
description: 'List directories containing files synced to the current workspace using -H (optional)',
|
|
2029
|
+
},
|
|
2030
|
+
stream: {
|
|
2031
|
+
type: 'string',
|
|
2032
|
+
description: 'Limit to directories mapped in a stream view using -S (optional)',
|
|
2033
|
+
},
|
|
1545
2034
|
workspacePath: {
|
|
1546
2035
|
type: 'string',
|
|
1547
2036
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1561,10 +2050,19 @@ class MCPPerforceServer {
|
|
|
1561
2050
|
type: 'string',
|
|
1562
2051
|
description: 'Specific user to show (optional)',
|
|
1563
2052
|
},
|
|
2053
|
+
users: {
|
|
2054
|
+
type: 'array',
|
|
2055
|
+
items: { type: 'string' },
|
|
2056
|
+
description: 'Specific users to show in one command (optional)',
|
|
2057
|
+
},
|
|
1564
2058
|
max: {
|
|
1565
2059
|
type: 'number',
|
|
1566
2060
|
description: 'Maximum number of results (optional)',
|
|
1567
2061
|
},
|
|
2062
|
+
includeServiceUsers: {
|
|
2063
|
+
type: 'boolean',
|
|
2064
|
+
description: 'Include service and operator users using -a (optional)',
|
|
2065
|
+
},
|
|
1568
2066
|
workspacePath: {
|
|
1569
2067
|
type: 'string',
|
|
1570
2068
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1619,6 +2117,23 @@ class MCPPerforceServer {
|
|
|
1619
2117
|
type: 'string',
|
|
1620
2118
|
description: 'Specific job to show (optional)',
|
|
1621
2119
|
},
|
|
2120
|
+
files: {
|
|
2121
|
+
type: 'array',
|
|
2122
|
+
items: { type: 'string' },
|
|
2123
|
+
description: 'Optional file/filespec filters for jobs',
|
|
2124
|
+
},
|
|
2125
|
+
jobView: {
|
|
2126
|
+
type: 'string',
|
|
2127
|
+
description: 'Jobview expression for -e (optional)',
|
|
2128
|
+
},
|
|
2129
|
+
includeIntegrated: {
|
|
2130
|
+
type: 'boolean',
|
|
2131
|
+
description: 'Include fixes from integrated changelists using -i (optional)',
|
|
2132
|
+
},
|
|
2133
|
+
reverseOrder: {
|
|
2134
|
+
type: 'boolean',
|
|
2135
|
+
description: 'Reverse job sort order using -r (optional)',
|
|
2136
|
+
},
|
|
1622
2137
|
max: {
|
|
1623
2138
|
type: 'number',
|
|
1624
2139
|
description: 'Maximum number of results (optional)',
|
|
@@ -1664,6 +2179,11 @@ class MCPPerforceServer {
|
|
|
1664
2179
|
type: 'string',
|
|
1665
2180
|
description: 'Filter by changelist (optional)',
|
|
1666
2181
|
},
|
|
2182
|
+
files: {
|
|
2183
|
+
type: 'array',
|
|
2184
|
+
items: { type: 'string' },
|
|
2185
|
+
description: 'Optional file/filespec filters for fixes',
|
|
2186
|
+
},
|
|
1667
2187
|
workspacePath: {
|
|
1668
2188
|
type: 'string',
|
|
1669
2189
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1686,6 +2206,39 @@ class MCPPerforceServer {
|
|
|
1686
2206
|
type: 'string',
|
|
1687
2207
|
description: 'Filter by user (optional)',
|
|
1688
2208
|
},
|
|
2209
|
+
filespec: {
|
|
2210
|
+
type: 'string',
|
|
2211
|
+
description: 'Single filespec filter for labels containing matching files (optional)',
|
|
2212
|
+
},
|
|
2213
|
+
filespecs: {
|
|
2214
|
+
type: 'array',
|
|
2215
|
+
items: { type: 'string' },
|
|
2216
|
+
description: 'Multiple filespec filters for labels in one command (optional)',
|
|
2217
|
+
},
|
|
2218
|
+
nameFilter: {
|
|
2219
|
+
type: 'string',
|
|
2220
|
+
description: 'Label name filter using -e (optional)',
|
|
2221
|
+
},
|
|
2222
|
+
caseInsensitiveNameFilter: {
|
|
2223
|
+
type: 'string',
|
|
2224
|
+
description: 'Case-insensitive label name filter using -E (optional)',
|
|
2225
|
+
},
|
|
2226
|
+
unloaded: {
|
|
2227
|
+
type: 'boolean',
|
|
2228
|
+
description: 'List unloaded labels using -U (optional)',
|
|
2229
|
+
},
|
|
2230
|
+
autoreloadOnly: {
|
|
2231
|
+
type: 'boolean',
|
|
2232
|
+
description: 'List only autoreload labels using -R (optional)',
|
|
2233
|
+
},
|
|
2234
|
+
allServers: {
|
|
2235
|
+
type: 'boolean',
|
|
2236
|
+
description: 'List labels across all servers using -a (optional)',
|
|
2237
|
+
},
|
|
2238
|
+
serverId: {
|
|
2239
|
+
type: 'string',
|
|
2240
|
+
description: 'Limit labels to a specific server using -s (optional)',
|
|
2241
|
+
},
|
|
1689
2242
|
max: {
|
|
1690
2243
|
type: 'number',
|
|
1691
2244
|
description: 'Maximum number of results (optional)',
|
|
@@ -1727,6 +2280,31 @@ class MCPPerforceServer {
|
|
|
1727
2280
|
type: 'string',
|
|
1728
2281
|
description: 'Filespec to get sizes for (optional, defaults to current directory)',
|
|
1729
2282
|
},
|
|
2283
|
+
filespecs: {
|
|
2284
|
+
type: 'array',
|
|
2285
|
+
items: { type: 'string' },
|
|
2286
|
+
description: 'Filespecs to get sizes for in one command (optional)',
|
|
2287
|
+
},
|
|
2288
|
+
allRevisions: {
|
|
2289
|
+
type: 'boolean',
|
|
2290
|
+
description: 'List all revisions in the range using -a (optional)',
|
|
2291
|
+
},
|
|
2292
|
+
shelvedOnly: {
|
|
2293
|
+
type: 'boolean',
|
|
2294
|
+
description: 'Display size info for shelved files only using -S (optional)',
|
|
2295
|
+
},
|
|
2296
|
+
omitLazyCopies: {
|
|
2297
|
+
type: 'boolean',
|
|
2298
|
+
description: 'Omit lazy copies from totals using -z (optional)',
|
|
2299
|
+
},
|
|
2300
|
+
max: {
|
|
2301
|
+
type: 'number',
|
|
2302
|
+
description: 'Limit output to the first max files using -m (optional)',
|
|
2303
|
+
},
|
|
2304
|
+
blockSize: {
|
|
2305
|
+
type: 'number',
|
|
2306
|
+
description: 'Round sizes up to a block size in bytes using -b (optional)',
|
|
2307
|
+
},
|
|
1730
2308
|
workspacePath: {
|
|
1731
2309
|
type: 'string',
|
|
1732
2310
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1745,6 +2323,11 @@ class MCPPerforceServer {
|
|
|
1745
2323
|
type: 'string',
|
|
1746
2324
|
description: 'Filespec to check (optional)',
|
|
1747
2325
|
},
|
|
2326
|
+
filespecs: {
|
|
2327
|
+
type: 'array',
|
|
2328
|
+
items: { type: 'string' },
|
|
2329
|
+
description: 'Filespecs to check in one command (optional)',
|
|
2330
|
+
},
|
|
1748
2331
|
workspacePath: {
|
|
1749
2332
|
type: 'string',
|
|
1750
2333
|
description: 'Path to workspace directory (optional, defaults to current directory)',
|
|
@@ -1830,19 +2413,21 @@ class MCPPerforceServer {
|
|
|
1830
2413
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
1831
2414
|
const startTime = Date.now();
|
|
1832
2415
|
const { name, arguments: args } = request.params;
|
|
2416
|
+
// Normalize tool name: support both dot notation (p4.changes) and underscore (p4_changes)
|
|
2417
|
+
const normalizedName = name.replace(/_/g, '.');
|
|
1833
2418
|
try {
|
|
1834
|
-
log.debug(`Calling tool: ${name}`);
|
|
2419
|
+
log.debug(`Calling tool: ${name}${name !== normalizedName ? ` (normalized to ${normalizedName})` : ''}`);
|
|
1835
2420
|
// Rate limiting check
|
|
1836
|
-
const rateLimitResult = this.context.security.checkRateLimit(
|
|
2421
|
+
const rateLimitResult = this.context.security.checkRateLimit(normalizedName);
|
|
1837
2422
|
if (!rateLimitResult.allowed) {
|
|
1838
|
-
const errorMsg = `Rate limit exceeded for tool ${
|
|
1839
|
-
log.warn(`Rate limit exceeded: ${
|
|
2423
|
+
const errorMsg = `Rate limit exceeded for tool ${normalizedName}. Try again after ${new Date(rateLimitResult.resetTime).toISOString()}`;
|
|
2424
|
+
log.warn(`Rate limit exceeded: ${normalizedName}`);
|
|
1840
2425
|
// Audit log the blocked request
|
|
1841
2426
|
this.context.security.logAuditEntry({
|
|
1842
|
-
tool:
|
|
2427
|
+
tool: normalizedName,
|
|
1843
2428
|
user: 'unknown', // Could be enhanced to extract from P4 config
|
|
1844
2429
|
client: 'unknown',
|
|
1845
|
-
operation:
|
|
2430
|
+
operation: normalizedName,
|
|
1846
2431
|
args: request.params.arguments || {},
|
|
1847
2432
|
result: 'blocked',
|
|
1848
2433
|
errorCode: 'RATE_LIMIT_EXCEEDED',
|
|
@@ -1860,18 +2445,18 @@ class MCPPerforceServer {
|
|
|
1860
2445
|
}
|
|
1861
2446
|
}
|
|
1862
2447
|
const toolArgs = (args || {});
|
|
1863
|
-
const execution = await this.executeToolWithCaching(
|
|
2448
|
+
const execution = await this.executeToolWithCaching(normalizedName, toolArgs);
|
|
1864
2449
|
const result = execution.result;
|
|
1865
|
-
if (WRITE_TOOLS.has(
|
|
2450
|
+
if (WRITE_TOOLS.has(normalizedName) && result && typeof result === 'object' && result.ok) {
|
|
1866
2451
|
this.clearReadCache();
|
|
1867
2452
|
}
|
|
1868
|
-
this.recordToolPerformance(
|
|
2453
|
+
this.recordToolPerformance(normalizedName, Date.now() - startTime, result, execution.cacheStatus, this.extractSubcallCounts(result));
|
|
1869
2454
|
// Audit log successful operation
|
|
1870
2455
|
this.context.security.logAuditEntry({
|
|
1871
|
-
tool:
|
|
2456
|
+
tool: normalizedName,
|
|
1872
2457
|
user: result?.configUsed?.P4USER || 'unknown',
|
|
1873
2458
|
client: result?.configUsed?.P4CLIENT || 'unknown',
|
|
1874
|
-
operation:
|
|
2459
|
+
operation: normalizedName,
|
|
1875
2460
|
args: toolArgs,
|
|
1876
2461
|
result: 'success',
|
|
1877
2462
|
duration: Date.now() - startTime,
|
|
@@ -1881,14 +2466,14 @@ class MCPPerforceServer {
|
|
|
1881
2466
|
catch (error) {
|
|
1882
2467
|
const duration = Date.now() - startTime;
|
|
1883
2468
|
const errorCode = error instanceof types_js_1.McpError ? error.code : 'INTERNAL_ERROR';
|
|
1884
|
-
this.recordToolPerformance(
|
|
2469
|
+
this.recordToolPerformance(normalizedName, duration, { ok: false, error: { code: String(errorCode) } }, 'uncacheable');
|
|
1885
2470
|
log.error('Tool execution error:', error);
|
|
1886
2471
|
// Audit log failed operation
|
|
1887
2472
|
this.context.security.logAuditEntry({
|
|
1888
|
-
tool:
|
|
2473
|
+
tool: normalizedName,
|
|
1889
2474
|
user: 'unknown', // Could be enhanced to extract from context
|
|
1890
2475
|
client: 'unknown',
|
|
1891
|
-
operation:
|
|
2476
|
+
operation: normalizedName,
|
|
1892
2477
|
args: args || {},
|
|
1893
2478
|
result: 'error',
|
|
1894
2479
|
errorCode: typeof errorCode === 'string' ? errorCode : errorCode.toString(),
|
|
@@ -1919,17 +2504,17 @@ if (require.main === module) {
|
|
|
1919
2504
|
}
|
|
1920
2505
|
// Handle help flag
|
|
1921
2506
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
1922
|
-
console.log(`
|
|
1923
|
-
MCP Perforce Server v${packageJson.version}
|
|
1924
|
-
===========================
|
|
1925
|
-
|
|
1926
|
-
A production-ready MCP (Model Context Protocol) server for Perforce operations.
|
|
1927
|
-
|
|
1928
|
-
Usage:
|
|
1929
|
-
mcp-perforce-server Start the MCP server (stdio transport)
|
|
1930
|
-
mcp-perforce-server --help Show this help message
|
|
1931
|
-
mcp-perforce-server --version Show version information
|
|
1932
|
-
|
|
2507
|
+
console.log(`
|
|
2508
|
+
MCP Perforce Server v${packageJson.version}
|
|
2509
|
+
===========================
|
|
2510
|
+
|
|
2511
|
+
A production-ready MCP (Model Context Protocol) server for Perforce operations.
|
|
2512
|
+
|
|
2513
|
+
Usage:
|
|
2514
|
+
mcp-perforce-server Start the MCP server (stdio transport)
|
|
2515
|
+
mcp-perforce-server --help Show this help message
|
|
2516
|
+
mcp-perforce-server --version Show version information
|
|
2517
|
+
|
|
1933
2518
|
Environment Variables:
|
|
1934
2519
|
P4_READONLY_MODE=false Enable write operations (default: read-only enabled)
|
|
1935
2520
|
P4_DISABLE_DELETE=false Enable delete operations (default: delete disabled)
|
|
@@ -1956,23 +2541,23 @@ Compliance & Security:
|
|
|
1956
2541
|
P4_ENABLE_MEMORY_LIMITS=true|false Override memory limits (default in fast mode: false)
|
|
1957
2542
|
P4_ENABLE_INPUT_SANITIZATION=false Disable input sanitization (default: enabled)
|
|
1958
2543
|
P4_MAX_MEMORY_MB=1024 Memory limit in MB (default: 512)
|
|
1959
|
-
P4_AUDIT_RETENTION_DAYS=365 Audit log retention days (default: 90)
|
|
1960
|
-
P4_RATE_LIMIT_REQUESTS=100 Max requests per window (default: 100)
|
|
1961
|
-
P4_RATE_LIMIT_WINDOW_MS=600000 Rate limit window ms (default: 10min)
|
|
1962
|
-
P4_RATE_LIMIT_BLOCK_MS=3600000 Rate limit block duration ms (default: 1hr)
|
|
1963
|
-
|
|
1964
|
-
Configuration:
|
|
1965
|
-
Place a .p4config file in your project root or parent directories:
|
|
1966
|
-
|
|
1967
|
-
P4PORT=your-server:1666
|
|
1968
|
-
P4USER=your-username
|
|
1969
|
-
P4CLIENT=your-workspace-name
|
|
1970
|
-
|
|
1971
|
-
IDE Integration:
|
|
1972
|
-
Configure your IDE's MCP client to use this server.
|
|
1973
|
-
See README.md for VS Code and Cursor setup instructions.
|
|
1974
|
-
|
|
1975
|
-
For more information: https://github.com/iPraBhu/mcp-perforce-server
|
|
2544
|
+
P4_AUDIT_RETENTION_DAYS=365 Audit log retention days (default: 90)
|
|
2545
|
+
P4_RATE_LIMIT_REQUESTS=100 Max requests per window (default: 100)
|
|
2546
|
+
P4_RATE_LIMIT_WINDOW_MS=600000 Rate limit window ms (default: 10min)
|
|
2547
|
+
P4_RATE_LIMIT_BLOCK_MS=3600000 Rate limit block duration ms (default: 1hr)
|
|
2548
|
+
|
|
2549
|
+
Configuration:
|
|
2550
|
+
Place a .p4config file in your project root or parent directories:
|
|
2551
|
+
|
|
2552
|
+
P4PORT=your-server:1666
|
|
2553
|
+
P4USER=your-username
|
|
2554
|
+
P4CLIENT=your-workspace-name
|
|
2555
|
+
|
|
2556
|
+
IDE Integration:
|
|
2557
|
+
Configure your IDE's MCP client to use this server.
|
|
2558
|
+
See README.md for VS Code and Cursor setup instructions.
|
|
2559
|
+
|
|
2560
|
+
For more information: https://github.com/iPraBhu/mcp-perforce-server
|
|
1976
2561
|
`);
|
|
1977
2562
|
process.exit(0);
|
|
1978
2563
|
}
|