tmcp 1.10.2 → 1.11.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 CHANGED
@@ -249,6 +249,67 @@ Send notifications for subscriptions.
249
249
  server.changed('resource', 'file://path/to/resource');
250
250
  ```
251
251
 
252
+ ##### `progress(progress, total?, message?)`
253
+
254
+ Report progress during long-running operations. Progress notifications are only sent when a progress token is provided by the client in the request's `_meta.progressToken` field.
255
+
256
+ ```javascript
257
+ server.tool(
258
+ {
259
+ name: 'process-large-file',
260
+ description: 'Process a large file with progress updates',
261
+ },
262
+ async (input) => {
263
+ const totalSteps = 100;
264
+
265
+ for (let i = 0; i <= totalSteps; i++) {
266
+ // Report progress with current step, total steps, and optional message
267
+ server.progress(
268
+ i,
269
+ totalSteps,
270
+ `Processing step ${i}/${totalSteps}`,
271
+ );
272
+
273
+ // Simulate work
274
+ await processStep(i);
275
+ }
276
+
277
+ return {
278
+ content: [{ type: 'text', text: 'Processing complete!' }],
279
+ };
280
+ },
281
+ );
282
+ ```
283
+
284
+ **Parameters:**
285
+
286
+ - `progress` (number): Current progress value (should be ≤ total and always increase)
287
+ - `total` (number, optional): Maximum progress value (defaults to 1)
288
+ - `message` (string, optional): Descriptive message about current progress
289
+
290
+ **Notes:**
291
+
292
+ - Progress notifications are only sent when the client provides a `progressToken` in the request
293
+ - Progress values should be monotonically increasing within a single operation
294
+ - Each session maintains its own progress context
295
+
296
+ ##### `log(level, data, logger?)`
297
+
298
+ Send log messages to connected clients when logging is enabled.
299
+
300
+ ```javascript
301
+ // Log at different severity levels
302
+ server.log('info', 'Server started successfully');
303
+ server.log('warning', 'Configuration missing, using defaults');
304
+ server.log('error', 'Failed to connect to database', 'database-logger');
305
+ ```
306
+
307
+ **Parameters:**
308
+
309
+ - `level` (string): Log level ('debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency')
310
+ - `data` (any): Data to log
311
+ - `logger` (string, optional): Logger name/category
312
+
252
313
  ##### `on(event, callback)`
253
314
 
254
315
  Listen to server events.
@@ -265,6 +326,94 @@ server.on('send', ({ request, context }) => {
265
326
 
266
327
  ## Advanced Examples
267
328
 
329
+ ### Progress Reporting
330
+
331
+ Provide real-time progress updates for long-running operations:
332
+
333
+ ```javascript
334
+ server.tool(
335
+ {
336
+ name: 'analyze-codebase',
337
+ description: 'Analyze a large codebase with progress tracking',
338
+ schema: z.object({
339
+ path: z.string(),
340
+ includeTests: z.boolean().default(false),
341
+ }),
342
+ },
343
+ async ({ path, includeTests }) => {
344
+ // Discover files to analyze
345
+ const files = await discoverFiles(path, includeTests);
346
+ const totalFiles = files.length;
347
+
348
+ server.progress(0, totalFiles, 'Starting analysis...');
349
+
350
+ const results = [];
351
+ for (let i = 0; i < files.length; i++) {
352
+ const file = files[i];
353
+
354
+ // Update progress with current file being processed
355
+ server.progress(
356
+ i + 1,
357
+ totalFiles,
358
+ `Analyzing ${file} (${i + 1}/${totalFiles})`,
359
+ );
360
+
361
+ // Analyze the file
362
+ const analysis = await analyzeFile(file);
363
+ results.push(analysis);
364
+ }
365
+
366
+ // Final progress update
367
+ server.progress(totalFiles, totalFiles, 'Analysis complete!');
368
+
369
+ return {
370
+ content: [
371
+ {
372
+ type: 'text',
373
+ text: `Analyzed ${totalFiles} files. Found ${results.length} issues.`,
374
+ },
375
+ ],
376
+ structuredContent: {
377
+ totalFiles,
378
+ results,
379
+ issues: results.length,
380
+ },
381
+ };
382
+ },
383
+ );
384
+
385
+ // Progress also works in prompts and resources
386
+ server.prompt(
387
+ {
388
+ name: 'generate-report',
389
+ description: 'Generate a comprehensive report',
390
+ schema: z.object({
391
+ sections: z.array(z.string()),
392
+ }),
393
+ },
394
+ async ({ sections }) => {
395
+ const messages = [];
396
+
397
+ for (let i = 0; i < sections.length; i++) {
398
+ server.progress(
399
+ i,
400
+ sections.length,
401
+ `Generating section: ${sections[i]}`,
402
+ );
403
+
404
+ const content = await generateSection(sections[i]);
405
+ messages.push({
406
+ role: 'user',
407
+ content: { type: 'text', text: content },
408
+ });
409
+ }
410
+
411
+ server.progress(sections.length, sections.length, 'Report complete');
412
+ return { messages };
413
+ },
414
+ );
415
+ ```
416
+
268
417
  ### Client Interaction Features
269
418
 
270
419
  ```javascript
@@ -625,6 +774,232 @@ server.tool(
625
774
  );
626
775
  ```
627
776
 
777
+ ## Dynamic Enabling/Disabling
778
+
779
+ All MCP capabilities (tools, prompts, resources, templates) support dynamic enabling and disabling through the `enabled` function. This allows you to conditionally show or hide capabilities based on runtime conditions, user permissions, or any other logic.
780
+
781
+ ### Basic Usage
782
+
783
+ The `enabled` function is called before each list operation and determines whether the capability should be included in the response:
784
+
785
+ ```javascript
786
+ server.tool(
787
+ {
788
+ name: 'admin-only-tool',
789
+ description: 'Administrative tool',
790
+ enabled: () => {
791
+ // Only show this tool if user is admin
792
+ return getCurrentUser().isAdmin;
793
+ },
794
+ },
795
+ async (input) => {
796
+ return { content: [{ type: 'text', text: 'Admin action completed' }] };
797
+ },
798
+ );
799
+ ```
800
+
801
+ ### Async Enabled Functions
802
+
803
+ The `enabled` function can be synchronous or asynchronous:
804
+
805
+ ```javascript
806
+ server.resource(
807
+ {
808
+ name: 'private-document',
809
+ description: 'Access private documents',
810
+ uri: 'private://document.txt',
811
+ enabled: async () => {
812
+ // Check permissions asynchronously
813
+ const user = await getCurrentUser();
814
+ return await hasPermission(user.id, 'read-private-docs');
815
+ },
816
+ },
817
+ async (uri) => {
818
+ return {
819
+ contents: [
820
+ {
821
+ uri,
822
+ mimeType: 'text/plain',
823
+ text: await readPrivateDocument(uri),
824
+ },
825
+ ],
826
+ };
827
+ },
828
+ );
829
+ ```
830
+
831
+ ### Context-Aware Enabling
832
+
833
+ Within the `enabled` function you can read the session context with `server.ctx`, allowing for user-specific or session-specific logic:
834
+
835
+ ```javascript
836
+ server.prompt(
837
+ {
838
+ name: 'personalized-prompt',
839
+ description: 'User-specific prompt template',
840
+ enabled: () => {
841
+ // Access session information
842
+ const sessionId = server.ctx.sessionId;
843
+ const userPrefs = getUserPreferences(sessionId);
844
+ return userPrefs.enablePersonalization;
845
+ },
846
+ },
847
+ async (input) => {
848
+ return {
849
+ messages: [
850
+ {
851
+ role: 'user',
852
+ content: { type: 'text', text: 'Personalized content...' },
853
+ },
854
+ ],
855
+ };
856
+ },
857
+ );
858
+ ```
859
+
860
+ or enable a something based on client capabilities or info
861
+
862
+ ```javascript
863
+ server.prompt(
864
+ {
865
+ name: 'personalized-prompt',
866
+ description: 'Claude Code prompt',
867
+ enabled: () => {
868
+ // Access session information
869
+ const clientInfo = server.currentClientInfo();
870
+ return clientInfo.name === 'Claude Code';
871
+ },
872
+ },
873
+ async (input) => {
874
+ return {
875
+ messages: [
876
+ {
877
+ role: 'user',
878
+ content: { type: 'text', text: 'Personalized content...' },
879
+ },
880
+ ],
881
+ };
882
+ },
883
+ );
884
+ ```
885
+
886
+ or
887
+
888
+ ```javascript
889
+ server.prompt(
890
+ {
891
+ name: 'fetch-repositories',
892
+ description: 'fetch the repositories of the user',
893
+ enabled: () => {
894
+ // Access session information
895
+ const clientInfo = server.currentClientCapabilities();
896
+ return clientInfo.elicitation != null;
897
+ },
898
+ },
899
+ async (input) => {
900
+ const username = await server.elicitation(
901
+ v.object({
902
+ value: v.string(),
903
+ }),
904
+ );
905
+ const repos = await fetchRepos(username.value);
906
+ return {
907
+ messages: [
908
+ {
909
+ role: 'user',
910
+ content: {
911
+ type: 'text',
912
+ text: `Your repositories are ${repos.join(', ')}`,
913
+ },
914
+ },
915
+ ],
916
+ };
917
+ },
918
+ );
919
+ ```
920
+
921
+ ### Template Enabling
922
+
923
+ URI templates also support the `enabled` function:
924
+
925
+ ```javascript
926
+ server.template(
927
+ {
928
+ name: 'user-files',
929
+ description: 'Access user-specific files',
930
+ uri: 'users/{userId}/files/{filename}',
931
+ enabled: async () => {
932
+ // Check if file system is available
933
+ return await isFileSystemMounted();
934
+ },
935
+ complete: {
936
+ userId: (arg, context) => ({
937
+ completion: {
938
+ values: ['user1', 'user2', 'user3'],
939
+ total: 3,
940
+ hasMore: false,
941
+ },
942
+ }),
943
+ },
944
+ },
945
+ async (uri, params) => {
946
+ const content = await readUserFile(params.userId, params.filename);
947
+ return {
948
+ contents: [
949
+ {
950
+ uri,
951
+ mimeType: 'text/plain',
952
+ text: content,
953
+ },
954
+ ],
955
+ };
956
+ },
957
+ );
958
+ ```
959
+
960
+ ### Error Handling
961
+
962
+ If an `enabled` function throws an error, the capability will be treated as disabled:
963
+
964
+ ```javascript
965
+ server.tool(
966
+ {
967
+ name: 'network-tool',
968
+ description: 'Tool requiring network access',
969
+ enabled: () => {
970
+ // If network check fails, tool is disabled
971
+ if (!checkNetworkConnection()) {
972
+ throw new Error('Network unavailable');
973
+ }
974
+ return true;
975
+ },
976
+ },
977
+ async (input) => {
978
+ return {
979
+ content: [{ type: 'text', text: 'Network operation completed' }],
980
+ };
981
+ },
982
+ );
983
+ ```
984
+
985
+ ### Performance Considerations
986
+
987
+ - The `enabled` function is called every time a list is requested
988
+ - Keep enabled functions lightweight to avoid performance issues
989
+ - Consider caching expensive checks when possible
990
+ - Async functions add latency to list operations
991
+
992
+ ### Use Cases
993
+
994
+ Common scenarios where `enabled` functions are useful:
995
+
996
+ 1. **Permission-based access**: Show tools only to authorized users
997
+ 2. **Feature flags**: Enable/disable features based on configuration
998
+ 3. **Resource availability**: Hide resources when underlying systems are unavailable
999
+ 4. **User preferences**: Customize available capabilities per user
1000
+ 5. **Time-based access**: Enable tools only during specific hours
1001
+ 6. **License restrictions**: Limit features based on subscription level
1002
+
628
1003
  ## Contributing
629
1004
 
630
1005
  Contributions are welcome! Please see our [contributing guidelines](../../CONTRIBUTING.md) for details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmcp",
3
- "version": "1.10.2",
3
+ "version": "1.11.0",
4
4
  "description": "The main tmcp library",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -1,9 +1,10 @@
1
+ /* eslint-disable jsdoc/no-undefined-types */
1
2
  /**
2
3
  * @import { StandardSchemaV1 } from "@standard-schema/spec";
3
4
  * @import SqidsType from "sqids";
4
5
  * @import { JSONRPCRequest, JSONRPCParams } from "json-rpc-2.0";
5
6
  * @import { ExtractURITemplateVariables } from "./internal/uri-template.js";
6
- * @import { CallToolResult, ReadResourceResult, GetPromptResult, ClientCapabilities as ClientCapabilitiesType, JSONRPCRequest as JSONRPCRequestType, JSONRPCResponse, CreateMessageRequestParams, CreateMessageResult, Resource, LoggingLevel, ToolAnnotations } from "./validation/index.js";
7
+ * @import { CallToolResult, ReadResourceResult, GetPromptResult, ClientCapabilities as ClientCapabilitiesType, JSONRPCRequest as JSONRPCRequestType, JSONRPCResponse, CreateMessageRequestParams, CreateMessageResult, Resource, LoggingLevel, ToolAnnotations, ClientInfo } from "./validation/index.js";
7
8
  * @import { Tool, Completion, Prompt, StoredResource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents } from "./internal/internal.js";
8
9
  */
9
10
  import { JSONRPCClient, JSONRPCServer } from 'json-rpc-2.0';
@@ -43,9 +44,11 @@ import { should_version_negotiation_fail } from './validation/version.js';
43
44
  */
44
45
 
45
46
  /**
47
+ * @template {Record<string, unknown> | undefined} [TCustom=undefined]
46
48
  * @typedef {Object} Context
47
49
  * @property {string} [sessionId]
48
50
  * @property {AuthInfo} [auth]
51
+ * @property {TCustom} [custom]
49
52
  */
50
53
 
51
54
  /**
@@ -77,12 +80,24 @@ async function decode_cursor(cursor) {
77
80
  return decoded;
78
81
  }
79
82
 
83
+ /**
84
+ * @param {()=>boolean | Promise<boolean>} enabled
85
+ */
86
+ async function safe_enabled(enabled) {
87
+ try {
88
+ return await enabled();
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
80
94
  /**
81
95
  * @typedef {ClientCapabilitiesType} ClientCapabilities
82
96
  */
83
97
 
84
98
  /**
85
- * @template {StandardSchemaV1} StandardSchema
99
+ * @template {StandardSchemaV1 | undefined} [StandardSchema=undefined]
100
+ * @template {Record<string, unknown> | undefined} [CustomContext=undefined]
86
101
  */
87
102
  export class McpServer {
88
103
  #server = new JSONRPCServer();
@@ -129,7 +144,7 @@ export class McpServer {
129
144
  };
130
145
 
131
146
  /**
132
- * @type {AsyncLocalStorage<Context>}
147
+ * @type {AsyncLocalStorage<Context<CustomContext> & { progress_token?: string }>}
133
148
  */
134
149
  #ctx_storage = new AsyncLocalStorage();
135
150
 
@@ -138,6 +153,11 @@ export class McpServer {
138
153
  */
139
154
  #client_capabilities_map = new Map();
140
155
 
156
+ /**
157
+ * @type {Map<string|undefined, ClientInfo>}
158
+ */
159
+ #client_info_map = new Map();
160
+
141
161
  /**
142
162
  * @type {Map<string|undefined, string>}
143
163
  */
@@ -195,6 +215,12 @@ export class McpServer {
195
215
  validated_initialize.capabilities,
196
216
  );
197
217
 
218
+ // Store client info
219
+ this.#client_info_map.set(
220
+ session_id,
221
+ validated_initialize.clientInfo,
222
+ );
223
+
198
224
  // Dispatch initialization event
199
225
  this.#event_target.dispatchEvent(
200
226
  new CustomEvent('initialize', {
@@ -254,18 +280,51 @@ export class McpServer {
254
280
  this.#init_logging();
255
281
  }
256
282
 
283
+ /**
284
+ * Utility method to specify the type of the custom context for this server instance without the need to specify the standard schema type.
285
+ * @example
286
+ * const server = new McpServer({ ... }, { ... }).withContext<{ name: string }>();
287
+ * @template {Record<string, unknown>} TCustom
288
+ * @returns {McpServer<StandardSchema, TCustom>}
289
+ */
290
+ withContext() {
291
+ return /** @type {McpServer<StandardSchema, TCustom>} */ (
292
+ /** @type {unknown} */ (this)
293
+ );
294
+ }
295
+
257
296
  get #session_id() {
258
297
  return this.#ctx_storage.getStore()?.sessionId;
259
298
  }
260
299
 
300
+ get #progress_token() {
301
+ return this.#ctx_storage.getStore()?.progress_token;
302
+ }
303
+
304
+ /**
305
+ * The context of the current request, include the session ID, any auth information, and custom data.
306
+ * @type {Context<CustomContext>}
307
+ */
261
308
  get ctx() {
262
- return this.#ctx_storage.getStore() ?? {};
309
+ // eslint-disable-next-line no-unused-vars
310
+ const { progress_token, ...rest } = this.#ctx_storage.getStore() ?? {};
311
+ return rest;
263
312
  }
264
313
 
265
314
  get #client_capabilities() {
266
315
  return this.#client_capabilities_map.get(this.#session_id);
267
316
  }
268
317
 
318
+ /**
319
+ * Get the client information (name, version, etc.) of the client that initiated the current request...useful if you want to do something different based on the client.
320
+ */
321
+ currentClientInfo() {
322
+ return this.#client_info_map.get(this.#session_id);
323
+ }
324
+
325
+ /**
326
+ * Get the client capabilities of the client that initiated the current request, you can use this to verify the client support something before invoking the respective method.
327
+ */
269
328
  currentClientCapabilities() {
270
329
  return this.#client_capabilities;
271
330
  }
@@ -322,34 +381,41 @@ export class McpServer {
322
381
  #init_tools() {
323
382
  if (!this.#options.capabilities?.tools) return;
324
383
  this.#server.addMethod('tools/list', async () => {
325
- const available_tools = await Promise.all(
326
- [...this.#tools].map(async ([name, tool]) => {
327
- return {
328
- name,
329
- title: tool.title || tool.description,
330
- description: tool.description,
331
-
332
- inputSchema: tool.schema
333
- ? await this.#options.adapter.toJsonSchema(
334
- tool.schema,
335
- )
336
- : { type: 'object', properties: {} },
337
- ...(tool.outputSchema
338
- ? {
339
- outputSchema:
340
- await this.#options.adapter.toJsonSchema(
341
- tool.outputSchema,
342
- ),
343
- }
344
- : {}),
345
- ...(tool.annotations
346
- ? {
347
- annotations: tool.annotations,
348
- }
349
- : {}),
350
- };
351
- }),
352
- );
384
+ const available_tools = (
385
+ await Promise.all(
386
+ [...this.#tools].map(async ([name, tool]) => {
387
+ if (
388
+ tool.enabled != null &&
389
+ (await safe_enabled(tool.enabled)) === false
390
+ )
391
+ return null;
392
+ return {
393
+ name,
394
+ title: tool.title || tool.description,
395
+ description: tool.description,
396
+
397
+ inputSchema: tool.schema
398
+ ? await this.#options.adapter.toJsonSchema(
399
+ tool.schema,
400
+ )
401
+ : { type: 'object', properties: {} },
402
+ ...(tool.outputSchema
403
+ ? {
404
+ outputSchema:
405
+ await this.#options.adapter.toJsonSchema(
406
+ tool.outputSchema,
407
+ ),
408
+ }
409
+ : {}),
410
+ ...(tool.annotations
411
+ ? {
412
+ annotations: tool.annotations,
413
+ }
414
+ : {}),
415
+ };
416
+ }),
417
+ )
418
+ ).filter((tool) => tool !== null);
353
419
  return {
354
420
  tools: available_tools,
355
421
  };
@@ -419,39 +485,49 @@ export class McpServer {
419
485
  #init_prompts() {
420
486
  if (!this.#options.capabilities?.prompts) return;
421
487
  this.#server.addMethod('prompts/list', async ({ cursor } = {}) => {
422
- const all_prompts = await Promise.all(
423
- [...this.#prompts].map(async ([name, prompt]) => {
424
- const arguments_schema = prompt.schema
425
- ? await this.#options.adapter.toJsonSchema(
426
- prompt.schema,
427
- )
428
- : {
429
- type: 'object',
430
- properties:
431
- /** @type {Record<string, {description: string}>} */ ({}),
432
- required: [],
433
- };
434
- const keys = Object.keys(arguments_schema.properties ?? {});
435
- const required = arguments_schema.required ?? [];
436
- return {
437
- name,
438
- title: prompt.title || prompt.description,
439
- description: prompt.description,
440
- arguments: keys.map((key) => {
441
- const property = arguments_schema.properties?.[key];
442
- const description =
443
- property && property !== true
444
- ? property.description
445
- : key;
446
- return {
447
- name: key,
448
- required: required.includes(key),
449
- description,
450
- };
451
- }),
452
- };
453
- }),
454
- );
488
+ const all_prompts = (
489
+ await Promise.all(
490
+ [...this.#prompts].map(async ([name, prompt]) => {
491
+ if (
492
+ prompt.enabled != null &&
493
+ (await safe_enabled(prompt.enabled)) === false
494
+ )
495
+ return null;
496
+ const arguments_schema = prompt.schema
497
+ ? await this.#options.adapter.toJsonSchema(
498
+ prompt.schema,
499
+ )
500
+ : {
501
+ type: 'object',
502
+ properties:
503
+ /** @type {Record<string, {description: string}>} */ ({}),
504
+ required: [],
505
+ };
506
+ const keys = Object.keys(
507
+ arguments_schema.properties ?? {},
508
+ );
509
+ const required = arguments_schema.required ?? [];
510
+ return {
511
+ name,
512
+ title: prompt.title || prompt.description,
513
+ description: prompt.description,
514
+ arguments: keys.map((key) => {
515
+ const property =
516
+ arguments_schema.properties?.[key];
517
+ const description =
518
+ property && property !== true
519
+ ? property.description
520
+ : key;
521
+ return {
522
+ name: key,
523
+ required: required.includes(key),
524
+ description,
525
+ };
526
+ }),
527
+ };
528
+ }),
529
+ )
530
+ ).filter((prompt) => prompt !== null);
455
531
 
456
532
  const pagination_options = this.#options.pagination?.prompts;
457
533
  if (!pagination_options || pagination_options.size == null) {
@@ -528,6 +604,11 @@ export class McpServer {
528
604
  for (const [uri, { description, name, title, ...resource }] of this
529
605
  .#resources) {
530
606
  if (!resource.template) {
607
+ if (
608
+ resource.enabled != null &&
609
+ (await safe_enabled(resource.enabled)) === false
610
+ )
611
+ continue;
531
612
  all_resources.push({
532
613
  name,
533
614
  title: title || description,
@@ -535,6 +616,11 @@ export class McpServer {
535
616
  uri,
536
617
  });
537
618
  } else if (resource.list_resources) {
619
+ if (
620
+ resource.enabled != null &&
621
+ (await safe_enabled(resource.enabled)) === false
622
+ )
623
+ continue;
538
624
  const template_resources = await resource.list_resources();
539
625
  all_resources.push(...template_resources);
540
626
  }
@@ -563,20 +649,29 @@ export class McpServer {
563
649
  });
564
650
  this.#server.addMethod('resources/templates/list', async () => {
565
651
  return {
566
- resourceTemplates: [...this.#resources].reduce(
567
- (arr, [uri, { description, name, title, template }]) => {
568
- if (template) {
569
- arr.push({
570
- name,
571
- title: title || description,
572
- description,
573
- uriTemplate: uri,
574
- });
575
- }
576
- return arr;
577
- },
578
- /** @type {Array<{name: string, title: string, description: string, uriTemplate: string}>} */ ([]),
579
- ),
652
+ resourceTemplates: (
653
+ await Promise.all(
654
+ [...this.#resources].map(
655
+ async ([
656
+ uri,
657
+ { description, name, title, template, enabled },
658
+ ]) => {
659
+ if (!template) return null;
660
+ if (
661
+ enabled != null &&
662
+ (await safe_enabled(enabled)) === false
663
+ )
664
+ return null;
665
+ return {
666
+ name,
667
+ title: title || description,
668
+ description,
669
+ uriTemplate: uri,
670
+ };
671
+ },
672
+ ),
673
+ )
674
+ ).filter((resource) => resource != null),
580
675
  };
581
676
  });
582
677
  this.#server.addMethod('resources/read', async ({ uri }) => {
@@ -640,9 +735,7 @@ export class McpServer {
640
735
  this.roots = [];
641
736
  }
642
737
  }
643
- /**
644
- *
645
- */
738
+
646
739
  #init_completion() {
647
740
  this.#server.addMethod(
648
741
  'completion/complete',
@@ -660,9 +753,7 @@ export class McpServer {
660
753
  },
661
754
  );
662
755
  }
663
- /**
664
- *
665
- */
756
+
666
757
  #init_logging() {
667
758
  if (!this.#options.capabilities?.logging) return;
668
759
 
@@ -672,13 +763,25 @@ export class McpServer {
672
763
  });
673
764
  }
674
765
  /**
766
+ * Add a tool to the server. If you want to receive any input you need to provide a schema. The schema needs to be a valid Standard Schema V1 schema and needs to be an Object with the properties you need,
767
+ * Use the description and title to help the LLM to understand what the tool does and when to use it. If you provide an outputSchema, you need to return a structuredContent that matches the schema.
768
+ *
769
+ * Tools will be invoked by the LLM when it thinks it needs to use them, you can use the annotations to provide additional information about the tool, like what it does, how to use it, etc.
675
770
  * @template {StandardSchema | undefined} [TSchema=undefined]
676
771
  * @template {StandardSchema | undefined} [TOutputSchema=undefined]
677
- * @param {{ name: string; description: string; title?: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never; annotations?: ToolAnnotations }} options
772
+ * @param {{ name: string; description: string; title?: string; enabled?: ()=>boolean | Promise<boolean>; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never; annotations?: ToolAnnotations }} options
678
773
  * @param {TSchema extends undefined ? (()=>Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>)} execute
679
774
  */
680
775
  tool(
681
- { name, description, title, schema, outputSchema, annotations },
776
+ {
777
+ name,
778
+ description,
779
+ title,
780
+ schema,
781
+ outputSchema,
782
+ annotations,
783
+ enabled,
784
+ },
682
785
  execute,
683
786
  ) {
684
787
  if (this.#options.capabilities?.tools?.listChanged) {
@@ -687,6 +790,7 @@ export class McpServer {
687
790
  this.#tools.set(name, {
688
791
  description,
689
792
  title,
793
+ enabled,
690
794
  schema,
691
795
  outputSchema,
692
796
  execute,
@@ -694,11 +798,16 @@ export class McpServer {
694
798
  });
695
799
  }
696
800
  /**
801
+ * Add a prompt to the server. Prompts are used to provide the user with pre-defined messages that adds context to the LLM.
802
+ * Use the description and title to help the user to understand what the prompt does and when to use it.
803
+ *
804
+ * A prompt can also have a schema that defines the input it expects, the user will be prompted to enter the inputs you request. It can also have a complete function
805
+ * for each input that will be used to provide completions for the user.
697
806
  * @template {StandardSchema | undefined} [TSchema=undefined]
698
- * @param {{ name: string; description: string; title?: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion>>> }} options
807
+ * @param {{ name: string; description: string; title?: string; enabled?: ()=>boolean | Promise<boolean>; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never; complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof (StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>), Completion>>> }} options
699
808
  * @param {TSchema extends undefined ? (()=>Promise<GetPromptResult> | GetPromptResult) : (input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<GetPromptResult> | GetPromptResult} execute
700
809
  */
701
- prompt({ name, description, title, schema, complete }, execute) {
810
+ prompt({ name, description, title, schema, complete, enabled }, execute) {
702
811
  if (complete) {
703
812
  this.#completions['ref/prompt'].set(name, complete);
704
813
  }
@@ -710,6 +819,7 @@ export class McpServer {
710
819
  title,
711
820
  schema,
712
821
  execute,
822
+ enabled,
713
823
  });
714
824
  }
715
825
  /**
@@ -727,32 +837,50 @@ export class McpServer {
727
837
  }
728
838
  this.#resources.set(uri, resource);
729
839
  }
840
+
730
841
  /**
731
- * @param {{ name: string; description: string; title?: string; uri: string }} options
842
+ * Add a resource to the server. Resources are added manually to the context by the user to provide the LLM with additional context.
843
+ * Use the description and title to help the user to understand what the resource is.
844
+ * @param {{ name: string; description: string; title?: string; uri: string, enabled?: ()=>boolean | Promise<boolean>; }} options
732
845
  * @param {(uri: string) => Promise<ReadResourceResult> | ReadResourceResult} execute
733
846
  */
734
- resource({ name, description, title, uri }, execute) {
847
+ resource({ name, description, title, uri, enabled }, execute) {
735
848
  this.#resource({
736
849
  name,
737
850
  description,
738
851
  title,
739
852
  uri,
740
853
  execute,
854
+ enabled,
741
855
  template: false,
742
856
  });
743
857
  }
744
858
  /**
859
+ * Add a resource template to the server. Resources are added manually to the context by the user to provide the LLM with additional context.
860
+ * Resource templates are used to create resources dynamically based on a URI template. The URI template should be a valid URI template as defined in RFC 6570.
861
+ * Resource templates can have a list method that returns a list of resources that match the template and a complete method that returns a list of resources given one of the template variables, this method will
862
+ * be invoked to provide completions for the template variables to the user.
863
+ * Use the description and title to help the user to understand what the resource is.
745
864
  * @template {string} TUri
746
865
  * @template {ExtractURITemplateVariables<TUri>} TVariables
747
- * @param {{ name: string; description: string; title?: string; uri: TUri; complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>>; list?: () => Promise<Array<Resource>> | Array<Resource> }} options
866
+ * @param {{ name: string; description: string; title?: string; enabled?: ()=>boolean | Promise<boolean>; uri: TUri; complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>>; list?: () => Promise<Array<Resource>> | Array<Resource> }} options
748
867
  * @param {(uri: string, params: Record<TVariables, string | string[]>) => Promise<ReadResourceResult> | ReadResourceResult} execute
749
868
  */
750
869
  template(
751
- { name, description, title, uri, complete, list: list_resources },
870
+ {
871
+ name,
872
+ description,
873
+ title,
874
+ uri,
875
+ complete,
876
+ list: list_resources,
877
+ enabled,
878
+ },
752
879
  execute,
753
880
  ) {
754
881
  this.#resource({
755
882
  name,
883
+ enabled,
756
884
  description,
757
885
  title,
758
886
  uri,
@@ -763,8 +891,10 @@ export class McpServer {
763
891
  });
764
892
  }
765
893
  /**
894
+ * The main function that receive a JSONRpc message and either dispatch a `send` event or process the request.
895
+ *
766
896
  * @param {JSONRPCResponse | JSONRPCRequest} message
767
- * @param {Context} [ctx]
897
+ * @param {Context<CustomContext>} [ctx]
768
898
  * @returns {ReturnType<JSONRPCServer['receive']> | ReturnType<JSONRPCClient['receive'] | undefined>}
769
899
  */
770
900
  receive(message, ctx) {
@@ -788,8 +918,11 @@ export class McpServer {
788
918
  this.#options.logging?.default ?? 'info',
789
919
  );
790
920
  }
921
+ const progress_token = /** @type {string | undefined} */ (
922
+ validated_message.output.params?._meta?.progressToken
923
+ );
791
924
  return this.#ctx_storage.run(
792
- ctx ?? {},
925
+ { ...(ctx ?? {}), progress_token },
793
926
  async () =>
794
927
  await this.#server.receive(validated_message.output),
795
928
  );
@@ -833,7 +966,13 @@ export class McpServer {
833
966
  }
834
967
 
835
968
  /**
836
- * @template {StandardSchema} TSchema
969
+ * Emit an elicitation request to the client. Elicitations are used to ask the user for input in a structured way, the client will show a UI to the user to fill the input.
970
+ * The schema should be a valid Standard Schema V1 schema and should be an Object with the properties you need.
971
+ * The client will return the validated input as a JSON object that matches the schema.
972
+ *
973
+ * If the client doesn't support elicitation, it will throw an error.
974
+ *
975
+ * @template {StandardSchema extends undefined ? never : StandardSchema} TSchema
837
976
  * @param {TSchema} schema
838
977
  * @returns {Promise<StandardSchemaV1.InferOutput<TSchema>>}
839
978
  */
@@ -894,8 +1033,33 @@ export class McpServer {
894
1033
  return v.parse(CreateMessageResultSchema, response);
895
1034
  }
896
1035
 
1036
+ /**
1037
+ * Send a progress notification to the client. This is useful for long-running operations where you want to inform the user about the progress.
1038
+ *
1039
+ * @param {number} progress The current progress value, it should be between 0 and total and should always increase
1040
+ * @param {number} [total] The total value, defaults to 1
1041
+ * @param {string} [message] An optional message to accompany the progress update
1042
+ */
1043
+ progress(progress, total = 1, message = undefined) {
1044
+ if (this.#progress_token != null) {
1045
+ this.#notify(
1046
+ 'notifications/progress',
1047
+ {
1048
+ progress,
1049
+ total,
1050
+ message,
1051
+ progressToken: this.#progress_token,
1052
+ },
1053
+ {
1054
+ sessions: this.#session_id ? [this.#session_id] : undefined,
1055
+ },
1056
+ );
1057
+ }
1058
+ }
1059
+
897
1060
  /**
898
1061
  * Log a message to the client if logging is enabled and the level is appropriate
1062
+ *
899
1063
  * @param {LoggingLevel} level
900
1064
  * @param {unknown} data
901
1065
  * @param {string} [logger]
@@ -19,6 +19,7 @@ export type Tool<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>, TOutp
19
19
  outputSchema?: TOutputSchema;
20
20
  title?: string;
21
21
  annotations?: ToolAnnotations;
22
+ enabled?: () => boolean | Promise<boolean>;
22
23
  execute: (
23
24
  input?: StandardSchemaV1.InferInput<TSchema>,
24
25
  ) => Promise<CallToolResult> | CallToolResult;
@@ -33,6 +34,7 @@ export type Prompt<TSchema extends StandardSchemaV1 = StandardSchemaV1<any>> = {
33
34
  description: string;
34
35
  schema: TSchema;
35
36
  title?: string;
37
+ enabled?: () => boolean | Promise<boolean>;
36
38
  execute: (
37
39
  input?: StandardSchemaV1.InferInput<TSchema>,
38
40
  ) => Promise<GetPromptResult> | GetPromptResult;
@@ -44,6 +46,7 @@ export type StoredResource =
44
46
  name: string;
45
47
  template: true;
46
48
  title?: string;
49
+ enabled?: () => boolean | Promise<boolean>;
47
50
  list_resources?: () =>
48
51
  | Promise<Array<Resource>>
49
52
  | Array<Resource>;
@@ -57,12 +60,13 @@ export type StoredResource =
57
60
  name: string;
58
61
  template: false;
59
62
  title?: string;
63
+ enabled?: () => boolean | Promise<boolean>;
60
64
  execute: (
61
65
  uri: string,
62
66
  ) => Promise<ReadResourceResult> | ReadResourceResult;
63
67
  };
64
68
 
65
- export type ServerOptions<TSchema extends StandardSchemaV1> = {
69
+ export type ServerOptions<TSchema extends StandardSchemaV1 | undefined> = {
66
70
  capabilities?: ServerCapabilities;
67
71
  instructions?: string;
68
72
  adapter: JsonSchemaAdapter<TSchema>;
@@ -3,7 +3,7 @@ declare module 'tmcp' {
3
3
  import type { JSONRPCRequest, JSONRPCServer, JSONRPCClient } from 'json-rpc-2.0';
4
4
  import type { JSONSchema7 } from 'json-schema';
5
5
  import * as v from 'valibot';
6
- export class McpServer<StandardSchema extends StandardSchemaV1> {
6
+ export class McpServer<StandardSchema extends StandardSchemaV1 | undefined = undefined, CustomContext extends Record<string, unknown> | undefined = undefined> {
7
7
 
8
8
  constructor(server_info: ServerInfo, options: ServerOptions<StandardSchema>);
9
9
 
@@ -11,7 +11,27 @@ declare module 'tmcp' {
11
11
  uri: string;
12
12
  name?: string;
13
13
  }>;
14
- get ctx(): Context;
14
+ /**
15
+ * Utility method to specify the type of the custom context for this server instance without the need to specify the standard schema type.
16
+ * @example
17
+ * const server = new McpServer({ ... }, { ... }).withContext<{ name: string }>();
18
+ * */
19
+ withContext<TCustom extends Record<string, unknown>>(): McpServer<StandardSchema, TCustom>;
20
+ /**
21
+ * The context of the current request, include the session ID, any auth information, and custom data.
22
+ * */
23
+ get ctx(): Context<CustomContext>;
24
+ /**
25
+ * Get the client information (name, version, etc.) of the client that initiated the current request...useful if you want to do something different based on the client.
26
+ */
27
+ currentClientInfo(): {
28
+ version: string;
29
+ name: string;
30
+ title?: string | undefined;
31
+ } | undefined;
32
+ /**
33
+ * Get the client capabilities of the client that initiated the current request, you can use this to verify the client support something before invoking the respective method.
34
+ */
15
35
  currentClientCapabilities(): {
16
36
  experimental?: {} | undefined;
17
37
  sampling?: {} | undefined;
@@ -22,41 +42,68 @@ declare module 'tmcp' {
22
42
  } | undefined;
23
43
 
24
44
  on<TEvent extends keyof McpEvents>(event: TEvent, callback: McpEvents[TEvent], options?: AddEventListenerOptions): () => void;
25
-
26
- tool<TSchema extends StandardSchema | undefined = undefined, TOutputSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, outputSchema, annotations }: {
45
+ /**
46
+ * Add a tool to the server. If you want to receive any input you need to provide a schema. The schema needs to be a valid Standard Schema V1 schema and needs to be an Object with the properties you need,
47
+ * Use the description and title to help the LLM to understand what the tool does and when to use it. If you provide an outputSchema, you need to return a structuredContent that matches the schema.
48
+ *
49
+ * Tools will be invoked by the LLM when it thinks it needs to use them, you can use the annotations to provide additional information about the tool, like what it does, how to use it, etc.
50
+ * */
51
+ tool<TSchema extends StandardSchema | undefined = undefined, TOutputSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, outputSchema, annotations, enabled, }: {
27
52
  name: string;
28
53
  description: string;
29
54
  title?: string;
55
+ enabled?: () => boolean | Promise<boolean>;
30
56
  schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never;
31
57
  outputSchema?: StandardSchemaV1.InferOutput<TOutputSchema extends undefined ? never : TOutputSchema> extends Record<string, unknown> ? TOutputSchema : never;
32
58
  annotations?: ToolAnnotations;
33
59
  }, execute: TSchema extends undefined ? (() => Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>) : ((input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>> | CallToolResult<TOutputSchema extends undefined ? undefined : StandardSchemaV1.InferInput<TOutputSchema extends undefined ? never : TOutputSchema>>)): void;
34
-
35
- prompt<TSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, complete }: {
60
+ /**
61
+ * Add a prompt to the server. Prompts are used to provide the user with pre-defined messages that adds context to the LLM.
62
+ * Use the description and title to help the user to understand what the prompt does and when to use it.
63
+ *
64
+ * A prompt can also have a schema that defines the input it expects, the user will be prompted to enter the inputs you request. It can also have a complete function
65
+ * for each input that will be used to provide completions for the user.
66
+ * */
67
+ prompt<TSchema extends StandardSchema | undefined = undefined>({ name, description, title, schema, complete, enabled }: {
36
68
  name: string;
37
69
  description: string;
38
70
  title?: string;
71
+ enabled?: () => boolean | Promise<boolean>;
39
72
  schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never;
40
73
  complete?: NoInfer<TSchema extends undefined ? never : Partial<Record<keyof StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>, Completion>>>;
41
74
  }, execute: TSchema extends undefined ? (() => Promise<GetPromptResult> | GetPromptResult) : (input: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema>) => Promise<GetPromptResult> | GetPromptResult): void;
42
-
43
- resource({ name, description, title, uri }: {
75
+ /**
76
+ * Add a resource to the server. Resources are added manually to the context by the user to provide the LLM with additional context.
77
+ * Use the description and title to help the user to understand what the resource is.
78
+ * */
79
+ resource({ name, description, title, uri, enabled }: {
44
80
  name: string;
45
81
  description: string;
46
82
  title?: string;
47
83
  uri: string;
84
+ enabled?: () => boolean | Promise<boolean>;
48
85
  }, execute: (uri: string) => Promise<ReadResourceResult> | ReadResourceResult): void;
49
-
50
- template<TUri extends string, TVariables extends ExtractURITemplateVariables<TUri>>({ name, description, title, uri, complete, list: list_resources }: {
86
+ /**
87
+ * Add a resource template to the server. Resources are added manually to the context by the user to provide the LLM with additional context.
88
+ * Resource templates are used to create resources dynamically based on a URI template. The URI template should be a valid URI template as defined in RFC 6570.
89
+ * Resource templates can have a list method that returns a list of resources that match the template and a complete method that returns a list of resources given one of the template variables, this method will
90
+ * be invoked to provide completions for the template variables to the user.
91
+ * Use the description and title to help the user to understand what the resource is.
92
+ * */
93
+ template<TUri extends string, TVariables extends ExtractURITemplateVariables<TUri>>({ name, description, title, uri, complete, list: list_resources, enabled, }: {
51
94
  name: string;
52
95
  description: string;
53
96
  title?: string;
97
+ enabled?: () => boolean | Promise<boolean>;
54
98
  uri: TUri;
55
99
  complete?: NoInfer<TVariables extends never ? never : Partial<Record<TVariables, Completion>>>;
56
100
  list?: () => Promise<Array<Resource>> | Array<Resource>;
57
101
  }, execute: (uri: string, params: Record<TVariables, string | string[]>) => Promise<ReadResourceResult> | ReadResourceResult): void;
58
-
59
- receive(message: JSONRPCResponse | JSONRPCRequest, ctx?: Context): ReturnType<JSONRPCServer["receive"]> | ReturnType<JSONRPCClient["receive"] | undefined>;
102
+ /**
103
+ * The main function that receive a JSONRpc message and either dispatch a `send` event or process the request.
104
+ *
105
+ * */
106
+ receive(message: JSONRPCResponse | JSONRPCRequest, ctx?: Context<CustomContext>): ReturnType<JSONRPCServer["receive"]> | ReturnType<JSONRPCClient["receive"] | undefined>;
60
107
  /**
61
108
  * Send a notification for subscriptions
62
109
  * */
@@ -65,14 +112,30 @@ declare module 'tmcp' {
65
112
  * Refresh roots list from client
66
113
  */
67
114
  refreshRoots(): Promise<void>;
68
-
69
- elicitation<TSchema extends StandardSchema>(schema: TSchema): Promise<StandardSchemaV1.InferOutput<TSchema>>;
115
+ /**
116
+ * Emit an elicitation request to the client. Elicitations are used to ask the user for input in a structured way, the client will show a UI to the user to fill the input.
117
+ * The schema should be a valid Standard Schema V1 schema and should be an Object with the properties you need.
118
+ * The client will return the validated input as a JSON object that matches the schema.
119
+ *
120
+ * If the client doesn't support elicitation, it will throw an error.
121
+ *
122
+ * */
123
+ elicitation<TSchema extends StandardSchema extends undefined ? never : StandardSchema>(schema: TSchema): Promise<StandardSchemaV1.InferOutput<TSchema>>;
70
124
  /**
71
125
  * Request language model sampling from the client
72
126
  * */
73
127
  message(request: CreateMessageRequestParams): Promise<CreateMessageResult>;
128
+ /**
129
+ * Send a progress notification to the client. This is useful for long-running operations where you want to inform the user about the progress.
130
+ *
131
+ * @param progress The current progress value, it should be between 0 and total and should always increase
132
+ * @param total The total value, defaults to 1
133
+ * @param message An optional message to accompany the progress update
134
+ */
135
+ progress(progress: number, total?: number, message?: string): void;
74
136
  /**
75
137
  * Log a message to the client if logging is enabled and the level is appropriate
138
+ *
76
139
  *
77
140
  */
78
141
  log(level: LoggingLevel, data: unknown, logger?: string): void;
@@ -109,9 +172,10 @@ declare module 'tmcp' {
109
172
  */
110
173
  extra?: Record<string, unknown> | undefined;
111
174
  };
112
- export type Context = {
175
+ export type Context<TCustom extends Record<string, unknown> | undefined = undefined> = {
113
176
  sessionId?: string | undefined;
114
177
  auth?: AuthInfo | undefined;
178
+ custom?: TCustom | undefined;
115
179
  };
116
180
  export type ClientCapabilities = ClientCapabilities_1;
117
181
  type Completion = (
@@ -119,7 +183,7 @@ declare module 'tmcp' {
119
183
  context: { arguments: Record<string, string> },
120
184
  ) => CompleteResult | Promise<CompleteResult>;
121
185
 
122
- type ServerOptions<TSchema extends StandardSchemaV1> = {
186
+ type ServerOptions<TSchema extends StandardSchemaV1 | undefined> = {
123
187
  capabilities?: ServerCapabilities;
124
188
  instructions?: string;
125
189
  adapter: JsonSchemaAdapter<TSchema>;
@@ -55,6 +55,6 @@
55
55
  null,
56
56
  null
57
57
  ],
58
- "mappings": ";;;;;cAsFaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCi3CsCC,kBAAkBA;MC76ClEC,UAAUA;;;;;MAsCVC,aAAaA;;;;;;;;;;;;;MAabC,UAAUA;;;;;;MAMVC,iBAAiBA;;MAEjBC,SAASA;;;;;;;;;;;;ODeRC,qBAAqBA;;;;;;;;;;;;;;OAuGrBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+LzBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;MA8H2BC,kBAAkBA;MASbC,uBAAuBA;;;;;;MAO5BC,kBAAkBA;MAGrBC,eAAeA;MAGhBC,cAAcA;MAGFC,0BAA0BA;MAGjCC,mBAAmBA;MAY9BC,QAAQA;MAMDC,eAAeA;MAGlBC,YAAYA;MAGTC,eAAeA;;ME7/CnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
58
+ "mappings": ";;;;;cAqGaA,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aCk2CsCC,kBAAkBA;MC56ClEC,UAAUA;;;;;MAyCVC,aAAaA;;;;;;;;;;;;;MAabC,UAAUA;;;;;;MAMVC,iBAAiBA;;MAEjBC,SAASA;;;;;;;;;;;;ODWRC,qBAAqBA;;;;;;;;;;;;;;OAuGrBC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;OA6BxBC,6BAA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuB7BC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmMxBC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4GdC,wBAAwBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8PxBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BrBC,qBAAqBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2GrBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEpBC,kBAAkBA;OAuGlBC,gCAAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8ChCC,yBAAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+LzBC,oBAAoBA;;;;;;;;;;;;;;;;;;;;;;MA8H2BC,kBAAkBA;MASbC,uBAAuBA;;;;;;MAO5BC,kBAAkBA;MAGrBC,eAAeA;MAGhBC,cAAcA;MAGFC,0BAA0BA;MAGjCC,mBAAmBA;MAY9BC,QAAQA;MAMDC,eAAeA;MAGlBC,YAAYA;MAGTC,eAAeA;;ME7/CnEC,IAAIA;;;;;;;MAOJC,cAAcA;;;;;;;MAOdC,cAAcA;;;;;MAKdC,qBAAqBA;;;;;;;;;;;;;;;;;MAiBrBC,4BAA4BA;;;;;;MAMrBC,2BAA2BA;;;;;;;OCjC1BC,iBAAiBA;;;;;;;;;;;;;;;;cAAjBA,iBAAiBA",
59
59
  "ignoreList": []
60
60
  }