@kya-os/mcp-i
Version:
The TypeScript MCP framework with identity features built-in
161 lines (160 loc) • 5.44 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfig = getConfig;
exports.readConfig = readConfig;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const webpack_1 = require("webpack");
const memfs_1 = require("memfs");
const compiler_context_1 = require("./compiler-context");
const config_1 = require("./config");
const constants_1 = require("./config/constants");
function validateConfig(config) {
return config_1.configSchema.parse(config);
}
// read if exists
function readConfigFile(pathToConfig) {
const configPath = path_1.default.resolve(process.cwd(), pathToConfig);
if (!fs_1.default.existsSync(configPath)) {
return null;
}
return fs_1.default.readFileSync(configPath, "utf8");
}
const configPaths = {
ts: "xmcp.config.ts",
json: "xmcp.config.json",
};
/**
* Parse and validate xmcp config file
*/
async function getConfig() {
const config = await readConfig();
const { platforms } = compiler_context_1.compilerContext.getContext();
if (platforms.vercel) {
// Remove stdio to deploy on vercel
delete config.stdio;
}
return config;
}
/**
* Read config from file or return default
*/
async function readConfig() {
// Simple json config
const jsonFile = readConfigFile(configPaths.json);
if (jsonFile) {
return validateConfig(JSON.parse(jsonFile));
}
// TypeScript config, compile it
const tsFile = readConfigFile(configPaths.ts);
if (tsFile) {
try {
return await compileConfig();
}
catch (error) {
throw new Error(`Failed to compile xmcp.config.ts:\n${error}`);
}
}
// Default config
return {
stdio: true,
http: true,
paths: constants_1.DEFAULT_PATHS_CONFIG,
};
}
/**
* If the user is using a typescript config file,
* we need to bundle it, run it and return its copiled code
* */
async function compileConfig() {
const configPath = path_1.default.resolve(process.cwd(), configPaths.ts);
// Create memory filesystem
const memoryFs = (0, memfs_1.createFsFromVolume)(new memfs_1.Volume());
// Webpack configuration
const webpackConfig = {
mode: "production",
entry: configPath,
target: "node",
output: {
path: "/",
filename: "config.js",
library: {
type: "commonjs2",
},
},
resolve: {
extensions: [".ts", ".js"],
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "swc-loader",
options: {
jsc: {
parser: {
syntax: "typescript",
},
target: "es2020",
},
module: {
type: "commonjs",
},
},
},
exclude: /node_modules/,
},
],
},
externals: {
webpack: "commonjs2 webpack",
},
};
return new Promise((resolve, reject) => {
const compiler = (0, webpack_1.webpack)(webpackConfig);
// Webpack returns null if config is invalid
if (!compiler) {
reject(new Error("Failed to create webpack compiler - invalid config"));
return;
}
// Use memory filesystem for output
compiler.outputFileSystem = memoryFs;
compiler.run((err, stats) => {
if (err) {
reject(err);
return;
}
if (stats?.hasErrors()) {
reject(new Error(stats.toString({ colors: false, errors: true })));
return;
}
try {
// Read the bundled code from memory
const bundledCode = memoryFs.readFileSync("/config.js", "utf8");
// Create a temporary module to evaluate the bundled code
const module = { exports: {} };
const require = (id) => {
// Handle webpack require
if (id === "webpack") {
return webpack_1.webpack;
}
throw new Error(`Cannot resolve module: ${id}`);
};
// Evaluate the bundled code
const func = new Function("module", "exports", "require", "__filename", "__dirname", bundledCode);
func(module, module.exports, require, configPath, path_1.default.dirname(configPath));
// Extract the config - it could be default export or direct export
const configExport = module.exports.default || module.exports;
const config = typeof configExport === "function" ? configExport() : configExport;
resolve(validateConfig(config));
}
catch (evalError) {
reject(evalError);
}
});
});
}