@eaperezc/mcpgen 0.1.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.
@@ -0,0 +1,1056 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ var async_hooks = require('async_hooks');
5
+ var crypto = require('crypto');
6
+ var pino = require('pino');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var pino__default = /*#__PURE__*/_interopDefault(pino);
11
+
12
+ // src/testing/TestClient.ts
13
+
14
+ // src/errors/McpError.ts
15
+ var McpError = class _McpError extends Error {
16
+ code;
17
+ details;
18
+ timestamp;
19
+ constructor(options) {
20
+ super(options.message);
21
+ this.name = "McpError";
22
+ this.code = options.code;
23
+ this.details = options.details;
24
+ this.timestamp = /* @__PURE__ */ new Date();
25
+ if (options.cause) {
26
+ this.cause = options.cause;
27
+ }
28
+ Error.captureStackTrace?.(this, this.constructor);
29
+ }
30
+ /**
31
+ * Convert error to a JSON-serializable object
32
+ */
33
+ toJSON() {
34
+ return {
35
+ name: this.name,
36
+ code: this.code,
37
+ message: this.message,
38
+ details: this.details,
39
+ timestamp: this.timestamp.toISOString(),
40
+ stack: this.stack
41
+ };
42
+ }
43
+ /**
44
+ * Create an error for tool not found
45
+ */
46
+ static toolNotFound(toolName) {
47
+ return new _McpError({
48
+ code: "TOOL_NOT_FOUND" /* TOOL_NOT_FOUND */,
49
+ message: `Tool '${toolName}' not found`,
50
+ details: { toolName }
51
+ });
52
+ }
53
+ /**
54
+ * Create an error for resource not found
55
+ */
56
+ static resourceNotFound(uri) {
57
+ return new _McpError({
58
+ code: "RESOURCE_NOT_FOUND" /* RESOURCE_NOT_FOUND */,
59
+ message: `Resource '${uri}' not found`,
60
+ details: { uri }
61
+ });
62
+ }
63
+ /**
64
+ * Create an error for prompt not found
65
+ */
66
+ static promptNotFound(promptName) {
67
+ return new _McpError({
68
+ code: "PROMPT_NOT_FOUND" /* PROMPT_NOT_FOUND */,
69
+ message: `Prompt '${promptName}' not found`,
70
+ details: { promptName }
71
+ });
72
+ }
73
+ /**
74
+ * Create a validation error
75
+ */
76
+ static validationError(message, details) {
77
+ return new _McpError({
78
+ code: "VALIDATION_ERROR" /* VALIDATION_ERROR */,
79
+ message,
80
+ details
81
+ });
82
+ }
83
+ /**
84
+ * Create an authentication error
85
+ */
86
+ static authError(code, message) {
87
+ return new _McpError({
88
+ code,
89
+ message
90
+ });
91
+ }
92
+ /**
93
+ * Create an internal error
94
+ */
95
+ static internal(message, cause) {
96
+ return new _McpError({
97
+ code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
98
+ message,
99
+ cause
100
+ });
101
+ }
102
+ };
103
+
104
+ // src/logging/types.ts
105
+ var LOG_LEVEL_PRIORITY = {
106
+ debug: 0,
107
+ info: 1,
108
+ warn: 2,
109
+ error: 3
110
+ };
111
+
112
+ // src/logging/Logger.ts
113
+ var Logger = class _Logger {
114
+ pino;
115
+ config;
116
+ defaultContext;
117
+ constructor(config = {}) {
118
+ this.config = {
119
+ level: config.level ?? "info",
120
+ json: config.json ?? process.env["NODE_ENV"] === "production",
121
+ timestamps: config.timestamps ?? true,
122
+ pretty: config.pretty ?? process.env["NODE_ENV"] !== "production",
123
+ defaultContext: config.defaultContext ?? {}
124
+ };
125
+ this.defaultContext = this.config.defaultContext ?? {};
126
+ this.pino = pino__default.default({
127
+ level: this.config.level,
128
+ transport: this.config.pretty ? {
129
+ target: "pino-pretty",
130
+ options: {
131
+ colorize: true,
132
+ translateTime: "SYS:standard",
133
+ ignore: "pid,hostname"
134
+ }
135
+ } : void 0,
136
+ formatters: {
137
+ level: (label) => ({ level: label })
138
+ },
139
+ timestamp: this.config.timestamps ? pino__default.default.stdTimeFunctions.isoTime : false
140
+ });
141
+ }
142
+ /**
143
+ * Check if a log level should be output
144
+ */
145
+ shouldLog(level) {
146
+ return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.config.level];
147
+ }
148
+ /**
149
+ * Create a child logger with additional context
150
+ */
151
+ child(context) {
152
+ const child = new _Logger(this.config);
153
+ child.defaultContext = { ...this.defaultContext, ...context };
154
+ child.pino = this.pino.child(context);
155
+ return child;
156
+ }
157
+ /**
158
+ * Log a debug message
159
+ */
160
+ debug(message, context) {
161
+ if (this.shouldLog("debug")) {
162
+ this.pino.debug({ ...this.defaultContext, ...context }, message);
163
+ }
164
+ }
165
+ /**
166
+ * Log an info message
167
+ */
168
+ info(message, context) {
169
+ if (this.shouldLog("info")) {
170
+ this.pino.info({ ...this.defaultContext, ...context }, message);
171
+ }
172
+ }
173
+ /**
174
+ * Log a warning message
175
+ */
176
+ warn(message, context) {
177
+ if (this.shouldLog("warn")) {
178
+ this.pino.warn({ ...this.defaultContext, ...context }, message);
179
+ }
180
+ }
181
+ /**
182
+ * Log an error message
183
+ */
184
+ error(message, error) {
185
+ if (this.shouldLog("error")) {
186
+ if (error instanceof Error) {
187
+ this.pino.error(
188
+ {
189
+ ...this.defaultContext,
190
+ err: {
191
+ message: error.message,
192
+ name: error.name,
193
+ stack: error.stack
194
+ }
195
+ },
196
+ message
197
+ );
198
+ } else {
199
+ this.pino.error({ ...this.defaultContext, ...error }, message);
200
+ }
201
+ }
202
+ }
203
+ /**
204
+ * Log with correlation ID for request tracing
205
+ */
206
+ withCorrelationId(correlationId) {
207
+ return this.child({ correlationId });
208
+ }
209
+ /**
210
+ * Set the log level
211
+ */
212
+ setLevel(level) {
213
+ this.config.level = level;
214
+ this.pino.level = level;
215
+ }
216
+ /**
217
+ * Get the current log level
218
+ */
219
+ getLevel() {
220
+ return this.config.level;
221
+ }
222
+ };
223
+ var logger = new Logger();
224
+
225
+ // src/context/RequestContext.ts
226
+ var asyncLocalStorage = new async_hooks.AsyncLocalStorage();
227
+ function createRequestContext(correlationId, logger2) {
228
+ const id = crypto.randomUUID();
229
+ const contextLogger = (logger2 ?? logger).withCorrelationId(id);
230
+ return {
231
+ correlationId: id,
232
+ startTime: /* @__PURE__ */ new Date(),
233
+ logger: contextLogger,
234
+ custom: /* @__PURE__ */ new Map()
235
+ };
236
+ }
237
+ async function runInRequestContextAsync(fn, context) {
238
+ const ctx = context ?? createRequestContext();
239
+ return asyncLocalStorage.run(ctx, fn);
240
+ }
241
+ function getRequestContext() {
242
+ return asyncLocalStorage.getStore();
243
+ }
244
+ function requireRequestContext() {
245
+ const context = getRequestContext();
246
+ if (!context) {
247
+ throw new Error("No request context available. Ensure code is running within runInRequestContext.");
248
+ }
249
+ return context;
250
+ }
251
+ function getContextLogger() {
252
+ return getRequestContext()?.logger ?? logger;
253
+ }
254
+ function setAuthContext(auth) {
255
+ const context = requireRequestContext();
256
+ context.auth = auth;
257
+ }
258
+
259
+ // src/tools/BaseTool.ts
260
+ var BaseTool = class {
261
+ /** Required scopes for this tool (optional) */
262
+ scopes = [];
263
+ /**
264
+ * Validate and execute the tool
265
+ */
266
+ async run(input) {
267
+ const logger2 = getContextLogger();
268
+ const parseResult = this.schema.safeParse(input);
269
+ if (!parseResult.success) {
270
+ const errors = parseResult.error.errors.map((e) => ({
271
+ path: e.path.join("."),
272
+ message: e.message
273
+ }));
274
+ logger2.warn("Tool input validation failed", {
275
+ tool: this.name,
276
+ errors
277
+ });
278
+ throw new McpError({
279
+ code: "TOOL_VALIDATION_ERROR" /* TOOL_VALIDATION_ERROR */,
280
+ message: `Invalid input for tool '${this.name}'`,
281
+ details: { errors }
282
+ });
283
+ }
284
+ try {
285
+ logger2.debug("Executing tool", { tool: this.name });
286
+ const result = await this.execute(parseResult.data);
287
+ logger2.debug("Tool executed successfully", { tool: this.name });
288
+ return result;
289
+ } catch (error) {
290
+ if (error instanceof McpError) {
291
+ throw error;
292
+ }
293
+ logger2.error("Tool execution failed", error instanceof Error ? error : void 0);
294
+ throw new McpError({
295
+ code: "TOOL_EXECUTION_ERROR" /* TOOL_EXECUTION_ERROR */,
296
+ message: `Tool '${this.name}' execution failed: ${error instanceof Error ? error.message : "Unknown error"}`,
297
+ cause: error instanceof Error ? error : void 0
298
+ });
299
+ }
300
+ }
301
+ /**
302
+ * Get tool metadata for registration
303
+ */
304
+ getMetadata() {
305
+ return {
306
+ name: this.name,
307
+ description: this.description,
308
+ inputSchema: this.schema,
309
+ scopes: this.scopes
310
+ };
311
+ }
312
+ /**
313
+ * Convert schema to JSON Schema format for MCP protocol
314
+ */
315
+ getJsonSchema() {
316
+ return zodToJsonSchema(this.schema);
317
+ }
318
+ };
319
+ function zodToJsonSchema(schema) {
320
+ const def = schema._def;
321
+ const typeName = def.typeName;
322
+ if (typeName === "ZodObject") {
323
+ const shape = schema.shape;
324
+ const properties = {};
325
+ const required = [];
326
+ for (const [key, value] of Object.entries(shape)) {
327
+ const zodValue = value;
328
+ properties[key] = zodToJsonSchema(zodValue);
329
+ if (!zodValue.isOptional()) {
330
+ required.push(key);
331
+ }
332
+ }
333
+ return {
334
+ type: "object",
335
+ properties,
336
+ required: required.length > 0 ? required : void 0
337
+ };
338
+ }
339
+ if (typeName === "ZodString") {
340
+ const result = { type: "string" };
341
+ if (def.description) result["description"] = def.description;
342
+ return result;
343
+ }
344
+ if (typeName === "ZodNumber") {
345
+ const result = { type: "number" };
346
+ if (def.description) result["description"] = def.description;
347
+ return result;
348
+ }
349
+ if (typeName === "ZodBoolean") {
350
+ const result = { type: "boolean" };
351
+ if (def.description) result["description"] = def.description;
352
+ return result;
353
+ }
354
+ if (typeName === "ZodArray") {
355
+ return {
356
+ type: "array",
357
+ items: zodToJsonSchema(def.type)
358
+ };
359
+ }
360
+ if (typeName === "ZodOptional") {
361
+ return zodToJsonSchema(def.innerType);
362
+ }
363
+ if (typeName === "ZodDefault") {
364
+ const inner = zodToJsonSchema(def.innerType);
365
+ return { ...inner, default: def.defaultValue() };
366
+ }
367
+ return {};
368
+ }
369
+
370
+ // src/tools/registry.ts
371
+ var InlineTool = class extends BaseTool {
372
+ name;
373
+ description;
374
+ schema;
375
+ scopes;
376
+ handler;
377
+ constructor(name, definition) {
378
+ super();
379
+ this.name = name;
380
+ this.description = definition.description;
381
+ this.schema = definition.schema;
382
+ this.scopes = definition.scopes ?? [];
383
+ this.handler = definition.handler;
384
+ }
385
+ async execute(input) {
386
+ return this.handler(input);
387
+ }
388
+ };
389
+ var ToolRegistry = class {
390
+ tools = /* @__PURE__ */ new Map();
391
+ /**
392
+ * Register a tool instance
393
+ */
394
+ register(tool) {
395
+ if (this.tools.has(tool.name)) {
396
+ throw new McpError({
397
+ code: "TOOL_ALREADY_REGISTERED" /* TOOL_ALREADY_REGISTERED */,
398
+ message: `Tool '${tool.name}' is already registered`,
399
+ details: { toolName: tool.name }
400
+ });
401
+ }
402
+ this.tools.set(tool.name, tool);
403
+ }
404
+ /**
405
+ * Register an inline tool definition
406
+ */
407
+ registerInline(name, definition) {
408
+ const tool = new InlineTool(name, definition);
409
+ this.register(tool);
410
+ }
411
+ /**
412
+ * Get a tool by name
413
+ */
414
+ get(name) {
415
+ return this.tools.get(name);
416
+ }
417
+ /**
418
+ * Get a tool by name or throw if not found
419
+ */
420
+ getOrThrow(name) {
421
+ const tool = this.tools.get(name);
422
+ if (!tool) {
423
+ throw McpError.toolNotFound(name);
424
+ }
425
+ return tool;
426
+ }
427
+ /**
428
+ * Check if a tool exists
429
+ */
430
+ has(name) {
431
+ return this.tools.has(name);
432
+ }
433
+ /**
434
+ * Remove a tool
435
+ */
436
+ remove(name) {
437
+ return this.tools.delete(name);
438
+ }
439
+ /**
440
+ * Get all registered tools
441
+ */
442
+ getAll() {
443
+ return Array.from(this.tools.values());
444
+ }
445
+ /**
446
+ * Get all tool names
447
+ */
448
+ getNames() {
449
+ return Array.from(this.tools.keys());
450
+ }
451
+ /**
452
+ * Get the number of registered tools
453
+ */
454
+ get size() {
455
+ return this.tools.size;
456
+ }
457
+ /**
458
+ * Clear all tools
459
+ */
460
+ clear() {
461
+ this.tools.clear();
462
+ }
463
+ };
464
+
465
+ // src/resources/BaseResource.ts
466
+ var BaseResource = class {
467
+ /** Description of the resource */
468
+ description;
469
+ /** MIME type of the resource content */
470
+ mimeType = "text/plain";
471
+ /** Required scopes for this resource (optional) */
472
+ scopes = [];
473
+ /**
474
+ * Safely read the resource with error handling
475
+ */
476
+ async safeRead() {
477
+ const logger2 = getContextLogger();
478
+ try {
479
+ logger2.debug("Reading resource", { uri: this.uri });
480
+ const result = await this.read();
481
+ logger2.debug("Resource read successfully", { uri: this.uri });
482
+ return result;
483
+ } catch (error) {
484
+ if (error instanceof McpError) {
485
+ throw error;
486
+ }
487
+ logger2.error("Resource read failed", error instanceof Error ? error : void 0);
488
+ throw new McpError({
489
+ code: "RESOURCE_READ_ERROR" /* RESOURCE_READ_ERROR */,
490
+ message: `Failed to read resource '${this.uri}': ${error instanceof Error ? error.message : "Unknown error"}`,
491
+ cause: error instanceof Error ? error : void 0,
492
+ details: { uri: this.uri }
493
+ });
494
+ }
495
+ }
496
+ /**
497
+ * Get resource metadata for registration
498
+ */
499
+ getMetadata() {
500
+ return {
501
+ uri: this.uri,
502
+ name: this.name,
503
+ description: this.description,
504
+ mimeType: this.mimeType,
505
+ scopes: this.scopes
506
+ };
507
+ }
508
+ /**
509
+ * Helper to create text content
510
+ */
511
+ text(content) {
512
+ return { type: "text", text: content };
513
+ }
514
+ /**
515
+ * Helper to create JSON content
516
+ */
517
+ json(data) {
518
+ return { type: "text", text: JSON.stringify(data, null, 2) };
519
+ }
520
+ /**
521
+ * Helper to create blob content
522
+ */
523
+ blob(data, mimeType) {
524
+ return { type: "blob", data, mimeType };
525
+ }
526
+ };
527
+
528
+ // src/resources/registry.ts
529
+ var InlineResource = class extends BaseResource {
530
+ uri;
531
+ name;
532
+ description;
533
+ mimeType;
534
+ scopes;
535
+ handler;
536
+ constructor(uri, definition) {
537
+ super();
538
+ this.uri = uri;
539
+ this.name = definition.name;
540
+ this.description = definition.description;
541
+ this.mimeType = definition.mimeType;
542
+ this.scopes = definition.scopes ?? [];
543
+ this.handler = definition.read;
544
+ }
545
+ async read() {
546
+ return this.handler();
547
+ }
548
+ };
549
+ var ResourceRegistry = class {
550
+ resources = /* @__PURE__ */ new Map();
551
+ /**
552
+ * Register a resource instance
553
+ */
554
+ register(resource) {
555
+ if (this.resources.has(resource.uri)) {
556
+ throw new McpError({
557
+ code: "RESOURCE_ALREADY_REGISTERED" /* RESOURCE_ALREADY_REGISTERED */,
558
+ message: `Resource '${resource.uri}' is already registered`,
559
+ details: { uri: resource.uri }
560
+ });
561
+ }
562
+ this.resources.set(resource.uri, resource);
563
+ }
564
+ /**
565
+ * Register an inline resource definition
566
+ */
567
+ registerInline(uri, definition) {
568
+ const resource = new InlineResource(uri, definition);
569
+ this.register(resource);
570
+ }
571
+ /**
572
+ * Get a resource by URI
573
+ */
574
+ get(uri) {
575
+ return this.resources.get(uri);
576
+ }
577
+ /**
578
+ * Get a resource by URI or throw if not found
579
+ */
580
+ getOrThrow(uri) {
581
+ const resource = this.resources.get(uri);
582
+ if (!resource) {
583
+ throw McpError.resourceNotFound(uri);
584
+ }
585
+ return resource;
586
+ }
587
+ /**
588
+ * Check if a resource exists
589
+ */
590
+ has(uri) {
591
+ return this.resources.has(uri);
592
+ }
593
+ /**
594
+ * Remove a resource
595
+ */
596
+ remove(uri) {
597
+ return this.resources.delete(uri);
598
+ }
599
+ /**
600
+ * Get all registered resources
601
+ */
602
+ getAll() {
603
+ return Array.from(this.resources.values());
604
+ }
605
+ /**
606
+ * Get all resource URIs
607
+ */
608
+ getUris() {
609
+ return Array.from(this.resources.keys());
610
+ }
611
+ /**
612
+ * Get the number of registered resources
613
+ */
614
+ get size() {
615
+ return this.resources.size;
616
+ }
617
+ /**
618
+ * Clear all resources
619
+ */
620
+ clear() {
621
+ this.resources.clear();
622
+ }
623
+ };
624
+
625
+ // src/prompts/BasePrompt.ts
626
+ var BasePrompt = class {
627
+ /** Human-readable description */
628
+ description;
629
+ /** Zod schema for arguments validation */
630
+ arguments;
631
+ /** Required scopes for this prompt (optional) */
632
+ scopes = [];
633
+ /**
634
+ * Validate arguments and render the prompt
635
+ */
636
+ async safeRender(args) {
637
+ const logger2 = getContextLogger();
638
+ if (this.arguments) {
639
+ const parseResult = this.arguments.safeParse(args);
640
+ if (!parseResult.success) {
641
+ const errors = parseResult.error.errors.map((e) => ({
642
+ path: e.path.join("."),
643
+ message: e.message
644
+ }));
645
+ logger2.warn("Prompt argument validation failed", {
646
+ prompt: this.name,
647
+ errors
648
+ });
649
+ throw new McpError({
650
+ code: "VALIDATION_ERROR" /* VALIDATION_ERROR */,
651
+ message: `Invalid arguments for prompt '${this.name}'`,
652
+ details: { errors }
653
+ });
654
+ }
655
+ args = parseResult.data;
656
+ }
657
+ try {
658
+ logger2.debug("Rendering prompt", { prompt: this.name });
659
+ const result = await this.render(args);
660
+ logger2.debug("Prompt rendered successfully", { prompt: this.name });
661
+ return result;
662
+ } catch (error) {
663
+ if (error instanceof McpError) {
664
+ throw error;
665
+ }
666
+ logger2.error("Prompt render failed", error instanceof Error ? error : void 0);
667
+ throw new McpError({
668
+ code: "PROMPT_RENDER_ERROR" /* PROMPT_RENDER_ERROR */,
669
+ message: `Failed to render prompt '${this.name}': ${error instanceof Error ? error.message : "Unknown error"}`,
670
+ cause: error instanceof Error ? error : void 0,
671
+ details: { promptName: this.name }
672
+ });
673
+ }
674
+ }
675
+ /**
676
+ * Get prompt metadata for registration
677
+ */
678
+ getMetadata() {
679
+ return {
680
+ name: this.name,
681
+ description: this.description,
682
+ arguments: this.getArgumentsMetadata(),
683
+ scopes: this.scopes
684
+ };
685
+ }
686
+ /**
687
+ * Get arguments metadata from schema
688
+ */
689
+ getArgumentsMetadata() {
690
+ if (!this.arguments) return [];
691
+ const def = this.arguments._def;
692
+ if (def.typeName !== "ZodObject") return [];
693
+ const shape = this.arguments.shape;
694
+ const result = [];
695
+ for (const [name, value] of Object.entries(shape)) {
696
+ const zodValue = value;
697
+ const zodDef = zodValue._def;
698
+ result.push({
699
+ name,
700
+ description: zodDef.description,
701
+ required: !zodValue.isOptional()
702
+ });
703
+ }
704
+ return result;
705
+ }
706
+ /**
707
+ * Helper to create a user message
708
+ */
709
+ user(content) {
710
+ return { role: "user", content };
711
+ }
712
+ /**
713
+ * Helper to create an assistant message
714
+ */
715
+ assistant(content) {
716
+ return { role: "assistant", content };
717
+ }
718
+ };
719
+
720
+ // src/prompts/registry.ts
721
+ var InlinePrompt = class extends BasePrompt {
722
+ name;
723
+ description;
724
+ arguments;
725
+ scopes;
726
+ handler;
727
+ constructor(name, definition) {
728
+ super();
729
+ this.name = name;
730
+ this.description = definition.description;
731
+ this.arguments = definition.arguments;
732
+ this.scopes = definition.scopes ?? [];
733
+ this.handler = definition.render;
734
+ }
735
+ async render(args) {
736
+ return this.handler(args);
737
+ }
738
+ };
739
+ var PromptRegistry = class {
740
+ prompts = /* @__PURE__ */ new Map();
741
+ /**
742
+ * Register a prompt instance
743
+ */
744
+ register(prompt) {
745
+ if (this.prompts.has(prompt.name)) {
746
+ throw new McpError({
747
+ code: "PROMPT_ALREADY_REGISTERED" /* PROMPT_ALREADY_REGISTERED */,
748
+ message: `Prompt '${prompt.name}' is already registered`,
749
+ details: { promptName: prompt.name }
750
+ });
751
+ }
752
+ this.prompts.set(prompt.name, prompt);
753
+ }
754
+ /**
755
+ * Register an inline prompt definition
756
+ */
757
+ registerInline(name, definition) {
758
+ const prompt = new InlinePrompt(name, definition);
759
+ this.register(prompt);
760
+ }
761
+ /**
762
+ * Get a prompt by name
763
+ */
764
+ get(name) {
765
+ return this.prompts.get(name);
766
+ }
767
+ /**
768
+ * Get a prompt by name or throw if not found
769
+ */
770
+ getOrThrow(name) {
771
+ const prompt = this.prompts.get(name);
772
+ if (!prompt) {
773
+ throw McpError.promptNotFound(name);
774
+ }
775
+ return prompt;
776
+ }
777
+ /**
778
+ * Check if a prompt exists
779
+ */
780
+ has(name) {
781
+ return this.prompts.has(name);
782
+ }
783
+ /**
784
+ * Remove a prompt
785
+ */
786
+ remove(name) {
787
+ return this.prompts.delete(name);
788
+ }
789
+ /**
790
+ * Get all registered prompts
791
+ */
792
+ getAll() {
793
+ return Array.from(this.prompts.values());
794
+ }
795
+ /**
796
+ * Get all prompt names
797
+ */
798
+ getNames() {
799
+ return Array.from(this.prompts.keys());
800
+ }
801
+ /**
802
+ * Get the number of registered prompts
803
+ */
804
+ get size() {
805
+ return this.prompts.size;
806
+ }
807
+ /**
808
+ * Clear all prompts
809
+ */
810
+ clear() {
811
+ this.prompts.clear();
812
+ }
813
+ };
814
+
815
+ // src/testing/TestClient.ts
816
+ var MockTool = class extends BaseTool {
817
+ name;
818
+ description;
819
+ schema = zod.z.object({}).passthrough();
820
+ response;
821
+ error;
822
+ customHandler;
823
+ constructor(config) {
824
+ super();
825
+ this.name = config.name;
826
+ this.description = config.description ?? `Mock tool: ${config.name}`;
827
+ this.response = config.response;
828
+ this.error = config.error;
829
+ this.customHandler = config.handler;
830
+ }
831
+ async execute(input) {
832
+ if (this.error) {
833
+ throw this.error;
834
+ }
835
+ if (this.customHandler) {
836
+ const result = await this.customHandler(input);
837
+ return { content: result };
838
+ }
839
+ return { content: this.response ?? { success: true } };
840
+ }
841
+ };
842
+ var MockResource = class extends BaseResource {
843
+ uri;
844
+ name;
845
+ content;
846
+ error;
847
+ customHandler;
848
+ constructor(config) {
849
+ super();
850
+ this.uri = config.uri;
851
+ this.name = config.name ?? `Mock resource: ${config.uri}`;
852
+ this.content = config.content;
853
+ this.error = config.error;
854
+ this.customHandler = config.handler;
855
+ }
856
+ async read() {
857
+ if (this.error) {
858
+ throw this.error;
859
+ }
860
+ if (this.customHandler) {
861
+ const result = await this.customHandler();
862
+ const text2 = typeof result === "string" ? result : JSON.stringify(result);
863
+ return { contents: [{ type: "text", text: text2 }] };
864
+ }
865
+ const text = typeof this.content === "string" ? this.content : JSON.stringify(this.content ?? {});
866
+ return { contents: [{ type: "text", text }] };
867
+ }
868
+ };
869
+ var MockPrompt = class extends BasePrompt {
870
+ name;
871
+ description;
872
+ arguments = zod.z.object({}).passthrough();
873
+ messages;
874
+ error;
875
+ customHandler;
876
+ constructor(config) {
877
+ super();
878
+ this.name = config.name;
879
+ this.description = config.description;
880
+ this.messages = config.messages;
881
+ this.error = config.error;
882
+ this.customHandler = config.handler;
883
+ }
884
+ async render(args) {
885
+ if (this.error) {
886
+ throw this.error;
887
+ }
888
+ if (this.customHandler) {
889
+ return this.customHandler(args);
890
+ }
891
+ return {
892
+ messages: this.messages ?? [{ role: "user", content: "Mock prompt" }]
893
+ };
894
+ }
895
+ };
896
+ var TestClient = class _TestClient {
897
+ toolRegistry = new ToolRegistry();
898
+ resourceRegistry = new ResourceRegistry();
899
+ promptRegistry = new PromptRegistry();
900
+ config;
901
+ logger;
902
+ constructor(config = {}) {
903
+ this.config = config;
904
+ this.logger = new Logger({
905
+ level: config.debug ? "debug" : "error",
906
+ pretty: true
907
+ });
908
+ }
909
+ /**
910
+ * Create a test client from an existing McpServer
911
+ */
912
+ static fromServer(server, config) {
913
+ const client = new _TestClient(config);
914
+ for (const tool of server.getToolRegistry().getAll()) {
915
+ client.toolRegistry.register(tool);
916
+ }
917
+ for (const resource of server.getResourceRegistry().getAll()) {
918
+ client.resourceRegistry.register(resource);
919
+ }
920
+ for (const prompt of server.getPromptRegistry().getAll()) {
921
+ client.promptRegistry.register(prompt);
922
+ }
923
+ return client;
924
+ }
925
+ /**
926
+ * Register a tool for testing
927
+ */
928
+ registerTool(tool) {
929
+ this.toolRegistry.register(tool);
930
+ return this;
931
+ }
932
+ /**
933
+ * Register a resource for testing
934
+ */
935
+ registerResource(resource) {
936
+ this.resourceRegistry.register(resource);
937
+ return this;
938
+ }
939
+ /**
940
+ * Register a prompt for testing
941
+ */
942
+ registerPrompt(prompt) {
943
+ this.promptRegistry.register(prompt);
944
+ return this;
945
+ }
946
+ /**
947
+ * Register a mock tool
948
+ */
949
+ mockTool(config) {
950
+ this.toolRegistry.register(new MockTool(config));
951
+ return this;
952
+ }
953
+ /**
954
+ * Register a mock resource
955
+ */
956
+ mockResource(config) {
957
+ this.resourceRegistry.register(new MockResource(config));
958
+ return this;
959
+ }
960
+ /**
961
+ * Register a mock prompt
962
+ */
963
+ mockPrompt(config) {
964
+ this.promptRegistry.register(new MockPrompt(config));
965
+ return this;
966
+ }
967
+ /**
968
+ * Call a tool
969
+ */
970
+ async callTool(name, input) {
971
+ return runInRequestContextAsync(async () => {
972
+ if (this.config.auth) {
973
+ setAuthContext(this.config.auth);
974
+ }
975
+ const tool = this.toolRegistry.getOrThrow(name);
976
+ return tool.run(input ?? {});
977
+ }, createRequestContext(void 0, this.logger));
978
+ }
979
+ /**
980
+ * Read a resource
981
+ */
982
+ async readResource(uri) {
983
+ return runInRequestContextAsync(async () => {
984
+ if (this.config.auth) {
985
+ setAuthContext(this.config.auth);
986
+ }
987
+ const resource = this.resourceRegistry.getOrThrow(uri);
988
+ return resource.safeRead();
989
+ }, createRequestContext(void 0, this.logger));
990
+ }
991
+ /**
992
+ * Render a prompt
993
+ */
994
+ async renderPrompt(name, args) {
995
+ return runInRequestContextAsync(async () => {
996
+ if (this.config.auth) {
997
+ setAuthContext(this.config.auth);
998
+ }
999
+ const prompt = this.promptRegistry.getOrThrow(name);
1000
+ return prompt.safeRender(args ?? {});
1001
+ }, createRequestContext(void 0, this.logger));
1002
+ }
1003
+ /**
1004
+ * List all registered tools
1005
+ */
1006
+ listTools() {
1007
+ return this.toolRegistry.getNames();
1008
+ }
1009
+ /**
1010
+ * List all registered resources
1011
+ */
1012
+ listResources() {
1013
+ return this.resourceRegistry.getUris();
1014
+ }
1015
+ /**
1016
+ * List all registered prompts
1017
+ */
1018
+ listPrompts() {
1019
+ return this.promptRegistry.getNames();
1020
+ }
1021
+ /**
1022
+ * Check if a tool exists
1023
+ */
1024
+ hasTool(name) {
1025
+ return this.toolRegistry.has(name);
1026
+ }
1027
+ /**
1028
+ * Check if a resource exists
1029
+ */
1030
+ hasResource(uri) {
1031
+ return this.resourceRegistry.has(uri);
1032
+ }
1033
+ /**
1034
+ * Check if a prompt exists
1035
+ */
1036
+ hasPrompt(name) {
1037
+ return this.promptRegistry.has(name);
1038
+ }
1039
+ /**
1040
+ * Clear all registered items
1041
+ */
1042
+ clear() {
1043
+ this.toolRegistry.clear();
1044
+ this.resourceRegistry.clear();
1045
+ this.promptRegistry.clear();
1046
+ return this;
1047
+ }
1048
+ };
1049
+ function createTestClient(config) {
1050
+ return new TestClient(config);
1051
+ }
1052
+
1053
+ exports.TestClient = TestClient;
1054
+ exports.createTestClient = createTestClient;
1055
+ //# sourceMappingURL=index.cjs.map
1056
+ //# sourceMappingURL=index.cjs.map