@leanmcp/core 0.3.17 → 0.3.18-alpha.6.6dae082

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