@nestia/core 11.2.1 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/lib/adaptors/McpAdaptor.d.ts +75 -0
  2. package/lib/adaptors/McpAdaptor.js +256 -0
  3. package/lib/adaptors/McpAdaptor.js.map +1 -0
  4. package/lib/decorators/McpRoute.d.ts +73 -0
  5. package/lib/decorators/McpRoute.js +60 -0
  6. package/lib/decorators/McpRoute.js.map +1 -0
  7. package/lib/decorators/internal/IMcpRouteReflect.d.ts +2 -0
  8. package/lib/decorators/internal/IMcpRouteReflect.js +3 -0
  9. package/lib/decorators/internal/IMcpRouteReflect.js.map +1 -0
  10. package/lib/module.d.ts +2 -0
  11. package/lib/module.js +2 -0
  12. package/lib/module.js.map +1 -1
  13. package/lib/programmers/McpRouteProgrammer.d.ts +26 -0
  14. package/lib/programmers/McpRouteProgrammer.js +56 -0
  15. package/lib/programmers/McpRouteProgrammer.js.map +1 -0
  16. package/lib/programmers/McpRouteReturnProgrammer.d.ts +24 -0
  17. package/lib/programmers/McpRouteReturnProgrammer.js +63 -0
  18. package/lib/programmers/McpRouteReturnProgrammer.js.map +1 -0
  19. package/lib/programmers/internal/check_mcp_object.d.ts +1 -0
  20. package/lib/programmers/internal/check_mcp_object.js +28 -0
  21. package/lib/programmers/internal/check_mcp_object.js.map +1 -0
  22. package/lib/transformers/McpRouteTransformer.d.ts +33 -0
  23. package/lib/transformers/McpRouteTransformer.js +182 -0
  24. package/lib/transformers/McpRouteTransformer.js.map +1 -0
  25. package/lib/transformers/MethodTransformer.js +6 -0
  26. package/lib/transformers/MethodTransformer.js.map +1 -1
  27. package/lib/transformers/ParameterDecoratorTransformer.js +3 -0
  28. package/lib/transformers/ParameterDecoratorTransformer.js.map +1 -1
  29. package/package.json +4 -3
  30. package/src/adaptors/McpAdaptor.ts +276 -0
  31. package/src/decorators/McpRoute.ts +159 -0
  32. package/src/decorators/internal/IMcpRouteReflect.ts +41 -0
  33. package/src/module.ts +2 -0
  34. package/src/programmers/McpRouteProgrammer.ts +75 -0
  35. package/src/programmers/McpRouteReturnProgrammer.ts +77 -0
  36. package/src/programmers/internal/check_mcp_object.ts +37 -0
  37. package/src/transformers/McpRouteTransformer.ts +271 -0
  38. package/src/transformers/MethodTransformer.ts +6 -0
  39. package/src/transformers/ParameterDecoratorTransformer.ts +5 -0
@@ -0,0 +1,75 @@
1
+ import { INestApplication } from "@nestjs/common";
2
+ /**
3
+ * MCP (Model Context Protocol) adaptor.
4
+ *
5
+ * `McpAdaptor` exposes every method decorated with {@link McpRoute} as an MCP
6
+ * tool, reachable by LLM clients through a stateless Streamable HTTP endpoint.
7
+ *
8
+ * At bootstrap the adaptor walks the {@link NestContainer}, collects every
9
+ * controller method carrying `"nestia/McpRoute"` metadata, and caches a tool
10
+ * registry. A fresh MCP server and transport pair is spun up per incoming HTTP
11
+ * request, following MCP stateless Streamable HTTP mode. This adaptor
12
+ * intentionally does not manage `Mcp-Session-Id` state.
13
+ *
14
+ * Typia-generated JSON Schemas flow through unchanged; the Zod-based high-level
15
+ * registration API of `McpServer` is bypassed by accessing the low-level
16
+ * `.server` handler.
17
+ *
18
+ * Error mapping follows the MCP specification:
19
+ *
20
+ * - Unknown tool name: JSON-RPC `-32601`.
21
+ * - Typia validation failure: JSON-RPC `-32602` with structured diagnostics.
22
+ * - Handler throws {@link HttpException}: success response with `isError: true`,
23
+ * so the LLM can read the message and recover.
24
+ * - Any other throw: JSON-RPC `-32603`.
25
+ *
26
+ * @author wildduck - https://github.com/wildduck2
27
+ * @example
28
+ * ```typescript
29
+ * import core from "@nestia/core";
30
+ * import { NestFactory } from "@nestjs/core";
31
+ *
32
+ * const app = await NestFactory.create(AppModule);
33
+ * await core.McpAdaptor.upgrade(app, { path: "/mcp" });
34
+ * await app.listen(3000);
35
+ * ```;
36
+ */
37
+ export declare class McpAdaptor {
38
+ /**
39
+ * Upgrade a running Nest application with a stateless MCP endpoint.
40
+ *
41
+ * Scans the application container for methods decorated with {@link McpRoute},
42
+ * then registers a catch-all HTTP route at the configured path. Each incoming
43
+ * request builds a fresh MCP server + transport on demand, wires the
44
+ * registered tools into it, and delegates handling.
45
+ *
46
+ * Must be called after `NestFactory.create(...)` but before `app.listen(...)`
47
+ * if you want the MCP endpoint to be reachable alongside your regular HTTP
48
+ * routes.
49
+ *
50
+ * @param app Running Nest application instance.
51
+ * @param options Transport and identity overrides.
52
+ */
53
+ static upgrade(app: INestApplication, options?: McpAdaptor.IOptions): Promise<void>;
54
+ }
55
+ export declare namespace McpAdaptor {
56
+ /** Configuration options for {@link McpAdaptor.upgrade}. */
57
+ interface IOptions {
58
+ /**
59
+ * HTTP path where the MCP endpoint will be mounted.
60
+ *
61
+ * @default "/mcp"
62
+ */
63
+ path?: string;
64
+ /**
65
+ * Identity advertised to MCP clients during the initialize handshake. Shows
66
+ * up in Claude Desktop / Cursor's MCP panel.
67
+ *
68
+ * @default { name: "nestia-mcp", version: "1.0.0" }
69
+ */
70
+ serverInfo?: {
71
+ name: string;
72
+ version: string;
73
+ };
74
+ }
75
+ }
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.McpAdaptor = void 0;
46
+ const common_1 = require("@nestjs/common");
47
+ /**
48
+ * MCP (Model Context Protocol) adaptor.
49
+ *
50
+ * `McpAdaptor` exposes every method decorated with {@link McpRoute} as an MCP
51
+ * tool, reachable by LLM clients through a stateless Streamable HTTP endpoint.
52
+ *
53
+ * At bootstrap the adaptor walks the {@link NestContainer}, collects every
54
+ * controller method carrying `"nestia/McpRoute"` metadata, and caches a tool
55
+ * registry. A fresh MCP server and transport pair is spun up per incoming HTTP
56
+ * request, following MCP stateless Streamable HTTP mode. This adaptor
57
+ * intentionally does not manage `Mcp-Session-Id` state.
58
+ *
59
+ * Typia-generated JSON Schemas flow through unchanged; the Zod-based high-level
60
+ * registration API of `McpServer` is bypassed by accessing the low-level
61
+ * `.server` handler.
62
+ *
63
+ * Error mapping follows the MCP specification:
64
+ *
65
+ * - Unknown tool name: JSON-RPC `-32601`.
66
+ * - Typia validation failure: JSON-RPC `-32602` with structured diagnostics.
67
+ * - Handler throws {@link HttpException}: success response with `isError: true`,
68
+ * so the LLM can read the message and recover.
69
+ * - Any other throw: JSON-RPC `-32603`.
70
+ *
71
+ * @author wildduck - https://github.com/wildduck2
72
+ * @example
73
+ * ```typescript
74
+ * import core from "@nestia/core";
75
+ * import { NestFactory } from "@nestjs/core";
76
+ *
77
+ * const app = await NestFactory.create(AppModule);
78
+ * await core.McpAdaptor.upgrade(app, { path: "/mcp" });
79
+ * await app.listen(3000);
80
+ * ```;
81
+ */
82
+ class McpAdaptor {
83
+ /**
84
+ * Upgrade a running Nest application with a stateless MCP endpoint.
85
+ *
86
+ * Scans the application container for methods decorated with {@link McpRoute},
87
+ * then registers a catch-all HTTP route at the configured path. Each incoming
88
+ * request builds a fresh MCP server + transport on demand, wires the
89
+ * registered tools into it, and delegates handling.
90
+ *
91
+ * Must be called after `NestFactory.create(...)` but before `app.listen(...)`
92
+ * if you want the MCP endpoint to be reachable alongside your regular HTTP
93
+ * routes.
94
+ *
95
+ * @param app Running Nest application instance.
96
+ * @param options Transport and identity overrides.
97
+ */
98
+ static upgrade(app_1) {
99
+ return __awaiter(this, arguments, void 0, function* (app, options = {}) {
100
+ var _a, _b, _c, _d, _e, _f, _g, _h;
101
+ if ("sessioned" in options)
102
+ throw new Error("McpAdaptor.upgrade() supports stateless Streamable HTTP only; sessioned mode is not implemented.");
103
+ const tools = [];
104
+ const container = app.container;
105
+ for (const module of container.getModules().values()) {
106
+ for (const wrapper of module.controllers.values()) {
107
+ const instance = wrapper.instance;
108
+ if (!instance)
109
+ continue;
110
+ const proto = Object.getPrototypeOf(instance);
111
+ for (const key of Object.getOwnPropertyNames(proto)) {
112
+ if (key === "constructor")
113
+ continue;
114
+ const method = proto[key];
115
+ if (typeof method !== "function")
116
+ continue;
117
+ const meta = Reflect.getMetadata("nestia/McpRoute", method);
118
+ if (!meta)
119
+ continue;
120
+ const params = (_a = Reflect.getMetadata("nestia/McpRoute/Parameters", proto, key)) !== null && _a !== void 0 ? _a : [];
121
+ const paramValidator = (_b = params.find((p) => p.category === "params")) === null || _b === void 0 ? void 0 : _b.validate;
122
+ tools.push({
123
+ meta,
124
+ source: `${(_f = (_d = (_c = wrapper.metatype) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : (_e = proto.constructor) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : "UnknownController"}.${String(key)}`,
125
+ validateArgs: paramValidator,
126
+ handler: (args) => __awaiter(this, void 0, void 0, function* () { return method.call(instance, args); }),
127
+ });
128
+ }
129
+ }
130
+ }
131
+ assertUniqueTools(tools);
132
+ const serverInfo = (_g = options.serverInfo) !== null && _g !== void 0 ? _g : {
133
+ name: "nestia-mcp",
134
+ version: "1.0.0",
135
+ };
136
+ const { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, McpServer, StreamableHTTPServerTransport, } = yield loadMcpSdk();
137
+ const http = app.getHttpAdapter();
138
+ const route = (_h = options.path) !== null && _h !== void 0 ? _h : "/mcp";
139
+ http.all(route, (req, res) => __awaiter(this, void 0, void 0, function* () {
140
+ var _a, _b;
141
+ // Stateless mode requires a fresh transport per request; sharing one
142
+ // across clients races on internal initialization and request IDs.
143
+ const mcp = new McpServer(serverInfo, {
144
+ capabilities: { tools: {} },
145
+ });
146
+ const server = mcp.server;
147
+ server.setRequestHandler(ListToolsRequestSchema, () => __awaiter(this, void 0, void 0, function* () {
148
+ return ({
149
+ tools: tools.map((t) => ({
150
+ name: t.meta.name,
151
+ title: t.meta.title,
152
+ description: t.meta.description,
153
+ inputSchema: t.meta.inputSchema,
154
+ outputSchema: t.meta.outputSchema,
155
+ annotations: t.meta.annotations,
156
+ })),
157
+ });
158
+ }));
159
+ server.setRequestHandler(CallToolRequestSchema, (reqMsg) => __awaiter(this, void 0, void 0, function* () {
160
+ var _a;
161
+ const tool = tools.find((t) => t.meta.name === reqMsg.params.name);
162
+ if (!tool)
163
+ throw new McpError(ErrorCode.MethodNotFound, `Tool not found: ${reqMsg.params.name}`);
164
+ const args = (_a = reqMsg.params.arguments) !== null && _a !== void 0 ? _a : {};
165
+ if (tool.validateArgs) {
166
+ const err = tool.validateArgs(args);
167
+ if (err !== null) {
168
+ const body = err instanceof common_1.BadRequestException
169
+ ? err.getResponse()
170
+ : undefined;
171
+ throw new McpError(ErrorCode.InvalidParams, err.message, {
172
+ errors: body === null || body === void 0 ? void 0 : body.errors,
173
+ path: body === null || body === void 0 ? void 0 : body.path,
174
+ expected: body === null || body === void 0 ? void 0 : body.expected,
175
+ value: body === null || body === void 0 ? void 0 : body.value,
176
+ reason: body === null || body === void 0 ? void 0 : body.reason,
177
+ });
178
+ }
179
+ }
180
+ try {
181
+ const result = yield tool.handler(args);
182
+ if (result === undefined)
183
+ return { content: [] };
184
+ return {
185
+ content: [
186
+ {
187
+ type: "text",
188
+ text: typeof result === "string" ? result : JSON.stringify(result),
189
+ },
190
+ ],
191
+ };
192
+ }
193
+ catch (e) {
194
+ if (e instanceof common_1.HttpException) {
195
+ return {
196
+ content: [{ type: "text", text: e.message }],
197
+ isError: true,
198
+ };
199
+ }
200
+ throw new McpError(ErrorCode.InternalError, e instanceof Error ? e.message : "Internal error");
201
+ }
202
+ }));
203
+ const transport = new StreamableHTTPServerTransport({
204
+ sessionIdGenerator: undefined,
205
+ enableJsonResponse: true,
206
+ });
207
+ try {
208
+ yield mcp.connect(transport);
209
+ yield transport.handleRequest((_a = req.raw) !== null && _a !== void 0 ? _a : req, (_b = res.raw) !== null && _b !== void 0 ? _b : res, req.body);
210
+ }
211
+ finally {
212
+ yield transport.close().catch(() => { });
213
+ yield mcp.close().catch(() => { });
214
+ }
215
+ }));
216
+ });
217
+ }
218
+ }
219
+ exports.McpAdaptor = McpAdaptor;
220
+ const assertUniqueTools = (tools) => {
221
+ var _a;
222
+ const dict = new Map();
223
+ for (const tool of tools) {
224
+ const array = (_a = dict.get(tool.meta.name)) !== null && _a !== void 0 ? _a : [];
225
+ array.push(tool);
226
+ dict.set(tool.meta.name, array);
227
+ }
228
+ const duplicated = Array.from(dict.entries()).filter(([, list]) => list.length > 1);
229
+ if (duplicated.length === 0)
230
+ return;
231
+ throw new Error([
232
+ "Duplicated MCP tool names are not allowed.",
233
+ ...duplicated.map(([name, list]) => ` - ${JSON.stringify(name)}: ${list.map((tool) => tool.source).join(", ")}`),
234
+ ].join("\n"));
235
+ };
236
+ const loadMcpSdk = () => __awaiter(void 0, void 0, void 0, function* () {
237
+ try {
238
+ const [server, transport, types] = yield Promise.all([
239
+ Promise.resolve().then(() => __importStar(require("@modelcontextprotocol/sdk/server/mcp.js"))),
240
+ Promise.resolve().then(() => __importStar(require("@modelcontextprotocol/sdk/server/streamableHttp.js"))),
241
+ Promise.resolve().then(() => __importStar(require("@modelcontextprotocol/sdk/types.js"))),
242
+ ]);
243
+ return {
244
+ McpServer: server.McpServer,
245
+ StreamableHTTPServerTransport: transport.StreamableHTTPServerTransport,
246
+ CallToolRequestSchema: types.CallToolRequestSchema,
247
+ ErrorCode: types.ErrorCode,
248
+ ListToolsRequestSchema: types.ListToolsRequestSchema,
249
+ McpError: types.McpError,
250
+ };
251
+ }
252
+ catch (_a) {
253
+ throw new Error("McpAdaptor.upgrade() requires @modelcontextprotocol/sdk. Install it before enabling MCP routes.");
254
+ }
255
+ });
256
+ //# sourceMappingURL=McpAdaptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpAdaptor.js","sourceRoot":"","sources":["../../src/adaptors/McpAdaptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { IRequestBodyValidator } from "../options/IRequestBodyValidator";
2
+ /**
3
+ * MCP (Model Context Protocol) route decorator.
4
+ *
5
+ * `@McpRoute()` marks a controller method as a callable MCP tool. When the
6
+ * application bootstraps, every method annotated with this decorator is
7
+ * registered on the MCP server built by {@link McpAdaptor.upgrade}, making it
8
+ * reachable by LLM clients (Claude Desktop, Cursor, OpenAI function calling,
9
+ * etc.) through the standard Streamable HTTP transport.
10
+ *
11
+ * The public form takes only the tool's `name` (string). Human-readable
12
+ * `description` and `title` are read from the method's JSDoc:
13
+ *
14
+ * - `description`: the JSDoc comment body.
15
+ * - `title`: the value of an optional `@title` JSDoc tag.
16
+ *
17
+ * For type-safe tool inputs, decorate exactly one parameter of the method with
18
+ * {@link McpRoute.Params}. The parameter type `T` is analyzed at compile time by
19
+ * the nestia transformer, which generates both a runtime validator (powered by
20
+ * typia) and the JSON Schema attached to `inputSchema` in `tools/list`
21
+ * responses.
22
+ *
23
+ * For the MCP endpoint to actually be served, you must call
24
+ * {@link McpAdaptor.upgrade} on the {@link INestApplication} instance at
25
+ * bootstrap. The decorator alone only stores reflection metadata.
26
+ *
27
+ * @author wildduck - https://github.com/wildduck2
28
+ * @example
29
+ * ```typescript
30
+ * import core from "@nestia/core";
31
+ *
32
+ * @Controller()
33
+ * export class WeatherController {
34
+ * /**
35
+ * * Return current weather for a city.
36
+ * *
37
+ * * @title Get weather
38
+ * *\/
39
+ * @core.McpRoute("get_weather")
40
+ * public async get(
41
+ * @core.McpRoute.Params() params: { city: string },
42
+ * ): Promise<{ temp: number }> {
43
+ * return { temp: 22 };
44
+ * }
45
+ * }
46
+ * ```;
47
+ *
48
+ * @param name Unique tool identifier exposed to MCP clients via `tools/list`.
49
+ * @returns Method decorator.
50
+ */
51
+ export declare function McpRoute(name: string): MethodDecorator;
52
+ export declare namespace McpRoute {
53
+ /**
54
+ * Parameter decorator for an MCP tool's input arguments.
55
+ *
56
+ * `@McpRoute.Params<T>()` validates the `arguments` object from a
57
+ * `tools/call` request against the TypeScript type `T` using typia. A failed
58
+ * validation surfaces to the client as a JSON-RPC `-32602` (`InvalidParams`)
59
+ * error with structured diagnostics, giving the LLM precise feedback to
60
+ * self-correct.
61
+ *
62
+ * MCP tools accept exactly one arguments object; applying this decorator more
63
+ * than once on a single method is a compile-time error. The decorated type
64
+ * `T` must be an object type without dynamic properties (no `Record<string,
65
+ * X>`, no index signatures); the nestia transformer enforces this through
66
+ * `LlmSchemaProgrammer.validate`.
67
+ *
68
+ * @author wildduck - https://github.com/wildduck2
69
+ * @param validator Optional custom validator. Default is `typia.assert()`.
70
+ * @returns Parameter decorator.
71
+ */
72
+ function Params<T>(validator?: IRequestBodyValidator<T>): ParameterDecorator;
73
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpRoute = McpRoute;
4
+ const validate_request_body_1 = require("./internal/validate_request_body");
5
+ function McpRoute(input) {
6
+ const config = typeof input === "string" ? { name: input } : input;
7
+ return function McpRoute(_target, _propertyKey, descriptor) {
8
+ var _a;
9
+ Reflect.defineMetadata("nestia/McpRoute", {
10
+ name: config.name,
11
+ title: config.title,
12
+ description: config.description,
13
+ inputSchema: (_a = config.inputSchema) !== null && _a !== void 0 ? _a : { type: "object", properties: {} },
14
+ outputSchema: config.outputSchema,
15
+ annotations: config.annotations,
16
+ }, descriptor.value);
17
+ return descriptor;
18
+ };
19
+ }
20
+ (function (McpRoute) {
21
+ /**
22
+ * Parameter decorator for an MCP tool's input arguments.
23
+ *
24
+ * `@McpRoute.Params<T>()` validates the `arguments` object from a
25
+ * `tools/call` request against the TypeScript type `T` using typia. A failed
26
+ * validation surfaces to the client as a JSON-RPC `-32602` (`InvalidParams`)
27
+ * error with structured diagnostics, giving the LLM precise feedback to
28
+ * self-correct.
29
+ *
30
+ * MCP tools accept exactly one arguments object; applying this decorator more
31
+ * than once on a single method is a compile-time error. The decorated type
32
+ * `T` must be an object type without dynamic properties (no `Record<string,
33
+ * X>`, no index signatures); the nestia transformer enforces this through
34
+ * `LlmSchemaProgrammer.validate`.
35
+ *
36
+ * @author wildduck - https://github.com/wildduck2
37
+ * @param validator Optional custom validator. Default is `typia.assert()`.
38
+ * @returns Parameter decorator.
39
+ */
40
+ function Params(validator) {
41
+ const validate = (0, validate_request_body_1.validate_request_body)("McpRoute.Params")(validator);
42
+ return function McpRouteParams(target, propertyKey, parameterIndex) {
43
+ emplace(target, propertyKey !== null && propertyKey !== void 0 ? propertyKey : "", {
44
+ category: "params",
45
+ index: parameterIndex,
46
+ validate,
47
+ });
48
+ };
49
+ }
50
+ McpRoute.Params = Params;
51
+ /** @internal */
52
+ const emplace = (target, propertyKey, value) => {
53
+ const array = Reflect.getMetadata("nestia/McpRoute/Parameters", target, propertyKey);
54
+ if (array !== undefined)
55
+ array.push(value);
56
+ else
57
+ Reflect.defineMetadata("nestia/McpRoute/Parameters", [value], target, propertyKey);
58
+ };
59
+ })(McpRoute || (exports.McpRoute = McpRoute = {}));
60
+ //# sourceMappingURL=McpRoute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpRoute.js","sourceRoot":"","sources":["../../src/decorators/McpRoute.ts"],"names":[],"mappings":";;AA0DA,4BAsBC;AA9ED,4EAAyE;AAwDzE,SAAgB,QAAQ,CAAC,KAAgC;IACvD,MAAM,MAAM,GACV,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IACtD,OAAO,SAAS,QAAQ,CACtB,OAAe,EACf,YAA6B,EAC7B,UAAwC;;QAExC,OAAO,CAAC,cAAc,CACpB,iBAAiB,EACjB;YACE,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAA,MAAM,CAAC,WAAW,mCAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;YACrE,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,WAAW,EAAE,MAAM,CAAC,WAAW;SACL,EAC5B,UAAU,CAAC,KAAK,CACjB,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED,WAAiB,QAAQ;IAoBvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAgB,MAAM,CACpB,SAAoC;QAEpC,MAAM,QAAQ,GAAG,IAAA,6CAAqB,EAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC;QACrE,OAAO,SAAS,cAAc,CAC5B,MAAc,EACd,WAAwC,EACxC,cAAsB;YAEtB,OAAO,CAAC,MAAM,EAAE,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,EAAE,EAAE;gBACjC,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,cAAc;gBACrB,QAAQ;aACT,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAfe,eAAM,SAerB,CAAA;IAED,gBAAgB;IAChB,MAAM,OAAO,GAAG,CACd,MAAc,EACd,WAA4B,EAC5B,KAAiC,EACjC,EAAE;QACF,MAAM,KAAK,GAA6C,OAAO,CAAC,WAAW,CACzE,4BAA4B,EAC5B,MAAM,EACN,WAAW,CACZ,CAAC;QACF,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YAEzC,OAAO,CAAC,cAAc,CACpB,4BAA4B,EAC5B,CAAC,KAAK,CAAC,EACP,MAAM,EACN,WAAW,CACZ,CAAC;IACN,CAAC,CAAC;AACJ,CAAC,EA5EgB,QAAQ,wBAAR,QAAQ,QA4ExB"}
@@ -0,0 +1,2 @@
1
+ export declare namespace IMcpRouteReflect {
2
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IMcpRouteReflect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMcpRouteReflect.js","sourceRoot":"","sources":["../../../src/decorators/internal/IMcpRouteReflect.ts"],"names":[],"mappings":""}
package/lib/module.d.ts CHANGED
@@ -17,4 +17,6 @@ export * from "./decorators/SwaggerCustomizer";
17
17
  export * from "./decorators/SwaggerExample";
18
18
  export * from "./adaptors/WebSocketAdaptor";
19
19
  export * from "./decorators/WebSocketRoute";
20
+ export * from "./adaptors/McpAdaptor";
21
+ export * from "./decorators/McpRoute";
20
22
  export * from "./decorators/doNotThrowTransformError";
package/lib/module.js CHANGED
@@ -33,5 +33,7 @@ __exportStar(require("./decorators/SwaggerCustomizer"), exports);
33
33
  __exportStar(require("./decorators/SwaggerExample"), exports);
34
34
  __exportStar(require("./adaptors/WebSocketAdaptor"), exports);
35
35
  __exportStar(require("./decorators/WebSocketRoute"), exports);
36
+ __exportStar(require("./adaptors/McpAdaptor"), exports);
37
+ __exportStar(require("./decorators/McpRoute"), exports);
36
38
  __exportStar(require("./decorators/doNotThrowTransformError"), exports);
37
39
  //# sourceMappingURL=module.js.map
package/lib/module.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6DAA2C;AAC3C,2DAAyC;AAEzC,0DAAwC;AACxC,0DAAwC;AACxC,yDAAuC;AACvC,0DAAwC;AACxC,8DAA4C;AAC5C,4DAA0C;AAC1C,6DAA2C;AAC3C,0DAAwC;AAExC,mEAAiD;AACjD,8DAA4C;AAC5C,6DAA2C;AAC3C,+DAA6C;AAC7C,yDAAuC;AACvC,iEAA+C;AAC/C,8DAA4C;AAE5C,8DAA4C;AAC5C,8DAA4C;AAC5C,wEAAsD"}
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6DAA2C;AAC3C,2DAAyC;AAEzC,0DAAwC;AACxC,0DAAwC;AACxC,yDAAuC;AACvC,0DAAwC;AACxC,8DAA4C;AAC5C,4DAA0C;AAC1C,6DAA2C;AAC3C,0DAAwC;AAExC,mEAAiD;AACjD,8DAA4C;AAC5C,6DAA2C;AAC3C,+DAA6C;AAC7C,yDAAuC;AACvC,iEAA+C;AAC/C,8DAA4C;AAE5C,8DAA4C;AAC5C,8DAA4C;AAC5C,wDAAsC;AACtC,wDAAsC;AACtC,wEAAsD"}
@@ -0,0 +1,26 @@
1
+ import ts from "typescript";
2
+ import { INestiaTransformContext } from "../options/INestiaTransformProject";
3
+ /**
4
+ * Compile-time JSON Schema emitter for `@McpRoute.Params<T>()` types.
5
+ *
6
+ * Mirrors {@link TypedBodyProgrammer} for runtime validators, but instead of
7
+ * emitting a `typia.assert` closure it emits a literal JSON Schema object.
8
+ * The MCP specification requires `inputSchema` to be a single static object
9
+ * type — no primitives, no unions, no dynamic-key records — so this
10
+ * programmer rejects anything else with a {@link TransformerError}.
11
+ *
12
+ * The emitted shape is `LlmParametersProgrammer`'s parameters block —
13
+ * `{ type: "object", properties, required, $defs }` — which is exactly what
14
+ * the MCP `tools/list` response requires for `inputSchema`. Plain
15
+ * `JsonSchemaProgrammer.write` cannot be used here because it may produce a
16
+ * top-level `$ref` to a `$defs` entry, which MCP clients reject.
17
+ *
18
+ * @author wildduck - https://github.com/wildduck2
19
+ */
20
+ export declare namespace McpRouteProgrammer {
21
+ const generate: (props: {
22
+ context: INestiaTransformContext;
23
+ modulo: ts.LeftHandSideExpression;
24
+ type: ts.Type;
25
+ }) => ts.Expression;
26
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpRouteProgrammer = void 0;
4
+ const core_1 = require("@typia/core");
5
+ const check_mcp_object_1 = require("./internal/check_mcp_object");
6
+ /**
7
+ * Compile-time JSON Schema emitter for `@McpRoute.Params<T>()` types.
8
+ *
9
+ * Mirrors {@link TypedBodyProgrammer} for runtime validators, but instead of
10
+ * emitting a `typia.assert` closure it emits a literal JSON Schema object.
11
+ * The MCP specification requires `inputSchema` to be a single static object
12
+ * type — no primitives, no unions, no dynamic-key records — so this
13
+ * programmer rejects anything else with a {@link TransformerError}.
14
+ *
15
+ * The emitted shape is `LlmParametersProgrammer`'s parameters block —
16
+ * `{ type: "object", properties, required, $defs }` — which is exactly what
17
+ * the MCP `tools/list` response requires for `inputSchema`. Plain
18
+ * `JsonSchemaProgrammer.write` cannot be used here because it may produce a
19
+ * top-level `$ref` to a `$defs` entry, which MCP clients reject.
20
+ *
21
+ * @author wildduck - https://github.com/wildduck2
22
+ */
23
+ var McpRouteProgrammer;
24
+ (function (McpRouteProgrammer) {
25
+ McpRouteProgrammer.generate = (props) => {
26
+ const result = core_1.MetadataFactory.analyze({
27
+ checker: props.context.checker,
28
+ transformer: props.context.transformer,
29
+ options: {
30
+ escape: true,
31
+ constant: true,
32
+ absorb: true,
33
+ },
34
+ components: new core_1.MetadataCollection(),
35
+ type: props.type,
36
+ });
37
+ if (result.success === false)
38
+ throw core_1.TransformerError.from({
39
+ code: "@nestia.core.McpRoute.Params",
40
+ errors: result.errors,
41
+ });
42
+ const violations = (0, check_mcp_object_1.check_mcp_object)("params")(result.data);
43
+ if (violations.length)
44
+ throw new Error(`[@nestia.core.McpRoute.Params] ${violations.join(" ")}`);
45
+ return core_1.LlmParametersProgrammer.write({
46
+ context: Object.assign(Object.assign({}, props.context), { options: {
47
+ numeric: false,
48
+ finite: false,
49
+ functional: false,
50
+ } }),
51
+ config: { strict: false },
52
+ metadata: result.data,
53
+ });
54
+ };
55
+ })(McpRouteProgrammer || (exports.McpRouteProgrammer = McpRouteProgrammer = {}));
56
+ //# sourceMappingURL=McpRouteProgrammer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpRouteProgrammer.js","sourceRoot":"","sources":["../../src/programmers/McpRouteProgrammer.ts"],"names":[],"mappings":";;;AAAA,sCAMqB;AAKrB,kEAA+D;AAE/D;;;;;;;;;;;;;;;;GAgBG;AACH,IAAiB,kBAAkB,CA4ClC;AA5CD,WAAiB,kBAAkB;IACpB,2BAAQ,GAAG,CAAC,KAIxB,EAAiB,EAAE;QAClB,MAAM,MAAM,GACV,sBAAe,CAAC,OAAO,CAAC;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;YAC9B,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;YACtC,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI;aACb;YACD,UAAU,EAAE,IAAI,yBAAkB,EAAE;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CAAC;QACL,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK;YAC1B,MAAM,uBAAgB,CAAC,IAAI,CAAC;gBAC1B,IAAI,EAAE,8BAA8B;gBACpC,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;QAEL,MAAM,UAAU,GAAa,IAAA,mCAAgB,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrE,IAAI,UAAU,CAAC,MAAM;YACnB,MAAM,IAAI,KAAK,CACb,kCAAkC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACzD,CAAC;QAEJ,OAAO,8BAAuB,CAAC,KAAK,CAAC;YACnC,OAAO,kCACF,KAAK,CAAC,OAAO,KAChB,OAAO,EAAE;oBACP,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE,KAAK;iBAClB,GACF;YACD,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;YACzB,QAAQ,EAAE,MAAM,CAAC,IAAI;SACtB,CAAC,CAAC;IACL,CAAC,CAAC;AAEJ,CAAC,EA5CgB,kBAAkB,kCAAlB,kBAAkB,QA4ClC"}
@@ -0,0 +1,24 @@
1
+ import ts from "typescript";
2
+ import { INestiaTransformContext } from "../options/INestiaTransformProject";
3
+ /**
4
+ * Compile-time validator for the return type of an `@McpRoute()` method.
5
+ *
6
+ * Mirrors {@link TypedRouteProgrammer} but adapted to MCP's structured-output
7
+ * rules. The MCP specification requires every tool's output to be a single
8
+ * object value or nothing at all. To enforce that:
9
+ *
10
+ * - `void` returns short-circuit (nothing emitted).
11
+ * - Object returns are inspected directly on the analyzed metadata to reject
12
+ * primitives, unions, and dynamic-key records.
13
+ * - Mixed unions of `void` and a value type are rejected outright; MCP has no
14
+ * way to model "sometimes returns nothing, sometimes returns X".
15
+ *
16
+ * @author wildduck - https://github.com/wildduck2
17
+ */
18
+ export declare namespace McpRouteReturnProgrammer {
19
+ const generate: (props: {
20
+ context: INestiaTransformContext;
21
+ modulo: ts.LeftHandSideExpression;
22
+ type: ts.Type;
23
+ }) => void;
24
+ }