@leanmcp/core 0.4.5 → 0.4.6
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/dist/chunk-GTCGBX2K.mjs +279 -0
- package/dist/dynamodb-session-store-G7V5ZRR6.mjs +10 -0
- package/dist/index.d.mts +23 -7
- package/dist/index.d.ts +23 -7
- package/dist/index.js +261 -27
- package/dist/index.mjs +250 -26
- package/package.json +3 -2
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// src/dynamodb-session-store.ts
|
|
11
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
12
|
+
import { DynamoDBDocumentClient, GetCommand, PutCommand, DeleteCommand, UpdateCommand } from "@aws-sdk/lib-dynamodb";
|
|
13
|
+
|
|
14
|
+
// src/logger.ts
|
|
15
|
+
var LogLevel = /* @__PURE__ */ (function(LogLevel2) {
|
|
16
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
17
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
18
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
19
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
20
|
+
LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
|
|
21
|
+
return LogLevel2;
|
|
22
|
+
})({});
|
|
23
|
+
var COLORS = {
|
|
24
|
+
reset: "\x1B[0m",
|
|
25
|
+
gray: "\x1B[38;5;244m",
|
|
26
|
+
blue: "\x1B[1;34m",
|
|
27
|
+
amber: "\x1B[38;5;214m",
|
|
28
|
+
red: "\x1B[1;31m"
|
|
29
|
+
};
|
|
30
|
+
var levelStyles = {
|
|
31
|
+
[0]: {
|
|
32
|
+
label: "DEBUG",
|
|
33
|
+
color: COLORS.gray
|
|
34
|
+
},
|
|
35
|
+
[1]: {
|
|
36
|
+
label: "INFO",
|
|
37
|
+
color: COLORS.blue
|
|
38
|
+
},
|
|
39
|
+
[2]: {
|
|
40
|
+
label: "WARN",
|
|
41
|
+
color: COLORS.amber
|
|
42
|
+
},
|
|
43
|
+
[3]: {
|
|
44
|
+
label: "ERROR",
|
|
45
|
+
color: COLORS.red
|
|
46
|
+
},
|
|
47
|
+
[4]: {
|
|
48
|
+
label: "NONE",
|
|
49
|
+
color: COLORS.gray
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var Logger = class {
|
|
53
|
+
static {
|
|
54
|
+
__name(this, "Logger");
|
|
55
|
+
}
|
|
56
|
+
level;
|
|
57
|
+
prefix;
|
|
58
|
+
timestamps;
|
|
59
|
+
colorize;
|
|
60
|
+
context;
|
|
61
|
+
handlers;
|
|
62
|
+
constructor(options = {}) {
|
|
63
|
+
this.level = options.level ?? 1;
|
|
64
|
+
this.prefix = options.prefix ?? "";
|
|
65
|
+
this.timestamps = options.timestamps ?? true;
|
|
66
|
+
this.colorize = options.colorize ?? true;
|
|
67
|
+
this.context = options.context;
|
|
68
|
+
this.handlers = options.handlers ?? [];
|
|
69
|
+
}
|
|
70
|
+
format(level, message) {
|
|
71
|
+
const style = levelStyles[level];
|
|
72
|
+
const timestamp = this.timestamps ? `[${(/* @__PURE__ */ new Date()).toISOString()}]` : "";
|
|
73
|
+
const prefix = this.prefix ? `[${this.prefix}]` : "";
|
|
74
|
+
const context = this.context ? `[${this.context}]` : "";
|
|
75
|
+
const label = `[${style.label}]`;
|
|
76
|
+
const parts = `${timestamp}${prefix}${context}${label} ${message}`;
|
|
77
|
+
if (!this.colorize) return parts;
|
|
78
|
+
return `${style.color}${parts}${COLORS.reset}`;
|
|
79
|
+
}
|
|
80
|
+
shouldLog(level) {
|
|
81
|
+
return level >= this.level && this.level !== 4;
|
|
82
|
+
}
|
|
83
|
+
emit(level, message, consoleFn, ...args) {
|
|
84
|
+
if (!this.shouldLog(level)) return;
|
|
85
|
+
const payload = {
|
|
86
|
+
level,
|
|
87
|
+
levelLabel: levelStyles[level].label,
|
|
88
|
+
message,
|
|
89
|
+
args,
|
|
90
|
+
prefix: this.prefix,
|
|
91
|
+
context: this.context,
|
|
92
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
|
+
};
|
|
94
|
+
consoleFn(this.format(level, message), ...args);
|
|
95
|
+
this.handlers.forEach((handler) => {
|
|
96
|
+
try {
|
|
97
|
+
handler(payload);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
console.debug("Logger handler error", err);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
debug(message, ...args) {
|
|
104
|
+
this.emit(0, message, console.debug, ...args);
|
|
105
|
+
}
|
|
106
|
+
info(message, ...args) {
|
|
107
|
+
this.emit(1, message, console.info, ...args);
|
|
108
|
+
}
|
|
109
|
+
warn(message, ...args) {
|
|
110
|
+
this.emit(2, message, console.warn, ...args);
|
|
111
|
+
}
|
|
112
|
+
error(message, ...args) {
|
|
113
|
+
this.emit(3, message, console.error, ...args);
|
|
114
|
+
}
|
|
115
|
+
setLevel(level) {
|
|
116
|
+
this.level = level;
|
|
117
|
+
}
|
|
118
|
+
getLevel() {
|
|
119
|
+
return this.level;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var defaultLogger = new Logger({
|
|
123
|
+
level: 1,
|
|
124
|
+
prefix: "LeanMCP"
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// src/dynamodb-session-store.ts
|
|
128
|
+
var DEFAULT_TABLE_NAME = "leanmcp-sessions";
|
|
129
|
+
var DEFAULT_TTL_SECONDS = 86400;
|
|
130
|
+
var DynamoDBSessionStore = class {
|
|
131
|
+
static {
|
|
132
|
+
__name(this, "DynamoDBSessionStore");
|
|
133
|
+
}
|
|
134
|
+
client;
|
|
135
|
+
tableName;
|
|
136
|
+
ttlSeconds;
|
|
137
|
+
logger;
|
|
138
|
+
constructor(options) {
|
|
139
|
+
this.tableName = options?.tableName || process.env.DYNAMODB_TABLE_NAME || DEFAULT_TABLE_NAME;
|
|
140
|
+
this.ttlSeconds = options?.ttlSeconds || DEFAULT_TTL_SECONDS;
|
|
141
|
+
this.logger = new Logger({
|
|
142
|
+
level: options?.logging ? LogLevel.INFO : LogLevel.NONE,
|
|
143
|
+
prefix: "DynamoDBSessionStore"
|
|
144
|
+
});
|
|
145
|
+
const dynamoClient = new DynamoDBClient({
|
|
146
|
+
region: options?.region || process.env.AWS_REGION || "us-east-1"
|
|
147
|
+
});
|
|
148
|
+
this.client = DynamoDBDocumentClient.from(dynamoClient);
|
|
149
|
+
this.logger.info(`Initialized with table: ${this.tableName}, TTL: ${this.ttlSeconds}s`);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check if a session exists in DynamoDB
|
|
153
|
+
*/
|
|
154
|
+
async sessionExists(sessionId) {
|
|
155
|
+
try {
|
|
156
|
+
const result = await this.client.send(new GetCommand({
|
|
157
|
+
TableName: this.tableName,
|
|
158
|
+
Key: {
|
|
159
|
+
sessionId
|
|
160
|
+
},
|
|
161
|
+
ProjectionExpression: "sessionId"
|
|
162
|
+
}));
|
|
163
|
+
const exists = !!result.Item;
|
|
164
|
+
this.logger.debug(`Session ${sessionId} exists: ${exists}`);
|
|
165
|
+
return exists;
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.logger.error(`Error checking session existence: ${error.message}`);
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Create a new session in DynamoDB
|
|
173
|
+
*/
|
|
174
|
+
async createSession(sessionId, data) {
|
|
175
|
+
try {
|
|
176
|
+
const now = /* @__PURE__ */ new Date();
|
|
177
|
+
const ttl = Math.floor(Date.now() / 1e3) + this.ttlSeconds;
|
|
178
|
+
await this.client.send(new PutCommand({
|
|
179
|
+
TableName: this.tableName,
|
|
180
|
+
Item: {
|
|
181
|
+
sessionId,
|
|
182
|
+
createdAt: now.toISOString(),
|
|
183
|
+
updatedAt: now.toISOString(),
|
|
184
|
+
ttl,
|
|
185
|
+
data: data || {}
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
188
|
+
this.logger.info(`Created session: ${sessionId} (TTL: ${new Date(ttl * 1e3).toISOString()})`);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
this.logger.error(`Error creating session ${sessionId}: ${error.message}`);
|
|
191
|
+
throw new Error(`Failed to create session: ${error.message}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get session data from DynamoDB
|
|
196
|
+
*/
|
|
197
|
+
async getSession(sessionId) {
|
|
198
|
+
try {
|
|
199
|
+
const result = await this.client.send(new GetCommand({
|
|
200
|
+
TableName: this.tableName,
|
|
201
|
+
Key: {
|
|
202
|
+
sessionId
|
|
203
|
+
}
|
|
204
|
+
}));
|
|
205
|
+
if (!result.Item) {
|
|
206
|
+
this.logger.debug(`Session ${sessionId} not found`);
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const sessionData = {
|
|
210
|
+
sessionId: result.Item.sessionId,
|
|
211
|
+
createdAt: new Date(result.Item.createdAt),
|
|
212
|
+
updatedAt: new Date(result.Item.updatedAt),
|
|
213
|
+
ttl: result.Item.ttl,
|
|
214
|
+
data: result.Item.data
|
|
215
|
+
};
|
|
216
|
+
this.logger.debug(`Retrieved session: ${sessionId}`);
|
|
217
|
+
return sessionData;
|
|
218
|
+
} catch (error) {
|
|
219
|
+
this.logger.error(`Error getting session ${sessionId}: ${error.message}`);
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Update session data in DynamoDB
|
|
225
|
+
* Automatically refreshes TTL on each update
|
|
226
|
+
*/
|
|
227
|
+
async updateSession(sessionId, updates) {
|
|
228
|
+
try {
|
|
229
|
+
const ttl = Math.floor(Date.now() / 1e3) + this.ttlSeconds;
|
|
230
|
+
await this.client.send(new UpdateCommand({
|
|
231
|
+
TableName: this.tableName,
|
|
232
|
+
Key: {
|
|
233
|
+
sessionId
|
|
234
|
+
},
|
|
235
|
+
UpdateExpression: "SET updatedAt = :now, #data = :data, #ttl = :ttl",
|
|
236
|
+
ExpressionAttributeNames: {
|
|
237
|
+
"#data": "data",
|
|
238
|
+
"#ttl": "ttl"
|
|
239
|
+
},
|
|
240
|
+
ExpressionAttributeValues: {
|
|
241
|
+
":now": (/* @__PURE__ */ new Date()).toISOString(),
|
|
242
|
+
":data": updates.data || {},
|
|
243
|
+
":ttl": ttl
|
|
244
|
+
}
|
|
245
|
+
}));
|
|
246
|
+
this.logger.debug(`Updated session: ${sessionId}`);
|
|
247
|
+
} catch (error) {
|
|
248
|
+
this.logger.error(`Error updating session ${sessionId}: ${error.message}`);
|
|
249
|
+
throw new Error(`Failed to update session: ${error.message}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Delete a session from DynamoDB
|
|
254
|
+
*/
|
|
255
|
+
async deleteSession(sessionId) {
|
|
256
|
+
try {
|
|
257
|
+
await this.client.send(new DeleteCommand({
|
|
258
|
+
TableName: this.tableName,
|
|
259
|
+
Key: {
|
|
260
|
+
sessionId
|
|
261
|
+
}
|
|
262
|
+
}));
|
|
263
|
+
this.logger.info(`Deleted session: ${sessionId}`);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
this.logger.error(`Error deleting session ${sessionId}: ${error.message}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export {
|
|
271
|
+
__name,
|
|
272
|
+
__require,
|
|
273
|
+
LogLevel,
|
|
274
|
+
Logger,
|
|
275
|
+
defaultLogger,
|
|
276
|
+
DEFAULT_TABLE_NAME,
|
|
277
|
+
DEFAULT_TTL_SECONDS,
|
|
278
|
+
DynamoDBSessionStore
|
|
279
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -382,15 +382,31 @@ declare function SchemaConstraint(constraints: {
|
|
|
382
382
|
enum?: any[];
|
|
383
383
|
description?: string;
|
|
384
384
|
default?: any;
|
|
385
|
-
|
|
386
|
-
type: string;
|
|
387
|
-
description?: string;
|
|
388
|
-
};
|
|
385
|
+
type?: string;
|
|
389
386
|
}): PropertyDecorator;
|
|
390
387
|
/**
|
|
391
|
-
* Enhanced schema generator that includes constraints
|
|
388
|
+
* Enhanced schema generator that includes constraints.
|
|
389
|
+
* Now integrates with type-parser to extract actual TypeScript types
|
|
390
|
+
* (including array element types like `string[]`).
|
|
391
|
+
*/
|
|
392
|
+
declare function classToJsonSchemaWithConstraints(classConstructor: new () => any, sourceFilePath?: string): any;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Register the source file path for an input class.
|
|
396
|
+
* This is called during decorator execution to capture the source location.
|
|
397
|
+
*/
|
|
398
|
+
declare function registerClassSource(className: string, sourceFile: string): void;
|
|
399
|
+
/**
|
|
400
|
+
* Parse a TypeScript class and extract JSON Schema types for each property.
|
|
401
|
+
* Automatically detects array types like `string[]` and adds proper `items`.
|
|
402
|
+
*
|
|
403
|
+
* This is now SYNCHRONOUS for easier integration with existing code.
|
|
404
|
+
*/
|
|
405
|
+
declare function parseClassTypesSync(classConstructor: new () => any, sourceFilePath?: string): Map<string, any>;
|
|
406
|
+
/**
|
|
407
|
+
* Clear the type cache (useful for hot reloading)
|
|
392
408
|
*/
|
|
393
|
-
declare function
|
|
409
|
+
declare function clearTypeCache(): void;
|
|
394
410
|
|
|
395
411
|
/**
|
|
396
412
|
* Input validation utilities for LeanMCP
|
|
@@ -969,4 +985,4 @@ declare class MCPServerRuntime {
|
|
|
969
985
|
*/
|
|
970
986
|
declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
|
|
971
987
|
|
|
972
|
-
export { Auth, type AuthErrorOptions, type AuthErrorResult, type AuthOptions, DEFAULT_TABLE_NAME, DEFAULT_TTL_SECONDS, Deprecated, DynamoDBSessionStore, type HTTPServerAuthOptions, type HTTPServerInput, type HTTPServerOptions, type ISessionStore, InMemorySessionStore, LeanMCPSessionProvider, type LeanMCPSessionProviderOptions, LogLevel, type LogPayload, Logger, type LoggerHandler, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, type ProtectedResourceMetadata, Render, Resource, type ResourceOptions, SchemaConstraint, type SecurityScheme, type SessionData, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createAuthError, createHTTPServer, createProtectedResourceMetadata, defaultLogger, extractBearerToken, getDecoratedMethods, getMethodMetadata, isAuthError, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
|
|
988
|
+
export { Auth, type AuthErrorOptions, type AuthErrorResult, type AuthOptions, DEFAULT_TABLE_NAME, DEFAULT_TTL_SECONDS, Deprecated, DynamoDBSessionStore, type HTTPServerAuthOptions, type HTTPServerInput, type HTTPServerOptions, type ISessionStore, InMemorySessionStore, LeanMCPSessionProvider, type LeanMCPSessionProviderOptions, LogLevel, type LogPayload, Logger, type LoggerHandler, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, type ProtectedResourceMetadata, Render, Resource, type ResourceOptions, SchemaConstraint, type SecurityScheme, type SessionData, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, clearTypeCache, createAuthError, createHTTPServer, createProtectedResourceMetadata, defaultLogger, extractBearerToken, getDecoratedMethods, getMethodMetadata, isAuthError, parseClassTypesSync, registerClassSource, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
|
package/dist/index.d.ts
CHANGED
|
@@ -382,15 +382,31 @@ declare function SchemaConstraint(constraints: {
|
|
|
382
382
|
enum?: any[];
|
|
383
383
|
description?: string;
|
|
384
384
|
default?: any;
|
|
385
|
-
|
|
386
|
-
type: string;
|
|
387
|
-
description?: string;
|
|
388
|
-
};
|
|
385
|
+
type?: string;
|
|
389
386
|
}): PropertyDecorator;
|
|
390
387
|
/**
|
|
391
|
-
* Enhanced schema generator that includes constraints
|
|
388
|
+
* Enhanced schema generator that includes constraints.
|
|
389
|
+
* Now integrates with type-parser to extract actual TypeScript types
|
|
390
|
+
* (including array element types like `string[]`).
|
|
391
|
+
*/
|
|
392
|
+
declare function classToJsonSchemaWithConstraints(classConstructor: new () => any, sourceFilePath?: string): any;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Register the source file path for an input class.
|
|
396
|
+
* This is called during decorator execution to capture the source location.
|
|
397
|
+
*/
|
|
398
|
+
declare function registerClassSource(className: string, sourceFile: string): void;
|
|
399
|
+
/**
|
|
400
|
+
* Parse a TypeScript class and extract JSON Schema types for each property.
|
|
401
|
+
* Automatically detects array types like `string[]` and adds proper `items`.
|
|
402
|
+
*
|
|
403
|
+
* This is now SYNCHRONOUS for easier integration with existing code.
|
|
404
|
+
*/
|
|
405
|
+
declare function parseClassTypesSync(classConstructor: new () => any, sourceFilePath?: string): Map<string, any>;
|
|
406
|
+
/**
|
|
407
|
+
* Clear the type cache (useful for hot reloading)
|
|
392
408
|
*/
|
|
393
|
-
declare function
|
|
409
|
+
declare function clearTypeCache(): void;
|
|
394
410
|
|
|
395
411
|
/**
|
|
396
412
|
* Input validation utilities for LeanMCP
|
|
@@ -969,4 +985,4 @@ declare class MCPServerRuntime {
|
|
|
969
985
|
*/
|
|
970
986
|
declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
|
|
971
987
|
|
|
972
|
-
export { Auth, type AuthErrorOptions, type AuthErrorResult, type AuthOptions, DEFAULT_TABLE_NAME, DEFAULT_TTL_SECONDS, Deprecated, DynamoDBSessionStore, type HTTPServerAuthOptions, type HTTPServerInput, type HTTPServerOptions, type ISessionStore, InMemorySessionStore, LeanMCPSessionProvider, type LeanMCPSessionProviderOptions, LogLevel, type LogPayload, Logger, type LoggerHandler, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, type ProtectedResourceMetadata, Render, Resource, type ResourceOptions, SchemaConstraint, type SecurityScheme, type SessionData, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, createAuthError, createHTTPServer, createProtectedResourceMetadata, defaultLogger, extractBearerToken, getDecoratedMethods, getMethodMetadata, isAuthError, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
|
|
988
|
+
export { Auth, type AuthErrorOptions, type AuthErrorResult, type AuthOptions, DEFAULT_TABLE_NAME, DEFAULT_TTL_SECONDS, Deprecated, DynamoDBSessionStore, type HTTPServerAuthOptions, type HTTPServerInput, type HTTPServerOptions, type ISessionStore, InMemorySessionStore, LeanMCPSessionProvider, type LeanMCPSessionProviderOptions, LogLevel, type LogPayload, Logger, type LoggerHandler, type LoggerOptions, MCPServer, type MCPServerConstructorOptions, type MCPServerFactory, type MCPServerOptions, MCPServerRuntime, Optional, Prompt, type PromptOptions, type ProtectedResourceMetadata, Render, Resource, type ResourceOptions, SchemaConstraint, type SecurityScheme, type SessionData, Tool, type ToolOptions, UI, UserEnvs, classToJsonSchema, classToJsonSchemaWithConstraints, clearTypeCache, createAuthError, createHTTPServer, createProtectedResourceMetadata, defaultLogger, extractBearerToken, getDecoratedMethods, getMethodMetadata, isAuthError, parseClassTypesSync, registerClassSource, startMCPServer, validateNonEmpty, validatePath, validatePort, validateServiceName, validateUrl };
|
package/dist/index.js
CHANGED
|
@@ -185,6 +185,186 @@ var init_decorators = __esm({
|
|
|
185
185
|
}
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
// src/type-parser.ts
|
|
189
|
+
function loadTsMorph() {
|
|
190
|
+
if (tsMorphLoaded) {
|
|
191
|
+
return tsMorphProject !== null;
|
|
192
|
+
}
|
|
193
|
+
tsMorphLoaded = true;
|
|
194
|
+
try {
|
|
195
|
+
const customRequire = (0, import_node_module.createRequire)(import_meta.url);
|
|
196
|
+
const tsMorph = customRequire("ts-morph");
|
|
197
|
+
tsMorphProject = tsMorph.Project;
|
|
198
|
+
tsMorphNode = tsMorph.Node;
|
|
199
|
+
return true;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.warn(`[type-parser] ts-morph not available: ${error.message}`);
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function registerClassSource(className, sourceFile) {
|
|
206
|
+
classSourceMap.set(className, sourceFile);
|
|
207
|
+
}
|
|
208
|
+
function parseClassTypesSync(classConstructor, sourceFilePath) {
|
|
209
|
+
if (!loadTsMorph()) {
|
|
210
|
+
return /* @__PURE__ */ new Map();
|
|
211
|
+
}
|
|
212
|
+
const className = classConstructor.name;
|
|
213
|
+
let filePath = sourceFilePath || classSourceMap.get(className) || findSourceFile();
|
|
214
|
+
if (!filePath) {
|
|
215
|
+
return /* @__PURE__ */ new Map();
|
|
216
|
+
}
|
|
217
|
+
if (filePath.endsWith(".js")) {
|
|
218
|
+
const tsPath = filePath.replace(/\.js$/, ".ts");
|
|
219
|
+
if (import_fs.default.existsSync(tsPath)) {
|
|
220
|
+
filePath = tsPath;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const cacheKey = `${filePath}:${className}`;
|
|
224
|
+
if (typeCache.has(cacheKey)) {
|
|
225
|
+
return typeCache.get(cacheKey);
|
|
226
|
+
}
|
|
227
|
+
if (!import_fs.default.existsSync(filePath)) {
|
|
228
|
+
return /* @__PURE__ */ new Map();
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const project = new tsMorphProject({
|
|
232
|
+
skipAddingFilesFromTsConfig: true,
|
|
233
|
+
skipFileDependencyResolution: true,
|
|
234
|
+
useInMemoryFileSystem: false
|
|
235
|
+
});
|
|
236
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
237
|
+
const classDecl = sourceFile.getClass(className);
|
|
238
|
+
if (!classDecl) {
|
|
239
|
+
return /* @__PURE__ */ new Map();
|
|
240
|
+
}
|
|
241
|
+
const propertyTypes = /* @__PURE__ */ new Map();
|
|
242
|
+
for (const prop of classDecl.getInstanceProperties()) {
|
|
243
|
+
if (tsMorphNode.isPropertyDeclaration(prop)) {
|
|
244
|
+
const propName = prop.getName();
|
|
245
|
+
const typeNode = prop.getTypeNode();
|
|
246
|
+
if (typeNode) {
|
|
247
|
+
const typeText = typeNode.getText();
|
|
248
|
+
const jsonSchemaType = typeTextToJsonSchema(typeText);
|
|
249
|
+
propertyTypes.set(propName, jsonSchemaType);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
typeCache.set(cacheKey, propertyTypes);
|
|
254
|
+
return propertyTypes;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.warn(`[type-parser] Failed to parse ${filePath}: ${error.message}`);
|
|
257
|
+
return /* @__PURE__ */ new Map();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function typeTextToJsonSchema(typeText) {
|
|
261
|
+
const type = typeText.trim().replace(/\?$/, "");
|
|
262
|
+
if (type.endsWith("[]")) {
|
|
263
|
+
const elementType = type.slice(0, -2);
|
|
264
|
+
return {
|
|
265
|
+
type: "array",
|
|
266
|
+
items: typeTextToJsonSchema(elementType)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const arrayMatch = type.match(/^Array<(.+)>$/);
|
|
270
|
+
if (arrayMatch) {
|
|
271
|
+
return {
|
|
272
|
+
type: "array",
|
|
273
|
+
items: typeTextToJsonSchema(arrayMatch[1])
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const lowerType = type.toLowerCase();
|
|
277
|
+
switch (lowerType) {
|
|
278
|
+
case "string":
|
|
279
|
+
return {
|
|
280
|
+
type: "string"
|
|
281
|
+
};
|
|
282
|
+
case "number":
|
|
283
|
+
return {
|
|
284
|
+
type: "number"
|
|
285
|
+
};
|
|
286
|
+
case "integer":
|
|
287
|
+
return {
|
|
288
|
+
type: "integer"
|
|
289
|
+
};
|
|
290
|
+
case "boolean":
|
|
291
|
+
return {
|
|
292
|
+
type: "boolean"
|
|
293
|
+
};
|
|
294
|
+
case "object":
|
|
295
|
+
return {
|
|
296
|
+
type: "object"
|
|
297
|
+
};
|
|
298
|
+
case "any":
|
|
299
|
+
case "unknown":
|
|
300
|
+
return {};
|
|
301
|
+
// No constraints
|
|
302
|
+
case "null":
|
|
303
|
+
return {
|
|
304
|
+
type: "null"
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (type.includes("|")) {
|
|
308
|
+
const parts = type.split("|").map((p) => p.trim());
|
|
309
|
+
const nonNullParts = parts.filter((p) => p.toLowerCase() !== "null");
|
|
310
|
+
if (nonNullParts.length === 1) {
|
|
311
|
+
return typeTextToJsonSchema(nonNullParts[0]);
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
anyOf: nonNullParts.map((p) => typeTextToJsonSchema(p))
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
type: "object"
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function findSourceFile() {
|
|
322
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
323
|
+
try {
|
|
324
|
+
Error.prepareStackTrace = (_, stack2) => stack2;
|
|
325
|
+
const err = new Error();
|
|
326
|
+
const stack = err.stack;
|
|
327
|
+
for (const site of stack) {
|
|
328
|
+
const fileName = site.getFileName();
|
|
329
|
+
if (fileName && !fileName.includes("node_modules") && !fileName.includes("type-parser") && !fileName.includes("schema-generator") && (fileName.endsWith(".ts") || fileName.endsWith(".js"))) {
|
|
330
|
+
if (fileName.endsWith(".js")) {
|
|
331
|
+
const tsPath = fileName.replace(/\.js$/, ".ts");
|
|
332
|
+
if (import_fs.default.existsSync(tsPath)) {
|
|
333
|
+
return tsPath;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return fileName;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
} finally {
|
|
340
|
+
Error.prepareStackTrace = originalPrepareStackTrace;
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
function clearTypeCache() {
|
|
345
|
+
typeCache.clear();
|
|
346
|
+
}
|
|
347
|
+
var import_fs, import_node_module, import_meta, typeCache, classSourceMap, tsMorphProject, tsMorphNode, tsMorphLoaded;
|
|
348
|
+
var init_type_parser = __esm({
|
|
349
|
+
"src/type-parser.ts"() {
|
|
350
|
+
"use strict";
|
|
351
|
+
import_fs = __toESM(require("fs"));
|
|
352
|
+
import_node_module = require("module");
|
|
353
|
+
import_meta = {};
|
|
354
|
+
typeCache = /* @__PURE__ */ new Map();
|
|
355
|
+
classSourceMap = /* @__PURE__ */ new Map();
|
|
356
|
+
tsMorphProject = null;
|
|
357
|
+
tsMorphNode = null;
|
|
358
|
+
tsMorphLoaded = false;
|
|
359
|
+
__name(loadTsMorph, "loadTsMorph");
|
|
360
|
+
__name(registerClassSource, "registerClassSource");
|
|
361
|
+
__name(parseClassTypesSync, "parseClassTypesSync");
|
|
362
|
+
__name(typeTextToJsonSchema, "typeTextToJsonSchema");
|
|
363
|
+
__name(findSourceFile, "findSourceFile");
|
|
364
|
+
__name(clearTypeCache, "clearTypeCache");
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
188
368
|
// src/schema-generator.ts
|
|
189
369
|
function classToJsonSchema(classConstructor) {
|
|
190
370
|
const instance = new classConstructor();
|
|
@@ -240,19 +420,44 @@ function Optional() {
|
|
|
240
420
|
function SchemaConstraint(constraints) {
|
|
241
421
|
return (target, propertyKey) => {
|
|
242
422
|
Reflect.defineMetadata("schema:constraints", constraints, target, propertyKey);
|
|
423
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
424
|
+
try {
|
|
425
|
+
Error.prepareStackTrace = (_, stack2) => stack2;
|
|
426
|
+
const err = new Error();
|
|
427
|
+
const stack = err.stack;
|
|
428
|
+
for (const site of stack) {
|
|
429
|
+
const fileName = site.getFileName();
|
|
430
|
+
if (fileName && !fileName.includes("node_modules") && !fileName.includes("schema-generator") && (fileName.endsWith(".ts") || fileName.endsWith(".js"))) {
|
|
431
|
+
const className = target.constructor.name;
|
|
432
|
+
if (className && className !== "Object") {
|
|
433
|
+
registerClassSource(className, fileName);
|
|
434
|
+
}
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
} finally {
|
|
439
|
+
Error.prepareStackTrace = originalPrepareStackTrace;
|
|
440
|
+
}
|
|
243
441
|
};
|
|
244
442
|
}
|
|
245
|
-
function classToJsonSchemaWithConstraints(classConstructor) {
|
|
443
|
+
function classToJsonSchemaWithConstraints(classConstructor, sourceFilePath) {
|
|
246
444
|
const instance = new classConstructor();
|
|
247
445
|
const properties = {};
|
|
248
446
|
const required = [];
|
|
447
|
+
const parsedTypes = parseClassTypesSync(classConstructor, sourceFilePath);
|
|
249
448
|
const propertyNames = Object.keys(instance);
|
|
250
449
|
for (const propertyName of propertyNames) {
|
|
251
450
|
const propertyType = Reflect.getMetadata("design:type", instance, propertyName);
|
|
252
451
|
const constraints = Reflect.getMetadata("schema:constraints", instance, propertyName);
|
|
253
452
|
const isOptional = Reflect.getMetadata("optional", instance, propertyName);
|
|
254
|
-
|
|
255
|
-
|
|
453
|
+
const parsedType = parsedTypes.get(propertyName);
|
|
454
|
+
let propertySchema;
|
|
455
|
+
if (parsedType && parsedType.type) {
|
|
456
|
+
propertySchema = {
|
|
457
|
+
...parsedType
|
|
458
|
+
};
|
|
459
|
+
} else if (propertyType) {
|
|
460
|
+
let jsonSchemaType = "string";
|
|
256
461
|
switch (propertyType.name) {
|
|
257
462
|
case "String":
|
|
258
463
|
jsonSchemaType = "string";
|
|
@@ -272,8 +477,16 @@ function classToJsonSchemaWithConstraints(classConstructor) {
|
|
|
272
477
|
default:
|
|
273
478
|
jsonSchemaType = "object";
|
|
274
479
|
}
|
|
480
|
+
propertySchema = {
|
|
481
|
+
type: jsonSchemaType
|
|
482
|
+
};
|
|
275
483
|
} else if (constraints) {
|
|
276
|
-
|
|
484
|
+
let jsonSchemaType = "string";
|
|
485
|
+
if (constraints.type) {
|
|
486
|
+
jsonSchemaType = constraints.type;
|
|
487
|
+
} else if (constraints.items) {
|
|
488
|
+
jsonSchemaType = "array";
|
|
489
|
+
} else if (constraints.minLength !== void 0 || constraints.maxLength !== void 0 || constraints.pattern) {
|
|
277
490
|
jsonSchemaType = "string";
|
|
278
491
|
} else if (constraints.minimum !== void 0 || constraints.maximum !== void 0) {
|
|
279
492
|
jsonSchemaType = "number";
|
|
@@ -287,12 +500,25 @@ function classToJsonSchemaWithConstraints(classConstructor) {
|
|
|
287
500
|
jsonSchemaType = "string";
|
|
288
501
|
}
|
|
289
502
|
}
|
|
503
|
+
propertySchema = {
|
|
504
|
+
type: jsonSchemaType
|
|
505
|
+
};
|
|
506
|
+
} else {
|
|
507
|
+
propertySchema = {
|
|
508
|
+
type: "string"
|
|
509
|
+
};
|
|
290
510
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
511
|
+
if (constraints) {
|
|
512
|
+
const parsedItems = propertySchema.items;
|
|
513
|
+
propertySchema = {
|
|
514
|
+
...propertySchema,
|
|
515
|
+
...constraints
|
|
516
|
+
};
|
|
517
|
+
if (parsedItems && !constraints.items) {
|
|
518
|
+
propertySchema.items = parsedItems;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (propertySchema.type === "array" && !propertySchema.items) {
|
|
296
522
|
propertySchema.items = {
|
|
297
523
|
type: "string"
|
|
298
524
|
};
|
|
@@ -313,6 +539,7 @@ var init_schema_generator = __esm({
|
|
|
313
539
|
"src/schema-generator.ts"() {
|
|
314
540
|
"use strict";
|
|
315
541
|
import_reflect_metadata2 = require("reflect-metadata");
|
|
542
|
+
init_type_parser();
|
|
316
543
|
__name(classToJsonSchema, "classToJsonSchema");
|
|
317
544
|
__name(Optional, "Optional");
|
|
318
545
|
__name(SchemaConstraint, "SchemaConstraint");
|
|
@@ -1617,6 +1844,7 @@ __export(index_exports, {
|
|
|
1617
1844
|
UserEnvs: () => UserEnvs,
|
|
1618
1845
|
classToJsonSchema: () => classToJsonSchema,
|
|
1619
1846
|
classToJsonSchemaWithConstraints: () => classToJsonSchemaWithConstraints,
|
|
1847
|
+
clearTypeCache: () => clearTypeCache,
|
|
1620
1848
|
createAuthError: () => createAuthError,
|
|
1621
1849
|
createHTTPServer: () => createHTTPServer,
|
|
1622
1850
|
createProtectedResourceMetadata: () => createProtectedResourceMetadata,
|
|
@@ -1625,6 +1853,8 @@ __export(index_exports, {
|
|
|
1625
1853
|
getDecoratedMethods: () => getDecoratedMethods,
|
|
1626
1854
|
getMethodMetadata: () => getMethodMetadata,
|
|
1627
1855
|
isAuthError: () => isAuthError,
|
|
1856
|
+
parseClassTypesSync: () => parseClassTypesSync,
|
|
1857
|
+
registerClassSource: () => registerClassSource,
|
|
1628
1858
|
startMCPServer: () => startMCPServer,
|
|
1629
1859
|
validateNonEmpty: () => validateNonEmpty,
|
|
1630
1860
|
validatePath: () => validatePath,
|
|
@@ -1638,11 +1868,11 @@ async function startMCPServer(options) {
|
|
|
1638
1868
|
await runtime.start();
|
|
1639
1869
|
return runtime;
|
|
1640
1870
|
}
|
|
1641
|
-
var import_reflect_metadata3,
|
|
1871
|
+
var import_reflect_metadata3, import_fs2, import_path, import_url, import_server, import_stdio, import_types, import_ajv, ajv, MCPServer, MCPServerRuntime;
|
|
1642
1872
|
var init_index = __esm({
|
|
1643
1873
|
"src/index.ts"() {
|
|
1644
1874
|
import_reflect_metadata3 = require("reflect-metadata");
|
|
1645
|
-
|
|
1875
|
+
import_fs2 = __toESM(require("fs"));
|
|
1646
1876
|
import_path = __toESM(require("path"));
|
|
1647
1877
|
import_url = require("url");
|
|
1648
1878
|
import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -1651,6 +1881,7 @@ var init_index = __esm({
|
|
|
1651
1881
|
import_ajv = __toESM(require("ajv"));
|
|
1652
1882
|
init_decorators();
|
|
1653
1883
|
init_schema_generator();
|
|
1884
|
+
init_type_parser();
|
|
1654
1885
|
init_http_server();
|
|
1655
1886
|
init_logger();
|
|
1656
1887
|
init_validation();
|
|
@@ -1739,7 +1970,7 @@ var init_index = __esm({
|
|
|
1739
1970
|
mcpDir = import_path.default.join(process.cwd(), "mcp");
|
|
1740
1971
|
}
|
|
1741
1972
|
}
|
|
1742
|
-
if (
|
|
1973
|
+
if (import_fs2.default.existsSync(mcpDir)) {
|
|
1743
1974
|
this.logger.debug(`Auto-discovering services from: ${mcpDir}`);
|
|
1744
1975
|
await this.autoRegisterServices(mcpDir, serviceFactories);
|
|
1745
1976
|
} else {
|
|
@@ -1989,7 +2220,7 @@ var init_index = __esm({
|
|
|
1989
2220
|
*/
|
|
1990
2221
|
async autoRegisterServices(mcpDir, serviceFactories) {
|
|
1991
2222
|
this.logger.debug(`Auto-registering services from: ${mcpDir}`);
|
|
1992
|
-
if (!
|
|
2223
|
+
if (!import_fs2.default.existsSync(mcpDir)) {
|
|
1993
2224
|
this.logger.warn(`MCP directory not found: ${mcpDir}`);
|
|
1994
2225
|
return;
|
|
1995
2226
|
}
|
|
@@ -2008,7 +2239,7 @@ var init_index = __esm({
|
|
|
2008
2239
|
*/
|
|
2009
2240
|
findServiceFiles(dir) {
|
|
2010
2241
|
const files = [];
|
|
2011
|
-
const entries =
|
|
2242
|
+
const entries = import_fs2.default.readdirSync(dir, {
|
|
2012
2243
|
withFileTypes: true
|
|
2013
2244
|
});
|
|
2014
2245
|
for (const entry of entries) {
|
|
@@ -2143,7 +2374,7 @@ var init_index = __esm({
|
|
|
2143
2374
|
}
|
|
2144
2375
|
try {
|
|
2145
2376
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2146
|
-
if (!
|
|
2377
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2147
2378
|
return;
|
|
2148
2379
|
}
|
|
2149
2380
|
if (this.logging) {
|
|
@@ -2186,7 +2417,7 @@ var init_index = __esm({
|
|
|
2186
2417
|
async reloadUIManifest() {
|
|
2187
2418
|
try {
|
|
2188
2419
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2189
|
-
if (!
|
|
2420
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2190
2421
|
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
2191
2422
|
for (const uri of uiResourceUris) {
|
|
2192
2423
|
this.resources.delete(uri);
|
|
@@ -2196,7 +2427,7 @@ var init_index = __esm({
|
|
|
2196
2427
|
}
|
|
2197
2428
|
return;
|
|
2198
2429
|
}
|
|
2199
|
-
const manifest = JSON.parse(
|
|
2430
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
2200
2431
|
const currentUIUris = new Set(Object.keys(manifest));
|
|
2201
2432
|
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
2202
2433
|
for (const uri of registeredUIUris) {
|
|
@@ -2212,7 +2443,7 @@ var init_index = __esm({
|
|
|
2212
2443
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
2213
2444
|
const isGPTApp = !isString && entry.isGPTApp;
|
|
2214
2445
|
const gptMeta = !isString ? entry.gptMeta : void 0;
|
|
2215
|
-
if (!
|
|
2446
|
+
if (!import_fs2.default.existsSync(htmlPath)) {
|
|
2216
2447
|
if (this.logging) {
|
|
2217
2448
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
2218
2449
|
}
|
|
@@ -2233,8 +2464,8 @@ var init_index = __esm({
|
|
|
2233
2464
|
mimeType,
|
|
2234
2465
|
inputSchema: void 0,
|
|
2235
2466
|
method: /* @__PURE__ */ __name(async () => {
|
|
2236
|
-
if (
|
|
2237
|
-
const html =
|
|
2467
|
+
if (import_fs2.default.existsSync(htmlPath)) {
|
|
2468
|
+
const html = import_fs2.default.readFileSync(htmlPath, "utf-8");
|
|
2238
2469
|
return {
|
|
2239
2470
|
text: html,
|
|
2240
2471
|
_meta: Object.keys(_meta).length > 0 ? _meta : void 0
|
|
@@ -2263,10 +2494,10 @@ var init_index = __esm({
|
|
|
2263
2494
|
async loadUIManifest() {
|
|
2264
2495
|
try {
|
|
2265
2496
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2266
|
-
if (!
|
|
2497
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2267
2498
|
return;
|
|
2268
2499
|
}
|
|
2269
|
-
const manifest = JSON.parse(
|
|
2500
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
2270
2501
|
for (const [uri, entry] of Object.entries(manifest)) {
|
|
2271
2502
|
const isString = typeof entry === "string";
|
|
2272
2503
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
@@ -2278,13 +2509,13 @@ var init_index = __esm({
|
|
|
2278
2509
|
}
|
|
2279
2510
|
continue;
|
|
2280
2511
|
}
|
|
2281
|
-
if (!
|
|
2512
|
+
if (!import_fs2.default.existsSync(htmlPath)) {
|
|
2282
2513
|
if (this.logging) {
|
|
2283
2514
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
2284
2515
|
}
|
|
2285
2516
|
continue;
|
|
2286
2517
|
}
|
|
2287
|
-
const html =
|
|
2518
|
+
const html = import_fs2.default.readFileSync(htmlPath, "utf-8");
|
|
2288
2519
|
const mimeType = isGPTApp ? "text/html+skybridge" : "text/html;profile=mcp-app";
|
|
2289
2520
|
const _meta = {};
|
|
2290
2521
|
if (isGPTApp) {
|
|
@@ -2536,18 +2767,18 @@ var init_index = __esm({
|
|
|
2536
2767
|
}
|
|
2537
2768
|
async loadServices() {
|
|
2538
2769
|
const absPath = import_path.default.resolve(this.options.servicesDir);
|
|
2539
|
-
if (!
|
|
2770
|
+
if (!import_fs2.default.existsSync(absPath)) {
|
|
2540
2771
|
this.logger.error(`Services directory not found: ${absPath}`);
|
|
2541
2772
|
return;
|
|
2542
2773
|
}
|
|
2543
|
-
const files =
|
|
2774
|
+
const files = import_fs2.default.readdirSync(absPath);
|
|
2544
2775
|
let toolCount = 0;
|
|
2545
2776
|
let promptCount = 0;
|
|
2546
2777
|
let resourceCount = 0;
|
|
2547
2778
|
for (const dir of files) {
|
|
2548
2779
|
const modulePath = import_path.default.join(absPath, dir, "index.ts");
|
|
2549
2780
|
const modulePathJs = import_path.default.join(absPath, dir, "index.js");
|
|
2550
|
-
const finalPath =
|
|
2781
|
+
const finalPath = import_fs2.default.existsSync(modulePath) ? modulePath : import_fs2.default.existsSync(modulePathJs) ? modulePathJs : null;
|
|
2551
2782
|
if (finalPath) {
|
|
2552
2783
|
try {
|
|
2553
2784
|
const fileUrl = (0, import_url.pathToFileURL)(finalPath).href;
|
|
@@ -2681,6 +2912,7 @@ init_index();
|
|
|
2681
2912
|
UserEnvs,
|
|
2682
2913
|
classToJsonSchema,
|
|
2683
2914
|
classToJsonSchemaWithConstraints,
|
|
2915
|
+
clearTypeCache,
|
|
2684
2916
|
createAuthError,
|
|
2685
2917
|
createHTTPServer,
|
|
2686
2918
|
createProtectedResourceMetadata,
|
|
@@ -2689,6 +2921,8 @@ init_index();
|
|
|
2689
2921
|
getDecoratedMethods,
|
|
2690
2922
|
getMethodMetadata,
|
|
2691
2923
|
isAuthError,
|
|
2924
|
+
parseClassTypesSync,
|
|
2925
|
+
registerClassSource,
|
|
2692
2926
|
startMCPServer,
|
|
2693
2927
|
validateNonEmpty,
|
|
2694
2928
|
validatePath,
|
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
|
|
11
11
|
// src/index.ts
|
|
12
12
|
import "reflect-metadata";
|
|
13
|
-
import
|
|
13
|
+
import fs2 from "fs";
|
|
14
14
|
import path from "path";
|
|
15
15
|
import { pathToFileURL } from "url";
|
|
16
16
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -168,6 +168,181 @@ __name(getDecoratedMethods, "getDecoratedMethods");
|
|
|
168
168
|
|
|
169
169
|
// src/schema-generator.ts
|
|
170
170
|
import "reflect-metadata";
|
|
171
|
+
|
|
172
|
+
// src/type-parser.ts
|
|
173
|
+
import fs from "fs";
|
|
174
|
+
import { createRequire } from "module";
|
|
175
|
+
var typeCache = /* @__PURE__ */ new Map();
|
|
176
|
+
var classSourceMap = /* @__PURE__ */ new Map();
|
|
177
|
+
var tsMorphProject = null;
|
|
178
|
+
var tsMorphNode = null;
|
|
179
|
+
var tsMorphLoaded = false;
|
|
180
|
+
function loadTsMorph() {
|
|
181
|
+
if (tsMorphLoaded) {
|
|
182
|
+
return tsMorphProject !== null;
|
|
183
|
+
}
|
|
184
|
+
tsMorphLoaded = true;
|
|
185
|
+
try {
|
|
186
|
+
const customRequire = createRequire(import.meta.url);
|
|
187
|
+
const tsMorph = customRequire("ts-morph");
|
|
188
|
+
tsMorphProject = tsMorph.Project;
|
|
189
|
+
tsMorphNode = tsMorph.Node;
|
|
190
|
+
return true;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.warn(`[type-parser] ts-morph not available: ${error.message}`);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
__name(loadTsMorph, "loadTsMorph");
|
|
197
|
+
function registerClassSource(className, sourceFile) {
|
|
198
|
+
classSourceMap.set(className, sourceFile);
|
|
199
|
+
}
|
|
200
|
+
__name(registerClassSource, "registerClassSource");
|
|
201
|
+
function parseClassTypesSync(classConstructor, sourceFilePath) {
|
|
202
|
+
if (!loadTsMorph()) {
|
|
203
|
+
return /* @__PURE__ */ new Map();
|
|
204
|
+
}
|
|
205
|
+
const className = classConstructor.name;
|
|
206
|
+
let filePath = sourceFilePath || classSourceMap.get(className) || findSourceFile();
|
|
207
|
+
if (!filePath) {
|
|
208
|
+
return /* @__PURE__ */ new Map();
|
|
209
|
+
}
|
|
210
|
+
if (filePath.endsWith(".js")) {
|
|
211
|
+
const tsPath = filePath.replace(/\.js$/, ".ts");
|
|
212
|
+
if (fs.existsSync(tsPath)) {
|
|
213
|
+
filePath = tsPath;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const cacheKey = `${filePath}:${className}`;
|
|
217
|
+
if (typeCache.has(cacheKey)) {
|
|
218
|
+
return typeCache.get(cacheKey);
|
|
219
|
+
}
|
|
220
|
+
if (!fs.existsSync(filePath)) {
|
|
221
|
+
return /* @__PURE__ */ new Map();
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const project = new tsMorphProject({
|
|
225
|
+
skipAddingFilesFromTsConfig: true,
|
|
226
|
+
skipFileDependencyResolution: true,
|
|
227
|
+
useInMemoryFileSystem: false
|
|
228
|
+
});
|
|
229
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
230
|
+
const classDecl = sourceFile.getClass(className);
|
|
231
|
+
if (!classDecl) {
|
|
232
|
+
return /* @__PURE__ */ new Map();
|
|
233
|
+
}
|
|
234
|
+
const propertyTypes = /* @__PURE__ */ new Map();
|
|
235
|
+
for (const prop of classDecl.getInstanceProperties()) {
|
|
236
|
+
if (tsMorphNode.isPropertyDeclaration(prop)) {
|
|
237
|
+
const propName = prop.getName();
|
|
238
|
+
const typeNode = prop.getTypeNode();
|
|
239
|
+
if (typeNode) {
|
|
240
|
+
const typeText = typeNode.getText();
|
|
241
|
+
const jsonSchemaType = typeTextToJsonSchema(typeText);
|
|
242
|
+
propertyTypes.set(propName, jsonSchemaType);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
typeCache.set(cacheKey, propertyTypes);
|
|
247
|
+
return propertyTypes;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn(`[type-parser] Failed to parse ${filePath}: ${error.message}`);
|
|
250
|
+
return /* @__PURE__ */ new Map();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
__name(parseClassTypesSync, "parseClassTypesSync");
|
|
254
|
+
function typeTextToJsonSchema(typeText) {
|
|
255
|
+
const type = typeText.trim().replace(/\?$/, "");
|
|
256
|
+
if (type.endsWith("[]")) {
|
|
257
|
+
const elementType = type.slice(0, -2);
|
|
258
|
+
return {
|
|
259
|
+
type: "array",
|
|
260
|
+
items: typeTextToJsonSchema(elementType)
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const arrayMatch = type.match(/^Array<(.+)>$/);
|
|
264
|
+
if (arrayMatch) {
|
|
265
|
+
return {
|
|
266
|
+
type: "array",
|
|
267
|
+
items: typeTextToJsonSchema(arrayMatch[1])
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
const lowerType = type.toLowerCase();
|
|
271
|
+
switch (lowerType) {
|
|
272
|
+
case "string":
|
|
273
|
+
return {
|
|
274
|
+
type: "string"
|
|
275
|
+
};
|
|
276
|
+
case "number":
|
|
277
|
+
return {
|
|
278
|
+
type: "number"
|
|
279
|
+
};
|
|
280
|
+
case "integer":
|
|
281
|
+
return {
|
|
282
|
+
type: "integer"
|
|
283
|
+
};
|
|
284
|
+
case "boolean":
|
|
285
|
+
return {
|
|
286
|
+
type: "boolean"
|
|
287
|
+
};
|
|
288
|
+
case "object":
|
|
289
|
+
return {
|
|
290
|
+
type: "object"
|
|
291
|
+
};
|
|
292
|
+
case "any":
|
|
293
|
+
case "unknown":
|
|
294
|
+
return {};
|
|
295
|
+
// No constraints
|
|
296
|
+
case "null":
|
|
297
|
+
return {
|
|
298
|
+
type: "null"
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (type.includes("|")) {
|
|
302
|
+
const parts = type.split("|").map((p) => p.trim());
|
|
303
|
+
const nonNullParts = parts.filter((p) => p.toLowerCase() !== "null");
|
|
304
|
+
if (nonNullParts.length === 1) {
|
|
305
|
+
return typeTextToJsonSchema(nonNullParts[0]);
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
anyOf: nonNullParts.map((p) => typeTextToJsonSchema(p))
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
type: "object"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
__name(typeTextToJsonSchema, "typeTextToJsonSchema");
|
|
316
|
+
function findSourceFile() {
|
|
317
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
318
|
+
try {
|
|
319
|
+
Error.prepareStackTrace = (_, stack2) => stack2;
|
|
320
|
+
const err = new Error();
|
|
321
|
+
const stack = err.stack;
|
|
322
|
+
for (const site of stack) {
|
|
323
|
+
const fileName = site.getFileName();
|
|
324
|
+
if (fileName && !fileName.includes("node_modules") && !fileName.includes("type-parser") && !fileName.includes("schema-generator") && (fileName.endsWith(".ts") || fileName.endsWith(".js"))) {
|
|
325
|
+
if (fileName.endsWith(".js")) {
|
|
326
|
+
const tsPath = fileName.replace(/\.js$/, ".ts");
|
|
327
|
+
if (fs.existsSync(tsPath)) {
|
|
328
|
+
return tsPath;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return fileName;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
} finally {
|
|
335
|
+
Error.prepareStackTrace = originalPrepareStackTrace;
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
__name(findSourceFile, "findSourceFile");
|
|
340
|
+
function clearTypeCache() {
|
|
341
|
+
typeCache.clear();
|
|
342
|
+
}
|
|
343
|
+
__name(clearTypeCache, "clearTypeCache");
|
|
344
|
+
|
|
345
|
+
// src/schema-generator.ts
|
|
171
346
|
function classToJsonSchema(classConstructor) {
|
|
172
347
|
const instance = new classConstructor();
|
|
173
348
|
const properties = {};
|
|
@@ -224,20 +399,45 @@ __name(Optional, "Optional");
|
|
|
224
399
|
function SchemaConstraint(constraints) {
|
|
225
400
|
return (target, propertyKey) => {
|
|
226
401
|
Reflect.defineMetadata("schema:constraints", constraints, target, propertyKey);
|
|
402
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
403
|
+
try {
|
|
404
|
+
Error.prepareStackTrace = (_, stack2) => stack2;
|
|
405
|
+
const err = new Error();
|
|
406
|
+
const stack = err.stack;
|
|
407
|
+
for (const site of stack) {
|
|
408
|
+
const fileName = site.getFileName();
|
|
409
|
+
if (fileName && !fileName.includes("node_modules") && !fileName.includes("schema-generator") && (fileName.endsWith(".ts") || fileName.endsWith(".js"))) {
|
|
410
|
+
const className = target.constructor.name;
|
|
411
|
+
if (className && className !== "Object") {
|
|
412
|
+
registerClassSource(className, fileName);
|
|
413
|
+
}
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
} finally {
|
|
418
|
+
Error.prepareStackTrace = originalPrepareStackTrace;
|
|
419
|
+
}
|
|
227
420
|
};
|
|
228
421
|
}
|
|
229
422
|
__name(SchemaConstraint, "SchemaConstraint");
|
|
230
|
-
function classToJsonSchemaWithConstraints(classConstructor) {
|
|
423
|
+
function classToJsonSchemaWithConstraints(classConstructor, sourceFilePath) {
|
|
231
424
|
const instance = new classConstructor();
|
|
232
425
|
const properties = {};
|
|
233
426
|
const required = [];
|
|
427
|
+
const parsedTypes = parseClassTypesSync(classConstructor, sourceFilePath);
|
|
234
428
|
const propertyNames = Object.keys(instance);
|
|
235
429
|
for (const propertyName of propertyNames) {
|
|
236
430
|
const propertyType = Reflect.getMetadata("design:type", instance, propertyName);
|
|
237
431
|
const constraints = Reflect.getMetadata("schema:constraints", instance, propertyName);
|
|
238
432
|
const isOptional = Reflect.getMetadata("optional", instance, propertyName);
|
|
239
|
-
|
|
240
|
-
|
|
433
|
+
const parsedType = parsedTypes.get(propertyName);
|
|
434
|
+
let propertySchema;
|
|
435
|
+
if (parsedType && parsedType.type) {
|
|
436
|
+
propertySchema = {
|
|
437
|
+
...parsedType
|
|
438
|
+
};
|
|
439
|
+
} else if (propertyType) {
|
|
440
|
+
let jsonSchemaType = "string";
|
|
241
441
|
switch (propertyType.name) {
|
|
242
442
|
case "String":
|
|
243
443
|
jsonSchemaType = "string";
|
|
@@ -257,8 +457,16 @@ function classToJsonSchemaWithConstraints(classConstructor) {
|
|
|
257
457
|
default:
|
|
258
458
|
jsonSchemaType = "object";
|
|
259
459
|
}
|
|
460
|
+
propertySchema = {
|
|
461
|
+
type: jsonSchemaType
|
|
462
|
+
};
|
|
260
463
|
} else if (constraints) {
|
|
261
|
-
|
|
464
|
+
let jsonSchemaType = "string";
|
|
465
|
+
if (constraints.type) {
|
|
466
|
+
jsonSchemaType = constraints.type;
|
|
467
|
+
} else if (constraints.items) {
|
|
468
|
+
jsonSchemaType = "array";
|
|
469
|
+
} else if (constraints.minLength !== void 0 || constraints.maxLength !== void 0 || constraints.pattern) {
|
|
262
470
|
jsonSchemaType = "string";
|
|
263
471
|
} else if (constraints.minimum !== void 0 || constraints.maximum !== void 0) {
|
|
264
472
|
jsonSchemaType = "number";
|
|
@@ -272,12 +480,25 @@ function classToJsonSchemaWithConstraints(classConstructor) {
|
|
|
272
480
|
jsonSchemaType = "string";
|
|
273
481
|
}
|
|
274
482
|
}
|
|
483
|
+
propertySchema = {
|
|
484
|
+
type: jsonSchemaType
|
|
485
|
+
};
|
|
486
|
+
} else {
|
|
487
|
+
propertySchema = {
|
|
488
|
+
type: "string"
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (constraints) {
|
|
492
|
+
const parsedItems = propertySchema.items;
|
|
493
|
+
propertySchema = {
|
|
494
|
+
...propertySchema,
|
|
495
|
+
...constraints
|
|
496
|
+
};
|
|
497
|
+
if (parsedItems && !constraints.items) {
|
|
498
|
+
propertySchema.items = parsedItems;
|
|
499
|
+
}
|
|
275
500
|
}
|
|
276
|
-
|
|
277
|
-
type: jsonSchemaType,
|
|
278
|
-
...constraints || {}
|
|
279
|
-
};
|
|
280
|
-
if (jsonSchemaType === "array" && !propertySchema.items) {
|
|
501
|
+
if (propertySchema.type === "array" && !propertySchema.items) {
|
|
281
502
|
propertySchema.items = {
|
|
282
503
|
type: "string"
|
|
283
504
|
};
|
|
@@ -1334,7 +1555,7 @@ var MCPServer = class {
|
|
|
1334
1555
|
mcpDir = path.join(process.cwd(), "mcp");
|
|
1335
1556
|
}
|
|
1336
1557
|
}
|
|
1337
|
-
if (
|
|
1558
|
+
if (fs2.existsSync(mcpDir)) {
|
|
1338
1559
|
this.logger.debug(`Auto-discovering services from: ${mcpDir}`);
|
|
1339
1560
|
await this.autoRegisterServices(mcpDir, serviceFactories);
|
|
1340
1561
|
} else {
|
|
@@ -1584,7 +1805,7 @@ var MCPServer = class {
|
|
|
1584
1805
|
*/
|
|
1585
1806
|
async autoRegisterServices(mcpDir, serviceFactories) {
|
|
1586
1807
|
this.logger.debug(`Auto-registering services from: ${mcpDir}`);
|
|
1587
|
-
if (!
|
|
1808
|
+
if (!fs2.existsSync(mcpDir)) {
|
|
1588
1809
|
this.logger.warn(`MCP directory not found: ${mcpDir}`);
|
|
1589
1810
|
return;
|
|
1590
1811
|
}
|
|
@@ -1603,7 +1824,7 @@ var MCPServer = class {
|
|
|
1603
1824
|
*/
|
|
1604
1825
|
findServiceFiles(dir) {
|
|
1605
1826
|
const files = [];
|
|
1606
|
-
const entries =
|
|
1827
|
+
const entries = fs2.readdirSync(dir, {
|
|
1607
1828
|
withFileTypes: true
|
|
1608
1829
|
});
|
|
1609
1830
|
for (const entry of entries) {
|
|
@@ -1738,7 +1959,7 @@ var MCPServer = class {
|
|
|
1738
1959
|
}
|
|
1739
1960
|
try {
|
|
1740
1961
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1741
|
-
if (!
|
|
1962
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1742
1963
|
return;
|
|
1743
1964
|
}
|
|
1744
1965
|
if (this.logging) {
|
|
@@ -1781,7 +2002,7 @@ var MCPServer = class {
|
|
|
1781
2002
|
async reloadUIManifest() {
|
|
1782
2003
|
try {
|
|
1783
2004
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1784
|
-
if (!
|
|
2005
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1785
2006
|
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1786
2007
|
for (const uri of uiResourceUris) {
|
|
1787
2008
|
this.resources.delete(uri);
|
|
@@ -1791,7 +2012,7 @@ var MCPServer = class {
|
|
|
1791
2012
|
}
|
|
1792
2013
|
return;
|
|
1793
2014
|
}
|
|
1794
|
-
const manifest = JSON.parse(
|
|
2015
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
1795
2016
|
const currentUIUris = new Set(Object.keys(manifest));
|
|
1796
2017
|
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1797
2018
|
for (const uri of registeredUIUris) {
|
|
@@ -1807,7 +2028,7 @@ var MCPServer = class {
|
|
|
1807
2028
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
1808
2029
|
const isGPTApp = !isString && entry.isGPTApp;
|
|
1809
2030
|
const gptMeta = !isString ? entry.gptMeta : void 0;
|
|
1810
|
-
if (!
|
|
2031
|
+
if (!fs2.existsSync(htmlPath)) {
|
|
1811
2032
|
if (this.logging) {
|
|
1812
2033
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1813
2034
|
}
|
|
@@ -1828,8 +2049,8 @@ var MCPServer = class {
|
|
|
1828
2049
|
mimeType,
|
|
1829
2050
|
inputSchema: void 0,
|
|
1830
2051
|
method: /* @__PURE__ */ __name(async () => {
|
|
1831
|
-
if (
|
|
1832
|
-
const html =
|
|
2052
|
+
if (fs2.existsSync(htmlPath)) {
|
|
2053
|
+
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
1833
2054
|
return {
|
|
1834
2055
|
text: html,
|
|
1835
2056
|
_meta: Object.keys(_meta).length > 0 ? _meta : void 0
|
|
@@ -1858,10 +2079,10 @@ var MCPServer = class {
|
|
|
1858
2079
|
async loadUIManifest() {
|
|
1859
2080
|
try {
|
|
1860
2081
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1861
|
-
if (!
|
|
2082
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1862
2083
|
return;
|
|
1863
2084
|
}
|
|
1864
|
-
const manifest = JSON.parse(
|
|
2085
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
1865
2086
|
for (const [uri, entry] of Object.entries(manifest)) {
|
|
1866
2087
|
const isString = typeof entry === "string";
|
|
1867
2088
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
@@ -1873,13 +2094,13 @@ var MCPServer = class {
|
|
|
1873
2094
|
}
|
|
1874
2095
|
continue;
|
|
1875
2096
|
}
|
|
1876
|
-
if (!
|
|
2097
|
+
if (!fs2.existsSync(htmlPath)) {
|
|
1877
2098
|
if (this.logging) {
|
|
1878
2099
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1879
2100
|
}
|
|
1880
2101
|
continue;
|
|
1881
2102
|
}
|
|
1882
|
-
const html =
|
|
2103
|
+
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
1883
2104
|
const mimeType = isGPTApp ? "text/html+skybridge" : "text/html;profile=mcp-app";
|
|
1884
2105
|
const _meta = {};
|
|
1885
2106
|
if (isGPTApp) {
|
|
@@ -2131,18 +2352,18 @@ var MCPServerRuntime = class {
|
|
|
2131
2352
|
}
|
|
2132
2353
|
async loadServices() {
|
|
2133
2354
|
const absPath = path.resolve(this.options.servicesDir);
|
|
2134
|
-
if (!
|
|
2355
|
+
if (!fs2.existsSync(absPath)) {
|
|
2135
2356
|
this.logger.error(`Services directory not found: ${absPath}`);
|
|
2136
2357
|
return;
|
|
2137
2358
|
}
|
|
2138
|
-
const files =
|
|
2359
|
+
const files = fs2.readdirSync(absPath);
|
|
2139
2360
|
let toolCount = 0;
|
|
2140
2361
|
let promptCount = 0;
|
|
2141
2362
|
let resourceCount = 0;
|
|
2142
2363
|
for (const dir of files) {
|
|
2143
2364
|
const modulePath = path.join(absPath, dir, "index.ts");
|
|
2144
2365
|
const modulePathJs = path.join(absPath, dir, "index.js");
|
|
2145
|
-
const finalPath =
|
|
2366
|
+
const finalPath = fs2.existsSync(modulePath) ? modulePath : fs2.existsSync(modulePathJs) ? modulePathJs : null;
|
|
2146
2367
|
if (finalPath) {
|
|
2147
2368
|
try {
|
|
2148
2369
|
const fileUrl = pathToFileURL(finalPath).href;
|
|
@@ -2277,6 +2498,7 @@ export {
|
|
|
2277
2498
|
UserEnvs,
|
|
2278
2499
|
classToJsonSchema,
|
|
2279
2500
|
classToJsonSchemaWithConstraints,
|
|
2501
|
+
clearTypeCache,
|
|
2280
2502
|
createAuthError,
|
|
2281
2503
|
createHTTPServer,
|
|
2282
2504
|
createProtectedResourceMetadata,
|
|
@@ -2285,6 +2507,8 @@ export {
|
|
|
2285
2507
|
getDecoratedMethods,
|
|
2286
2508
|
getMethodMetadata,
|
|
2287
2509
|
isAuthError,
|
|
2510
|
+
parseClassTypesSync,
|
|
2511
|
+
registerClassSource,
|
|
2288
2512
|
startMCPServer,
|
|
2289
2513
|
validateNonEmpty,
|
|
2290
2514
|
validatePath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leanmcp/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "Core library implementing decorators, reflection, and MCP runtime server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"ajv": "^8.12.0",
|
|
31
31
|
"chokidar": "^4.0.0",
|
|
32
32
|
"dotenv": "^16.3.1",
|
|
33
|
-
"reflect-metadata": "^0.2.1"
|
|
33
|
+
"reflect-metadata": "^0.2.1",
|
|
34
|
+
"ts-morph": "^24.0.0"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"cors": "^2.8.5",
|