@leanmcp/core 0.3.3 → 0.3.5

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
@@ -1,555 +1,555 @@
1
- # @leanmcp/core
2
-
3
- Core library for building Model Context Protocol (MCP) servers with TypeScript decorators and declarative schema definition.
4
-
5
- ## Features
6
-
7
- - **Type-safe decorators** - `@Tool`, `@Prompt`, `@Resource` with full TypeScript support
8
- - **Schema generation** - Define JSON Schema declaratively using `@SchemaConstraint` decorators on class properties
9
- - **Streamable HTTP transport** - Production-ready HTTP server with session management
10
- - **Input validation** - Built-in AJV validation for all inputs
11
- - **Clean API** - Function names automatically become tool/prompt/resource names
12
- - **MCP compliant** - Built on official `@modelcontextprotocol/sdk`
13
-
14
- ## Installation
15
-
16
- ```bash
17
- npm install @leanmcp/core
18
- ```
19
-
20
- ### Peer Dependencies
21
-
22
- For HTTP server support:
23
- ```bash
24
- npm install express cors
25
- ```
26
-
27
- ## Quick Start
28
-
29
- ### 1. Define Your Service with Class-Based Schema
30
-
31
- ```typescript
32
- import { Tool, SchemaConstraint, Optional } from "@leanmcp/core";
33
-
34
- // Define input schema as a class
35
- class AnalyzeSentimentInput {
36
- @SchemaConstraint({
37
- description: 'Text to analyze',
38
- minLength: 1
39
- })
40
- text!: string;
41
-
42
- @Optional()
43
- @SchemaConstraint({
44
- description: 'Language code',
45
- enum: ['en', 'es', 'fr'],
46
- default: 'en'
47
- })
48
- language?: string;
49
- }
50
-
51
- // Define output schema
52
- class AnalyzeSentimentOutput {
53
- @SchemaConstraint({ enum: ['positive', 'negative', 'neutral'] })
54
- sentiment!: string;
55
-
56
- @SchemaConstraint({ minimum: -1, maximum: 1 })
57
- score!: number;
58
- }
59
-
60
- export class SentimentService {
61
- @Tool({
62
- description: 'Analyze sentiment of text',
63
- inputClass: AnalyzeSentimentInput
64
- })
65
- async analyzeSentiment(input: AnalyzeSentimentInput): Promise<AnalyzeSentimentOutput> {
66
- // Your implementation
67
- return {
68
- sentiment: 'positive',
69
- score: 0.8,
70
- confidence: 0.95
71
- };
72
- }
73
- }
74
- ```
75
-
76
- ### 2. Create and Start Server
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
-
122
- ```typescript
123
- import { createHTTPServer, MCPServer } from "@leanmcp/core";
124
- import { SentimentService } from "./services/sentiment";
125
-
126
- // Create MCP server with factory function
127
- const serverFactory = async () => {
128
- const server = new MCPServer({
129
- name: "my-mcp-server",
130
- version: "1.0.0",
131
- logging: true,
132
- autoDiscover: false // Disable auto-discovery for manual registration
133
- });
134
-
135
- // Register services manually
136
- server.registerService(new SentimentService());
137
-
138
- return server.getServer();
139
- };
140
-
141
- // Start HTTP server with factory
142
- await createHTTPServer(serverFactory, {
143
- port: 3000,
144
- cors: true,
145
- logging: true
146
- });
147
- ```
148
-
149
- ## Decorators
150
-
151
- ### @Tool
152
-
153
- Marks a method as an MCP tool (callable function). Use `inputClass` to specify the input schema class.
154
-
155
- ```typescript
156
- class CalculateInput {
157
- @SchemaConstraint({ description: 'First number' })
158
- a!: number;
159
-
160
- @SchemaConstraint({ description: 'Second number' })
161
- b!: number;
162
- }
163
-
164
- @Tool({
165
- description: 'Calculate sum of two numbers',
166
- inputClass: CalculateInput
167
- })
168
- async calculate(input: CalculateInput) {
169
- return { result: input.a + input.b };
170
- }
171
- ```
172
-
173
- ### @Prompt
174
-
175
- Marks a method as an MCP prompt template. Input schema is automatically inferred from parameter type.
176
-
177
- ```typescript
178
- class CodeReviewInput {
179
- @SchemaConstraint({ description: 'Code to review' })
180
- code!: string;
181
-
182
- @SchemaConstraint({ description: 'Programming language' })
183
- language!: string;
184
- }
185
-
186
- @Prompt({ description: 'Generate code review prompt' })
187
- codeReview(input: CodeReviewInput) {
188
- return {
189
- messages: [{
190
- role: "user",
191
- content: {
192
- type: "text",
193
- text: `Review this ${input.language} code:\n\n${input.code}`
194
- }
195
- }]
196
- };
197
- }
198
- ```
199
-
200
- ### @Resource
201
-
202
- Marks a method as an MCP resource (data source).
203
-
204
- ```typescript
205
- @Resource({ description: 'Get system configuration', mimeType: 'application/json' })
206
- async getConfig() {
207
- return {
208
- version: "1.0.0",
209
- environment: process.env.NODE_ENV
210
- };
211
- }
212
- ```
213
-
214
- ### @SchemaConstraint
215
-
216
- Add validation constraints to class properties for automatic schema generation.
217
-
218
- ```typescript
219
- class UserInput {
220
- @SchemaConstraint({
221
- description: 'User email',
222
- format: 'email',
223
- minLength: 5,
224
- maxLength: 100
225
- })
226
- email!: string;
227
-
228
- @SchemaConstraint({
229
- description: 'User age',
230
- minimum: 18,
231
- maximum: 120
232
- })
233
- age!: number;
234
-
235
- @Optional()
236
- @SchemaConstraint({
237
- description: 'User role',
238
- enum: ['admin', 'user', 'guest'],
239
- default: 'user'
240
- })
241
- role?: string;
242
- }
243
- ```
244
-
245
- ### @Optional
246
-
247
- Marks a property as optional in the schema.
248
-
249
- ```typescript
250
- class SearchInput {
251
- @SchemaConstraint({ description: 'Search query' })
252
- query!: string;
253
-
254
- @Optional()
255
- @SchemaConstraint({ description: 'Max results', default: 10 })
256
- limit?: number;
257
- }
258
- ```
259
-
260
- ## API Reference
261
-
262
- ### MCPServer
263
-
264
- Main server class for registering services.
265
-
266
- ```typescript
267
- const server = new MCPServer({
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)
274
- });
275
-
276
- // Manual registration
277
- server.registerService(instance: any): void;
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
394
- ```
395
-
396
- ### createHTTPServer
397
-
398
- Create and start an HTTP server with streamable transport.
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):**
416
- ```typescript
417
- await createHTTPServer(
418
- serverFactory: () => Server | Promise<Server>,
419
- options: {
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)
424
- }
425
- );
426
- ```
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
-
448
- ### Schema Generation
449
-
450
- Generate JSON Schema from TypeScript classes:
451
-
452
- ```typescript
453
- import { classToJsonSchemaWithConstraints } from "@leanmcp/core";
454
-
455
- const schema = classToJsonSchemaWithConstraints(MyInputClass);
456
- ```
457
-
458
- ## HTTP Endpoints
459
-
460
- When using `createHTTPServer`, the following endpoints are available:
461
-
462
- - `POST /mcp` - MCP protocol endpoint (accepts JSON-RPC 2.0 messages)
463
- - `GET /health` - Health check endpoint
464
- - `GET /` - Welcome message
465
-
466
- ## Environment Variables
467
-
468
- ```bash
469
- PORT=3000 # Server port (optional)
470
- NODE_ENV=production # Environment (optional)
471
- ```
472
-
473
- ## Error Handling
474
-
475
- All tools automatically handle errors and return them in MCP format:
476
-
477
- ```typescript
478
- class DivideInput {
479
- @SchemaConstraint({ description: 'Numerator' })
480
- a!: number;
481
-
482
- @SchemaConstraint({ description: 'Denominator' })
483
- b!: number;
484
- }
485
-
486
- @Tool({
487
- description: 'Divide numbers',
488
- inputClass: DivideInput
489
- })
490
- async divide(input: DivideInput) {
491
- if (input.b === 0) {
492
- throw new Error("Division by zero");
493
- }
494
- return { result: input.a / input.b };
495
- }
496
- ```
497
-
498
- Errors are returned as:
499
- ```json
500
- {
501
- "content": [{"type": "text", "text": "Error: Division by zero"}],
502
- "isError": true
503
- }
504
- ```
505
-
506
- ## TypeScript Support
507
-
508
- Full TypeScript support with type inference:
509
-
510
- ```typescript
511
- class MyInput {
512
- @SchemaConstraint({ description: 'Input field' })
513
- field!: string;
514
- }
515
-
516
- class MyOutput {
517
- result!: string;
518
- }
519
-
520
- // Input schema defined via inputClass, output type inferred from return type
521
- @Tool({
522
- description: 'My tool',
523
- inputClass: MyInput
524
- })
525
- async myTool(input: MyInput): Promise<MyOutput> {
526
- // TypeScript knows the exact types
527
- const result: MyOutput = {
528
- result: input.field.toUpperCase()
529
- // Full autocomplete and type checking
530
- };
531
- return result;
532
- }
533
- ```
534
-
535
- **Key Points:**
536
- - Input schema is defined using `inputClass` in the `@Tool` decorator
537
- - Output schema is inferred from the return type
538
- - For tools with no input parameters, omit the `inputClass` option
539
- - Use `@SchemaConstraint` decorators to add validation and documentation to your input classes
540
-
541
- ## License
542
-
543
- MIT
544
-
545
- ## Related Packages
546
-
547
- - [@leanmcp/cli](../cli) - CLI tool for creating new projects
548
- - [@leanmcp/auth](../auth) - Authentication decorators and providers
549
- - [@leanmcp/utils](../utils) - Utility functions
550
-
551
- ## Links
552
-
553
- - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
554
- - [MCP Specification](https://spec.modelcontextprotocol.io/)
555
- - [Documentation](https://github.com/LeanMCP/leanmcp-sdk#readme)
1
+ # @leanmcp/core
2
+
3
+ Core library for building Model Context Protocol (MCP) servers with TypeScript decorators and declarative schema definition.
4
+
5
+ ## Features
6
+
7
+ - **Type-safe decorators** - `@Tool`, `@Prompt`, `@Resource` with full TypeScript support
8
+ - **Schema generation** - Define JSON Schema declaratively using `@SchemaConstraint` decorators on class properties
9
+ - **Streamable HTTP transport** - Production-ready HTTP server with session management
10
+ - **Input validation** - Built-in AJV validation for all inputs
11
+ - **Clean API** - Function names automatically become tool/prompt/resource names
12
+ - **MCP compliant** - Built on official `@modelcontextprotocol/sdk`
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @leanmcp/core
18
+ ```
19
+
20
+ ### Peer Dependencies
21
+
22
+ For HTTP server support:
23
+ ```bash
24
+ npm install express cors
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Define Your Service with Class-Based Schema
30
+
31
+ ```typescript
32
+ import { Tool, SchemaConstraint, Optional } from "@leanmcp/core";
33
+
34
+ // Define input schema as a class
35
+ class AnalyzeSentimentInput {
36
+ @SchemaConstraint({
37
+ description: 'Text to analyze',
38
+ minLength: 1
39
+ })
40
+ text!: string;
41
+
42
+ @Optional()
43
+ @SchemaConstraint({
44
+ description: 'Language code',
45
+ enum: ['en', 'es', 'fr'],
46
+ default: 'en'
47
+ })
48
+ language?: string;
49
+ }
50
+
51
+ // Define output schema
52
+ class AnalyzeSentimentOutput {
53
+ @SchemaConstraint({ enum: ['positive', 'negative', 'neutral'] })
54
+ sentiment!: string;
55
+
56
+ @SchemaConstraint({ minimum: -1, maximum: 1 })
57
+ score!: number;
58
+ }
59
+
60
+ export class SentimentService {
61
+ @Tool({
62
+ description: 'Analyze sentiment of text',
63
+ inputClass: AnalyzeSentimentInput
64
+ })
65
+ async analyzeSentiment(input: AnalyzeSentimentInput): Promise<AnalyzeSentimentOutput> {
66
+ // Your implementation
67
+ return {
68
+ sentiment: 'positive',
69
+ score: 0.8,
70
+ confidence: 0.95
71
+ };
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### 2. Create and Start Server
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
+
122
+ ```typescript
123
+ import { createHTTPServer, MCPServer } from "@leanmcp/core";
124
+ import { SentimentService } from "./services/sentiment";
125
+
126
+ // Create MCP server with factory function
127
+ const serverFactory = async () => {
128
+ const server = new MCPServer({
129
+ name: "my-mcp-server",
130
+ version: "1.0.0",
131
+ logging: true,
132
+ autoDiscover: false // Disable auto-discovery for manual registration
133
+ });
134
+
135
+ // Register services manually
136
+ server.registerService(new SentimentService());
137
+
138
+ return server.getServer();
139
+ };
140
+
141
+ // Start HTTP server with factory
142
+ await createHTTPServer(serverFactory, {
143
+ port: 3000,
144
+ cors: true,
145
+ logging: true
146
+ });
147
+ ```
148
+
149
+ ## Decorators
150
+
151
+ ### @Tool
152
+
153
+ Marks a method as an MCP tool (callable function). Use `inputClass` to specify the input schema class.
154
+
155
+ ```typescript
156
+ class CalculateInput {
157
+ @SchemaConstraint({ description: 'First number' })
158
+ a!: number;
159
+
160
+ @SchemaConstraint({ description: 'Second number' })
161
+ b!: number;
162
+ }
163
+
164
+ @Tool({
165
+ description: 'Calculate sum of two numbers',
166
+ inputClass: CalculateInput
167
+ })
168
+ async calculate(input: CalculateInput) {
169
+ return { result: input.a + input.b };
170
+ }
171
+ ```
172
+
173
+ ### @Prompt
174
+
175
+ Marks a method as an MCP prompt template. Input schema is automatically inferred from parameter type.
176
+
177
+ ```typescript
178
+ class CodeReviewInput {
179
+ @SchemaConstraint({ description: 'Code to review' })
180
+ code!: string;
181
+
182
+ @SchemaConstraint({ description: 'Programming language' })
183
+ language!: string;
184
+ }
185
+
186
+ @Prompt({ description: 'Generate code review prompt' })
187
+ codeReview(input: CodeReviewInput) {
188
+ return {
189
+ messages: [{
190
+ role: "user",
191
+ content: {
192
+ type: "text",
193
+ text: `Review this ${input.language} code:\n\n${input.code}`
194
+ }
195
+ }]
196
+ };
197
+ }
198
+ ```
199
+
200
+ ### @Resource
201
+
202
+ Marks a method as an MCP resource (data source).
203
+
204
+ ```typescript
205
+ @Resource({ description: 'Get system configuration', mimeType: 'application/json' })
206
+ async getConfig() {
207
+ return {
208
+ version: "1.0.0",
209
+ environment: process.env.NODE_ENV
210
+ };
211
+ }
212
+ ```
213
+
214
+ ### @SchemaConstraint
215
+
216
+ Add validation constraints to class properties for automatic schema generation.
217
+
218
+ ```typescript
219
+ class UserInput {
220
+ @SchemaConstraint({
221
+ description: 'User email',
222
+ format: 'email',
223
+ minLength: 5,
224
+ maxLength: 100
225
+ })
226
+ email!: string;
227
+
228
+ @SchemaConstraint({
229
+ description: 'User age',
230
+ minimum: 18,
231
+ maximum: 120
232
+ })
233
+ age!: number;
234
+
235
+ @Optional()
236
+ @SchemaConstraint({
237
+ description: 'User role',
238
+ enum: ['admin', 'user', 'guest'],
239
+ default: 'user'
240
+ })
241
+ role?: string;
242
+ }
243
+ ```
244
+
245
+ ### @Optional
246
+
247
+ Marks a property as optional in the schema.
248
+
249
+ ```typescript
250
+ class SearchInput {
251
+ @SchemaConstraint({ description: 'Search query' })
252
+ query!: string;
253
+
254
+ @Optional()
255
+ @SchemaConstraint({ description: 'Max results', default: 10 })
256
+ limit?: number;
257
+ }
258
+ ```
259
+
260
+ ## API Reference
261
+
262
+ ### MCPServer
263
+
264
+ Main server class for registering services.
265
+
266
+ ```typescript
267
+ const server = new MCPServer({
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)
274
+ });
275
+
276
+ // Manual registration
277
+ server.registerService(instance: any): void;
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
394
+ ```
395
+
396
+ ### createHTTPServer
397
+
398
+ Create and start an HTTP server with streamable transport.
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):**
416
+ ```typescript
417
+ await createHTTPServer(
418
+ serverFactory: () => Server | Promise<Server>,
419
+ options: {
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)
424
+ }
425
+ );
426
+ ```
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
+
448
+ ### Schema Generation
449
+
450
+ Generate JSON Schema from TypeScript classes:
451
+
452
+ ```typescript
453
+ import { classToJsonSchemaWithConstraints } from "@leanmcp/core";
454
+
455
+ const schema = classToJsonSchemaWithConstraints(MyInputClass);
456
+ ```
457
+
458
+ ## HTTP Endpoints
459
+
460
+ When using `createHTTPServer`, the following endpoints are available:
461
+
462
+ - `POST /mcp` - MCP protocol endpoint (accepts JSON-RPC 2.0 messages)
463
+ - `GET /health` - Health check endpoint
464
+ - `GET /` - Welcome message
465
+
466
+ ## Environment Variables
467
+
468
+ ```bash
469
+ PORT=3000 # Server port (optional)
470
+ NODE_ENV=production # Environment (optional)
471
+ ```
472
+
473
+ ## Error Handling
474
+
475
+ All tools automatically handle errors and return them in MCP format:
476
+
477
+ ```typescript
478
+ class DivideInput {
479
+ @SchemaConstraint({ description: 'Numerator' })
480
+ a!: number;
481
+
482
+ @SchemaConstraint({ description: 'Denominator' })
483
+ b!: number;
484
+ }
485
+
486
+ @Tool({
487
+ description: 'Divide numbers',
488
+ inputClass: DivideInput
489
+ })
490
+ async divide(input: DivideInput) {
491
+ if (input.b === 0) {
492
+ throw new Error("Division by zero");
493
+ }
494
+ return { result: input.a / input.b };
495
+ }
496
+ ```
497
+
498
+ Errors are returned as:
499
+ ```json
500
+ {
501
+ "content": [{"type": "text", "text": "Error: Division by zero"}],
502
+ "isError": true
503
+ }
504
+ ```
505
+
506
+ ## TypeScript Support
507
+
508
+ Full TypeScript support with type inference:
509
+
510
+ ```typescript
511
+ class MyInput {
512
+ @SchemaConstraint({ description: 'Input field' })
513
+ field!: string;
514
+ }
515
+
516
+ class MyOutput {
517
+ result!: string;
518
+ }
519
+
520
+ // Input schema defined via inputClass, output type inferred from return type
521
+ @Tool({
522
+ description: 'My tool',
523
+ inputClass: MyInput
524
+ })
525
+ async myTool(input: MyInput): Promise<MyOutput> {
526
+ // TypeScript knows the exact types
527
+ const result: MyOutput = {
528
+ result: input.field.toUpperCase()
529
+ // Full autocomplete and type checking
530
+ };
531
+ return result;
532
+ }
533
+ ```
534
+
535
+ **Key Points:**
536
+ - Input schema is defined using `inputClass` in the `@Tool` decorator
537
+ - Output schema is inferred from the return type
538
+ - For tools with no input parameters, omit the `inputClass` option
539
+ - Use `@SchemaConstraint` decorators to add validation and documentation to your input classes
540
+
541
+ ## License
542
+
543
+ MIT
544
+
545
+ ## Related Packages
546
+
547
+ - [@leanmcp/cli](../cli) - CLI tool for creating new projects
548
+ - [@leanmcp/auth](../auth) - Authentication decorators and providers
549
+ - [@leanmcp/utils](../utils) - Utility functions
550
+
551
+ ## Links
552
+
553
+ - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
554
+ - [MCP Specification](https://spec.modelcontextprotocol.io/)
555
+ - [Documentation](https://github.com/LeanMCP/leanmcp-sdk#readme)