tmcp 1.0.2 → 1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmcp",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "The main tmcp library",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.d.ts CHANGED
@@ -7,6 +7,13 @@ export class McpServer<StandardSchema extends StandardSchemaV1> {
7
7
  * @param {ServerOptions<StandardSchema>} options
8
8
  */
9
9
  constructor(server_info: ServerInfo, options: ServerOptions<StandardSchema>);
10
+ /**
11
+ * @template {keyof McpEvents} TEvent
12
+ * @param {TEvent} event
13
+ * @param {McpEvents[TEvent]} callback
14
+ * @param {AddEventListenerOptions} [options]
15
+ */
16
+ on<TEvent extends keyof McpEvents>(event: TEvent, callback: McpEvents[TEvent], options?: AddEventListenerOptions): void;
10
17
  /**
11
18
  * @template {StandardSchema | undefined} [TSchema=undefined]
12
19
  * @param {{ name: string; description: string; schema?: StandardSchemaV1.InferInput<TSchema extends undefined ? never : TSchema> extends Record<string, unknown> ? TSchema : never }} options
@@ -52,11 +59,19 @@ export class McpServer<StandardSchema extends StandardSchemaV1> {
52
59
  * @returns {ReturnType<JSONRPCServer['receive']>}
53
60
  */
54
61
  receive(request: JSONRPCRequest): ReturnType<JSONRPCServer["receive"]>;
62
+ /**
63
+ * Send a notification for subscriptions
64
+ * @param {SubscriptionsKeys} what
65
+ * @param {string} id
66
+ */
67
+ changed(what: SubscriptionsKeys, id: string): void;
55
68
  #private;
56
69
  }
57
70
  import type { StandardSchemaV1 } from "@standard-schema/spec";
71
+ import type { McpEvents } from "./internal/internal.js";
58
72
  import type { Completion } from "./internal/internal.js";
59
73
  import type { JSONRPCRequest } from "json-rpc-2.0";
60
74
  import { JSONRPCServer } from 'json-rpc-2.0';
75
+ import type { SubscriptionsKeys } from "./internal/internal.js";
61
76
  import type { ServerInfo } from "./internal/internal.js";
62
77
  import type { ServerOptions } from "./internal/internal.js";
package/src/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @import { StandardSchemaV1 } from "@standard-schema/spec";
3
3
  * @import { JSONRPCRequest, JSONRPCParams } from "json-rpc-2.0";
4
- * @import { Tool, Completion, Prompt, Resource, ServerOptions, ServerInfo } from "./internal/internal.js";
4
+ * @import { Tool, Completion, Prompt, Resource, ServerOptions, ServerInfo, SubscriptionsKeys, McpEvents } from "./internal/internal.js";
5
5
  */
6
6
  import { JSONRPCServer, JSONRPCClient } from 'json-rpc-2.0';
7
7
  import { UriTemplateMatcher } from 'uri-template-matcher';
@@ -36,17 +36,25 @@ export class McpServer {
36
36
  'ref/prompt': new Map(),
37
37
  'ref/resource': new Map(),
38
38
  };
39
+
40
+ #event_target = new EventTarget();
41
+
42
+ /**
43
+ * @type {Record<SubscriptionsKeys, Set<string>>}
44
+ */
45
+ #subscriptions = {
46
+ /**
47
+ * @type {Set<string>}
48
+ */
49
+ resource: new Set(),
50
+ };
51
+
39
52
  /**
40
53
  * @param {ServerInfo} server_info
41
54
  * @param {ServerOptions<StandardSchema>} options
42
55
  */
43
56
  constructor(server_info, options) {
44
57
  this.#options = options;
45
- if (options.send) {
46
- this.#client = new JSONRPCClient((payload) => {
47
- options.send?.(payload);
48
- });
49
- }
50
58
  this.#server.addMethod('initialize', ({ protocolVersion }) => {
51
59
  return {
52
60
  protocolVersion,
@@ -66,6 +74,30 @@ export class McpServer {
66
74
  this.#init_completion();
67
75
  }
68
76
 
77
+ /**
78
+ * @template {keyof McpEvents} TEvent
79
+ * @param {TEvent} event
80
+ * @param {McpEvents[TEvent]} callback
81
+ * @param {AddEventListenerOptions} [options]
82
+ */
83
+ on(event, callback, options) {
84
+ if (event === 'send' && !this.#client) {
85
+ this.#client = new JSONRPCClient((payload) => {
86
+ this.#event_target.dispatchEvent(
87
+ new CustomEvent('send', { detail: payload }),
88
+ );
89
+ });
90
+ }
91
+
92
+ this.#event_target.addEventListener(
93
+ event,
94
+ (e) => {
95
+ callback(/** @type {CustomEvent} */ (e).detail);
96
+ },
97
+ options,
98
+ );
99
+ }
100
+
69
101
  /**
70
102
  * @param {string} method
71
103
  * @param {JSONRPCParams} [params]
@@ -190,6 +222,14 @@ export class McpServer {
190
222
  */
191
223
  #init_resources() {
192
224
  if (!this.#options.capabilities?.resources) return;
225
+
226
+ if (this.#options.capabilities?.resources?.subscribe) {
227
+ this.#server.addMethod('resources/subscribe', async ({ uri }) => {
228
+ this.#subscriptions.resource.add(uri);
229
+ return {};
230
+ });
231
+ }
232
+
193
233
  this.#server.addMethod('resources/list', async () => {
194
234
  return {
195
235
  resources: [...this.#resources].reduce(
@@ -339,4 +379,20 @@ export class McpServer {
339
379
  receive(request) {
340
380
  return this.#server.receive(request);
341
381
  }
382
+
383
+ /**
384
+ * Send a notification for subscriptions
385
+ * @param {SubscriptionsKeys} what
386
+ * @param {string} id
387
+ */
388
+ changed(what, id) {
389
+ if (this.#subscriptions[what].has(id)) {
390
+ const resource = this.#resources.get(id);
391
+ if (!resource) return;
392
+ this.#notify(`notifications/resources/updated`, {
393
+ uri: id,
394
+ title: resource.name,
395
+ });
396
+ }
397
+ }
342
398
  }
@@ -31,11 +31,10 @@ export type Resource = {
31
31
  };
32
32
 
33
33
  export type ServerOptions<TSchema extends StandardSchemaV1> = {
34
- send?: (payload: JSONRPCRequest) => void;
35
34
  capabilities?: {
36
35
  tools?: { listChanged?: boolean };
37
36
  resources?: { listChanged?: boolean; subscribe?: boolean };
38
- prompts?: { listChanged?: boolean; subscribe?: boolean };
37
+ prompts?: { listChanged?: boolean };
39
38
  };
40
39
  instructions?: string;
41
40
  adapter: JsonSchemaAdapter<TSchema>;
@@ -46,3 +45,9 @@ export type ServerInfo = {
46
45
  version: string;
47
46
  description: string;
48
47
  };
48
+
49
+ export type SubscriptionsKeys = 'resource';
50
+
51
+ export type McpEvents = {
52
+ send: (message: JSONRPCRequest) => void;
53
+ };