@gabrielmaialva33/mcp-filesystem
Version:
MCP server for secure filesystem access
113 lines • 3.71 kB
JavaScript
import fs from 'node:fs/promises';
import path from 'node:path';
import { expandHome, normalizePath } from '../utils/path.js';
import { z } from 'zod';
const ConfigSchema = z.object({
serverName: z.string().default('secure-filesystem-server'),
serverVersion: z.string().default('0.3.0'),
allowedDirectories: z.array(z.string()).min(1, 'At least one allowed directory required'),
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
logFile: z.string().optional(),
cache: z
.object({
enabled: z.boolean().default(true),
maxSize: z.number().positive().default(1000),
ttlMs: z.number().positive().default(60000),
})
.default({}),
metrics: z
.object({
enabled: z.boolean().default(true),
reportIntervalMs: z.number().positive().default(60000),
})
.default({}),
security: z
.object({
maxFileSize: z
.number()
.nonnegative()
.default(10 * 1024 * 1024),
allowSymlinks: z.boolean().default(true),
validateRealPath: z.boolean().default(true),
})
.default({}),
});
const defaultConfig = {
allowedDirectories: [],
logLevel: 'info',
serverName: 'secure-filesystem-server',
serverVersion: '0.3.0',
cache: {
enabled: true,
maxSize: 1000,
ttlMs: 60000,
},
metrics: {
enabled: true,
reportIntervalMs: 60000,
},
security: {
maxFileSize: 10 * 1024 * 1024,
allowSymlinks: true,
validateRealPath: true,
},
};
export async function loadConfig(configPath) {
let userConfig = {};
if (configPath) {
try {
const expandedPath = expandHome(configPath);
const configContent = await fs.readFile(expandedPath, 'utf-8');
userConfig = JSON.parse(configContent);
console.error(`Loaded config from ${expandedPath}`);
}
catch (error) {
console.error(`Failed to load config from ${configPath}, using default config`);
}
}
if (!userConfig.allowedDirectories || userConfig.allowedDirectories.length === 0) {
const args = process.argv.slice(2);
if (args.length > 0) {
userConfig.allowedDirectories = args.map((dir) => normalizePath(path.resolve(expandHome(dir))));
}
}
else {
userConfig.allowedDirectories = userConfig.allowedDirectories.map((dir) => normalizePath(path.resolve(expandHome(dir))));
}
try {
const mergedConfig = { ...defaultConfig, ...userConfig };
return ConfigSchema.parse(mergedConfig);
}
catch (error) {
console.error('Invalid configuration:', error);
return ConfigSchema.parse({
...defaultConfig,
allowedDirectories: userConfig.allowedDirectories || [process.cwd()],
});
}
}
export async function createSampleConfig(outputPath) {
const sampleConfig = {
allowedDirectories: ['/path/to/allowed/dir1', '/path/to/allowed/dir2'],
logLevel: 'info',
logFile: '/path/to/logs/mcp-filesystem.log',
serverName: 'secure-filesystem-server',
serverVersion: '0.3.0',
cache: {
enabled: true,
maxSize: 1000,
ttlMs: 60000,
},
metrics: {
enabled: true,
reportIntervalMs: 60000,
},
security: {
maxFileSize: 10 * 1024 * 1024,
allowSymlinks: true,
validateRealPath: true,
},
};
await fs.writeFile(outputPath, JSON.stringify(sampleConfig, null, 2), 'utf-8');
}
//# sourceMappingURL=index.js.map