@leanmcp/core 0.4.4 → 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 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +266 -26
- package/dist/index.mjs +255 -25
- package/package.json +4 -3
|
@@ -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,11 +382,31 @@ declare function SchemaConstraint(constraints: {
|
|
|
382
382
|
enum?: any[];
|
|
383
383
|
description?: string;
|
|
384
384
|
default?: any;
|
|
385
|
+
type?: string;
|
|
385
386
|
}): PropertyDecorator;
|
|
386
387
|
/**
|
|
387
|
-
* 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[]`).
|
|
388
391
|
*/
|
|
389
|
-
declare function classToJsonSchemaWithConstraints(classConstructor: new () => any): any;
|
|
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)
|
|
408
|
+
*/
|
|
409
|
+
declare function clearTypeCache(): void;
|
|
390
410
|
|
|
391
411
|
/**
|
|
392
412
|
* Input validation utilities for LeanMCP
|
|
@@ -965,4 +985,4 @@ declare class MCPServerRuntime {
|
|
|
965
985
|
*/
|
|
966
986
|
declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
|
|
967
987
|
|
|
968
|
-
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,11 +382,31 @@ declare function SchemaConstraint(constraints: {
|
|
|
382
382
|
enum?: any[];
|
|
383
383
|
description?: string;
|
|
384
384
|
default?: any;
|
|
385
|
+
type?: string;
|
|
385
386
|
}): PropertyDecorator;
|
|
386
387
|
/**
|
|
387
|
-
* 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[]`).
|
|
388
391
|
*/
|
|
389
|
-
declare function classToJsonSchemaWithConstraints(classConstructor: new () => any): any;
|
|
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)
|
|
408
|
+
*/
|
|
409
|
+
declare function clearTypeCache(): void;
|
|
390
410
|
|
|
391
411
|
/**
|
|
392
412
|
* Input validation utilities for LeanMCP
|
|
@@ -965,4 +985,4 @@ declare class MCPServerRuntime {
|
|
|
965
985
|
*/
|
|
966
986
|
declare function startMCPServer(options: MCPServerOptions): Promise<MCPServerRuntime>;
|
|
967
987
|
|
|
968
|
-
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,11 +500,30 @@ 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
|
-
|
|
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) {
|
|
522
|
+
propertySchema.items = {
|
|
523
|
+
type: "string"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
properties[propertyName] = propertySchema;
|
|
295
527
|
if (!isOptional) {
|
|
296
528
|
required.push(propertyName);
|
|
297
529
|
}
|
|
@@ -307,6 +539,7 @@ var init_schema_generator = __esm({
|
|
|
307
539
|
"src/schema-generator.ts"() {
|
|
308
540
|
"use strict";
|
|
309
541
|
import_reflect_metadata2 = require("reflect-metadata");
|
|
542
|
+
init_type_parser();
|
|
310
543
|
__name(classToJsonSchema, "classToJsonSchema");
|
|
311
544
|
__name(Optional, "Optional");
|
|
312
545
|
__name(SchemaConstraint, "SchemaConstraint");
|
|
@@ -1611,6 +1844,7 @@ __export(index_exports, {
|
|
|
1611
1844
|
UserEnvs: () => UserEnvs,
|
|
1612
1845
|
classToJsonSchema: () => classToJsonSchema,
|
|
1613
1846
|
classToJsonSchemaWithConstraints: () => classToJsonSchemaWithConstraints,
|
|
1847
|
+
clearTypeCache: () => clearTypeCache,
|
|
1614
1848
|
createAuthError: () => createAuthError,
|
|
1615
1849
|
createHTTPServer: () => createHTTPServer,
|
|
1616
1850
|
createProtectedResourceMetadata: () => createProtectedResourceMetadata,
|
|
@@ -1619,6 +1853,8 @@ __export(index_exports, {
|
|
|
1619
1853
|
getDecoratedMethods: () => getDecoratedMethods,
|
|
1620
1854
|
getMethodMetadata: () => getMethodMetadata,
|
|
1621
1855
|
isAuthError: () => isAuthError,
|
|
1856
|
+
parseClassTypesSync: () => parseClassTypesSync,
|
|
1857
|
+
registerClassSource: () => registerClassSource,
|
|
1622
1858
|
startMCPServer: () => startMCPServer,
|
|
1623
1859
|
validateNonEmpty: () => validateNonEmpty,
|
|
1624
1860
|
validatePath: () => validatePath,
|
|
@@ -1632,11 +1868,11 @@ async function startMCPServer(options) {
|
|
|
1632
1868
|
await runtime.start();
|
|
1633
1869
|
return runtime;
|
|
1634
1870
|
}
|
|
1635
|
-
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;
|
|
1636
1872
|
var init_index = __esm({
|
|
1637
1873
|
"src/index.ts"() {
|
|
1638
1874
|
import_reflect_metadata3 = require("reflect-metadata");
|
|
1639
|
-
|
|
1875
|
+
import_fs2 = __toESM(require("fs"));
|
|
1640
1876
|
import_path = __toESM(require("path"));
|
|
1641
1877
|
import_url = require("url");
|
|
1642
1878
|
import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -1645,6 +1881,7 @@ var init_index = __esm({
|
|
|
1645
1881
|
import_ajv = __toESM(require("ajv"));
|
|
1646
1882
|
init_decorators();
|
|
1647
1883
|
init_schema_generator();
|
|
1884
|
+
init_type_parser();
|
|
1648
1885
|
init_http_server();
|
|
1649
1886
|
init_logger();
|
|
1650
1887
|
init_validation();
|
|
@@ -1733,7 +1970,7 @@ var init_index = __esm({
|
|
|
1733
1970
|
mcpDir = import_path.default.join(process.cwd(), "mcp");
|
|
1734
1971
|
}
|
|
1735
1972
|
}
|
|
1736
|
-
if (
|
|
1973
|
+
if (import_fs2.default.existsSync(mcpDir)) {
|
|
1737
1974
|
this.logger.debug(`Auto-discovering services from: ${mcpDir}`);
|
|
1738
1975
|
await this.autoRegisterServices(mcpDir, serviceFactories);
|
|
1739
1976
|
} else {
|
|
@@ -1983,7 +2220,7 @@ var init_index = __esm({
|
|
|
1983
2220
|
*/
|
|
1984
2221
|
async autoRegisterServices(mcpDir, serviceFactories) {
|
|
1985
2222
|
this.logger.debug(`Auto-registering services from: ${mcpDir}`);
|
|
1986
|
-
if (!
|
|
2223
|
+
if (!import_fs2.default.existsSync(mcpDir)) {
|
|
1987
2224
|
this.logger.warn(`MCP directory not found: ${mcpDir}`);
|
|
1988
2225
|
return;
|
|
1989
2226
|
}
|
|
@@ -2002,7 +2239,7 @@ var init_index = __esm({
|
|
|
2002
2239
|
*/
|
|
2003
2240
|
findServiceFiles(dir) {
|
|
2004
2241
|
const files = [];
|
|
2005
|
-
const entries =
|
|
2242
|
+
const entries = import_fs2.default.readdirSync(dir, {
|
|
2006
2243
|
withFileTypes: true
|
|
2007
2244
|
});
|
|
2008
2245
|
for (const entry of entries) {
|
|
@@ -2137,7 +2374,7 @@ var init_index = __esm({
|
|
|
2137
2374
|
}
|
|
2138
2375
|
try {
|
|
2139
2376
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2140
|
-
if (!
|
|
2377
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2141
2378
|
return;
|
|
2142
2379
|
}
|
|
2143
2380
|
if (this.logging) {
|
|
@@ -2180,7 +2417,7 @@ var init_index = __esm({
|
|
|
2180
2417
|
async reloadUIManifest() {
|
|
2181
2418
|
try {
|
|
2182
2419
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2183
|
-
if (!
|
|
2420
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2184
2421
|
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
2185
2422
|
for (const uri of uiResourceUris) {
|
|
2186
2423
|
this.resources.delete(uri);
|
|
@@ -2190,7 +2427,7 @@ var init_index = __esm({
|
|
|
2190
2427
|
}
|
|
2191
2428
|
return;
|
|
2192
2429
|
}
|
|
2193
|
-
const manifest = JSON.parse(
|
|
2430
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
2194
2431
|
const currentUIUris = new Set(Object.keys(manifest));
|
|
2195
2432
|
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
2196
2433
|
for (const uri of registeredUIUris) {
|
|
@@ -2206,7 +2443,7 @@ var init_index = __esm({
|
|
|
2206
2443
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
2207
2444
|
const isGPTApp = !isString && entry.isGPTApp;
|
|
2208
2445
|
const gptMeta = !isString ? entry.gptMeta : void 0;
|
|
2209
|
-
if (!
|
|
2446
|
+
if (!import_fs2.default.existsSync(htmlPath)) {
|
|
2210
2447
|
if (this.logging) {
|
|
2211
2448
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
2212
2449
|
}
|
|
@@ -2227,8 +2464,8 @@ var init_index = __esm({
|
|
|
2227
2464
|
mimeType,
|
|
2228
2465
|
inputSchema: void 0,
|
|
2229
2466
|
method: /* @__PURE__ */ __name(async () => {
|
|
2230
|
-
if (
|
|
2231
|
-
const html =
|
|
2467
|
+
if (import_fs2.default.existsSync(htmlPath)) {
|
|
2468
|
+
const html = import_fs2.default.readFileSync(htmlPath, "utf-8");
|
|
2232
2469
|
return {
|
|
2233
2470
|
text: html,
|
|
2234
2471
|
_meta: Object.keys(_meta).length > 0 ? _meta : void 0
|
|
@@ -2257,10 +2494,10 @@ var init_index = __esm({
|
|
|
2257
2494
|
async loadUIManifest() {
|
|
2258
2495
|
try {
|
|
2259
2496
|
const manifestPath = import_path.default.join(process.cwd(), "dist", "ui-manifest.json");
|
|
2260
|
-
if (!
|
|
2497
|
+
if (!import_fs2.default.existsSync(manifestPath)) {
|
|
2261
2498
|
return;
|
|
2262
2499
|
}
|
|
2263
|
-
const manifest = JSON.parse(
|
|
2500
|
+
const manifest = JSON.parse(import_fs2.default.readFileSync(manifestPath, "utf-8"));
|
|
2264
2501
|
for (const [uri, entry] of Object.entries(manifest)) {
|
|
2265
2502
|
const isString = typeof entry === "string";
|
|
2266
2503
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
@@ -2272,13 +2509,13 @@ var init_index = __esm({
|
|
|
2272
2509
|
}
|
|
2273
2510
|
continue;
|
|
2274
2511
|
}
|
|
2275
|
-
if (!
|
|
2512
|
+
if (!import_fs2.default.existsSync(htmlPath)) {
|
|
2276
2513
|
if (this.logging) {
|
|
2277
2514
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
2278
2515
|
}
|
|
2279
2516
|
continue;
|
|
2280
2517
|
}
|
|
2281
|
-
const html =
|
|
2518
|
+
const html = import_fs2.default.readFileSync(htmlPath, "utf-8");
|
|
2282
2519
|
const mimeType = isGPTApp ? "text/html+skybridge" : "text/html;profile=mcp-app";
|
|
2283
2520
|
const _meta = {};
|
|
2284
2521
|
if (isGPTApp) {
|
|
@@ -2530,18 +2767,18 @@ var init_index = __esm({
|
|
|
2530
2767
|
}
|
|
2531
2768
|
async loadServices() {
|
|
2532
2769
|
const absPath = import_path.default.resolve(this.options.servicesDir);
|
|
2533
|
-
if (!
|
|
2770
|
+
if (!import_fs2.default.existsSync(absPath)) {
|
|
2534
2771
|
this.logger.error(`Services directory not found: ${absPath}`);
|
|
2535
2772
|
return;
|
|
2536
2773
|
}
|
|
2537
|
-
const files =
|
|
2774
|
+
const files = import_fs2.default.readdirSync(absPath);
|
|
2538
2775
|
let toolCount = 0;
|
|
2539
2776
|
let promptCount = 0;
|
|
2540
2777
|
let resourceCount = 0;
|
|
2541
2778
|
for (const dir of files) {
|
|
2542
2779
|
const modulePath = import_path.default.join(absPath, dir, "index.ts");
|
|
2543
2780
|
const modulePathJs = import_path.default.join(absPath, dir, "index.js");
|
|
2544
|
-
const finalPath =
|
|
2781
|
+
const finalPath = import_fs2.default.existsSync(modulePath) ? modulePath : import_fs2.default.existsSync(modulePathJs) ? modulePathJs : null;
|
|
2545
2782
|
if (finalPath) {
|
|
2546
2783
|
try {
|
|
2547
2784
|
const fileUrl = (0, import_url.pathToFileURL)(finalPath).href;
|
|
@@ -2675,6 +2912,7 @@ init_index();
|
|
|
2675
2912
|
UserEnvs,
|
|
2676
2913
|
classToJsonSchema,
|
|
2677
2914
|
classToJsonSchemaWithConstraints,
|
|
2915
|
+
clearTypeCache,
|
|
2678
2916
|
createAuthError,
|
|
2679
2917
|
createHTTPServer,
|
|
2680
2918
|
createProtectedResourceMetadata,
|
|
@@ -2683,6 +2921,8 @@ init_index();
|
|
|
2683
2921
|
getDecoratedMethods,
|
|
2684
2922
|
getMethodMetadata,
|
|
2685
2923
|
isAuthError,
|
|
2924
|
+
parseClassTypesSync,
|
|
2925
|
+
registerClassSource,
|
|
2686
2926
|
startMCPServer,
|
|
2687
2927
|
validateNonEmpty,
|
|
2688
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,11 +480,30 @@ 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
|
+
};
|
|
275
490
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (propertySchema.type === "array" && !propertySchema.items) {
|
|
502
|
+
propertySchema.items = {
|
|
503
|
+
type: "string"
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
properties[propertyName] = propertySchema;
|
|
280
507
|
if (!isOptional) {
|
|
281
508
|
required.push(propertyName);
|
|
282
509
|
}
|
|
@@ -1328,7 +1555,7 @@ var MCPServer = class {
|
|
|
1328
1555
|
mcpDir = path.join(process.cwd(), "mcp");
|
|
1329
1556
|
}
|
|
1330
1557
|
}
|
|
1331
|
-
if (
|
|
1558
|
+
if (fs2.existsSync(mcpDir)) {
|
|
1332
1559
|
this.logger.debug(`Auto-discovering services from: ${mcpDir}`);
|
|
1333
1560
|
await this.autoRegisterServices(mcpDir, serviceFactories);
|
|
1334
1561
|
} else {
|
|
@@ -1578,7 +1805,7 @@ var MCPServer = class {
|
|
|
1578
1805
|
*/
|
|
1579
1806
|
async autoRegisterServices(mcpDir, serviceFactories) {
|
|
1580
1807
|
this.logger.debug(`Auto-registering services from: ${mcpDir}`);
|
|
1581
|
-
if (!
|
|
1808
|
+
if (!fs2.existsSync(mcpDir)) {
|
|
1582
1809
|
this.logger.warn(`MCP directory not found: ${mcpDir}`);
|
|
1583
1810
|
return;
|
|
1584
1811
|
}
|
|
@@ -1597,7 +1824,7 @@ var MCPServer = class {
|
|
|
1597
1824
|
*/
|
|
1598
1825
|
findServiceFiles(dir) {
|
|
1599
1826
|
const files = [];
|
|
1600
|
-
const entries =
|
|
1827
|
+
const entries = fs2.readdirSync(dir, {
|
|
1601
1828
|
withFileTypes: true
|
|
1602
1829
|
});
|
|
1603
1830
|
for (const entry of entries) {
|
|
@@ -1732,7 +1959,7 @@ var MCPServer = class {
|
|
|
1732
1959
|
}
|
|
1733
1960
|
try {
|
|
1734
1961
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1735
|
-
if (!
|
|
1962
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1736
1963
|
return;
|
|
1737
1964
|
}
|
|
1738
1965
|
if (this.logging) {
|
|
@@ -1775,7 +2002,7 @@ var MCPServer = class {
|
|
|
1775
2002
|
async reloadUIManifest() {
|
|
1776
2003
|
try {
|
|
1777
2004
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1778
|
-
if (!
|
|
2005
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1779
2006
|
const uiResourceUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1780
2007
|
for (const uri of uiResourceUris) {
|
|
1781
2008
|
this.resources.delete(uri);
|
|
@@ -1785,7 +2012,7 @@ var MCPServer = class {
|
|
|
1785
2012
|
}
|
|
1786
2013
|
return;
|
|
1787
2014
|
}
|
|
1788
|
-
const manifest = JSON.parse(
|
|
2015
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
1789
2016
|
const currentUIUris = new Set(Object.keys(manifest));
|
|
1790
2017
|
const registeredUIUris = Array.from(this.resources.keys()).filter((uri) => uri.startsWith("ui://"));
|
|
1791
2018
|
for (const uri of registeredUIUris) {
|
|
@@ -1801,7 +2028,7 @@ var MCPServer = class {
|
|
|
1801
2028
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
1802
2029
|
const isGPTApp = !isString && entry.isGPTApp;
|
|
1803
2030
|
const gptMeta = !isString ? entry.gptMeta : void 0;
|
|
1804
|
-
if (!
|
|
2031
|
+
if (!fs2.existsSync(htmlPath)) {
|
|
1805
2032
|
if (this.logging) {
|
|
1806
2033
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1807
2034
|
}
|
|
@@ -1822,8 +2049,8 @@ var MCPServer = class {
|
|
|
1822
2049
|
mimeType,
|
|
1823
2050
|
inputSchema: void 0,
|
|
1824
2051
|
method: /* @__PURE__ */ __name(async () => {
|
|
1825
|
-
if (
|
|
1826
|
-
const html =
|
|
2052
|
+
if (fs2.existsSync(htmlPath)) {
|
|
2053
|
+
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
1827
2054
|
return {
|
|
1828
2055
|
text: html,
|
|
1829
2056
|
_meta: Object.keys(_meta).length > 0 ? _meta : void 0
|
|
@@ -1852,10 +2079,10 @@ var MCPServer = class {
|
|
|
1852
2079
|
async loadUIManifest() {
|
|
1853
2080
|
try {
|
|
1854
2081
|
const manifestPath = path.join(process.cwd(), "dist", "ui-manifest.json");
|
|
1855
|
-
if (!
|
|
2082
|
+
if (!fs2.existsSync(manifestPath)) {
|
|
1856
2083
|
return;
|
|
1857
2084
|
}
|
|
1858
|
-
const manifest = JSON.parse(
|
|
2085
|
+
const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
|
|
1859
2086
|
for (const [uri, entry] of Object.entries(manifest)) {
|
|
1860
2087
|
const isString = typeof entry === "string";
|
|
1861
2088
|
const htmlPath = isString ? entry : entry.htmlPath;
|
|
@@ -1867,13 +2094,13 @@ var MCPServer = class {
|
|
|
1867
2094
|
}
|
|
1868
2095
|
continue;
|
|
1869
2096
|
}
|
|
1870
|
-
if (!
|
|
2097
|
+
if (!fs2.existsSync(htmlPath)) {
|
|
1871
2098
|
if (this.logging) {
|
|
1872
2099
|
this.logger.warn(`UI HTML file not found: ${htmlPath}`);
|
|
1873
2100
|
}
|
|
1874
2101
|
continue;
|
|
1875
2102
|
}
|
|
1876
|
-
const html =
|
|
2103
|
+
const html = fs2.readFileSync(htmlPath, "utf-8");
|
|
1877
2104
|
const mimeType = isGPTApp ? "text/html+skybridge" : "text/html;profile=mcp-app";
|
|
1878
2105
|
const _meta = {};
|
|
1879
2106
|
if (isGPTApp) {
|
|
@@ -2125,18 +2352,18 @@ var MCPServerRuntime = class {
|
|
|
2125
2352
|
}
|
|
2126
2353
|
async loadServices() {
|
|
2127
2354
|
const absPath = path.resolve(this.options.servicesDir);
|
|
2128
|
-
if (!
|
|
2355
|
+
if (!fs2.existsSync(absPath)) {
|
|
2129
2356
|
this.logger.error(`Services directory not found: ${absPath}`);
|
|
2130
2357
|
return;
|
|
2131
2358
|
}
|
|
2132
|
-
const files =
|
|
2359
|
+
const files = fs2.readdirSync(absPath);
|
|
2133
2360
|
let toolCount = 0;
|
|
2134
2361
|
let promptCount = 0;
|
|
2135
2362
|
let resourceCount = 0;
|
|
2136
2363
|
for (const dir of files) {
|
|
2137
2364
|
const modulePath = path.join(absPath, dir, "index.ts");
|
|
2138
2365
|
const modulePathJs = path.join(absPath, dir, "index.js");
|
|
2139
|
-
const finalPath =
|
|
2366
|
+
const finalPath = fs2.existsSync(modulePath) ? modulePath : fs2.existsSync(modulePathJs) ? modulePathJs : null;
|
|
2140
2367
|
if (finalPath) {
|
|
2141
2368
|
try {
|
|
2142
2369
|
const fileUrl = pathToFileURL(finalPath).href;
|
|
@@ -2271,6 +2498,7 @@ export {
|
|
|
2271
2498
|
UserEnvs,
|
|
2272
2499
|
classToJsonSchema,
|
|
2273
2500
|
classToJsonSchemaWithConstraints,
|
|
2501
|
+
clearTypeCache,
|
|
2274
2502
|
createAuthError,
|
|
2275
2503
|
createHTTPServer,
|
|
2276
2504
|
createProtectedResourceMetadata,
|
|
@@ -2279,6 +2507,8 @@ export {
|
|
|
2279
2507
|
getDecoratedMethods,
|
|
2280
2508
|
getMethodMetadata,
|
|
2281
2509
|
isAuthError,
|
|
2510
|
+
parseClassTypesSync,
|
|
2511
|
+
registerClassSource,
|
|
2282
2512
|
startMCPServer,
|
|
2283
2513
|
validateNonEmpty,
|
|
2284
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",
|
|
@@ -75,4 +76,4 @@
|
|
|
75
76
|
"publishConfig": {
|
|
76
77
|
"access": "public"
|
|
77
78
|
}
|
|
78
|
-
}
|
|
79
|
+
}
|