@vritti/api-sdk 0.4.7 → 0.4.9
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/auth.cjs +70 -4
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +16 -1
- package/dist/auth.d.ts +16 -1
- package/dist/auth.js +70 -4
- package/dist/auth.js.map +1 -1
- package/dist/bad-request.exception-D-KmhiXQ.d.cts +18 -0
- package/dist/bad-request.exception-Db94kZxY.d.ts +18 -0
- package/dist/data-table.cjs +3 -4
- package/dist/data-table.cjs.map +1 -1
- package/dist/data-table.js +3 -4
- package/dist/data-table.js.map +1 -1
- package/dist/database.cjs +11 -2
- package/dist/database.cjs.map +1 -1
- package/dist/database.d.cts +1 -0
- package/dist/database.d.ts +1 -0
- package/dist/database.js +26 -17
- package/dist/database.js.map +1 -1
- package/dist/decimal.d.cts +1 -0
- package/dist/decimal.d.ts +1 -0
- package/dist/exceptions.d.cts +4 -17
- package/dist/exceptions.d.ts +4 -17
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/mcp.cjs +814 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +135 -0
- package/dist/mcp.d.ts +135 -0
- package/dist/mcp.js +771 -0
- package/dist/mcp.js.map +1 -0
- package/dist/root.cjs +1 -0
- package/dist/root.cjs.map +1 -1
- package/dist/root.js +1 -0
- package/dist/root.js.map +1 -1
- package/dist/zod.cjs +25 -0
- package/dist/zod.cjs.map +1 -0
- package/dist/zod.d.cts +1 -0
- package/dist/zod.d.ts +1 -0
- package/dist/zod.js +3 -0
- package/dist/zod.js.map +1 -0
- package/package.json +24 -2
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/mcp/coverage.ts
|
|
5
|
+
import { METHOD_METADATA, MODULE_METADATA } from "@nestjs/common/constants";
|
|
6
|
+
function collectOperationIds(modules) {
|
|
7
|
+
const ids = [];
|
|
8
|
+
for (const module of modules) {
|
|
9
|
+
const controllers = Reflect.getMetadata(MODULE_METADATA.CONTROLLERS, module) ?? [];
|
|
10
|
+
for (const controller of controllers) {
|
|
11
|
+
const prototype = controller.prototype;
|
|
12
|
+
for (const method of Object.getOwnPropertyNames(prototype)) {
|
|
13
|
+
if (method === "constructor") continue;
|
|
14
|
+
const handler = prototype[method];
|
|
15
|
+
if (typeof handler !== "function") continue;
|
|
16
|
+
if (Reflect.getMetadata(METHOD_METADATA, handler) === void 0) continue;
|
|
17
|
+
ids.push(`${controller.name}_${method}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return ids;
|
|
22
|
+
}
|
|
23
|
+
__name(collectOperationIds, "collectOperationIds");
|
|
24
|
+
|
|
25
|
+
// src/mcp/mcp.module.ts
|
|
26
|
+
import { Module } from "@nestjs/common";
|
|
27
|
+
import { DiscoveryModule } from "@nestjs/core";
|
|
28
|
+
|
|
29
|
+
// src/mcp/mcp.options.ts
|
|
30
|
+
var MCP_SERVER_OPTIONS = /* @__PURE__ */ Symbol("MCP_SERVER_OPTIONS");
|
|
31
|
+
|
|
32
|
+
// src/exceptions/bad-gateway.exception.ts
|
|
33
|
+
import { HttpStatus } from "@nestjs/common";
|
|
34
|
+
|
|
35
|
+
// src/exceptions/base-field.exception.ts
|
|
36
|
+
import { HttpException } from "@nestjs/common";
|
|
37
|
+
var HttpProblemException = class extends HttpException {
|
|
38
|
+
static {
|
|
39
|
+
__name(this, "HttpProblemException");
|
|
40
|
+
}
|
|
41
|
+
constructor(detailOrOptions, httpStatus) {
|
|
42
|
+
const options = typeof detailOrOptions === "string" ? {
|
|
43
|
+
detail: detailOrOptions
|
|
44
|
+
} : detailOrOptions;
|
|
45
|
+
super({
|
|
46
|
+
type: options.type ?? "about:blank",
|
|
47
|
+
label: options.label,
|
|
48
|
+
detail: options.detail,
|
|
49
|
+
errors: options.errors ?? []
|
|
50
|
+
}, httpStatus);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/exceptions/bad-request.exception.ts
|
|
55
|
+
import { HttpStatus as HttpStatus2 } from "@nestjs/common";
|
|
56
|
+
var BadRequestException = class extends HttpProblemException {
|
|
57
|
+
static {
|
|
58
|
+
__name(this, "BadRequestException");
|
|
59
|
+
}
|
|
60
|
+
constructor(detailOrOptions) {
|
|
61
|
+
super(detailOrOptions ?? "Bad Request", HttpStatus2.BAD_REQUEST);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/exceptions/conflict.exception.ts
|
|
66
|
+
import { HttpStatus as HttpStatus3 } from "@nestjs/common";
|
|
67
|
+
|
|
68
|
+
// src/exceptions/forbidden.exception.ts
|
|
69
|
+
import { HttpStatus as HttpStatus4 } from "@nestjs/common";
|
|
70
|
+
|
|
71
|
+
// src/exceptions/gone.exception.ts
|
|
72
|
+
import { HttpStatus as HttpStatus5 } from "@nestjs/common";
|
|
73
|
+
|
|
74
|
+
// src/exceptions/internal-server-error.exception.ts
|
|
75
|
+
import { HttpStatus as HttpStatus6 } from "@nestjs/common";
|
|
76
|
+
|
|
77
|
+
// src/exceptions/method-not-allowed.exception.ts
|
|
78
|
+
import { HttpStatus as HttpStatus7 } from "@nestjs/common";
|
|
79
|
+
|
|
80
|
+
// src/exceptions/not-acceptable.exception.ts
|
|
81
|
+
import { HttpStatus as HttpStatus8 } from "@nestjs/common";
|
|
82
|
+
|
|
83
|
+
// src/exceptions/not-found.exception.ts
|
|
84
|
+
import { HttpStatus as HttpStatus9 } from "@nestjs/common";
|
|
85
|
+
|
|
86
|
+
// src/exceptions/not-implemented.exception.ts
|
|
87
|
+
import { HttpStatus as HttpStatus10 } from "@nestjs/common";
|
|
88
|
+
|
|
89
|
+
// src/exceptions/payload-too-large.exception.ts
|
|
90
|
+
import { HttpStatus as HttpStatus11 } from "@nestjs/common";
|
|
91
|
+
|
|
92
|
+
// src/exceptions/request-timeout.exception.ts
|
|
93
|
+
import { HttpStatus as HttpStatus12 } from "@nestjs/common";
|
|
94
|
+
|
|
95
|
+
// src/exceptions/service-unavailable.exception.ts
|
|
96
|
+
import { HttpStatus as HttpStatus13 } from "@nestjs/common";
|
|
97
|
+
|
|
98
|
+
// src/exceptions/too-many-requests.exception.ts
|
|
99
|
+
import { HttpStatus as HttpStatus14 } from "@nestjs/common";
|
|
100
|
+
|
|
101
|
+
// src/exceptions/unauthorized.exception.ts
|
|
102
|
+
import { HttpStatus as HttpStatus15 } from "@nestjs/common";
|
|
103
|
+
var UnauthorizedException = class extends HttpProblemException {
|
|
104
|
+
static {
|
|
105
|
+
__name(this, "UnauthorizedException");
|
|
106
|
+
}
|
|
107
|
+
constructor(detailOrOptions) {
|
|
108
|
+
super(detailOrOptions ?? "Unauthorized", HttpStatus15.UNAUTHORIZED);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/exceptions/unprocessable-entity.exception.ts
|
|
113
|
+
import { HttpStatus as HttpStatus16 } from "@nestjs/common";
|
|
114
|
+
|
|
115
|
+
// src/exceptions/unsupported-media-type.exception.ts
|
|
116
|
+
import { HttpStatus as HttpStatus17 } from "@nestjs/common";
|
|
117
|
+
|
|
118
|
+
// src/exceptions/validation.exception.ts
|
|
119
|
+
import { HttpStatus as HttpStatus18 } from "@nestjs/common";
|
|
120
|
+
|
|
121
|
+
// src/mcp/mcp-principal.ts
|
|
122
|
+
var McpPrincipal = class {
|
|
123
|
+
static {
|
|
124
|
+
__name(this, "McpPrincipal");
|
|
125
|
+
}
|
|
126
|
+
userId;
|
|
127
|
+
scopes;
|
|
128
|
+
clientId;
|
|
129
|
+
grantId;
|
|
130
|
+
organizationId;
|
|
131
|
+
constructor(userId, scopes, clientId, grantId, organizationId) {
|
|
132
|
+
this.userId = userId;
|
|
133
|
+
this.scopes = scopes;
|
|
134
|
+
this.clientId = clientId;
|
|
135
|
+
this.grantId = grantId;
|
|
136
|
+
this.organizationId = organizationId;
|
|
137
|
+
}
|
|
138
|
+
hasScope(scope) {
|
|
139
|
+
return this.scopes.includes(scope);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var MCP_PRINCIPAL_FACTORY = /* @__PURE__ */ Symbol("MCP_PRINCIPAL_FACTORY");
|
|
143
|
+
function principalFromOAuth(request) {
|
|
144
|
+
const auth = request.auth;
|
|
145
|
+
if (!auth || auth.kind !== "oauth" || !auth.userId || !auth.grantId) {
|
|
146
|
+
throw new UnauthorizedException("MCP request is not authenticated.");
|
|
147
|
+
}
|
|
148
|
+
return new McpPrincipal(auth.userId, auth.scopes ?? [], auth.clientId, auth.grantId, auth.organizationId);
|
|
149
|
+
}
|
|
150
|
+
__name(principalFromOAuth, "principalFromOAuth");
|
|
151
|
+
|
|
152
|
+
// src/mcp/mcp-request.handler.ts
|
|
153
|
+
import { Inject as Inject2, Injectable as Injectable4 } from "@nestjs/common";
|
|
154
|
+
|
|
155
|
+
// src/mcp/mcp-server.factory.ts
|
|
156
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
157
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
158
|
+
import { Inject, Injectable as Injectable2 } from "@nestjs/common";
|
|
159
|
+
|
|
160
|
+
// src/mcp/tool-registry.ts
|
|
161
|
+
import { Injectable, Logger as Logger2 } from "@nestjs/common";
|
|
162
|
+
import { DiscoveryService, Reflector } from "@nestjs/core";
|
|
163
|
+
import { z } from "zod";
|
|
164
|
+
|
|
165
|
+
// src/mcp/tool-definition.ts
|
|
166
|
+
import { SetMetadata } from "@nestjs/common";
|
|
167
|
+
var MCP_TOOL_PROVIDER_KEY = "mcp:tool-provider";
|
|
168
|
+
var McpTools = /* @__PURE__ */ __name(() => SetMetadata(MCP_TOOL_PROVIDER_KEY, true), "McpTools");
|
|
169
|
+
function defineTool(definition) {
|
|
170
|
+
return definition;
|
|
171
|
+
}
|
|
172
|
+
__name(defineTool, "defineTool");
|
|
173
|
+
|
|
174
|
+
// src/mcp/tool-result.ts
|
|
175
|
+
import { Logger } from "@nestjs/common";
|
|
176
|
+
import { ZodError } from "zod";
|
|
177
|
+
var PG_UNIQUE_VIOLATION = "23505";
|
|
178
|
+
var logger = new Logger("McpTool");
|
|
179
|
+
function isRecord(value) {
|
|
180
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
181
|
+
}
|
|
182
|
+
__name(isRecord, "isRecord");
|
|
183
|
+
function isHttpExceptionLike(value) {
|
|
184
|
+
return isRecord(value) && typeof value.getStatus === "function" && typeof value.getResponse === "function";
|
|
185
|
+
}
|
|
186
|
+
__name(isHttpExceptionLike, "isHttpExceptionLike");
|
|
187
|
+
function findPgUniqueViolation(error, depth = 0) {
|
|
188
|
+
if (!isRecord(error) || depth > 5) return void 0;
|
|
189
|
+
if (error.code === PG_UNIQUE_VIOLATION) return {
|
|
190
|
+
detail: typeof error.detail === "string" ? error.detail : void 0
|
|
191
|
+
};
|
|
192
|
+
return findPgUniqueViolation(error.cause, depth + 1);
|
|
193
|
+
}
|
|
194
|
+
__name(findPgUniqueViolation, "findPgUniqueViolation");
|
|
195
|
+
function normalizeFieldErrors(value) {
|
|
196
|
+
if (!Array.isArray(value)) return [];
|
|
197
|
+
return value.filter(isRecord).map((entry) => ({
|
|
198
|
+
field: typeof entry.field === "string" ? entry.field : void 0,
|
|
199
|
+
message: typeof entry.message === "string" ? entry.message : "Invalid value"
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
__name(normalizeFieldErrors, "normalizeFieldErrors");
|
|
203
|
+
function toolOk(payload) {
|
|
204
|
+
const structuredContent = isRecord(payload) ? payload : {
|
|
205
|
+
result: payload
|
|
206
|
+
};
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: JSON.stringify(payload)
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
structuredContent
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
__name(toolOk, "toolOk");
|
|
218
|
+
function toolError(problem) {
|
|
219
|
+
return {
|
|
220
|
+
isError: true,
|
|
221
|
+
content: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: JSON.stringify(problem)
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
structuredContent: {
|
|
228
|
+
...problem
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
__name(toolError, "toolError");
|
|
233
|
+
function problemFromError(error) {
|
|
234
|
+
if (error instanceof ZodError) {
|
|
235
|
+
return {
|
|
236
|
+
status: 400,
|
|
237
|
+
label: "Invalid Arguments",
|
|
238
|
+
detail: "The tool arguments did not match the schema.",
|
|
239
|
+
errors: error.issues.map((issue) => ({
|
|
240
|
+
field: issue.path.join("."),
|
|
241
|
+
message: issue.message
|
|
242
|
+
}))
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
if (isHttpExceptionLike(error)) {
|
|
246
|
+
const status = error.getStatus();
|
|
247
|
+
const body = error.getResponse();
|
|
248
|
+
if (isRecord(body)) {
|
|
249
|
+
const detail = typeof body.detail === "string" ? body.detail : typeof body.message === "string" ? body.message : "Request failed.";
|
|
250
|
+
return {
|
|
251
|
+
status,
|
|
252
|
+
label: typeof body.label === "string" ? body.label : void 0,
|
|
253
|
+
detail,
|
|
254
|
+
errors: normalizeFieldErrors(body.errors)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
status,
|
|
259
|
+
detail: typeof body === "string" ? body : "Request failed.",
|
|
260
|
+
errors: []
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const duplicate = findPgUniqueViolation(error);
|
|
264
|
+
if (duplicate) {
|
|
265
|
+
return {
|
|
266
|
+
status: 409,
|
|
267
|
+
label: "Duplicate Entry",
|
|
268
|
+
detail: duplicate.detail ?? "A record with these values already exists.",
|
|
269
|
+
errors: []
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
logger.error(`Unhandled tool error: ${error instanceof Error ? error.stack : String(error)}`);
|
|
273
|
+
return {
|
|
274
|
+
status: 500,
|
|
275
|
+
detail: "An unexpected error occurred.",
|
|
276
|
+
errors: []
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
__name(problemFromError, "problemFromError");
|
|
280
|
+
|
|
281
|
+
// src/mcp/tool-registry.ts
|
|
282
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
283
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
284
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
285
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
286
|
+
} else {
|
|
287
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
288
|
+
if (d = decorators[i]) {
|
|
289
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
294
|
+
}
|
|
295
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
296
|
+
function _ts_metadata(metadataKey, metadataValue) {
|
|
297
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
298
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
302
|
+
var TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
303
|
+
var ToolRegistry = class _ToolRegistry {
|
|
304
|
+
static {
|
|
305
|
+
__name(this, "ToolRegistry");
|
|
306
|
+
}
|
|
307
|
+
discovery;
|
|
308
|
+
reflector;
|
|
309
|
+
logger = new Logger2(_ToolRegistry.name);
|
|
310
|
+
definitions = /* @__PURE__ */ new Map();
|
|
311
|
+
catalog = [];
|
|
312
|
+
constructor(discovery, reflector) {
|
|
313
|
+
this.discovery = discovery;
|
|
314
|
+
this.reflector = reflector;
|
|
315
|
+
}
|
|
316
|
+
// After every module has initialised, so providers from any module are instantiated and discoverable
|
|
317
|
+
onApplicationBootstrap() {
|
|
318
|
+
for (const provider of this.findProviders()) {
|
|
319
|
+
for (const definition of provider.tools()) this.register(definition);
|
|
320
|
+
}
|
|
321
|
+
this.catalog = [
|
|
322
|
+
...this.definitions.values()
|
|
323
|
+
].map((definition) => this.toCatalogEntry(definition));
|
|
324
|
+
this.logger.log(`Registered ${this.catalog.length} MCP tools`);
|
|
325
|
+
}
|
|
326
|
+
listTools() {
|
|
327
|
+
return this.catalog;
|
|
328
|
+
}
|
|
329
|
+
// Every REST operation the tools stand in for — a coverage test compares this with the live route set
|
|
330
|
+
coveredOperationIds() {
|
|
331
|
+
return [
|
|
332
|
+
...this.definitions.values()
|
|
333
|
+
].flatMap((definition) => [
|
|
334
|
+
...definition.covers
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
337
|
+
async execute(name, rawArgs, principal) {
|
|
338
|
+
const started = Date.now();
|
|
339
|
+
const definition = this.definitions.get(name);
|
|
340
|
+
if (!definition) {
|
|
341
|
+
return toolError({
|
|
342
|
+
status: 404,
|
|
343
|
+
label: "Unknown Tool",
|
|
344
|
+
detail: `No tool named "${name}".`,
|
|
345
|
+
errors: []
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
let status = 200;
|
|
349
|
+
let result;
|
|
350
|
+
if (!principal.hasScope(definition.requiredScope)) {
|
|
351
|
+
status = 403;
|
|
352
|
+
result = toolError({
|
|
353
|
+
status,
|
|
354
|
+
label: "Insufficient Scope",
|
|
355
|
+
detail: `Tool "${name}" requires the ${definition.requiredScope} scope. Reconnect the client and grant it.`,
|
|
356
|
+
errors: []
|
|
357
|
+
});
|
|
358
|
+
} else {
|
|
359
|
+
try {
|
|
360
|
+
const args = definition.inputSchema.parse(rawArgs ?? {});
|
|
361
|
+
result = toolOk(await definition.handler(principal, args));
|
|
362
|
+
} catch (error) {
|
|
363
|
+
const problem = problemFromError(error);
|
|
364
|
+
status = problem.status;
|
|
365
|
+
result = toolError(problem);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
this.logger.log(`mcp tool=${name} user=${principal.userId} grant=${principal.grantId ?? "-"} client=${principal.clientId ?? "-"} scope=${definition.requiredScope} ok=${status < 400} status=${status} ms=${Date.now() - started}`);
|
|
369
|
+
return result;
|
|
370
|
+
}
|
|
371
|
+
findProviders() {
|
|
372
|
+
return this.discovery.getProviders().filter((wrapper) => typeof wrapper.metatype === "function" && wrapper.instance).filter((wrapper) => this.reflector.get(MCP_TOOL_PROVIDER_KEY, wrapper.metatype) === true).map((wrapper) => wrapper.instance);
|
|
373
|
+
}
|
|
374
|
+
register(definition) {
|
|
375
|
+
if (!TOOL_NAME_PATTERN.test(definition.name)) {
|
|
376
|
+
throw new Error(`MCP tool name "${definition.name}" is invalid (letters, digits, _ and -, max 64 chars).`);
|
|
377
|
+
}
|
|
378
|
+
if (this.definitions.has(definition.name)) {
|
|
379
|
+
throw new Error(`MCP tool "${definition.name}" is registered twice.`);
|
|
380
|
+
}
|
|
381
|
+
this.definitions.set(definition.name, definition);
|
|
382
|
+
}
|
|
383
|
+
toCatalogEntry(definition) {
|
|
384
|
+
return {
|
|
385
|
+
name: definition.name,
|
|
386
|
+
title: definition.title,
|
|
387
|
+
description: definition.description,
|
|
388
|
+
inputSchema: this.toInputSchema(definition),
|
|
389
|
+
annotations: {
|
|
390
|
+
title: definition.title,
|
|
391
|
+
readOnlyHint: definition.annotations.readOnlyHint,
|
|
392
|
+
destructiveHint: definition.annotations.destructiveHint,
|
|
393
|
+
idempotentHint: definition.annotations.idempotentHint,
|
|
394
|
+
openWorldHint: false
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
// MCP wants a bare JSON Schema object at the root; zod adds a $schema marker the catalog does not need
|
|
399
|
+
toInputSchema(definition) {
|
|
400
|
+
const schema = z.toJSONSchema(definition.inputSchema, {
|
|
401
|
+
io: "input"
|
|
402
|
+
});
|
|
403
|
+
delete schema.$schema;
|
|
404
|
+
if (schema.type !== "object") {
|
|
405
|
+
throw new Error(`MCP tool "${definition.name}" must declare an object input schema.`);
|
|
406
|
+
}
|
|
407
|
+
return schema;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
ToolRegistry = _ts_decorate([
|
|
411
|
+
Injectable(),
|
|
412
|
+
_ts_metadata("design:type", Function),
|
|
413
|
+
_ts_metadata("design:paramtypes", [
|
|
414
|
+
typeof DiscoveryService === "undefined" ? Object : DiscoveryService,
|
|
415
|
+
typeof Reflector === "undefined" ? Object : Reflector
|
|
416
|
+
])
|
|
417
|
+
], ToolRegistry);
|
|
418
|
+
|
|
419
|
+
// src/mcp/mcp-server.factory.ts
|
|
420
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
421
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
422
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
423
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
424
|
+
} else {
|
|
425
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
426
|
+
if (d = decorators[i]) {
|
|
427
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
432
|
+
}
|
|
433
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
434
|
+
function _ts_metadata2(metadataKey, metadataValue) {
|
|
435
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
436
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
440
|
+
function _ts_param(paramIndex, decorator) {
|
|
441
|
+
return function(target, key) {
|
|
442
|
+
decorator(target, key, paramIndex);
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
__name(_ts_param, "_ts_param");
|
|
446
|
+
var McpServerFactory = class {
|
|
447
|
+
static {
|
|
448
|
+
__name(this, "McpServerFactory");
|
|
449
|
+
}
|
|
450
|
+
options;
|
|
451
|
+
toolRegistry;
|
|
452
|
+
constructor(options, toolRegistry) {
|
|
453
|
+
this.options = options;
|
|
454
|
+
this.toolRegistry = toolRegistry;
|
|
455
|
+
}
|
|
456
|
+
create(principal) {
|
|
457
|
+
const server = new Server({
|
|
458
|
+
name: this.options.name,
|
|
459
|
+
version: this.options.version
|
|
460
|
+
}, {
|
|
461
|
+
capabilities: {
|
|
462
|
+
tools: {}
|
|
463
|
+
},
|
|
464
|
+
instructions: this.options.instructions
|
|
465
|
+
});
|
|
466
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
467
|
+
tools: this.toolRegistry.listTools()
|
|
468
|
+
}));
|
|
469
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => this.toolRegistry.execute(request.params.name, request.params.arguments, principal));
|
|
470
|
+
return server;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
McpServerFactory = _ts_decorate2([
|
|
474
|
+
Injectable2(),
|
|
475
|
+
_ts_param(0, Inject(MCP_SERVER_OPTIONS)),
|
|
476
|
+
_ts_metadata2("design:type", Function),
|
|
477
|
+
_ts_metadata2("design:paramtypes", [
|
|
478
|
+
typeof McpServerOptions === "undefined" ? Object : McpServerOptions,
|
|
479
|
+
typeof ToolRegistry === "undefined" ? Object : ToolRegistry
|
|
480
|
+
])
|
|
481
|
+
], McpServerFactory);
|
|
482
|
+
|
|
483
|
+
// src/mcp/mcp-transport.factory.ts
|
|
484
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
485
|
+
import { Injectable as Injectable3 } from "@nestjs/common";
|
|
486
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
487
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
488
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
489
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
490
|
+
} else {
|
|
491
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
492
|
+
if (d = decorators[i]) {
|
|
493
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
498
|
+
}
|
|
499
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
500
|
+
var McpTransportFactory = class {
|
|
501
|
+
static {
|
|
502
|
+
__name(this, "McpTransportFactory");
|
|
503
|
+
}
|
|
504
|
+
create() {
|
|
505
|
+
return new StreamableHTTPServerTransport({
|
|
506
|
+
sessionIdGenerator: void 0,
|
|
507
|
+
enableJsonResponse: true
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
McpTransportFactory = _ts_decorate3([
|
|
512
|
+
Injectable3()
|
|
513
|
+
], McpTransportFactory);
|
|
514
|
+
|
|
515
|
+
// src/mcp/mcp-request.handler.ts
|
|
516
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
517
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
518
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
519
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
520
|
+
} else {
|
|
521
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
522
|
+
if (d = decorators[i]) {
|
|
523
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
528
|
+
}
|
|
529
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
530
|
+
function _ts_metadata3(metadataKey, metadataValue) {
|
|
531
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
532
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
536
|
+
function _ts_param2(paramIndex, decorator) {
|
|
537
|
+
return function(target, key) {
|
|
538
|
+
decorator(target, key, paramIndex);
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
__name(_ts_param2, "_ts_param");
|
|
542
|
+
var McpRequestHandler = class {
|
|
543
|
+
static {
|
|
544
|
+
__name(this, "McpRequestHandler");
|
|
545
|
+
}
|
|
546
|
+
serverFactory;
|
|
547
|
+
transportFactory;
|
|
548
|
+
principalFactory;
|
|
549
|
+
constructor(serverFactory, transportFactory, principalFactory) {
|
|
550
|
+
this.serverFactory = serverFactory;
|
|
551
|
+
this.transportFactory = transportFactory;
|
|
552
|
+
this.principalFactory = principalFactory;
|
|
553
|
+
}
|
|
554
|
+
async handle(request, reply, body) {
|
|
555
|
+
const principal = this.principalFactory(request);
|
|
556
|
+
reply.hijack();
|
|
557
|
+
const transport = this.transportFactory.create();
|
|
558
|
+
const server = this.serverFactory.create(principal);
|
|
559
|
+
reply.raw.on("close", () => {
|
|
560
|
+
void transport.close();
|
|
561
|
+
void server.close();
|
|
562
|
+
});
|
|
563
|
+
await server.connect(transport);
|
|
564
|
+
await transport.handleRequest(request.raw, reply.raw, body);
|
|
565
|
+
}
|
|
566
|
+
// The JSON-RPC answer for verbs a stateless server does not serve (GET streams, DELETE session teardown)
|
|
567
|
+
methodNotAllowed(reply) {
|
|
568
|
+
reply.status(405).header("Allow", "POST").send({
|
|
569
|
+
jsonrpc: "2.0",
|
|
570
|
+
error: {
|
|
571
|
+
code: -32e3,
|
|
572
|
+
message: "Method not allowed."
|
|
573
|
+
},
|
|
574
|
+
id: null
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
McpRequestHandler = _ts_decorate4([
|
|
579
|
+
Injectable4(),
|
|
580
|
+
_ts_param2(2, Inject2(MCP_PRINCIPAL_FACTORY)),
|
|
581
|
+
_ts_metadata3("design:type", Function),
|
|
582
|
+
_ts_metadata3("design:paramtypes", [
|
|
583
|
+
typeof McpServerFactory === "undefined" ? Object : McpServerFactory,
|
|
584
|
+
typeof McpTransportFactory === "undefined" ? Object : McpTransportFactory,
|
|
585
|
+
typeof McpPrincipalFactory === "undefined" ? Object : McpPrincipalFactory
|
|
586
|
+
])
|
|
587
|
+
], McpRequestHandler);
|
|
588
|
+
|
|
589
|
+
// src/mcp/mcp-schema-registry.ts
|
|
590
|
+
import { Injectable as Injectable5 } from "@nestjs/common";
|
|
591
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
592
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
593
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
594
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
595
|
+
} else {
|
|
596
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
597
|
+
if (d = decorators[i]) {
|
|
598
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
603
|
+
}
|
|
604
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
605
|
+
var COMPONENT_REF = "#/components/schemas/";
|
|
606
|
+
var McpSchemaRegistry = class {
|
|
607
|
+
static {
|
|
608
|
+
__name(this, "McpSchemaRegistry");
|
|
609
|
+
}
|
|
610
|
+
schemas = {};
|
|
611
|
+
setDocument(document) {
|
|
612
|
+
this.schemas = document.components?.schemas ?? {};
|
|
613
|
+
}
|
|
614
|
+
// The schema for a DTO class, with its component references inlined as local $defs
|
|
615
|
+
schemaFor(dto) {
|
|
616
|
+
const root = this.schemas[dto.name];
|
|
617
|
+
if (!root) return {
|
|
618
|
+
type: "object",
|
|
619
|
+
description: `The schema for ${dto.name} is unavailable.`
|
|
620
|
+
};
|
|
621
|
+
const defs = {};
|
|
622
|
+
const rewritten = this.rewrite(root, defs);
|
|
623
|
+
return Object.keys(defs).length > 0 ? {
|
|
624
|
+
...rewritten,
|
|
625
|
+
$defs: defs
|
|
626
|
+
} : rewritten;
|
|
627
|
+
}
|
|
628
|
+
rewrite(node, defs) {
|
|
629
|
+
if (Array.isArray(node)) return node.map((item) => this.rewrite(item, defs));
|
|
630
|
+
if (typeof node !== "object" || node === null) return node;
|
|
631
|
+
const record = node;
|
|
632
|
+
if (typeof record.$ref === "string" && record.$ref.startsWith(COMPONENT_REF)) {
|
|
633
|
+
const name = record.$ref.slice(COMPONENT_REF.length);
|
|
634
|
+
if (!(name in defs)) {
|
|
635
|
+
defs[name] = {};
|
|
636
|
+
defs[name] = this.rewrite(this.schemas[name] ?? {}, defs);
|
|
637
|
+
}
|
|
638
|
+
return {
|
|
639
|
+
$ref: `#/$defs/${name}`
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
const out = {};
|
|
643
|
+
for (const [key, value] of Object.entries(record)) out[key] = this.rewrite(value, defs);
|
|
644
|
+
return out;
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
McpSchemaRegistry = _ts_decorate5([
|
|
648
|
+
Injectable5()
|
|
649
|
+
], McpSchemaRegistry);
|
|
650
|
+
|
|
651
|
+
// src/mcp/mcp.module.ts
|
|
652
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
653
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
654
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
655
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
656
|
+
} else {
|
|
657
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
658
|
+
if (d = decorators[i]) {
|
|
659
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
664
|
+
}
|
|
665
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
666
|
+
var McpModule = class _McpModule {
|
|
667
|
+
static {
|
|
668
|
+
__name(this, "McpModule");
|
|
669
|
+
}
|
|
670
|
+
static forRoot(options) {
|
|
671
|
+
const serverOptions = {
|
|
672
|
+
name: options.name,
|
|
673
|
+
version: options.version,
|
|
674
|
+
instructions: options.instructions
|
|
675
|
+
};
|
|
676
|
+
return {
|
|
677
|
+
module: _McpModule,
|
|
678
|
+
imports: [
|
|
679
|
+
DiscoveryModule
|
|
680
|
+
],
|
|
681
|
+
providers: [
|
|
682
|
+
{
|
|
683
|
+
provide: MCP_SERVER_OPTIONS,
|
|
684
|
+
useValue: serverOptions
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
provide: MCP_PRINCIPAL_FACTORY,
|
|
688
|
+
useValue: options.principal ?? principalFromOAuth
|
|
689
|
+
},
|
|
690
|
+
McpTransportFactory,
|
|
691
|
+
McpServerFactory,
|
|
692
|
+
McpRequestHandler,
|
|
693
|
+
McpSchemaRegistry,
|
|
694
|
+
ToolRegistry
|
|
695
|
+
],
|
|
696
|
+
exports: [
|
|
697
|
+
McpRequestHandler,
|
|
698
|
+
McpSchemaRegistry,
|
|
699
|
+
ToolRegistry
|
|
700
|
+
]
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
McpModule = _ts_decorate6([
|
|
705
|
+
Module({})
|
|
706
|
+
], McpModule);
|
|
707
|
+
|
|
708
|
+
// src/mcp/validate-dto.ts
|
|
709
|
+
import { plainToInstance } from "class-transformer";
|
|
710
|
+
import { validate } from "class-validator";
|
|
711
|
+
var McpValidationError = class extends BadRequestException {
|
|
712
|
+
static {
|
|
713
|
+
__name(this, "McpValidationError");
|
|
714
|
+
}
|
|
715
|
+
constructor(errors) {
|
|
716
|
+
super({
|
|
717
|
+
label: "Validation Failed",
|
|
718
|
+
detail: "Please check your input and try again.",
|
|
719
|
+
errors
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
function flattenValidationErrors(errors, parent = "") {
|
|
724
|
+
return errors.flatMap((error) => {
|
|
725
|
+
const field = parent ? `${parent}.${error.property}` : error.property;
|
|
726
|
+
const own = Object.values(error.constraints ?? {}).map((message) => ({
|
|
727
|
+
field,
|
|
728
|
+
message
|
|
729
|
+
}));
|
|
730
|
+
const nested = error.children?.length ? flattenValidationErrors(error.children, field) : [];
|
|
731
|
+
return [
|
|
732
|
+
...own,
|
|
733
|
+
...nested
|
|
734
|
+
];
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
__name(flattenValidationErrors, "flattenValidationErrors");
|
|
738
|
+
async function validateDto(cls, input) {
|
|
739
|
+
const instance = plainToInstance(cls, input ?? {}, {
|
|
740
|
+
enableImplicitConversion: true
|
|
741
|
+
});
|
|
742
|
+
const errors = await validate(instance, {
|
|
743
|
+
whitelist: true,
|
|
744
|
+
forbidNonWhitelisted: true
|
|
745
|
+
});
|
|
746
|
+
if (errors.length > 0) throw new McpValidationError(flattenValidationErrors(errors));
|
|
747
|
+
return instance;
|
|
748
|
+
}
|
|
749
|
+
__name(validateDto, "validateDto");
|
|
750
|
+
export {
|
|
751
|
+
MCP_PRINCIPAL_FACTORY,
|
|
752
|
+
MCP_SERVER_OPTIONS,
|
|
753
|
+
MCP_TOOL_PROVIDER_KEY,
|
|
754
|
+
McpModule,
|
|
755
|
+
McpPrincipal,
|
|
756
|
+
McpRequestHandler,
|
|
757
|
+
McpSchemaRegistry,
|
|
758
|
+
McpServerFactory,
|
|
759
|
+
McpTools,
|
|
760
|
+
McpTransportFactory,
|
|
761
|
+
McpValidationError,
|
|
762
|
+
ToolRegistry,
|
|
763
|
+
collectOperationIds,
|
|
764
|
+
defineTool,
|
|
765
|
+
principalFromOAuth,
|
|
766
|
+
problemFromError,
|
|
767
|
+
toolError,
|
|
768
|
+
toolOk,
|
|
769
|
+
validateDto
|
|
770
|
+
};
|
|
771
|
+
//# sourceMappingURL=mcp.js.map
|