228
*/
229
export class McpPrefixGenerator {
230
>
private readonly _buckets = new Map<string, { usedIndexes: Set<number>; size: number }>();
mcpServer.ts
231
232
take(name: string): IReference<string> {
233
>
const safeName = name.toLowerCase().replace(/[^a-z0-9_.-]+/g, '_').slice(0, McpToolName.MaxPrefixLen - McpToolName.Prefix.length - 1);
mcpServer.ts
234
>
let bucket = this._buckets.get(safeName);
235
>
if (!bucket) {
236
>
bucket = { usedIndexes: new Set(), size: 0 };
237
>
this._buckets.set(safeName, bucket);
238
>
}
239
>
240
>
let index = 1;
241
>
while (bucket.usedIndexes.has(index)) {
242
index++;
243
}
245
>
bucket.size++;
246
>
247
>
// Trim safeName for this output if a multi-digit suffix would push us past
248
>
// MaxPrefixLen. The bucket is keyed on the un-trimmed safeName so collisions
249
>
// are still detected consistently across indexes.
250
>
const suffix = (index === 1 ? '' : String(index)) + '_';
251
>
const maxNameLen = McpToolName.MaxPrefixLen - McpToolName.Prefix.length - suffix.length;
252
>
const prefix = McpToolName.Prefix + safeName.slice(0, maxNameLen) + suffix;
253
>
254
>
return {
255
>
object: prefix,
256
>
dispose: () => {
257
>
bucket!.usedIndexes.delete(index);
258
>
bucket!.size--;
259
>
if (bucket!.size === 0) {
260
>
this._buckets.delete(safeName);
261
>
}
262
>
},
263
>
};
264
>
}
265
}
266