@leanmcp/core 0.3.17 → 0.3.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/README.md CHANGED
@@ -1,474 +1,478 @@
1
- <p align="center">
2
- <img
3
- src="https://raw.githubusercontent.com/LeanMCP/leanmcp-sdk/refs/heads/main/assets/logo.png"
4
- alt="LeanMCP Logo"
5
- width="400"
6
- />
7
- </p>
8
-
9
- <p align="center">
10
- <strong>@leanmcp/core</strong><br/>
11
- Core library for building MCP servers with TypeScript decorators and declarative schema definition.
12
- </p>
13
-
14
- <p align="center">
15
- <a href="https://www.npmjs.com/package/@leanmcp/core">
16
- <img src="https://img.shields.io/npm/v/@leanmcp/core" alt="npm version" />
17
- </a>
18
- <a href="https://www.npmjs.com/package/@leanmcp/core">
19
- <img src="https://img.shields.io/npm/dm/@leanmcp/core" alt="npm downloads" />
20
- </a>
21
- <a href="https://docs.leanmcp.com/sdk/core">
22
- <img src="https://img.shields.io/badge/Docs-leanmcp-0A66C2?" />
23
- </a>
24
- <a href="https://discord.com/invite/DsRcA3GwPy">
25
- <img src="https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white" />
26
- </a>
27
- <a href="https://x.com/LeanMcp">
28
- <img src="https://img.shields.io/badge/@LeanMCP-f5f5f5?logo=x&logoColor=000000" />
29
- </a>
30
- </p>
31
-
32
- ## Features
33
-
34
- - **Type-Safe Decorators** — `@Tool`, `@Prompt`, `@Resource` with full TypeScript support
35
- - **Auto-Discovery** — Zero-config service discovery from `./mcp` directory
36
- - **Schema Generation** — Declarative JSON Schema with `@SchemaConstraint` decorators
37
- - **HTTP Transport** — Production-ready HTTP server with session management
38
- - **Input Validation** — Built-in AJV validation for all inputs
39
- - **Structured Content** — Automatic `structuredContent` for ChatGPT Apps SDK compatibility
40
- - **MCP Compliant** — Built on official `@modelcontextprotocol/sdk`
41
-
42
- ## Installation
43
-
44
- ```bash
45
- npm install @leanmcp/core
46
- ```
47
-
48
- For HTTP server support:
49
- ```bash
50
- npm install express cors
51
- ```
52
-
53
- ## Quick Start
54
-
55
- ### Zero-Config (Recommended)
56
-
57
- The simplest way to create an MCP server with auto-discovery:
58
-
59
- ```typescript
60
- import { createHTTPServer } from "@leanmcp/core";
61
-
62
- await createHTTPServer({
63
- name: "my-mcp-server",
64
- version: "1.0.0",
65
- port: 3001,
66
- cors: true,
67
- logging: true
68
- });
69
-
70
- // Services are automatically discovered from ./mcp directory
71
- ```
72
-
73
- **Directory Structure:**
74
- ```
75
- your-project/
76
- ├── main.ts
77
- └── mcp/
78
- ├── sentiment/
79
- │ └── index.ts # export class SentimentService
80
- ├── weather/
81
- └── index.ts # export class WeatherService
82
- └── config.ts # Optional: shared dependencies
83
- ```
84
-
85
- ### Define a Service
86
-
87
- ```typescript
88
- // mcp/sentiment/index.ts
89
- import { Tool, SchemaConstraint, Optional } from "@leanmcp/core";
90
-
91
- class AnalyzeSentimentInput {
92
- @SchemaConstraint({
93
- description: 'Text to analyze',
94
- minLength: 1
95
- })
96
- text!: string;
97
-
98
- @Optional()
99
- @SchemaConstraint({
100
- description: 'Language code',
101
- enum: ['en', 'es', 'fr'],
102
- default: 'en'
103
- })
104
- language?: string;
105
- }
106
-
107
- export class SentimentService {
108
- @Tool({
109
- description: 'Analyze sentiment of text',
110
- inputClass: AnalyzeSentimentInput
111
- })
112
- async analyzeSentiment(input: AnalyzeSentimentInput) {
113
- return {
114
- sentiment: 'positive',
115
- score: 0.8
116
- };
117
- }
118
- }
119
- ```
120
-
121
- ---
122
-
123
- ## Decorators
124
-
125
- ### @Tool
126
-
127
- Marks a method as a callable MCP tool.
128
-
129
- ```typescript
130
- class CalculateInput {
131
- @SchemaConstraint({ description: 'First number' })
132
- a!: number;
133
-
134
- @SchemaConstraint({ description: 'Second number' })
135
- b!: number;
136
- }
137
-
138
- @Tool({
139
- description: 'Calculate sum of two numbers',
140
- inputClass: CalculateInput
141
- })
142
- async calculate(input: CalculateInput) {
143
- return { result: input.a + input.b };
144
- }
145
- ```
146
-
147
- **Options:**
148
-
149
- | Option | Type | Description |
150
- |--------|------|-------------|
151
- | `description` | `string` | Tool description for the AI |
152
- | `inputClass` | `Class` | Class defining input schema |
153
-
154
- ### @Prompt
155
-
156
- Marks a method as a reusable prompt template.
157
-
158
- ```typescript
159
- class CodeReviewInput {
160
- @SchemaConstraint({ description: 'Code to review' })
161
- code!: string;
162
-
163
- @SchemaConstraint({ description: 'Programming language' })
164
- language!: string;
165
- }
166
-
167
- @Prompt({ description: 'Generate code review prompt' })
168
- codeReview(input: CodeReviewInput) {
169
- return {
170
- messages: [{
171
- role: "user",
172
- content: {
173
- type: "text",
174
- text: `Review this ${input.language} code:\n\n${input.code}`
175
- }
176
- }]
177
- };
178
- }
179
- ```
180
-
181
- ### @Resource
182
-
183
- Marks a method as an MCP resource (data source).
184
-
185
- ```typescript
186
- @Resource({
187
- description: 'Get system configuration',
188
- mimeType: 'application/json'
189
- })
190
- async getConfig() {
191
- return {
192
- version: "1.0.0",
193
- environment: process.env.NODE_ENV
194
- };
195
- }
196
- ```
197
-
198
- ### @SchemaConstraint
199
-
200
- Add validation constraints to class properties.
201
-
202
- ```typescript
203
- class UserInput {
204
- @SchemaConstraint({
205
- description: 'User email',
206
- format: 'email',
207
- minLength: 5,
208
- maxLength: 100
209
- })
210
- email!: string;
211
-
212
- @SchemaConstraint({
213
- description: 'User age',
214
- minimum: 18,
215
- maximum: 120
216
- })
217
- age!: number;
218
-
219
- @Optional()
220
- @SchemaConstraint({
221
- description: 'User role',
222
- enum: ['admin', 'user', 'guest'],
223
- default: 'user'
224
- })
225
- role?: string;
226
- }
227
- ```
228
-
229
- **Common constraints:**
230
- - `description`, `default` — Documentation
231
- - `minLength`, `maxLength` — String length
232
- - `minimum`, `maximum` — Number range
233
- - `enum` — Allowed values
234
- - `format` — String format (`email`, `uri`, `date`, etc.)
235
- - `pattern` — Regex pattern
236
-
237
- ### @Optional
238
-
239
- Marks a property as optional in the schema.
240
-
241
- ```typescript
242
- class SearchInput {
243
- @SchemaConstraint({ description: 'Search query' })
244
- query!: string;
245
-
246
- @Optional()
247
- @SchemaConstraint({ description: 'Max results', default: 10 })
248
- limit?: number;
249
- }
250
- ```
251
-
252
- ---
253
-
254
- ## API Reference
255
-
256
- ### createHTTPServer
257
-
258
- Create and start an HTTP server with auto-discovery.
259
-
260
- **Simplified API (Recommended):**
261
- ```typescript
262
- await createHTTPServer({
263
- name: string; // Server name (required)
264
- version: string; // Server version (required)
265
- port?: number; // Port (default: 3001)
266
- cors?: boolean | object; // Enable CORS (default: false)
267
- logging?: boolean; // Enable logging (default: false)
268
- debug?: boolean; // Verbose debug logs (default: false)
269
- autoDiscover?: boolean; // Auto-discover services (default: true)
270
- mcpDir?: string; // Custom mcp directory path
271
- sessionTimeout?: number; // Session timeout in ms
272
- stateless?: boolean; // Stateless mode for Lambda/serverless (default: true)
273
- dashboard?: boolean; // Serve dashboard UI at / (default: true)
274
- });
275
- ```
276
-
277
- **Factory Pattern (Advanced):**
278
- ```typescript
279
- const serverFactory = async () => {
280
- const server = new MCPServer({
281
- name: "my-server",
282
- version: "1.0.0",
283
- autoDiscover: false // Disable for manual registration
284
- });
285
-
286
- server.registerService(new MyService());
287
- return server.getServer();
288
- };
289
-
290
- await createHTTPServer(serverFactory, {
291
- port: 3001,
292
- cors: true
293
- });
294
- ```
295
-
296
- ### MCPServer
297
-
298
- Main server class for registering services.
299
-
300
- ```typescript
301
- const server = new MCPServer({
302
- name: string; // Server name
303
- version: string; // Server version
304
- logging?: boolean; // Enable logging (default: false)
305
- debug?: boolean; // Verbose debug logs (default: false)
306
- autoDiscover?: boolean; // Auto-discover from ./mcp (default: true)
307
- mcpDir?: string; // Custom mcp directory path
308
- });
309
-
310
- server.registerService(instance); // Manual registration
311
- server.getServer(); // Get underlying MCP SDK server
312
- ```
313
-
314
- ---
315
-
316
- ## Auto-Discovery
317
-
318
- Services are automatically discovered from the `./mcp` directory:
319
-
320
- 1. Recursively scans for `index.ts` or `index.js` files
321
- 2. Dynamically imports each file
322
- 3. Looks for exported classes
323
- 4. Instantiates with no-args constructors
324
- 5. Registers all decorated methods
325
-
326
- ### Shared Dependencies
327
-
328
- For services needing shared configuration (auth, database, etc.), create a `config.ts`:
329
-
330
- ```typescript
331
- // mcp/config.ts
332
- import { AuthProvider } from "@leanmcp/auth";
333
-
334
- export const authProvider = new AuthProvider('cognito', {
335
- region: process.env.AWS_REGION,
336
- userPoolId: process.env.COGNITO_USER_POOL_ID,
337
- clientId: process.env.COGNITO_CLIENT_ID
338
- });
339
-
340
- await authProvider.init();
341
- ```
342
-
343
- Then import in your services:
344
-
345
- ```typescript
346
- // mcp/slack/index.ts
347
- import { Tool } from "@leanmcp/core";
348
- import { Authenticated } from "@leanmcp/auth";
349
- import { authProvider } from "../config.js";
350
-
351
- @Authenticated(authProvider)
352
- export class SlackService {
353
- @Tool({ description: 'Send a message' })
354
- async sendMessage(args: { channel: string; message: string }) {
355
- // Implementation
356
- }
357
- }
358
- ```
359
-
360
- ---
361
-
362
- ## Structured Content
363
-
364
- Tool return values are automatically exposed as `structuredContent` in the MCP response, enabling ChatGPT Apps SDK compatibility.
365
-
366
- **Automatic Handling:**
367
-
368
- ```typescript
369
- @Tool({ description: 'List channels' })
370
- async listChannels() {
371
- // Return a plain object - it becomes structuredContent automatically
372
- return { channels: [...] };
373
- }
374
- ```
375
-
376
- The response includes both `content` (text) and `structuredContent` (object):
377
-
378
- ```json
379
- {
380
- "content": [{ "type": "text", "text": "{\"channels\": [...]}" }],
381
- "structuredContent": { "channels": [...] }
382
- }
383
- ```
384
-
385
- **Manual MCP Response:**
386
-
387
- If your tool returns a manual MCP response (with `content` array), the SDK extracts data from `content[0].text`:
388
-
389
- ```typescript
390
- return {
391
- content: [{ type: 'text', text: JSON.stringify({ channels }) }]
392
- };
393
- // structuredContent will be { channels: [...] }
394
- ```
395
-
396
- ---
397
-
398
- ## HTTP Endpoints
399
-
400
- | Endpoint | Method | Description |
401
- |----------|--------|-------------|
402
- | `/mcp` | POST | MCP protocol endpoint (JSON-RPC 2.0) |
403
- | `/health` | GET | Health check |
404
- | `/` | GET | Welcome message |
405
-
406
- ## Error Handling
407
-
408
- Errors are automatically caught and returned in MCP format:
409
-
410
- ```typescript
411
- @Tool({ description: 'Divide numbers', inputClass: DivideInput })
412
- async divide(input: DivideInput) {
413
- if (input.b === 0) {
414
- throw new Error("Division by zero");
415
- }
416
- return { result: input.a / input.b };
417
- }
418
- ```
419
-
420
- Returns:
421
- ```json
422
- {
423
- "content": [{"type": "text", "text": "Error: Division by zero"}],
424
- "isError": true
425
- }
426
- ```
427
-
428
- ## Environment Variables
429
-
430
- ```bash
431
- PORT=3001 # Server port
432
- NODE_ENV=production # Environment
433
- ```
434
-
435
- ## TypeScript Support
436
-
437
- **Key Points:**
438
- - Input schema is defined via `inputClass` in the decorator
439
- - Output type is inferred from the return type
440
- - For tools with no input, omit `inputClass`
441
- - Use `@SchemaConstraint` for validation and documentation
442
-
443
- ```typescript
444
- class MyInput {
445
- @SchemaConstraint({ description: 'Input field' })
446
- field!: string;
447
- }
448
-
449
- @Tool({ description: 'My tool', inputClass: MyInput })
450
- async myTool(input: MyInput): Promise<{ result: string }> {
451
- return { result: input.field.toUpperCase() };
452
- }
453
- ```
454
-
455
- ## Documentation
456
-
457
- - [Full Documentation](https://docs.leanmcp.com/sdk/core)
458
-
459
- ## Related Packages
460
-
461
- - [@leanmcp/cli](https://www.npmjs.com/package/@leanmcp/cli) — CLI tool for project creation
462
- - [@leanmcp/auth](https://www.npmjs.com/package/@leanmcp/auth) — Authentication decorators
463
- - [@leanmcp/ui](https://www.npmjs.com/package/@leanmcp/ui) — MCP App UI components
464
- - [@leanmcp/elicitation](https://www.npmjs.com/package/@leanmcp/elicitation) — Structured user input
465
-
466
- ## Links
467
-
468
- - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
469
- - [NPM Package](https://www.npmjs.com/package/@leanmcp/core)
470
- - [MCP Specification](https://spec.modelcontextprotocol.io/)
471
-
472
- ## License
473
-
474
- MIT
1
+ <p align="center">
2
+ <img
3
+ src="https://raw.githubusercontent.com/LeanMCP/leanmcp-sdk/refs/heads/main/assets/logo.png"
4
+ alt="LeanMCP Logo"
5
+ width="400"
6
+ />
7
+ </p>
8
+
9
+ <p align="center">
10
+ <strong>@leanmcp/core</strong><br/>
11
+ Core library for building MCP servers with TypeScript decorators and declarative schema definition.
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/@leanmcp/core">
16
+ <img src="https://img.shields.io/npm/v/@leanmcp/core" alt="npm version" />
17
+ </a>
18
+ <a href="https://www.npmjs.com/package/@leanmcp/core">
19
+ <img src="https://img.shields.io/npm/dm/@leanmcp/core" alt="npm downloads" />
20
+ </a>
21
+ <a href="https://docs.leanmcp.com/sdk/core">
22
+ <img src="https://img.shields.io/badge/Docs-leanmcp-0A66C2?" />
23
+ </a>
24
+ <a href="https://discord.com/invite/DsRcA3GwPy">
25
+ <img src="https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white" />
26
+ </a>
27
+ <a href="https://x.com/LeanMcp">
28
+ <img src="https://img.shields.io/badge/@LeanMCP-f5f5f5?logo=x&logoColor=000000" />
29
+ </a>
30
+ <a href="https://leanmcp.com/">
31
+ <img src="https://img.shields.io/badge/Website-leanmcp-0A66C2?" />
32
+ </a>
33
+ <a href="https://deepwiki.com/LeanMCP/leanmcp-sdk"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
34
+ </p>
35
+
36
+ ## Features
37
+
38
+ - **Type-Safe Decorators** — `@Tool`, `@Prompt`, `@Resource` with full TypeScript support
39
+ - **Auto-Discovery** — Zero-config service discovery from `./mcp` directory
40
+ - **Schema Generation** — Declarative JSON Schema with `@SchemaConstraint` decorators
41
+ - **HTTP Transport** — Production-ready HTTP server with session management
42
+ - **Input Validation** — Built-in AJV validation for all inputs
43
+ - **Structured Content** — Automatic `structuredContent` for ChatGPT Apps SDK compatibility
44
+ - **MCP Compliant** — Built on official `@modelcontextprotocol/sdk`
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install @leanmcp/core
50
+ ```
51
+
52
+ For HTTP server support:
53
+ ```bash
54
+ npm install express cors
55
+ ```
56
+
57
+ ## Quick Start
58
+
59
+ ### Zero-Config (Recommended)
60
+
61
+ The simplest way to create an MCP server with auto-discovery:
62
+
63
+ ```typescript
64
+ import { createHTTPServer } from "@leanmcp/core";
65
+
66
+ await createHTTPServer({
67
+ name: "my-mcp-server",
68
+ version: "1.0.0",
69
+ port: 3001,
70
+ cors: true,
71
+ logging: true
72
+ });
73
+
74
+ // Services are automatically discovered from ./mcp directory
75
+ ```
76
+
77
+ **Directory Structure:**
78
+ ```
79
+ your-project/
80
+ ├── main.ts
81
+ └── mcp/
82
+ ├── sentiment/
83
+ │ └── index.ts # export class SentimentService
84
+ ├── weather/
85
+ │ └── index.ts # export class WeatherService
86
+ └── config.ts # Optional: shared dependencies
87
+ ```
88
+
89
+ ### Define a Service
90
+
91
+ ```typescript
92
+ // mcp/sentiment/index.ts
93
+ import { Tool, SchemaConstraint, Optional } from "@leanmcp/core";
94
+
95
+ class AnalyzeSentimentInput {
96
+ @SchemaConstraint({
97
+ description: 'Text to analyze',
98
+ minLength: 1
99
+ })
100
+ text!: string;
101
+
102
+ @Optional()
103
+ @SchemaConstraint({
104
+ description: 'Language code',
105
+ enum: ['en', 'es', 'fr'],
106
+ default: 'en'
107
+ })
108
+ language?: string;
109
+ }
110
+
111
+ export class SentimentService {
112
+ @Tool({
113
+ description: 'Analyze sentiment of text',
114
+ inputClass: AnalyzeSentimentInput
115
+ })
116
+ async analyzeSentiment(input: AnalyzeSentimentInput) {
117
+ return {
118
+ sentiment: 'positive',
119
+ score: 0.8
120
+ };
121
+ }
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Decorators
128
+
129
+ ### @Tool
130
+
131
+ Marks a method as a callable MCP tool.
132
+
133
+ ```typescript
134
+ class CalculateInput {
135
+ @SchemaConstraint({ description: 'First number' })
136
+ a!: number;
137
+
138
+ @SchemaConstraint({ description: 'Second number' })
139
+ b!: number;
140
+ }
141
+
142
+ @Tool({
143
+ description: 'Calculate sum of two numbers',
144
+ inputClass: CalculateInput
145
+ })
146
+ async calculate(input: CalculateInput) {
147
+ return { result: input.a + input.b };
148
+ }
149
+ ```
150
+
151
+ **Options:**
152
+
153
+ | Option | Type | Description |
154
+ |--------|------|-------------|
155
+ | `description` | `string` | Tool description for the AI |
156
+ | `inputClass` | `Class` | Class defining input schema |
157
+
158
+ ### @Prompt
159
+
160
+ Marks a method as a reusable prompt template.
161
+
162
+ ```typescript
163
+ class CodeReviewInput {
164
+ @SchemaConstraint({ description: 'Code to review' })
165
+ code!: string;
166
+
167
+ @SchemaConstraint({ description: 'Programming language' })
168
+ language!: string;
169
+ }
170
+
171
+ @Prompt({ description: 'Generate code review prompt' })
172
+ codeReview(input: CodeReviewInput) {
173
+ return {
174
+ messages: [{
175
+ role: "user",
176
+ content: {
177
+ type: "text",
178
+ text: `Review this ${input.language} code:\n\n${input.code}`
179
+ }
180
+ }]
181
+ };
182
+ }
183
+ ```
184
+
185
+ ### @Resource
186
+
187
+ Marks a method as an MCP resource (data source).
188
+
189
+ ```typescript
190
+ @Resource({
191
+ description: 'Get system configuration',
192
+ mimeType: 'application/json'
193
+ })
194
+ async getConfig() {
195
+ return {
196
+ version: "1.0.0",
197
+ environment: process.env.NODE_ENV
198
+ };
199
+ }
200
+ ```
201
+
202
+ ### @SchemaConstraint
203
+
204
+ Add validation constraints to class properties.
205
+
206
+ ```typescript
207
+ class UserInput {
208
+ @SchemaConstraint({
209
+ description: 'User email',
210
+ format: 'email',
211
+ minLength: 5,
212
+ maxLength: 100
213
+ })
214
+ email!: string;
215
+
216
+ @SchemaConstraint({
217
+ description: 'User age',
218
+ minimum: 18,
219
+ maximum: 120
220
+ })
221
+ age!: number;
222
+
223
+ @Optional()
224
+ @SchemaConstraint({
225
+ description: 'User role',
226
+ enum: ['admin', 'user', 'guest'],
227
+ default: 'user'
228
+ })
229
+ role?: string;
230
+ }
231
+ ```
232
+
233
+ **Common constraints:**
234
+ - `description`, `default` — Documentation
235
+ - `minLength`, `maxLength`String length
236
+ - `minimum`, `maximum` — Number range
237
+ - `enum` — Allowed values
238
+ - `format` — String format (`email`, `uri`, `date`, etc.)
239
+ - `pattern` Regex pattern
240
+
241
+ ### @Optional
242
+
243
+ Marks a property as optional in the schema.
244
+
245
+ ```typescript
246
+ class SearchInput {
247
+ @SchemaConstraint({ description: 'Search query' })
248
+ query!: string;
249
+
250
+ @Optional()
251
+ @SchemaConstraint({ description: 'Max results', default: 10 })
252
+ limit?: number;
253
+ }
254
+ ```
255
+
256
+ ---
257
+
258
+ ## API Reference
259
+
260
+ ### createHTTPServer
261
+
262
+ Create and start an HTTP server with auto-discovery.
263
+
264
+ **Simplified API (Recommended):**
265
+ ```typescript
266
+ await createHTTPServer({
267
+ name: string; // Server name (required)
268
+ version: string; // Server version (required)
269
+ port?: number; // Port (default: 3001)
270
+ cors?: boolean | object; // Enable CORS (default: false)
271
+ logging?: boolean; // Enable logging (default: false)
272
+ debug?: boolean; // Verbose debug logs (default: false)
273
+ autoDiscover?: boolean; // Auto-discover services (default: true)
274
+ mcpDir?: string; // Custom mcp directory path
275
+ sessionTimeout?: number; // Session timeout in ms
276
+ stateless?: boolean; // Stateless mode for Lambda/serverless (default: true)
277
+ dashboard?: boolean; // Serve dashboard UI at / (default: true)
278
+ });
279
+ ```
280
+
281
+ **Factory Pattern (Advanced):**
282
+ ```typescript
283
+ const serverFactory = async () => {
284
+ const server = new MCPServer({
285
+ name: "my-server",
286
+ version: "1.0.0",
287
+ autoDiscover: false // Disable for manual registration
288
+ });
289
+
290
+ server.registerService(new MyService());
291
+ return server.getServer();
292
+ };
293
+
294
+ await createHTTPServer(serverFactory, {
295
+ port: 3001,
296
+ cors: true
297
+ });
298
+ ```
299
+
300
+ ### MCPServer
301
+
302
+ Main server class for registering services.
303
+
304
+ ```typescript
305
+ const server = new MCPServer({
306
+ name: string; // Server name
307
+ version: string; // Server version
308
+ logging?: boolean; // Enable logging (default: false)
309
+ debug?: boolean; // Verbose debug logs (default: false)
310
+ autoDiscover?: boolean; // Auto-discover from ./mcp (default: true)
311
+ mcpDir?: string; // Custom mcp directory path
312
+ });
313
+
314
+ server.registerService(instance); // Manual registration
315
+ server.getServer(); // Get underlying MCP SDK server
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Auto-Discovery
321
+
322
+ Services are automatically discovered from the `./mcp` directory:
323
+
324
+ 1. Recursively scans for `index.ts` or `index.js` files
325
+ 2. Dynamically imports each file
326
+ 3. Looks for exported classes
327
+ 4. Instantiates with no-args constructors
328
+ 5. Registers all decorated methods
329
+
330
+ ### Shared Dependencies
331
+
332
+ For services needing shared configuration (auth, database, etc.), create a `config.ts`:
333
+
334
+ ```typescript
335
+ // mcp/config.ts
336
+ import { AuthProvider } from "@leanmcp/auth";
337
+
338
+ export const authProvider = new AuthProvider('cognito', {
339
+ region: process.env.AWS_REGION,
340
+ userPoolId: process.env.COGNITO_USER_POOL_ID,
341
+ clientId: process.env.COGNITO_CLIENT_ID
342
+ });
343
+
344
+ await authProvider.init();
345
+ ```
346
+
347
+ Then import in your services:
348
+
349
+ ```typescript
350
+ // mcp/slack/index.ts
351
+ import { Tool } from "@leanmcp/core";
352
+ import { Authenticated } from "@leanmcp/auth";
353
+ import { authProvider } from "../config.js";
354
+
355
+ @Authenticated(authProvider)
356
+ export class SlackService {
357
+ @Tool({ description: 'Send a message' })
358
+ async sendMessage(args: { channel: string; message: string }) {
359
+ // Implementation
360
+ }
361
+ }
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Structured Content
367
+
368
+ Tool return values are automatically exposed as `structuredContent` in the MCP response, enabling ChatGPT Apps SDK compatibility.
369
+
370
+ **Automatic Handling:**
371
+
372
+ ```typescript
373
+ @Tool({ description: 'List channels' })
374
+ async listChannels() {
375
+ // Return a plain object - it becomes structuredContent automatically
376
+ return { channels: [...] };
377
+ }
378
+ ```
379
+
380
+ The response includes both `content` (text) and `structuredContent` (object):
381
+
382
+ ```json
383
+ {
384
+ "content": [{ "type": "text", "text": "{\"channels\": [...]}" }],
385
+ "structuredContent": { "channels": [...] }
386
+ }
387
+ ```
388
+
389
+ **Manual MCP Response:**
390
+
391
+ If your tool returns a manual MCP response (with `content` array), the SDK extracts data from `content[0].text`:
392
+
393
+ ```typescript
394
+ return {
395
+ content: [{ type: 'text', text: JSON.stringify({ channels }) }]
396
+ };
397
+ // structuredContent will be { channels: [...] }
398
+ ```
399
+
400
+ ---
401
+
402
+ ## HTTP Endpoints
403
+
404
+ | Endpoint | Method | Description |
405
+ |----------|--------|-------------|
406
+ | `/mcp` | POST | MCP protocol endpoint (JSON-RPC 2.0) |
407
+ | `/health` | GET | Health check |
408
+ | `/` | GET | Welcome message |
409
+
410
+ ## Error Handling
411
+
412
+ Errors are automatically caught and returned in MCP format:
413
+
414
+ ```typescript
415
+ @Tool({ description: 'Divide numbers', inputClass: DivideInput })
416
+ async divide(input: DivideInput) {
417
+ if (input.b === 0) {
418
+ throw new Error("Division by zero");
419
+ }
420
+ return { result: input.a / input.b };
421
+ }
422
+ ```
423
+
424
+ Returns:
425
+ ```json
426
+ {
427
+ "content": [{"type": "text", "text": "Error: Division by zero"}],
428
+ "isError": true
429
+ }
430
+ ```
431
+
432
+ ## Environment Variables
433
+
434
+ ```bash
435
+ PORT=3001 # Server port
436
+ NODE_ENV=production # Environment
437
+ ```
438
+
439
+ ## TypeScript Support
440
+
441
+ **Key Points:**
442
+ - Input schema is defined via `inputClass` in the decorator
443
+ - Output type is inferred from the return type
444
+ - For tools with no input, omit `inputClass`
445
+ - Use `@SchemaConstraint` for validation and documentation
446
+
447
+ ```typescript
448
+ class MyInput {
449
+ @SchemaConstraint({ description: 'Input field' })
450
+ field!: string;
451
+ }
452
+
453
+ @Tool({ description: 'My tool', inputClass: MyInput })
454
+ async myTool(input: MyInput): Promise<{ result: string }> {
455
+ return { result: input.field.toUpperCase() };
456
+ }
457
+ ```
458
+
459
+ ## Documentation
460
+
461
+ - [Full Documentation](https://docs.leanmcp.com/sdk/core)
462
+
463
+ ## Related Packages
464
+
465
+ - [@leanmcp/cli](https://www.npmjs.com/package/@leanmcp/cli) — CLI tool for project creation
466
+ - [@leanmcp/auth](https://www.npmjs.com/package/@leanmcp/auth) — Authentication decorators
467
+ - [@leanmcp/ui](https://www.npmjs.com/package/@leanmcp/ui) — MCP App UI components
468
+ - [@leanmcp/elicitation](https://www.npmjs.com/package/@leanmcp/elicitation) — Structured user input
469
+
470
+ ## Links
471
+
472
+ - [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
473
+ - [NPM Package](https://www.npmjs.com/package/@leanmcp/core)
474
+ - [MCP Specification](https://spec.modelcontextprotocol.io/)
475
+
476
+ ## License
477
+
478
+ MIT