@leanmcp/core 0.1.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/LICENSE +21 -0
- package/README.md +354 -0
- package/dist/chunk-O6YSETKJ.mjs +6 -0
- package/dist/dist-LQ4M5W3M.mjs +587 -0
- package/dist/index.d.mts +435 -0
- package/dist/index.d.ts +435 -0
- package/dist/index.js +1162 -0
- package/dist/index.mjs +1104 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LeanMCP Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
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
|
+
```typescript
|
|
79
|
+
import { createHTTPServer, MCPServer } from "@leanmcp/core";
|
|
80
|
+
import { SentimentService } from "./services/sentiment";
|
|
81
|
+
|
|
82
|
+
// Create MCP server
|
|
83
|
+
const serverFactory = () => {
|
|
84
|
+
const server = new MCPServer({
|
|
85
|
+
name: "my-mcp-server",
|
|
86
|
+
version: "1.0.0",
|
|
87
|
+
logging: true
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Register services
|
|
91
|
+
server.registerService(new SentimentService());
|
|
92
|
+
|
|
93
|
+
return server.getServer();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Start HTTP server
|
|
97
|
+
await createHTTPServer(serverFactory, {
|
|
98
|
+
port: 3000,
|
|
99
|
+
cors: true,
|
|
100
|
+
logging: true
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Decorators
|
|
105
|
+
|
|
106
|
+
### @Tool
|
|
107
|
+
|
|
108
|
+
Marks a method as an MCP tool (callable function). Use `inputClass` to specify the input schema class.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
class CalculateInput {
|
|
112
|
+
@SchemaConstraint({ description: 'First number' })
|
|
113
|
+
a!: number;
|
|
114
|
+
|
|
115
|
+
@SchemaConstraint({ description: 'Second number' })
|
|
116
|
+
b!: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@Tool({
|
|
120
|
+
description: 'Calculate sum of two numbers',
|
|
121
|
+
inputClass: CalculateInput
|
|
122
|
+
})
|
|
123
|
+
async calculate(input: CalculateInput) {
|
|
124
|
+
return { result: input.a + input.b };
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### @Prompt
|
|
129
|
+
|
|
130
|
+
Marks a method as an MCP prompt template. Input schema is automatically inferred from parameter type.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
class CodeReviewInput {
|
|
134
|
+
@SchemaConstraint({ description: 'Code to review' })
|
|
135
|
+
code!: string;
|
|
136
|
+
|
|
137
|
+
@SchemaConstraint({ description: 'Programming language' })
|
|
138
|
+
language!: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@Prompt({ description: 'Generate code review prompt' })
|
|
142
|
+
codeReview(input: CodeReviewInput) {
|
|
143
|
+
return {
|
|
144
|
+
messages: [{
|
|
145
|
+
role: "user",
|
|
146
|
+
content: {
|
|
147
|
+
type: "text",
|
|
148
|
+
text: `Review this ${input.language} code:\n\n${input.code}`
|
|
149
|
+
}
|
|
150
|
+
}]
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### @Resource
|
|
156
|
+
|
|
157
|
+
Marks a method as an MCP resource (data source).
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
@Resource({ description: 'Get system configuration', mimeType: 'application/json' })
|
|
161
|
+
async getConfig() {
|
|
162
|
+
return {
|
|
163
|
+
version: "1.0.0",
|
|
164
|
+
environment: process.env.NODE_ENV
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### @SchemaConstraint
|
|
170
|
+
|
|
171
|
+
Add validation constraints to class properties for automatic schema generation.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
class UserInput {
|
|
175
|
+
@SchemaConstraint({
|
|
176
|
+
description: 'User email',
|
|
177
|
+
format: 'email',
|
|
178
|
+
minLength: 5,
|
|
179
|
+
maxLength: 100
|
|
180
|
+
})
|
|
181
|
+
email!: string;
|
|
182
|
+
|
|
183
|
+
@SchemaConstraint({
|
|
184
|
+
description: 'User age',
|
|
185
|
+
minimum: 18,
|
|
186
|
+
maximum: 120
|
|
187
|
+
})
|
|
188
|
+
age!: number;
|
|
189
|
+
|
|
190
|
+
@Optional()
|
|
191
|
+
@SchemaConstraint({
|
|
192
|
+
description: 'User role',
|
|
193
|
+
enum: ['admin', 'user', 'guest'],
|
|
194
|
+
default: 'user'
|
|
195
|
+
})
|
|
196
|
+
role?: string;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### @Optional
|
|
201
|
+
|
|
202
|
+
Marks a property as optional in the schema.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
class SearchInput {
|
|
206
|
+
@SchemaConstraint({ description: 'Search query' })
|
|
207
|
+
query!: string;
|
|
208
|
+
|
|
209
|
+
@Optional()
|
|
210
|
+
@SchemaConstraint({ description: 'Max results', default: 10 })
|
|
211
|
+
limit?: number;
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## API Reference
|
|
216
|
+
|
|
217
|
+
### MCPServer
|
|
218
|
+
|
|
219
|
+
Main server class for registering services.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
const server = new MCPServer({
|
|
223
|
+
name: string; // Server name
|
|
224
|
+
version: string; // Server version
|
|
225
|
+
logging?: boolean; // Enable logging (default: false)
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
server.registerService(instance: any): void;
|
|
229
|
+
server.getServer(): Server; // Get underlying MCP SDK server
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### createHTTPServer
|
|
233
|
+
|
|
234
|
+
Create and start an HTTP server with streamable transport.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
await createHTTPServer(
|
|
238
|
+
serverFactory: () => Server,
|
|
239
|
+
options: {
|
|
240
|
+
port?: number; // Port number (default: 3000)
|
|
241
|
+
cors?: boolean; // Enable CORS (default: false)
|
|
242
|
+
logging?: boolean; // Enable logging (default: true)
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Schema Generation
|
|
248
|
+
|
|
249
|
+
Generate JSON Schema from TypeScript classes:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { classToJsonSchemaWithConstraints } from "@leanmcp/core";
|
|
253
|
+
|
|
254
|
+
const schema = classToJsonSchemaWithConstraints(MyInputClass);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## HTTP Endpoints
|
|
258
|
+
|
|
259
|
+
When using `createHTTPServer`, the following endpoints are available:
|
|
260
|
+
|
|
261
|
+
- `POST /mcp` - MCP protocol endpoint (accepts JSON-RPC 2.0 messages)
|
|
262
|
+
- `GET /health` - Health check endpoint
|
|
263
|
+
- `GET /` - Welcome message
|
|
264
|
+
|
|
265
|
+
## Environment Variables
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
PORT=3000 # Server port (optional)
|
|
269
|
+
NODE_ENV=production # Environment (optional)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Error Handling
|
|
273
|
+
|
|
274
|
+
All tools automatically handle errors and return them in MCP format:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
class DivideInput {
|
|
278
|
+
@SchemaConstraint({ description: 'Numerator' })
|
|
279
|
+
a!: number;
|
|
280
|
+
|
|
281
|
+
@SchemaConstraint({ description: 'Denominator' })
|
|
282
|
+
b!: number;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@Tool({
|
|
286
|
+
description: 'Divide numbers',
|
|
287
|
+
inputClass: DivideInput
|
|
288
|
+
})
|
|
289
|
+
async divide(input: DivideInput) {
|
|
290
|
+
if (input.b === 0) {
|
|
291
|
+
throw new Error("Division by zero");
|
|
292
|
+
}
|
|
293
|
+
return { result: input.a / input.b };
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Errors are returned as:
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"content": [{"type": "text", "text": "Error: Division by zero"}],
|
|
301
|
+
"isError": true
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## TypeScript Support
|
|
306
|
+
|
|
307
|
+
Full TypeScript support with type inference:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
class MyInput {
|
|
311
|
+
@SchemaConstraint({ description: 'Input field' })
|
|
312
|
+
field!: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
class MyOutput {
|
|
316
|
+
result!: string;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Input schema defined via inputClass, output type inferred from return type
|
|
320
|
+
@Tool({
|
|
321
|
+
description: 'My tool',
|
|
322
|
+
inputClass: MyInput
|
|
323
|
+
})
|
|
324
|
+
async myTool(input: MyInput): Promise<MyOutput> {
|
|
325
|
+
// TypeScript knows the exact types
|
|
326
|
+
const result: MyOutput = {
|
|
327
|
+
result: input.field.toUpperCase()
|
|
328
|
+
// Full autocomplete and type checking
|
|
329
|
+
};
|
|
330
|
+
return result;
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Key Points:**
|
|
335
|
+
- Input schema is defined using `inputClass` in the `@Tool` decorator
|
|
336
|
+
- Output schema is inferred from the return type
|
|
337
|
+
- For tools with no input parameters, omit the `inputClass` option
|
|
338
|
+
- Use `@SchemaConstraint` decorators to add validation and documentation to your input classes
|
|
339
|
+
|
|
340
|
+
## License
|
|
341
|
+
|
|
342
|
+
MIT
|
|
343
|
+
|
|
344
|
+
## Related Packages
|
|
345
|
+
|
|
346
|
+
- [@leanmcp/cli](../cli) - CLI tool for creating new projects
|
|
347
|
+
- [@leanmcp/auth](../auth) - Authentication decorators and providers
|
|
348
|
+
- [@leanmcp/utils](../utils) - Utility functions
|
|
349
|
+
|
|
350
|
+
## Links
|
|
351
|
+
|
|
352
|
+
- [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
|
|
353
|
+
- [MCP Specification](https://spec.modelcontextprotocol.io/)
|
|
354
|
+
- [Documentation](https://github.com/LeanMCP/leanmcp-sdk#readme)
|