@toolprint/hypertool-mcp
Version:
HyperTool MCP proxy server for routing requests between clients and multiple underlying MCP servers
138 lines • 5.33 kB
JavaScript
/**
* Base transformer for standard MCP configuration format
*/
import { ClaudeCodeTransformer } from "./claude-code.js";
/**
* Base transformer for applications using standard mcpServers format
*/
export class StandardTransformer {
/**
* Convert from standard format to standard format (pass-through)
*/
toStandard(appConfig) {
let mcpServers = {};
let metadata = appConfig._metadata;
// If it already has mcpServers, use that
if (appConfig.mcpServers && typeof appConfig.mcpServers === "object") {
mcpServers = appConfig.mcpServers;
}
else if (typeof appConfig === "object" && !Array.isArray(appConfig)) {
// If it's a bare object of servers, use it directly
mcpServers = appConfig;
}
// Add missing type fields to servers for backward compatibility
let hasAddedTypes = false;
for (const [name, server] of Object.entries(mcpServers)) {
if (server && typeof server === "object" && !server.type) {
// Default to stdio if has command field
if (server.command) {
server.type = "stdio";
hasAddedTypes = true;
}
}
}
if (hasAddedTypes) {
console.warn('Added missing "type" fields to server configurations. Please update your config files to include explicit type fields.');
}
return {
mcpServers,
_metadata: metadata,
};
}
/**
* Convert from standard format to standard format (pass-through)
*/
fromStandard(standardConfig, existingConfig) {
return standardConfig;
}
/**
* Validate standard MCP configuration format
*/
validate(config) {
const errors = [];
const warnings = [];
// Check if config is an object
if (typeof config !== "object" || config === null) {
errors.push("Configuration must be an object");
return { valid: false, errors };
}
// Check if mcpServers exists and is an object
if (!config.mcpServers) {
warnings.push("Configuration does not contain mcpServers field");
}
else if (typeof config.mcpServers !== "object" ||
Array.isArray(config.mcpServers)) {
errors.push("mcpServers must be an object");
}
else {
// Validate each server
for (const [name, server] of Object.entries(config.mcpServers)) {
if (typeof server !== "object" || server === null) {
errors.push(`Server "${name}" must be an object`);
continue;
}
const serverConfig = server;
// Check required fields
if (!serverConfig.type) {
errors.push(`Server "${name}" missing required field: type`);
}
else if (!["stdio", "http", "websocket", "sse"].includes(serverConfig.type)) {
errors.push(`Server "${name}" has invalid type: ${serverConfig.type}`);
}
// Check command/url based on transport type
if (serverConfig.type === "stdio") {
if (!serverConfig.command) {
errors.push(`Server "${name}" with type 'stdio' missing required field: command`);
}
}
else if (["http", "sse", "websocket"].includes(serverConfig.type)) {
if (!serverConfig.url) {
errors.push(`Server "${name}" with type '${serverConfig.type}' missing required field: url`);
}
if (serverConfig.command) {
warnings.push(`Server "${name}" with type '${serverConfig.type}' should use 'url' instead of 'command'`);
}
}
// Check optional fields
if (serverConfig.args && !Array.isArray(serverConfig.args)) {
errors.push(`Server "${name}" args must be an array`);
}
if (serverConfig.env && typeof serverConfig.env !== "object") {
errors.push(`Server "${name}" env must be an object`);
}
}
}
return {
valid: errors.length === 0,
errors: errors.length > 0 ? errors : undefined,
warnings: warnings.length > 0 ? warnings : undefined,
};
}
}
/**
* Registry of available transformers
*/
export class TransformerRegistry {
static transformers = new Map([
["standard", new StandardTransformer()],
["claude-code", new ClaudeCodeTransformer()],
]);
/**
* Get a transformer by name
*/
static getTransformer(name) {
const transformer = this.transformers.get(name);
if (!transformer) {
// Default to standard transformer
return this.transformers.get("standard");
}
return transformer;
}
/**
* Register a custom transformer
*/
static registerTransformer(name, transformer) {
this.transformers.set(name, transformer);
}
}
//# sourceMappingURL=base.js.map