@nestia/core 11.2.0 → 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.
- package/lib/adaptors/McpAdaptor.d.ts +75 -0
- package/lib/adaptors/McpAdaptor.js +256 -0
- package/lib/adaptors/McpAdaptor.js.map +1 -0
- package/lib/decorators/McpRoute.d.ts +73 -0
- package/lib/decorators/McpRoute.js +60 -0
- package/lib/decorators/McpRoute.js.map +1 -0
- package/lib/decorators/internal/IMcpRouteReflect.d.ts +2 -0
- package/lib/decorators/internal/IMcpRouteReflect.js +3 -0
- package/lib/decorators/internal/IMcpRouteReflect.js.map +1 -0
- package/lib/module.d.ts +2 -0
- package/lib/module.js +2 -0
- package/lib/module.js.map +1 -1
- package/lib/programmers/McpRouteProgrammer.d.ts +26 -0
- package/lib/programmers/McpRouteProgrammer.js +56 -0
- package/lib/programmers/McpRouteProgrammer.js.map +1 -0
- package/lib/programmers/McpRouteReturnProgrammer.d.ts +24 -0
- package/lib/programmers/McpRouteReturnProgrammer.js +63 -0
- package/lib/programmers/McpRouteReturnProgrammer.js.map +1 -0
- package/lib/programmers/internal/check_mcp_object.d.ts +1 -0
- package/lib/programmers/internal/check_mcp_object.js +28 -0
- package/lib/programmers/internal/check_mcp_object.js.map +1 -0
- package/lib/transformers/McpRouteTransformer.d.ts +33 -0
- package/lib/transformers/McpRouteTransformer.js +182 -0
- package/lib/transformers/McpRouteTransformer.js.map +1 -0
- package/lib/transformers/MethodTransformer.js +6 -0
- package/lib/transformers/MethodTransformer.js.map +1 -1
- package/lib/transformers/ParameterDecoratorTransformer.js +3 -0
- package/lib/transformers/ParameterDecoratorTransformer.js.map +1 -1
- package/package.json +4 -3
- package/src/adaptors/McpAdaptor.ts +276 -0
- package/src/decorators/McpRoute.ts +159 -0
- package/src/decorators/internal/IMcpRouteReflect.ts +41 -0
- package/src/module.ts +2 -0
- package/src/programmers/McpRouteProgrammer.ts +75 -0
- package/src/programmers/McpRouteReturnProgrammer.ts +77 -0
- package/src/programmers/internal/check_mcp_object.ts +37 -0
- package/src/transformers/McpRouteTransformer.ts +271 -0
- package/src/transformers/MethodTransformer.ts +6 -0
- 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAIwB;AAKxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAa,UAAU;IACrB;;;;;;;;;;;;;;OAcG;IACI,MAAM,CAAO,OAAO;6DACzB,GAAqB,EACrB,UAA+B,EAAE;;YAEjC,IAAI,WAAW,IAAK,OAAmC;gBACrD,MAAM,IAAI,KAAK,CACb,kGAAkG,CACnG,CAAC;YAEJ,MAAM,KAAK,GAAuB,EAAE,CAAC;YACrC,MAAM,SAAS,GAAI,GAAW,CAAC,SAA0B,CAAC;YAC1D,KAAK,MAAM,MAAM,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;oBAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;oBAClC,IAAI,CAAC,QAAQ;wBAAE,SAAS;oBACxB,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;oBAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;wBACpD,IAAI,GAAG,KAAK,aAAa;4BAAE,SAAS;wBACpC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;wBAC1B,IAAI,OAAO,MAAM,KAAK,UAAU;4BAAE,SAAS;wBAE3C,MAAM,IAAI,GAAiC,OAAO,CAAC,WAAW,CAC5D,iBAAiB,EACjB,MAAM,CACP,CAAC;wBACF,IAAI,CAAC,IAAI;4BAAE,SAAS;wBAEpB,MAAM,MAAM,GACV,MAAA,OAAO,CAAC,WAAW,CAAC,4BAA4B,EAAE,KAAK,EAAE,GAAG,CAAC,mCAAI,EAAE,CAAC;wBACtE,MAAM,cAAc,GAAG,MAAA,MAAM,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAC/B,0CAAE,QAAQ,CAAC;wBAEZ,KAAK,CAAC,IAAI,CAAC;4BACT,IAAI;4BACJ,MAAM,EAAE,GAAG,MAAA,MAAA,MAAA,OAAO,CAAC,QAAQ,0CAAE,IAAI,mCAAI,MAAA,KAAK,CAAC,WAAW,0CAAE,IAAI,mCAAI,mBAAmB,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE;4BACpG,YAAY,EAAE,cAAc;4BAC5B,OAAO,EAAE,CAAO,IAAI,EAAE,EAAE,gDAAC,OAAA,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA,GAAA;yBACrD,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YACD,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAEzB,MAAM,UAAU,GAAG,MAAA,OAAO,CAAC,UAAU,mCAAI;gBACvC,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,OAAO;aACjB,CAAC;YACF,MAAM,EACJ,qBAAqB,EACrB,SAAS,EACT,sBAAsB,EACtB,QAAQ,EACR,SAAS,EACT,6BAA6B,GAC9B,GAAG,MAAM,UAAU,EAAE,CAAC;YAEvB,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,MAAA,OAAO,CAAC,IAAI,mCAAI,MAAM,CAAC;YACrC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAO,GAAQ,EAAE,GAAQ,EAAE,EAAE;;gBAC3C,qEAAqE;gBACrE,mEAAmE;gBACnE,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,UAAU,EAAE;oBACpC,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;iBAC5B,CAAC,CAAC;gBACH,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;gBAE1B,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,GAAS,EAAE;oBAAC,OAAA,CAAC;wBAC5D,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BACvB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;4BACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK;4BACnB,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;4BAC/B,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;4BAC/B,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY;4BACjC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;yBAChC,CAAC,CAAC;qBACJ,CAAC,CAAA;kBAAA,CAAC,CAAC;gBAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,CAAO,MAAM,EAAE,EAAE;;oBAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACnE,IAAI,CAAC,IAAI;wBACP,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,cAAc,EACxB,mBAAmB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,CAAC;oBAEJ,MAAM,IAAI,GAAG,MAAA,MAAM,CAAC,MAAM,CAAC,SAAS,mCAAI,EAAE,CAAC;oBAC3C,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;wBACtB,MAAM,GAAG,GAAiB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;wBAClD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;4BACjB,MAAM,IAAI,GACR,GAAG,YAAY,4BAAmB;gCAChC,CAAC,CAAE,GAAG,CAAC,WAAW,EAAU;gCAC5B,CAAC,CAAC,SAAS,CAAC;4BAChB,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,EAAE;gCACvD,MAAM,EAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM;gCACpB,IAAI,EAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,IAAI;gCAChB,QAAQ,EAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,QAAQ;gCACxB,KAAK,EAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK;gCAClB,MAAM,EAAE,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM;6BACrB,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAED,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;wBACxC,IAAI,MAAM,KAAK,SAAS;4BAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;wBACjD,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAe;oCACrB,IAAI,EACF,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;iCAC/D;6BACF;yBACF,CAAC;oBACJ,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACX,IAAI,CAAC,YAAY,sBAAa,EAAE,CAAC;4BAC/B,OAAO;gCACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;gCACrD,OAAO,EAAE,IAAI;6BACd,CAAC;wBACJ,CAAC;wBACD,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAClD,CAAC;oBACJ,CAAC;gBACH,CAAC,CAAA,CAAC,CAAC;gBAEH,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;oBAClD,kBAAkB,EAAE,SAAS;oBAC7B,kBAAkB,EAAE,IAAI;iBACzB,CAAC,CAAC;gBACH,IAAI,CAAC;oBACH,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;oBAC7B,MAAM,SAAS,CAAC,aAAa,CAAC,MAAA,GAAG,CAAC,GAAG,mCAAI,GAAG,EAAE,MAAA,GAAG,CAAC,GAAG,mCAAI,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1E,CAAC;wBAAS,CAAC;oBACT,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACxC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC,CAAA,CAAC,CAAC;QACL,CAAC;KAAA;CACF;AA/JD,gCA+JC;AAED,MAAM,iBAAiB,GAAG,CAAC,KAAyB,EAAQ,EAAE;;IAC5D,MAAM,IAAI,GAAoC,IAAI,GAAG,EAAE,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAA,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAI,EAAE,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAClD,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAC9B,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACpC,MAAM,IAAI,KAAK,CACb;QACE,4CAA4C;QAC5C,GAAG,UAAU,CAAC,GAAG,CACf,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CACf,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/E;KACF,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,GAAS,EAAE;IAC5B,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;8DAC5C,yCAAyC;8DACzC,oDAAoD;8DACpD,oCAAoC;SAC5C,CAAC,CAAC;QACH,OAAO;YACL,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,6BAA6B,EAAE,SAAS,CAAC,6BAA6B;YACtE,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;YAClD,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;YACpD,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC;IACJ,CAAC;IAAC,WAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,iGAAiG,CAClG,CAAC;IACJ,CAAC;AACH,CAAC,CAAA,CAAC"}
|
|
@@ -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 @@
|
|
|
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
|
+
}
|