@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.
@@ -0,0 +1,435 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+
3
+ interface ToolOptions {
4
+ description?: string;
5
+ inputClass?: any;
6
+ }
7
+ interface PromptOptions {
8
+ description?: string;
9
+ inputClass?: any;
10
+ }
11
+ interface ResourceOptions {
12
+ description?: string;
13
+ mimeType?: string;
14
+ inputClass?: any;
15
+ }
16
+ /**
17
+ * Marks a method as an MCP tool (callable function)
18
+ * - Tool name is automatically derived from function name
19
+ * - Input schema is explicitly defined via inputClass
20
+ * - Full type safety at compile time
21
+ *
22
+ * @example
23
+ * class AnalyzeSentimentInput {
24
+ * @SchemaConstraint({ description: 'Text to analyze' })
25
+ * text!: string;
26
+ *
27
+ * @Optional()
28
+ * language?: string;
29
+ * }
30
+ *
31
+ * @Tool({
32
+ * description: 'Analyze sentiment of text',
33
+ * inputClass: AnalyzeSentimentInput
34
+ * })
35
+ * async analyzeSentiment(args: AnalyzeSentimentInput): Promise<AnalyzeSentimentOutput> {
36
+ * // Tool name will be: "analyzeSentiment"
37
+ * }
38
+ */
39
+ declare function Tool(options?: ToolOptions): MethodDecorator;
40
+ /**
41
+ * Marks a method as an MCP prompt template
42
+ * - Prompt name is automatically derived from function name
43
+ * - Input schema can be explicitly defined via inputClass or inferred from parameter type
44
+ *
45
+ * @example
46
+ * class PromptInput {
47
+ * @SchemaConstraint({ description: 'Auth token' })
48
+ * token!: string;
49
+ * }
50
+ *
51
+ * @Prompt({
52
+ * description: 'Generate sentiment analysis prompt',
53
+ * inputClass: PromptInput
54
+ * })
55
+ * sentimentPrompt(args: PromptInput) {
56
+ * // Prompt name will be: "sentimentPrompt"
57
+ * }
58
+ */
59
+ declare function Prompt(options?: PromptOptions): MethodDecorator;
60
+ /**
61
+ * Marks a method as an MCP resource (data source/endpoint)
62
+ * - Resource URI is automatically derived from function name (e.g., "myservice://functionName")
63
+ * - Can be customized with description, mimeType, and input schema
64
+ *
65
+ * @example
66
+ * class ResourceInput {
67
+ * @SchemaConstraint({ description: 'Auth token' })
68
+ * token!: string;
69
+ * }
70
+ *
71
+ * @Resource({
72
+ * description: 'Service statistics',
73
+ * mimeType: 'application/json',
74
+ * inputClass: ResourceInput
75
+ * })
76
+ * getStats(args: ResourceInput) {
77
+ * // Resource URI will be: "servicename://getStats"
78
+ * return { stats: '...' };
79
+ * }
80
+ */
81
+ declare function Resource(options?: ResourceOptions): MethodDecorator;
82
+ interface AuthOptions {
83
+ provider: string;
84
+ }
85
+ /**
86
+ * Adds authentication requirements using a specified provider
87
+ * @example
88
+ * @Auth({ provider: 'clerk' })
89
+ * export class MyService { }
90
+ *
91
+ * @Tool({ description: 'Premium feature' })
92
+ * @Auth({ provider: 'stripe' })
93
+ * async premiumAction() { }
94
+ */
95
+ declare function Auth(options: AuthOptions): ClassDecorator & MethodDecorator;
96
+ /**
97
+ * Injects environment variables or user-level configuration into the tool instance
98
+ */
99
+ declare function UserEnvs(): PropertyDecorator;
100
+ /**
101
+ * Property decorator to mark a field as optional in JSON Schema
102
+ *
103
+ * @example
104
+ * class MyInput {
105
+ * required!: string;
106
+ *
107
+ * @Optional()
108
+ * optional?: string;
109
+ * }
110
+ */
111
+ /**
112
+ * Links a UI component or frontend visualization to a tool or resource
113
+ * @param component - UI component name
114
+ */
115
+ declare function UI(component: string): ClassDecorator & MethodDecorator;
116
+ /**
117
+ * Specifies how output should be rendered
118
+ * @param format - Render format ('markdown', 'html', 'json', 'chart', 'table')
119
+ */
120
+ declare function Render(format: 'markdown' | 'html' | 'json' | 'chart' | 'table' | string): MethodDecorator;
121
+ /**
122
+ * Marks a tool, prompt, or resource as deprecated
123
+ * @param message - Optional deprecation message
124
+ */
125
+ declare function Deprecated(message?: string): ClassDecorator & MethodDecorator;
126
+ /**
127
+ * Get metadata for a specific method
128
+ */
129
+ declare function getMethodMetadata(method: Function): {
130
+ toolName: any;
131
+ toolDescription: any;
132
+ promptName: any;
133
+ promptDescription: any;
134
+ resourceUri: any;
135
+ resourceName: any;
136
+ resourceDescription: any;
137
+ inputSchema: any;
138
+ outputSchema: any;
139
+ authProvider: any;
140
+ authRequired: any;
141
+ uiComponent: any;
142
+ renderFormat: any;
143
+ deprecated: any;
144
+ deprecationMessage: any;
145
+ };
146
+ /**
147
+ * Get all methods with a specific decorator from a class
148
+ */
149
+ declare function getDecoratedMethods(target: any, metadataKey: string): Array<{
150
+ method: Function;
151
+ propertyKey: string;
152
+ metadata: any;
153
+ }>;
154
+
155
+ /**
156
+ * Converts a TypeScript class to JSON Schema
157
+ * Uses reflect-metadata and TypeScript design:type metadata
158
+ */
159
+ declare function classToJsonSchema(classConstructor: new () => any): any;
160
+ /**
161
+ * Property decorator to mark a field as optional in JSON Schema
162
+ */
163
+ declare function Optional(): PropertyDecorator;
164
+ /**
165
+ * Property decorator to add JSON Schema constraints
166
+ */
167
+ declare function SchemaConstraint(constraints: {
168
+ minLength?: number;
169
+ maxLength?: number;
170
+ minimum?: number;
171
+ maximum?: number;
172
+ pattern?: string;
173
+ enum?: any[];
174
+ description?: string;
175
+ default?: any;
176
+ }): PropertyDecorator;
177
+ /**
178
+ * Enhanced schema generator that includes constraints
179
+ */
180
+ declare function classToJsonSchemaWithConstraints(classConstructor: new () => any): any;
181
+
182
+ /**
183
+ * Simple configurable logger for LeanMCP SDK
184
+ */
185
+ declare enum LogLevel {
186
+ DEBUG = 0,
187
+ INFO = 1,
188
+ WARN = 2,
189
+ ERROR = 3,
190
+ NONE = 4
191
+ }
192
+ interface LoggerOptions {
193
+ level?: LogLevel;
194
+ prefix?: string;
195
+ timestamps?: boolean;
196
+ }
197
+ declare class Logger {
198
+ private level;
199
+ private prefix;
200
+ private timestamps;
201
+ constructor(options?: LoggerOptions);
202
+ private format;
203
+ private shouldLog;
204
+ debug(message: string, ...args: any[]): void;
205
+ info(message: string, ...args: any[]): void;
206
+ warn(message: string, ...args: any[]): void;
207
+ error(message: string, ...args: any[]): void;
208
+ setLevel(level: LogLevel): void;
209
+ getLevel(): LogLevel;
210
+ }
211
+ declare const defaultLogger: Logger;
212
+
213
+ interface HTTPServerOptions {
214
+ port?: number;
215
+ cors?: boolean | {
216
+ origin?: string | string[];
217
+ credentials?: boolean;
218
+ };
219
+ logging?: boolean;
220
+ logger?: Logger;
221
+ sessionTimeout?: number;
222
+ }
223
+ interface MCPServerFactory {
224
+ (): Server | Promise<Server>;
225
+ }
226
+ /**
227
+ * Create an HTTP server for MCP with Streamable HTTP transport
228
+ */
229
+ declare function createHTTPServer(serverFactory: MCPServerFactory, options?: HTTPServerOptions): Promise<void>;
230
+
231
+ /**
232
+ * Input validation utilities for LeanMCP
233
+ * Provides secure validation for common input types
234
+ */
235
+ /**
236
+ * Validates that a port number is within valid range (1-65535)
237
+ *
238
+ * @param port - Port number to validate
239
+ * @throws {Error} If port is invalid
240
+ *
241
+ * @example
242
+ * ```typescript
243
+ * validatePort(3000); // OK
244
+ * validatePort(0); // Throws error
245
+ * validatePort(70000); // Throws error
246
+ * ```
247
+ */
248
+ declare function validatePort(port: number): void;
249
+ /**
250
+ * Validates that a file path doesn't contain directory traversal patterns
251
+ * Prevents path traversal attacks by checking for '..' and '~'
252
+ *
253
+ * @param path - File path to validate
254
+ * @throws {Error} If path contains unsafe patterns
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * validatePath('./services'); // OK
259
+ * validatePath('../etc/passwd'); // Throws error
260
+ * validatePath('~/secrets'); // Throws error
261
+ * ```
262
+ */
263
+ declare function validatePath(path: string): void;
264
+ /**
265
+ * Validates that a service name contains only safe characters
266
+ * Allows alphanumeric, hyphens, and underscores only
267
+ *
268
+ * @param name - Service name to validate
269
+ * @throws {Error} If name contains unsafe characters
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * validateServiceName('my-service'); // OK
274
+ * validateServiceName('my_service_123'); // OK
275
+ * validateServiceName('my service'); // Throws error
276
+ * validateServiceName('../malicious'); // Throws error
277
+ * ```
278
+ */
279
+ declare function validateServiceName(name: string): void;
280
+ /**
281
+ * Validates that a string is not empty or only whitespace
282
+ *
283
+ * @param value - String to validate
284
+ * @param fieldName - Name of the field for error message
285
+ * @throws {Error} If string is empty or only whitespace
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * validateNonEmpty('hello', 'name'); // OK
290
+ * validateNonEmpty('', 'name'); // Throws error
291
+ * validateNonEmpty(' ', 'name'); // Throws error
292
+ * ```
293
+ */
294
+ declare function validateNonEmpty(value: string, fieldName: string): void;
295
+ /**
296
+ * Validates that a URL is well-formed and uses allowed protocols
297
+ *
298
+ * @param url - URL to validate
299
+ * @param allowedProtocols - Array of allowed protocols (default: ['http:', 'https:'])
300
+ * @throws {Error} If URL is invalid or uses disallowed protocol
301
+ *
302
+ * @example
303
+ * ```typescript
304
+ * validateUrl('https://example.com'); // OK
305
+ * validateUrl('http://localhost:3000'); // OK
306
+ * validateUrl('file:///etc/passwd'); // Throws error
307
+ * validateUrl('javascript:alert(1)'); // Throws error
308
+ * ```
309
+ */
310
+ declare function validateUrl(url: string, allowedProtocols?: string[]): void;
311
+
312
+ interface MCPServerOptions {
313
+ servicesDir: string;
314
+ port?: number;
315
+ cors?: boolean;
316
+ logging?: boolean;
317
+ }
318
+ interface RegisteredTool {
319
+ name: string;
320
+ description: string;
321
+ inputSchema: any;
322
+ method: Function;
323
+ instance: any;
324
+ propertyKey: string;
325
+ }
326
+ interface RegisteredPrompt {
327
+ name: string;
328
+ description: string;
329
+ arguments: any[];
330
+ method: Function;
331
+ instance: any;
332
+ propertyKey: string;
333
+ }
334
+ interface RegisteredResource {
335
+ uri: string;
336
+ name: string;
337
+ description: string;
338
+ mimeType: string;
339
+ inputSchema?: any;
340
+ method: Function;
341
+ instance: any;
342
+ propertyKey: string;
343
+ }
344
+ /**
345
+ * MCPServer - A simplified server class for manually registering services
346
+ * Use this when you want to explicitly instantiate and register your services
347
+ */
348
+ declare class MCPServer {
349
+ private server;
350
+ private tools;
351
+ private prompts;
352
+ private resources;
353
+ private logging;
354
+ private logger;
355
+ constructor(options: {
356
+ name: string;
357
+ version: string;
358
+ logging?: boolean;
359
+ });
360
+ private setupHandlers;
361
+ /**
362
+ * Register a service instance with decorated methods
363
+ */
364
+ registerService(instance: any): void;
365
+ /**
366
+ * Get the underlying MCP SDK Server instance
367
+ */
368
+ getServer(): Server<{
369
+ method: string;
370
+ params?: {
371
+ [x: string]: unknown;
372
+ _meta?: {
373
+ [x: string]: unknown;
374
+ progressToken?: string | number | undefined;
375
+ } | undefined;
376
+ } | undefined;
377
+ }, {
378
+ method: string;
379
+ params?: {
380
+ [x: string]: unknown;
381
+ _meta?: {
382
+ [x: string]: unknown;
383
+ } | undefined;
384
+ } | undefined;
385
+ }, {
386
+ [x: string]: unknown;
387
+ _meta?: {
388
+ [x: string]: unknown;
389
+ } | undefined;
390
+ }>;
391
+ }
392
+ declare class MCPServerRuntime {
393
+ private server;
394
+ private tools;
395
+ private prompts;
396
+ private resources;
397
+ private options;
398
+ private logger;
399
+ constructor(options: MCPServerOptions);
400
+ private setupHandlers;
401
+ loadServices(): Promise<void>;
402
+ start(): Promise<void>;
403
+ getServer(): Server<{
404
+ method: string;
405
+ params?: {
406
+ [x: string]: unknown;
407
+ _meta?: {
408
+ [x: string]: unknown;
409
+ progressToken?: string | number | undefined;
410
+ } | undefined;
411
+ } | undefined;
412
+ }, {
413
+ method: string;
414
+ params?: {
415
+ [x: string]: unknown;
416
+ _meta?: {
417
+ [x: string]: unknown;
418
+ } | undefined;
419
+ } | undefined;
420
+ }, {
421
+ [x: string]: unknown;
422
+ _meta?: {
423
+ [x: string]: unknown;
424
+ } | undefined;
425
+ }>;
426
+ getTools(): RegisteredTool[];
427
+ getPrompts(): RegisteredPrompt[];
428
+ getResources(): RegisteredResource[];
429
+ }
430
+ /**
431
+ * Start MCP server with tools from services directory
432
+ */
433
+ declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
434
+
435
+ export { Auth, type AuthOptions, Deprecated, type HTTPServerOptions, LogLevel, Logger, type LoggerOptions, MCPServer, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, Render, Resource, type ResourceOptions, SchemaConstraint, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createHTTPServer, defaultLogger, getDecoratedMethods, getMethodMetadata, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };