tiny-stdio-mcp-server 0.1.17 → 0.1.19

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { createServer } from "./server.js";
2
- export type { MessageHandler, MessageSession, Server } from "./server.js";
2
+ export type { CustomMethodHandler, MessageHandler, MessageSession, MessageSessionContext, Server } from "./server.js";
3
3
  export { defineSchema } from "./schema.js";
4
4
  export type { TypedSchema } from "./schema.js";
5
5
  export { Image, Audio, File, toContentBlocks, fileTypeFromBuffer, DEFAULT_FROM_URL_MAX_BYTES, } from "./content/index.js";
package/dist/server.d.ts CHANGED
@@ -6,6 +6,7 @@ export interface Server {
6
6
  prompt(definition: Prompt, handler: PromptHandler): Server;
7
7
  resource(definition: Resource, handler: ResourceHandler): Server;
8
8
  resourceTemplate(definition: ResourceTemplate, handler: ResourceHandler): Server;
9
+ method(name: string, handler: CustomMethodHandler): Server;
9
10
  onNotification(listener: (notification: JSONRPCNotification) => void): () => void;
10
11
  removeTool(name: string): boolean;
11
12
  removePrompt(name: string): boolean;
@@ -21,6 +22,11 @@ export interface Server {
21
22
  connect(transport: Transport): Promise<void>;
22
23
  connectSDK(transport: SDKTransport): Promise<void>;
23
24
  }
25
+ export interface MessageSessionContext {
26
+ readonly signal: AbortSignal;
27
+ notify(method: string, params?: Record<string, unknown>): Promise<void>;
28
+ }
29
+ export type CustomMethodHandler = (params: Record<string, unknown> | undefined, session: MessageSessionContext) => unknown | Promise<unknown>;
24
30
  export type MessageHandler = (method: string, params?: Record<string, unknown>) => Promise<HandleResult>;
25
31
  export interface MessageSession {
26
32
  handleMessage: MessageHandler;
package/dist/server.js CHANGED
@@ -20,13 +20,15 @@ export function createServer(options) {
20
20
  const prompts = new Map();
21
21
  const resources = new Map();
22
22
  const resourceTemplates = new Map();
23
+ const methods = new Map();
23
24
  const notificationListeners = new Set();
24
25
  const connectionNotificationListeners = new Map();
25
26
  const defaultLifecycle = {
26
27
  initialized: false,
27
28
  initializeAccepted: false,
28
29
  notificationReady: false,
29
- resourceSubscriptions: new Set()
30
+ resourceSubscriptions: new Set(),
31
+ abortController: new AbortController()
30
32
  };
31
33
  const messageLifecycles = new Set([defaultLifecycle]);
32
34
  const handleMessageWithLifecycle = async (method, lifecycle, params) => {
@@ -113,10 +115,11 @@ export function createServer(options) {
113
115
  }
114
116
  const tool = tools.get(toolName);
115
117
  if (!tool) {
118
+ const availableTools = [...tools.keys()].slice(0, 20);
116
119
  return {
117
120
  error: {
118
121
  code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
119
- message: `Tool not found: ${toolName}`
122
+ message: `Tool not found: ${toolName}${availableTools.length === 0 ? "" : `. Available: ${availableTools.join(", ")}`}`
120
123
  }
121
124
  };
122
125
  }
@@ -269,6 +272,28 @@ export function createServer(options) {
269
272
  }
270
273
  return { result: {} };
271
274
  }
275
+ const customMethod = methods.get(method);
276
+ if (customMethod !== undefined) {
277
+ try {
278
+ const result = await customMethod(params, {
279
+ signal: lifecycle.abortController.signal,
280
+ async notify(notificationMethod, notificationParams) {
281
+ if (!lifecycle.notificationReady || lifecycle.listener === undefined) {
282
+ return;
283
+ }
284
+ await lifecycle.listener({
285
+ jsonrpc: "2.0",
286
+ method: notificationMethod,
287
+ ...(notificationParams === undefined ? {} : { params: notificationParams })
288
+ });
289
+ }
290
+ });
291
+ return { result };
292
+ }
293
+ catch (error) {
294
+ return internalError(toErrorMessage(error));
295
+ }
296
+ }
272
297
  return {
273
298
  error: {
274
299
  code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND,
@@ -281,7 +306,9 @@ export function createServer(options) {
281
306
  initialized: false,
282
307
  initializeAccepted: false,
283
308
  notificationReady: false,
284
- resourceSubscriptions: new Set()
309
+ resourceSubscriptions: new Set(),
310
+ abortController: new AbortController(),
311
+ listener
285
312
  };
286
313
  messageLifecycles.add(lifecycle);
287
314
  if (listener !== undefined) {
@@ -290,6 +317,7 @@ export function createServer(options) {
290
317
  return {
291
318
  handleMessage: (method, params) => handleMessageWithLifecycle(method, lifecycle, params),
292
319
  close: () => {
320
+ lifecycle.abortController.abort();
293
321
  if (listener !== undefined) {
294
322
  connectionNotificationListeners.delete(listener);
295
323
  }
@@ -360,6 +388,9 @@ export function createServer(options) {
360
388
  const server = {
361
389
  tool(name, description, inputSchema, handler, outputSchema) {
362
390
  assertNonEmptyName(name, "Tool name required");
391
+ if (tools.has(name)) {
392
+ throw new Error(`Tool already registered: ${name}`);
393
+ }
363
394
  const inputValidator = jsonSchemaValidator.compile(inputSchema);
364
395
  let outputValidator;
365
396
  if (outputSchema !== undefined) {
@@ -379,6 +410,9 @@ export function createServer(options) {
379
410
  },
380
411
  registerTool(definition, handler) {
381
412
  assertNonEmptyName(definition.name, "Tool name required");
413
+ if (tools.has(definition.name)) {
414
+ throw new Error(`Tool already registered: ${definition.name}`);
415
+ }
382
416
  const inputValidator = jsonSchemaValidator.compile(definition.inputSchema);
383
417
  let outputValidator;
384
418
  if (definition.outputSchema !== undefined) {
@@ -395,6 +429,9 @@ export function createServer(options) {
395
429
  },
396
430
  prompt(definition, handler) {
397
431
  assertNonEmptyName(definition.name, "Prompt name required");
432
+ if (prompts.has(definition.name)) {
433
+ throw new Error(`Prompt already registered: ${definition.name}`);
434
+ }
398
435
  prompts.set(definition.name, { ...definition, handler });
399
436
  return server;
400
437
  },
@@ -402,15 +439,26 @@ export function createServer(options) {
402
439
  if (!isValidUri(definition.uri)) {
403
440
  throw new Error(`Invalid resource URI: ${definition.uri}`);
404
441
  }
442
+ if (resources.has(definition.uri)) {
443
+ throw new Error(`Resource already registered: ${definition.uri}`);
444
+ }
405
445
  resources.set(definition.uri, { ...definition, handler });
406
446
  return server;
407
447
  },
408
448
  resourceTemplate(definition, handler) {
409
449
  assertReadableUriTemplate(definition.uriTemplate);
410
450
  new UriTemplate(definition.uriTemplate);
451
+ if (resourceTemplates.has(definition.uriTemplate)) {
452
+ throw new Error(`Resource template already registered: ${definition.uriTemplate}`);
453
+ }
411
454
  resourceTemplates.set(definition.uriTemplate, { ...definition, handler });
412
455
  return server;
413
456
  },
457
+ method(name, handler) {
458
+ assertNonEmptyName(name, "Method name required");
459
+ methods.set(name, handler);
460
+ return server;
461
+ },
414
462
  onNotification(listener) {
415
463
  notificationListeners.add(listener);
416
464
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-stdio-mcp-server",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "bugs": {
5
5
  "url": "https://github.com/poe-platform/poe-code/issues"
6
6
  },