UNPKG

@nestia/sdk

Version:

Nestia SDK and Swagger generator

149 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SdkMcpRouteProgrammer = void 0; const factory_1 = require("@ttsc/factory"); const IdentifierFactory_1 = require("../../factories/IdentifierFactory"); const FilePrinter_1 = require("./FilePrinter"); /** * Emits a typed client wrapper for an MCP tool. * * Object output types are wrapped in `Primitive<T>` because MCP round-trips * values through JSON. Void MCP tools return `Promise<void>`. * * @author wildduck - https://github.com/wildduck2 */ var SdkMcpRouteProgrammer; (function (SdkMcpRouteProgrammer) { SdkMcpRouteProgrammer.write = (project) => (importer) => (route) => [ FilePrinter_1.FilePrinter.description(writeFunction(project)(importer)(route), writeDescription(route)), writeNamespace(project)(importer)(route), ]; const writeFunction = (_project) => (importer) => (route) => { const clientType = factory_1.factory.createTypeReferenceNode(importer.external({ declaration: true, file: "@modelcontextprotocol/sdk/client/index.js", type: "element", name: "Client", alias: "McpClient", })); const callToolResultTypeName = importer.external({ declaration: true, file: "@modelcontextprotocol/sdk/types.js", type: "element", name: "CallToolResult", alias: "McpCallToolResult", }); const isVoid = isVoidReturn(route); if (!isVoid) importer.external({ declaration: true, file: "typia", type: "element", name: "Primitive", }); const inputRef = route.input ? factory_1.factory.createTypeReferenceNode(`${route.name}.Input`) : factory_1.factory.createTypeLiteralNode([]); const outputRef = factory_1.factory.createTypeReferenceNode(`${route.name}.Output`); const params = [ factory_1.factory.createParameterDeclaration(undefined, undefined, "client", undefined, clientType, undefined), ]; if (route.input) params.push(factory_1.factory.createParameterDeclaration(undefined, undefined, "args", undefined, inputRef, undefined)); const toolNameExpr = factory_1.factory.createPropertyAccessExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier(route.name), "METADATA"), "tool"); const callToolParams = [ factory_1.factory.createPropertyAssignment("name", toolNameExpr), ]; if (route.input) callToolParams.push(factory_1.factory.createPropertyAssignment("arguments", factory_1.factory.createAsExpression(factory_1.factory.createAsExpression(factory_1.factory.createIdentifier("args"), factory_1.factory.createKeywordTypeNode(factory_1.SyntaxKind.AnyKeyword)), factory_1.factory.createTypeReferenceNode("Record", [ factory_1.factory.createKeywordTypeNode(factory_1.SyntaxKind.StringKeyword), factory_1.factory.createKeywordTypeNode(factory_1.SyntaxKind.AnyKeyword), ])))); const body = factory_1.factory.createBlock([ factory_1.factory.createVariableStatement(undefined, factory_1.factory.createVariableDeclarationList([ factory_1.factory.createVariableDeclaration("raw", undefined, undefined, factory_1.factory.createAwaitExpression(factory_1.factory.createCallExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("client"), "callTool"), undefined, [ factory_1.factory.createObjectLiteralExpression(callToolParams, true), ]))), ], factory_1.NodeFlags.Const)), factory_1.factory.createIfStatement(factory_1.factory.createCallExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("Object"), "prototype"), "hasOwnProperty"), "call"), undefined, [ factory_1.factory.createIdentifier("raw"), factory_1.factory.createStringLiteral("toolResult"), ]), throwToolError(toolNameExpr, '" returned a legacy (pre-2024-11-05) compatibility result')), factory_1.factory.createVariableStatement(undefined, factory_1.factory.createVariableDeclarationList([ factory_1.factory.createVariableDeclaration("result", undefined, factory_1.factory.createTypeReferenceNode(callToolResultTypeName), factory_1.factory.createAsExpression(factory_1.factory.createIdentifier("raw"), factory_1.factory.createTypeReferenceNode(callToolResultTypeName))), ], factory_1.NodeFlags.Const)), factory_1.factory.createIfStatement(factory_1.factory.createBinaryExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("result"), "isError"), factory_1.factory.createToken(factory_1.SyntaxKind.EqualsEqualsEqualsToken), factory_1.factory.createTrue()), throwToolError(toolNameExpr, '" returned isError')), ...(isVoid ? [factory_1.factory.createReturnStatement()] : [ factory_1.factory.createVariableStatement(undefined, factory_1.factory.createVariableDeclarationList([ factory_1.factory.createVariableDeclaration("first", undefined, undefined, factory_1.factory.createCallExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("result"), "content"), "find"), undefined, [ factory_1.factory.createArrowFunction(undefined, undefined, [IdentifierFactory_1.IdentifierFactory.parameter("entry")], undefined, undefined, factory_1.factory.createBinaryExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("entry"), "type"), factory_1.factory.createToken(factory_1.SyntaxKind.EqualsEqualsEqualsToken), factory_1.factory.createStringLiteral("text"))), ])), ], factory_1.NodeFlags.Const)), factory_1.factory.createIfStatement(factory_1.factory.createBinaryExpression(factory_1.factory.createIdentifier("first"), factory_1.factory.createToken(factory_1.SyntaxKind.EqualsEqualsEqualsToken), factory_1.factory.createIdentifier("undefined")), throwToolError(toolNameExpr, '" returned no text content')), factory_1.factory.createIfStatement(factory_1.factory.createBinaryExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("first"), "type"), factory_1.factory.createToken(factory_1.SyntaxKind.EqualsEqualsEqualsToken), factory_1.factory.createStringLiteral("text")), factory_1.factory.createReturnStatement(factory_1.factory.createAsExpression(factory_1.factory.createCallExpression(factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("JSON"), "parse"), undefined, [ factory_1.factory.createPropertyAccessExpression(factory_1.factory.createIdentifier("first"), "text"), ]), outputRef))), throwToolError(toolNameExpr, '" returned no text content'), ]), ], true); return factory_1.factory.createFunctionDeclaration([ factory_1.factory.createModifier(factory_1.SyntaxKind.ExportKeyword), factory_1.factory.createModifier(factory_1.SyntaxKind.AsyncKeyword), ], undefined, route.name, undefined, params, factory_1.factory.createTypeReferenceNode("Promise", [outputRef]), body); }; const writeNamespace = (_project) => (importer) => (route) => { const statements = []; if (route.input) statements.push(factory_1.factory.createTypeAliasDeclaration([factory_1.factory.createModifier(factory_1.SyntaxKind.ExportKeyword)], "Input", undefined, factory_1.factory.createTypeReferenceNode(route.input.type.name))); const outputType = !isVoidReturn(route) && route.returnType !== null ? factory_1.factory.createTypeReferenceNode(importer.external({ declaration: true, file: "typia", type: "element", name: "Primitive", }), [ factory_1.factory.createTypeReferenceNode(unwrapPromise(route.returnType.name)), ]) : factory_1.factory.createKeywordTypeNode(factory_1.SyntaxKind.VoidKeyword); statements.push(factory_1.factory.createTypeAliasDeclaration([factory_1.factory.createModifier(factory_1.SyntaxKind.ExportKeyword)], "Output", undefined, outputType)); statements.push(factory_1.factory.createVariableStatement([factory_1.factory.createModifier(factory_1.SyntaxKind.ExportKeyword)], factory_1.factory.createVariableDeclarationList([ factory_1.factory.createVariableDeclaration("METADATA", undefined, undefined, factory_1.factory.createAsExpression(factory_1.factory.createObjectLiteralExpression([ factory_1.factory.createPropertyAssignment("protocol", factory_1.factory.createStringLiteral("mcp")), factory_1.factory.createPropertyAssignment("tool", factory_1.factory.createStringLiteral(route.toolName)), factory_1.factory.createPropertyAssignment("title", route.title === null ? factory_1.factory.createNull() : factory_1.factory.createStringLiteral(route.title)), factory_1.factory.createPropertyAssignment("description", route.toolDescription === null ? factory_1.factory.createNull() : factory_1.factory.createStringLiteral(route.toolDescription)), ], true), factory_1.factory.createTypeReferenceNode("const"))), ], factory_1.NodeFlags.Const))); return factory_1.factory.createModuleDeclaration([factory_1.factory.createModifier(factory_1.SyntaxKind.ExportKeyword)], factory_1.factory.createIdentifier(route.name), factory_1.factory.createModuleBlock(statements), factory_1.NodeFlags.Namespace); }; const writeDescription = (route) => { const lines = []; if (route.toolDescription) lines.push(...route.toolDescription.split("\n")); else if (route.description) lines.push(...route.description.split("\n")); if (lines.length) lines.push(""); lines.push(`@controller ${route.controller.class.name}.${route.function.name || route.name}`, `@tool ${route.toolName}`, `@accessor ${["api", "functional", ...route.accessor].join(".")}`, `@protocol mcp`, `@nestia Generated by Nestia - https://github.com/samchon/nestia`); return lines.join("\n"); }; const unwrapPromise = (name) => { const m = /^Promise<(.+)>$/.exec(name); return m ? m[1] : name; }; const isVoidReturn = (route) => route.returnType === null || isVoidName(unwrapPromise(route.returnType.name)); const isVoidName = (name) => name === "void" || name === "undefined"; const throwToolError = (toolNameExpr, suffix) => factory_1.factory.createThrowStatement(factory_1.factory.createNewExpression(factory_1.factory.createIdentifier("Error"), undefined, [ factory_1.factory.createTemplateExpression(factory_1.factory.createTemplateHead('MCP tool "'), [ factory_1.factory.createTemplateSpan(toolNameExpr, factory_1.factory.createTemplateTail(suffix)), ]), ])); })(SdkMcpRouteProgrammer || (exports.SdkMcpRouteProgrammer = SdkMcpRouteProgrammer = {})); //# sourceMappingURL=SdkMcpRouteProgrammer.js.map