@mcptoolshop/file-forge 0.2.1 → 1.0.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.
Files changed (66) hide show
  1. package/README.md +33 -5
  2. package/build/config/index.d.ts +29 -0
  3. package/build/config/index.d.ts.map +1 -0
  4. package/build/config/index.js +229 -0
  5. package/build/config/index.js.map +1 -0
  6. package/build/index.d.ts +9 -0
  7. package/build/index.d.ts.map +1 -0
  8. package/build/index.js +25 -0
  9. package/build/index.js.map +1 -0
  10. package/build/security/index.d.ts +8 -0
  11. package/build/security/index.d.ts.map +1 -0
  12. package/build/security/index.js +8 -0
  13. package/build/security/index.js.map +1 -0
  14. package/build/security/read-only.d.ts +32 -0
  15. package/build/security/read-only.d.ts.map +1 -0
  16. package/build/security/read-only.js +62 -0
  17. package/build/security/read-only.js.map +1 -0
  18. package/build/security/sandbox.d.ts +60 -0
  19. package/build/security/sandbox.d.ts.map +1 -0
  20. package/build/security/sandbox.js +231 -0
  21. package/build/security/sandbox.js.map +1 -0
  22. package/build/server.d.ts +32 -0
  23. package/build/server.d.ts.map +1 -0
  24. package/build/server.js +171 -0
  25. package/build/server.js.map +1 -0
  26. package/build/tools/metadata.d.ts +11 -0
  27. package/build/tools/metadata.d.ts.map +1 -0
  28. package/build/tools/metadata.js +423 -0
  29. package/build/tools/metadata.js.map +1 -0
  30. package/build/tools/read.d.ts +11 -0
  31. package/build/tools/read.d.ts.map +1 -0
  32. package/build/tools/read.js +335 -0
  33. package/build/tools/read.js.map +1 -0
  34. package/build/tools/scaffold.d.ts +11 -0
  35. package/build/tools/scaffold.d.ts.map +1 -0
  36. package/build/tools/scaffold.js +345 -0
  37. package/build/tools/scaffold.js.map +1 -0
  38. package/build/tools/search.d.ts +11 -0
  39. package/build/tools/search.d.ts.map +1 -0
  40. package/build/tools/search.js +250 -0
  41. package/build/tools/search.js.map +1 -0
  42. package/build/tools/write.d.ts +11 -0
  43. package/build/tools/write.d.ts.map +1 -0
  44. package/build/tools/write.js +538 -0
  45. package/build/tools/write.js.map +1 -0
  46. package/build/types.d.ts +402 -0
  47. package/build/types.d.ts.map +1 -0
  48. package/build/types.js +146 -0
  49. package/build/types.js.map +1 -0
  50. package/build/utils/errors.d.ts +43 -0
  51. package/build/utils/errors.d.ts.map +1 -0
  52. package/build/utils/errors.js +125 -0
  53. package/build/utils/errors.js.map +1 -0
  54. package/build/utils/index.d.ts +10 -0
  55. package/build/utils/index.d.ts.map +1 -0
  56. package/build/utils/index.js +9 -0
  57. package/build/utils/index.js.map +1 -0
  58. package/build/utils/logger.d.ts +88 -0
  59. package/build/utils/logger.d.ts.map +1 -0
  60. package/build/utils/logger.js +166 -0
  61. package/build/utils/logger.js.map +1 -0
  62. package/build/utils/validation.d.ts +43 -0
  63. package/build/utils/validation.d.ts.map +1 -0
  64. package/build/utils/validation.js +196 -0
  65. package/build/utils/validation.js.map +1 -0
  66. package/package.json +1 -1
@@ -0,0 +1,231 @@
1
+ /**
2
+ * MCP File Forge - Sandbox Security Layer
3
+ *
4
+ * Path validation and access control for file operations.
5
+ */
6
+ import * as path from 'node:path';
7
+ import * as fs from 'node:fs/promises';
8
+ import { minimatch } from 'minimatch';
9
+ /**
10
+ * Sandbox manager for validating and controlling file access.
11
+ */
12
+ export class Sandbox {
13
+ config;
14
+ resolvedAllowedPaths = [];
15
+ initialized = false;
16
+ constructor(config = {}) {
17
+ this.config = {
18
+ allowed_paths: config.allowed_paths ?? ['.'],
19
+ denied_paths: config.denied_paths,
20
+ follow_symlinks: config.follow_symlinks ?? false,
21
+ max_file_size: config.max_file_size ?? 104857600, // 100MB
22
+ max_depth: config.max_depth ?? 20,
23
+ };
24
+ }
25
+ /**
26
+ * Initialize the sandbox by resolving all allowed paths to absolute paths.
27
+ */
28
+ async initialize() {
29
+ if (this.initialized)
30
+ return;
31
+ this.resolvedAllowedPaths = await Promise.all(this.config.allowed_paths.map(async (p) => {
32
+ const resolved = path.resolve(p);
33
+ // Verify the path exists
34
+ try {
35
+ await fs.access(resolved);
36
+ return resolved;
37
+ }
38
+ catch {
39
+ // Path doesn't exist yet, but we'll still allow it
40
+ return resolved;
41
+ }
42
+ }));
43
+ this.initialized = true;
44
+ }
45
+ /**
46
+ * Check if a path is within the allowed sandbox paths.
47
+ */
48
+ isPathAllowed(targetPath) {
49
+ const resolved = path.resolve(targetPath);
50
+ const normalized = path.normalize(resolved);
51
+ // Check if path is within any allowed path
52
+ const isWithinAllowed = this.resolvedAllowedPaths.some((allowedPath) => {
53
+ const normalizedAllowed = path.normalize(allowedPath);
54
+ return (normalized === normalizedAllowed ||
55
+ normalized.startsWith(normalizedAllowed + path.sep));
56
+ });
57
+ if (!isWithinAllowed) {
58
+ return false;
59
+ }
60
+ // Check if path matches any denied pattern
61
+ if (this.config.denied_paths) {
62
+ for (const pattern of this.config.denied_paths) {
63
+ if (minimatch(normalized, pattern, { dot: true, nocase: true })) {
64
+ return false;
65
+ }
66
+ // Also check relative path
67
+ const relativePath = path.relative(process.cwd(), normalized);
68
+ if (minimatch(relativePath, pattern, { dot: true, nocase: true })) {
69
+ return false;
70
+ }
71
+ }
72
+ }
73
+ return true;
74
+ }
75
+ /**
76
+ * Validate a path and return error if not allowed.
77
+ */
78
+ async validatePath(targetPath) {
79
+ await this.initialize();
80
+ const resolved = path.resolve(targetPath);
81
+ // Check path traversal attempts
82
+ if (this.hasPathTraversal(targetPath)) {
83
+ return {
84
+ code: 'PATH_OUTSIDE_SANDBOX',
85
+ message: 'Path traversal detected',
86
+ details: {
87
+ path: targetPath,
88
+ },
89
+ };
90
+ }
91
+ // Check if path is allowed
92
+ if (!this.isPathAllowed(resolved)) {
93
+ return {
94
+ code: 'PATH_OUTSIDE_SANDBOX',
95
+ message: `Path is outside allowed directories`,
96
+ details: {
97
+ path: resolved,
98
+ allowed_paths: this.resolvedAllowedPaths,
99
+ },
100
+ };
101
+ }
102
+ // Check symlinks if not allowed
103
+ if (!this.config.follow_symlinks) {
104
+ try {
105
+ const lstat = await fs.lstat(resolved);
106
+ if (lstat.isSymbolicLink()) {
107
+ const realPath = await fs.realpath(resolved);
108
+ if (!this.isPathAllowed(realPath)) {
109
+ return {
110
+ code: 'PATH_OUTSIDE_SANDBOX',
111
+ message: 'Symlink points outside allowed directories',
112
+ details: {
113
+ symlink: resolved,
114
+ target: realPath,
115
+ },
116
+ };
117
+ }
118
+ }
119
+ }
120
+ catch {
121
+ // File doesn't exist yet, which is OK for write operations
122
+ }
123
+ }
124
+ return null;
125
+ }
126
+ /**
127
+ * Check if a path contains traversal attempts.
128
+ */
129
+ hasPathTraversal(targetPath) {
130
+ const normalized = path.normalize(targetPath);
131
+ const parts = normalized.split(path.sep);
132
+ // Check for .. that would escape
133
+ let depth = 0;
134
+ for (const part of parts) {
135
+ if (part === '..') {
136
+ depth--;
137
+ if (depth < 0)
138
+ return true;
139
+ }
140
+ else if (part && part !== '.') {
141
+ depth++;
142
+ }
143
+ }
144
+ return false;
145
+ }
146
+ /**
147
+ * Validate file size against limits.
148
+ */
149
+ validateFileSize(size) {
150
+ if (size > this.config.max_file_size) {
151
+ return {
152
+ code: 'FILE_TOO_LARGE',
153
+ message: `File size ${size} bytes exceeds limit of ${this.config.max_file_size} bytes`,
154
+ details: {
155
+ size,
156
+ limit: this.config.max_file_size,
157
+ },
158
+ };
159
+ }
160
+ return null;
161
+ }
162
+ /**
163
+ * Validate recursion depth.
164
+ */
165
+ validateDepth(depth) {
166
+ if (depth > this.config.max_depth) {
167
+ return {
168
+ code: 'DEPTH_EXCEEDED',
169
+ message: `Recursion depth ${depth} exceeds limit of ${this.config.max_depth}`,
170
+ details: {
171
+ depth,
172
+ limit: this.config.max_depth,
173
+ },
174
+ };
175
+ }
176
+ return null;
177
+ }
178
+ /**
179
+ * Get the current configuration.
180
+ */
181
+ getConfig() {
182
+ return { ...this.config };
183
+ }
184
+ /**
185
+ * Get resolved allowed paths.
186
+ */
187
+ getAllowedPaths() {
188
+ return [...this.resolvedAllowedPaths];
189
+ }
190
+ /**
191
+ * Update configuration at runtime.
192
+ */
193
+ updateConfig(config) {
194
+ if (config.allowed_paths) {
195
+ this.config.allowed_paths = config.allowed_paths;
196
+ this.initialized = false; // Force re-initialization
197
+ }
198
+ if (config.denied_paths !== undefined) {
199
+ this.config.denied_paths = config.denied_paths;
200
+ }
201
+ if (config.follow_symlinks !== undefined) {
202
+ this.config.follow_symlinks = config.follow_symlinks;
203
+ }
204
+ if (config.max_file_size !== undefined) {
205
+ this.config.max_file_size = config.max_file_size;
206
+ }
207
+ if (config.max_depth !== undefined) {
208
+ this.config.max_depth = config.max_depth;
209
+ }
210
+ }
211
+ }
212
+ /**
213
+ * Global sandbox instance.
214
+ */
215
+ let globalSandbox = null;
216
+ /**
217
+ * Get or create the global sandbox instance.
218
+ */
219
+ export function getSandbox(config) {
220
+ if (!globalSandbox) {
221
+ globalSandbox = new Sandbox(config);
222
+ }
223
+ return globalSandbox;
224
+ }
225
+ /**
226
+ * Reset the global sandbox (useful for testing).
227
+ */
228
+ export function resetSandbox() {
229
+ globalSandbox = null;
230
+ }
231
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/security/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * MCP File Forge - Server Implementation
3
+ *
4
+ * Dual-mode MCP server: STDIO (local) or HTTP (deployed).
5
+ * Set PORT env var to enable HTTP mode for remote deployment.
6
+ */
7
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
+ /**
10
+ * Create and configure the MCP server instance.
11
+ */
12
+ export declare function createServer(): McpServer;
13
+ /**
14
+ * Create STDIO transport for local usage.
15
+ */
16
+ export declare function createStdioTransport(): StdioServerTransport;
17
+ /**
18
+ * Create a sandbox server instance for Smithery scanning.
19
+ *
20
+ * This allows Smithery to discover tools/resources without
21
+ * real configuration or credentials. Used during `smithery mcp publish`.
22
+ */
23
+ export declare function createSandboxServer(): McpServer;
24
+ /**
25
+ * Start the MCP server.
26
+ *
27
+ * Mode selection:
28
+ * - PORT env var set → HTTP mode (for Fly.io / remote deployment)
29
+ * - No PORT → STDIO mode (for local Claude Desktop / CLI usage)
30
+ */
31
+ export declare function startServer(): Promise<void>;
32
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAcjF;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAcxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,CAE3D;AAqGD;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA6BjD"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * MCP File Forge - Server Implementation
3
+ *
4
+ * Dual-mode MCP server: STDIO (local) or HTTP (deployed).
5
+ * Set PORT env var to enable HTTP mode for remote deployment.
6
+ */
7
+ import { randomUUID } from 'node:crypto';
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
11
+ import { registerReadTools } from './tools/read.js';
12
+ import { registerWriteTools } from './tools/write.js';
13
+ import { registerSearchTools } from './tools/search.js';
14
+ import { registerMetadataTools } from './tools/metadata.js';
15
+ import { registerScaffoldTools } from './tools/scaffold.js';
16
+ import { loadConfig } from './config/index.js';
17
+ import { getSandbox, enableReadOnlyMode } from './security/index.js';
18
+ // Server metadata
19
+ const SERVER_NAME = 'mcp-file-forge';
20
+ const SERVER_VERSION = '0.2.0';
21
+ /**
22
+ * Create and configure the MCP server instance.
23
+ */
24
+ export function createServer() {
25
+ const server = new McpServer({
26
+ name: SERVER_NAME,
27
+ version: SERVER_VERSION,
28
+ });
29
+ // Register all tools
30
+ registerReadTools(server);
31
+ registerWriteTools(server);
32
+ registerSearchTools(server);
33
+ registerMetadataTools(server);
34
+ registerScaffoldTools(server);
35
+ return server;
36
+ }
37
+ /**
38
+ * Create STDIO transport for local usage.
39
+ */
40
+ export function createStdioTransport() {
41
+ return new StdioServerTransport();
42
+ }
43
+ /**
44
+ * Start the MCP server in STDIO mode (local).
45
+ */
46
+ async function startStdioServer(server) {
47
+ const transport = createStdioTransport();
48
+ console.error(`[${SERVER_NAME}] Transport: stdio`);
49
+ await server.connect(transport);
50
+ console.error(`[${SERVER_NAME}] Server connected and ready (stdio)`);
51
+ }
52
+ /**
53
+ * Start the MCP server in HTTP mode (deployed).
54
+ *
55
+ * Uses StreamableHTTPServerTransport with stateful sessions.
56
+ * Each client gets its own transport + server instance per session.
57
+ */
58
+ async function startHttpServer(_server, port) {
59
+ // Dynamic import to keep express optional for stdio-only usage
60
+ const { default: express } = await import('express');
61
+ const app = express();
62
+ app.use(express.json());
63
+ // Health check for Fly.io / load balancers
64
+ app.get('/health', (_req, res) => {
65
+ res.json({ status: 'ok', server: SERVER_NAME, version: SERVER_VERSION });
66
+ });
67
+ // Session management: map sessionId → transport
68
+ const sessions = new Map();
69
+ // Handle MCP protocol requests (POST /mcp)
70
+ app.post('/mcp', async (req, res) => {
71
+ const sessionId = req.headers['mcp-session-id'];
72
+ let transport;
73
+ if (sessionId && sessions.has(sessionId)) {
74
+ // Existing session
75
+ transport = sessions.get(sessionId);
76
+ }
77
+ else if (!sessionId) {
78
+ // New session — create transport + connect a fresh server
79
+ transport = new StreamableHTTPServerTransport({
80
+ sessionIdGenerator: () => randomUUID(),
81
+ onsessioninitialized: (id) => {
82
+ sessions.set(id, transport);
83
+ console.error(`[${SERVER_NAME}] Session created: ${id}`);
84
+ },
85
+ });
86
+ transport.onclose = () => {
87
+ const sid = transport.sessionId;
88
+ if (sid) {
89
+ sessions.delete(sid);
90
+ console.error(`[${SERVER_NAME}] Session closed: ${sid}`);
91
+ }
92
+ };
93
+ // Each session gets its own server instance with all tools
94
+ const sessionServer = createServer();
95
+ await sessionServer.connect(transport);
96
+ }
97
+ else {
98
+ // Invalid session ID
99
+ res.status(404).json({ error: 'Session not found' });
100
+ return;
101
+ }
102
+ await transport.handleRequest(req, res, req.body);
103
+ });
104
+ // Handle SSE streams (GET /mcp)
105
+ app.get('/mcp', async (req, res) => {
106
+ const sessionId = req.headers['mcp-session-id'];
107
+ if (!sessionId || !sessions.has(sessionId)) {
108
+ res.status(404).json({ error: 'Session not found' });
109
+ return;
110
+ }
111
+ const transport = sessions.get(sessionId);
112
+ await transport.handleRequest(req, res);
113
+ });
114
+ // Handle session termination (DELETE /mcp)
115
+ app.delete('/mcp', async (req, res) => {
116
+ const sessionId = req.headers['mcp-session-id'];
117
+ if (!sessionId || !sessions.has(sessionId)) {
118
+ res.status(404).json({ error: 'Session not found' });
119
+ return;
120
+ }
121
+ const transport = sessions.get(sessionId);
122
+ await transport.handleRequest(req, res);
123
+ });
124
+ app.listen(port, '0.0.0.0', () => {
125
+ console.error(`[${SERVER_NAME}] Transport: HTTP (Streamable)`);
126
+ console.error(`[${SERVER_NAME}] Listening on http://0.0.0.0:${port}/mcp`);
127
+ console.error(`[${SERVER_NAME}] Health check: http://0.0.0.0:${port}/health`);
128
+ });
129
+ }
130
+ /**
131
+ * Create a sandbox server instance for Smithery scanning.
132
+ *
133
+ * This allows Smithery to discover tools/resources without
134
+ * real configuration or credentials. Used during `smithery mcp publish`.
135
+ */
136
+ export function createSandboxServer() {
137
+ return createServer();
138
+ }
139
+ /**
140
+ * Start the MCP server.
141
+ *
142
+ * Mode selection:
143
+ * - PORT env var set → HTTP mode (for Fly.io / remote deployment)
144
+ * - No PORT → STDIO mode (for local Claude Desktop / CLI usage)
145
+ */
146
+ export async function startServer() {
147
+ // Load configuration
148
+ const config = await loadConfig();
149
+ // Initialize sandbox with config
150
+ const sandbox = getSandbox(config.sandbox);
151
+ await sandbox.initialize();
152
+ // Enable read-only mode if configured
153
+ if (config.read_only) {
154
+ enableReadOnlyMode();
155
+ console.error(`[${SERVER_NAME}] Running in read-only mode`);
156
+ }
157
+ // Create server
158
+ const server = createServer();
159
+ // Log to stderr (stdout is reserved for MCP protocol in stdio mode)
160
+ console.error(`[${SERVER_NAME}] Starting server v${SERVER_VERSION}...`);
161
+ console.error(`[${SERVER_NAME}] Allowed paths: ${sandbox.getAllowedPaths().join(', ')}`);
162
+ // Select transport based on PORT env var
163
+ const port = process.env.PORT ? parseInt(process.env.PORT, 10) : undefined;
164
+ if (port) {
165
+ await startHttpServer(server, port);
166
+ }
167
+ else {
168
+ await startStdioServer(server);
169
+ }
170
+ }
171
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MCP File Forge - File Metadata Tools
3
+ *
4
+ * Tools for getting file statistics and checking existence.
5
+ */
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ /**
8
+ * Register file metadata tools with the MCP server.
9
+ */
10
+ export declare function registerMetadataTools(server: McpServer): void;
11
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/tools/metadata.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA+apE;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqD7D"}