@leanmcp/core 0.1.2 → 0.3.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
@@ -75,25 +75,70 @@ export class SentimentService {
75
75
 
76
76
  ### 2. Create and Start Server
77
77
 
78
+ #### Option A: Zero-Config Auto-Discovery (Recommended)
79
+
80
+ The simplest way to create an HTTP server with auto-discovery:
81
+
82
+ ```typescript
83
+ import { createHTTPServer } from "@leanmcp/core";
84
+
85
+ // Create and start HTTP server with auto-discovery
86
+ await createHTTPServer({
87
+ name: "my-mcp-server",
88
+ version: "1.0.0",
89
+ port: 3000,
90
+ cors: true,
91
+ logging: true
92
+ });
93
+
94
+ console.log('\nMCP Server running');
95
+ console.log('HTTP endpoint: http://localhost:3000/mcp');
96
+ console.log('Health check: http://localhost:3000/health');
97
+ ```
98
+
99
+ **What happens automatically:**
100
+ - Services are discovered from `./mcp` directory
101
+ - HTTP server is created and started
102
+ - Session management is configured
103
+ - CORS is enabled (if specified)
104
+
105
+ **Directory Structure:**
106
+ ```
107
+ your-project/
108
+ ├── main.ts
109
+ └── mcp/
110
+ ├── sentiment/
111
+ │ └── index.ts # export class SentimentService
112
+ ├── weather/
113
+ │ └── index.ts # export class WeatherService
114
+ └── database/
115
+ └── index.ts # export class DatabaseService
116
+ ```
117
+
118
+ #### Option B: Factory Pattern (Advanced)
119
+
120
+ For advanced use cases requiring manual service registration or custom configuration:
121
+
78
122
  ```typescript
79
123
  import { createHTTPServer, MCPServer } from "@leanmcp/core";
80
124
  import { SentimentService } from "./services/sentiment";
81
125
 
82
- // Create MCP server
83
- const serverFactory = () => {
126
+ // Create MCP server with factory function
127
+ const serverFactory = async () => {
84
128
  const server = new MCPServer({
85
129
  name: "my-mcp-server",
86
130
  version: "1.0.0",
87
- logging: true
131
+ logging: true,
132
+ autoDiscover: false // Disable auto-discovery for manual registration
88
133
  });
89
134
 
90
- // Register services
135
+ // Register services manually
91
136
  server.registerService(new SentimentService());
92
137
 
93
138
  return server.getServer();
94
139
  };
95
140
 
96
- // Start HTTP server
141
+ // Start HTTP server with factory
97
142
  await createHTTPServer(serverFactory, {
98
143
  port: 3000,
99
144
  cors: true,
@@ -220,30 +265,186 @@ Main server class for registering services.
220
265
 
221
266
  ```typescript
222
267
  const server = new MCPServer({
223
- name: string; // Server name
224
- version: string; // Server version
225
- logging?: boolean; // Enable logging (default: false)
268
+ name: string; // Server name
269
+ version: string; // Server version
270
+ logging?: boolean; // Enable logging (default: false)
271
+ debug?: boolean; // Enable verbose debug logs (default: false)
272
+ autoDiscover?: boolean; // Enable auto-discovery (default: true)
273
+ mcpDir?: string; // Custom mcp directory path (optional)
226
274
  });
227
275
 
276
+ // Manual registration
228
277
  server.registerService(instance: any): void;
229
- server.getServer(): Server; // Get underlying MCP SDK server
278
+
279
+ // Get underlying MCP SDK server
280
+ server.getServer(): Server;
281
+ ```
282
+
283
+ **Options:**
284
+
285
+ - **`logging`**: Enable basic logging for server operations
286
+ - **`debug`**: Enable verbose debug logs showing detailed service registration (requires `logging: true`)
287
+ - **`autoDiscover`**: Automatically discover and register services from `./mcp` directory (default: `true`)
288
+ - **`mcpDir`**: Custom path to the mcp directory (default: auto-detected `./mcp`)
289
+
290
+ #### Zero-Config Auto-Discovery
291
+
292
+ Services are automatically discovered and registered from the `./mcp` directory when the server is created:
293
+
294
+ **Basic Usage (Simplified API):**
295
+ ```typescript
296
+ import { createHTTPServer } from "@leanmcp/core";
297
+
298
+ await createHTTPServer({
299
+ name: "my-server",
300
+ version: "1.0.0",
301
+ port: 3000,
302
+ logging: true // Enable logging
303
+ });
304
+ ```
305
+
306
+ **With Debug Logging:**
307
+ ```typescript
308
+ await createHTTPServer({
309
+ name: "my-server",
310
+ version: "1.0.0",
311
+ port: 3000,
312
+ logging: true,
313
+ debug: true // Show detailed service registration logs
314
+ });
315
+ ```
316
+
317
+ **With Shared Dependencies:**
318
+
319
+ For services that need shared dependencies, create a `config.ts` (example) file in your `mcp` directory:
320
+
321
+ ```typescript
322
+ // mcp/config.ts
323
+ import { AuthProvider } from "@leanmcp/auth";
324
+
325
+ if (!process.env.COGNITO_USER_POOL_ID || !process.env.COGNITO_CLIENT_ID) {
326
+ throw new Error('Missing required Cognito configuration');
327
+ }
328
+
329
+ export const authProvider = new AuthProvider('cognito', {
330
+ region: process.env.AWS_REGION || 'us-east-1',
331
+ userPoolId: process.env.COGNITO_USER_POOL_ID,
332
+ clientId: process.env.COGNITO_CLIENT_ID,
333
+ clientSecret: process.env.COGNITO_CLIENT_SECRET
334
+ });
335
+
336
+ await authProvider.init();
337
+ ```
338
+
339
+ Then import in your services:
340
+
341
+ ```typescript
342
+ // mcp/slack/index.ts
343
+ import { Tool } from "@leanmcp/core";
344
+ import { Authenticated } from "@leanmcp/auth";
345
+ import { authProvider } from "../config.js";
346
+
347
+ @Authenticated(authProvider)
348
+ export class SlackService {
349
+ constructor() {
350
+ // No parameters needed - use environment or imported config
351
+ }
352
+
353
+ @Tool({ description: 'Send a message' })
354
+ async sendMessage(args: any) {
355
+ // Implementation
356
+ }
357
+ }
358
+ ```
359
+
360
+ Your main file stays clean:
361
+
362
+ ```typescript
363
+ import { createHTTPServer } from "@leanmcp/core";
364
+
365
+ await createHTTPServer({
366
+ name: "my-server",
367
+ version: "1.0.0",
368
+ port: 3000,
369
+ logging: true
370
+ });
371
+
372
+ // Services are automatically discovered and registered
373
+ ```
374
+
375
+ **How It Works:**
376
+ - Automatically discovers and registers services from the `./mcp` directory during server initialization
377
+ - Recursively scans for `index.ts` or `index.js` files
378
+ - Dynamically imports each file and looks for exported classes
379
+ - Instantiates services with no-args constructors
380
+ - Registers all discovered services with their decorated methods
381
+
382
+ **Directory Structure:**
383
+ ```
384
+ your-project/
385
+ ├── main.ts
386
+ └── mcp/
387
+ ├── config.ts # Optional: shared dependencies
388
+ ├── slack/
389
+ │ └── index.ts # export class SlackService
390
+ ├── database/
391
+ │ └── index.ts # export class DatabaseService
392
+ └── auth/
393
+ └── index.ts # export class AuthService
230
394
  ```
231
395
 
232
396
  ### createHTTPServer
233
397
 
234
398
  Create and start an HTTP server with streamable transport.
235
399
 
400
+ **Simplified API (Recommended):**
401
+ ```typescript
402
+ await createHTTPServer({
403
+ name: string; // Server name (required)
404
+ version: string; // Server version (required)
405
+ port?: number; // Port number (default: 3001)
406
+ cors?: boolean | object; // Enable CORS (default: false)
407
+ logging?: boolean; // Enable logging (default: false)
408
+ debug?: boolean; // Enable debug logs (default: false)
409
+ autoDiscover?: boolean; // Auto-discover services (default: true)
410
+ mcpDir?: string; // Custom mcp directory path (optional)
411
+ sessionTimeout?: number; // Session timeout in ms (optional)
412
+ });
413
+ ```
414
+
415
+ **Factory Pattern (Advanced):**
236
416
  ```typescript
237
417
  await createHTTPServer(
238
- serverFactory: () => Server,
418
+ serverFactory: () => Server | Promise<Server>,
239
419
  options: {
240
- port?: number; // Port number (default: 3000)
241
- cors?: boolean; // Enable CORS (default: false)
242
- logging?: boolean; // Enable logging (default: true)
420
+ port?: number; // Port number (default: 3001)
421
+ cors?: boolean | object; // Enable CORS (default: false)
422
+ logging?: boolean; // Enable HTTP request logging (default: false)
423
+ sessionTimeout?: number; // Session timeout in ms (optional)
243
424
  }
244
425
  );
245
426
  ```
246
427
 
428
+ **CORS Configuration:**
429
+ ```typescript
430
+ // Simple CORS (allow all origins - not recommended for production)
431
+ await createHTTPServer({
432
+ name: "my-server",
433
+ version: "1.0.0",
434
+ cors: true
435
+ });
436
+
437
+ // Advanced CORS configuration
438
+ await createHTTPServer({
439
+ name: "my-server",
440
+ version: "1.0.0",
441
+ cors: {
442
+ origin: 'https://example.com', // Specific origin
443
+ credentials: true // Allow credentials
444
+ }
445
+ });
446
+ ```
447
+
247
448
  ### Schema Generation
248
449
 
249
450
  Generate JSON Schema from TypeScript classes:
package/dist/index.d.mts CHANGED
@@ -223,10 +223,15 @@ interface HTTPServerOptions {
223
223
  interface MCPServerFactory {
224
224
  (): Server | Promise<Server>;
225
225
  }
226
+ type HTTPServerInput = MCPServerFactory | MCPServerConstructorOptions;
226
227
  /**
227
228
  * Create an HTTP server for MCP with Streamable HTTP transport
229
+ * Returns the HTTP server instance to keep the process alive
230
+ *
231
+ * @param serverInput - Either MCPServerConstructorOptions or a factory function that returns a Server
232
+ * @param options - HTTP server options (only used when serverInput is a factory function)
228
233
  */
229
- declare function createHTTPServer(serverFactory: MCPServerFactory, options?: HTTPServerOptions): Promise<void>;
234
+ declare function createHTTPServer(serverInput: HTTPServerInput, options?: HTTPServerOptions): Promise<any>;
230
235
 
231
236
  /**
232
237
  * Input validation utilities for LeanMCP
@@ -315,6 +320,21 @@ interface MCPServerOptions {
315
320
  cors?: boolean;
316
321
  logging?: boolean;
317
322
  }
323
+ interface MCPServerConstructorOptions {
324
+ name: string;
325
+ version: string;
326
+ logging?: boolean;
327
+ debug?: boolean;
328
+ autoDiscover?: boolean;
329
+ mcpDir?: string;
330
+ serviceFactories?: Record<string, () => any>;
331
+ port?: number;
332
+ cors?: boolean | {
333
+ origin?: string | string[];
334
+ credentials?: boolean;
335
+ };
336
+ sessionTimeout?: number;
337
+ }
318
338
  interface RegisteredTool {
319
339
  name: string;
320
340
  description: string;
@@ -352,18 +372,63 @@ declare class MCPServer {
352
372
  private resources;
353
373
  private logging;
354
374
  private logger;
355
- constructor(options: {
356
- name: string;
357
- version: string;
358
- logging?: boolean;
359
- });
375
+ private options;
376
+ private initPromise;
377
+ private autoDiscovered;
378
+ constructor(options: MCPServerConstructorOptions);
379
+ /**
380
+ * Internal initialization - runs automatically in constructor
381
+ */
382
+ private autoInit;
383
+ /**
384
+ * Wait for initialization to complete
385
+ * This is called internally by createHTTPServer
386
+ */
387
+ waitForInit(): Promise<void>;
388
+ /**
389
+ * Automatically discover and register services from the mcp directory
390
+ * Called by init() unless autoDiscover is set to false
391
+ */
392
+ private autoDiscoverServices;
393
+ /**
394
+ * Get the file path of the caller (the file that instantiated MCPServer)
395
+ */
396
+ private getCallerFile;
360
397
  private setupHandlers;
398
+ /**
399
+ * Auto-register all services from the mcp directory
400
+ * Scans the directory recursively and registers all exported classes
401
+ *
402
+ * @param mcpDir - Path to the mcp directory containing service files
403
+ * @param serviceFactories - Optional map of service class names to factory functions for dependency injection
404
+ *
405
+ * @example
406
+ * // Auto-register services with no dependencies
407
+ * await server.autoRegisterServices('./mcp');
408
+ *
409
+ * @example
410
+ * // Auto-register with dependency injection
411
+ * await server.autoRegisterServices('./mcp', {
412
+ * SlackService: () => new SlackService(process.env.SLACK_TOKEN),
413
+ * AuthService: () => new AuthService(authProvider)
414
+ * });
415
+ */
416
+ autoRegisterServices(mcpDir: string, serviceFactories?: Record<string, () => any>): Promise<void>;
417
+ /**
418
+ * Recursively find all index.ts/index.js files in the mcp directory
419
+ */
420
+ private findServiceFiles;
421
+ /**
422
+ * Load a service file and register all exported classes
423
+ */
424
+ private loadAndRegisterService;
361
425
  /**
362
426
  * Register a service instance with decorated methods
363
427
  */
364
428
  registerService(instance: any): void;
365
429
  /**
366
430
  * Get the underlying MCP SDK Server instance
431
+ * Attaches waitForInit method for HTTP server initialization
367
432
  */
368
433
  getServer(): Server<{
369
434
  method: string;
@@ -432,4 +497,4 @@ declare class MCPServerRuntime {
432
497
  */
433
498
  declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
434
499
 
435
- export { Auth, type AuthOptions, Deprecated, type HTTPServerOptions, LogLevel, Logger, type LoggerOptions, MCPServer, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, Render, Resource, type ResourceOptions, SchemaConstraint, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createHTTPServer, defaultLogger, getDecoratedMethods, getMethodMetadata, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
500
+ export { Auth, type AuthOptions, Deprecated, type HTTPServerInput, type HTTPServerOptions, LogLevel, Logger, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, Render, Resource, type ResourceOptions, SchemaConstraint, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createHTTPServer, defaultLogger, getDecoratedMethods, getMethodMetadata, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
package/dist/index.d.ts CHANGED
@@ -223,10 +223,15 @@ interface HTTPServerOptions {
223
223
  interface MCPServerFactory {
224
224
  (): Server | Promise<Server>;
225
225
  }
226
+ type HTTPServerInput = MCPServerFactory | MCPServerConstructorOptions;
226
227
  /**
227
228
  * Create an HTTP server for MCP with Streamable HTTP transport
229
+ * Returns the HTTP server instance to keep the process alive
230
+ *
231
+ * @param serverInput - Either MCPServerConstructorOptions or a factory function that returns a Server
232
+ * @param options - HTTP server options (only used when serverInput is a factory function)
228
233
  */
229
- declare function createHTTPServer(serverFactory: MCPServerFactory, options?: HTTPServerOptions): Promise<void>;
234
+ declare function createHTTPServer(serverInput: HTTPServerInput, options?: HTTPServerOptions): Promise<any>;
230
235
 
231
236
  /**
232
237
  * Input validation utilities for LeanMCP
@@ -315,6 +320,21 @@ interface MCPServerOptions {
315
320
  cors?: boolean;
316
321
  logging?: boolean;
317
322
  }
323
+ interface MCPServerConstructorOptions {
324
+ name: string;
325
+ version: string;
326
+ logging?: boolean;
327
+ debug?: boolean;
328
+ autoDiscover?: boolean;
329
+ mcpDir?: string;
330
+ serviceFactories?: Record<string, () => any>;
331
+ port?: number;
332
+ cors?: boolean | {
333
+ origin?: string | string[];
334
+ credentials?: boolean;
335
+ };
336
+ sessionTimeout?: number;
337
+ }
318
338
  interface RegisteredTool {
319
339
  name: string;
320
340
  description: string;
@@ -352,18 +372,63 @@ declare class MCPServer {
352
372
  private resources;
353
373
  private logging;
354
374
  private logger;
355
- constructor(options: {
356
- name: string;
357
- version: string;
358
- logging?: boolean;
359
- });
375
+ private options;
376
+ private initPromise;
377
+ private autoDiscovered;
378
+ constructor(options: MCPServerConstructorOptions);
379
+ /**
380
+ * Internal initialization - runs automatically in constructor
381
+ */
382
+ private autoInit;
383
+ /**
384
+ * Wait for initialization to complete
385
+ * This is called internally by createHTTPServer
386
+ */
387
+ waitForInit(): Promise<void>;
388
+ /**
389
+ * Automatically discover and register services from the mcp directory
390
+ * Called by init() unless autoDiscover is set to false
391
+ */
392
+ private autoDiscoverServices;
393
+ /**
394
+ * Get the file path of the caller (the file that instantiated MCPServer)
395
+ */
396
+ private getCallerFile;
360
397
  private setupHandlers;
398
+ /**
399
+ * Auto-register all services from the mcp directory
400
+ * Scans the directory recursively and registers all exported classes
401
+ *
402
+ * @param mcpDir - Path to the mcp directory containing service files
403
+ * @param serviceFactories - Optional map of service class names to factory functions for dependency injection
404
+ *
405
+ * @example
406
+ * // Auto-register services with no dependencies
407
+ * await server.autoRegisterServices('./mcp');
408
+ *
409
+ * @example
410
+ * // Auto-register with dependency injection
411
+ * await server.autoRegisterServices('./mcp', {
412
+ * SlackService: () => new SlackService(process.env.SLACK_TOKEN),
413
+ * AuthService: () => new AuthService(authProvider)
414
+ * });
415
+ */
416
+ autoRegisterServices(mcpDir: string, serviceFactories?: Record<string, () => any>): Promise<void>;
417
+ /**
418
+ * Recursively find all index.ts/index.js files in the mcp directory
419
+ */
420
+ private findServiceFiles;
421
+ /**
422
+ * Load a service file and register all exported classes
423
+ */
424
+ private loadAndRegisterService;
361
425
  /**
362
426
  * Register a service instance with decorated methods
363
427
  */
364
428
  registerService(instance: any): void;
365
429
  /**
366
430
  * Get the underlying MCP SDK Server instance
431
+ * Attaches waitForInit method for HTTP server initialization
367
432
  */
368
433
  getServer(): Server<{
369
434
  method: string;
@@ -432,4 +497,4 @@ declare class MCPServerRuntime {
432
497
  */
433
498
  declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
434
499
 
435
- export { Auth, type AuthOptions, Deprecated, type HTTPServerOptions, LogLevel, Logger, type LoggerOptions, MCPServer, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, Render, Resource, type ResourceOptions, SchemaConstraint, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createHTTPServer, defaultLogger, getDecoratedMethods, getMethodMetadata, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
500
+ export { Auth, type AuthOptions, Deprecated, type HTTPServerInput, type HTTPServerOptions, LogLevel, Logger, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, Render, Resource, type ResourceOptions, SchemaConstraint, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createHTTPServer, defaultLogger, getDecoratedMethods, getMethodMetadata, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };