Skip to main content
Glama

MCP File Editor Server

by pwilkin
create_file.test.ts9.22 kB
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import * as fs from 'fs'; import * as path from 'path'; import { TEST_DIR, client } from './setup.js'; describe('create_file tool', () => { // Test files that will be created during tests const testFiles = { simple: path.join(TEST_DIR, 'test-simple.txt'), nested: path.join(TEST_DIR, 'nested', 'deep', 'test-nested.txt'), existing: path.join(TEST_DIR, 'test-existing.txt'), empty: path.join(TEST_DIR, 'test-empty.txt'), specialChars: path.join(TEST_DIR, 'test-special-chars.txt') }; // Clean up any test files before and after each test beforeEach(() => { // Remove any test files that might exist from previous failed tests Object.values(testFiles).forEach(filePath => { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } }); // Remove nested directory structure const nestedDir = path.dirname(testFiles.nested); if (fs.existsSync(nestedDir)) { fs.rmSync(nestedDir, { recursive: true, force: true }); } }); afterEach(() => { // Clean up test files after each test Object.values(testFiles).forEach(filePath => { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } }); // Remove nested directory structure const nestedDir = path.dirname(testFiles.nested); if (fs.existsSync(nestedDir)) { fs.rmSync(nestedDir, { recursive: true, force: true }); } }); describe('Success cases', () => { it('should create a new file with specified content', async () => { const content = 'Hello, World!\nThis is a test file.'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.simple, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created with correct content expect(fs.existsSync(testFiles.simple)).toBe(true); const fileContent = fs.readFileSync(testFiles.simple, 'utf-8'); expect(fileContent).toBe(content); }); it('should create nested directories and file', async () => { const content = 'File in nested directory'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.nested, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created expect(fs.existsSync(testFiles.nested)).toBe(true); const fileContent = fs.readFileSync(testFiles.nested, 'utf-8'); expect(fileContent).toBe(content); // Verify the nested directory structure was created const nestedDir = path.dirname(testFiles.nested); expect(fs.existsSync(nestedDir)).toBe(true); }); it('should create an empty file', async () => { const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.empty, contents: '' } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created and is empty expect(fs.existsSync(testFiles.empty)).toBe(true); const fileContent = fs.readFileSync(testFiles.empty, 'utf-8'); expect(fileContent).toBe(''); }); it('should create file with special characters and unicode', async () => { const content = 'Special chars: !@#$%^&*()\nUnicode: café résumé naïve 🚀\nNewlines\nand\ttabs'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.specialChars, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created with correct content expect(fs.existsSync(testFiles.specialChars)).toBe(true); const fileContent = fs.readFileSync(testFiles.specialChars, 'utf-8'); expect(fileContent).toBe(content); }); it('should handle relative paths correctly', async () => { const relativePath = path.relative(process.cwd(), testFiles.simple); const content = 'File created with relative path'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: relativePath, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created expect(fs.existsSync(testFiles.simple)).toBe(true); const fileContent = fs.readFileSync(testFiles.simple, 'utf-8'); expect(fileContent).toBe(content); }); }); describe('Error cases', () => { it('should fail when file already exists', async () => { // Create a file first fs.writeFileSync(testFiles.existing, 'Existing content'); const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.existing, contents: 'New content' } }); expect(result.isError).toBe(true); expect((result.content as any)[0].text).toMatch(/File already exists/); expect((result.content as any)[0].text).toMatch(/does not overwrite existing files/); // Verify the original file content was not changed const originalContent = fs.readFileSync(testFiles.existing, 'utf-8'); expect(originalContent).toBe('Existing content'); }); it('should fail when a directory exists at the target path', async () => { // Create a directory at the target path fs.mkdirSync(testFiles.existing, { recursive: true }); const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.existing, contents: 'Content' } }); expect(result.isError).toBe(true); expect((result.content as any)[0].text).toMatch(/A directory already exists/); expect((result.content as any)[0].text).toMatch(/Cannot create a file at this location/); }); it('should reject relative paths that go outside the project', async () => { const result = await client.callTool({ name: 'create_file', arguments: { file_path: '../../../etc/passwd', contents: 'Should not work' } }); expect(result.isError).toBe(true); expect((result.content as any)[0].text).toMatch(/must be an absolute path/); }); }); describe('Edge cases', () => { it('should handle very long file paths', async () => { const longPath = path.join(TEST_DIR, 'a'.repeat(100), 'b'.repeat(100), 'c'.repeat(50) + '.txt'); const content = 'File with long path'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: longPath, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created expect(fs.existsSync(longPath)).toBe(true); const fileContent = fs.readFileSync(longPath, 'utf-8'); expect(fileContent).toBe(content); // Clean up the long path structure const longDir = path.dirname(longPath); fs.rmSync(path.dirname(longDir), { recursive: true, force: true }); }); it('should handle file with only newlines', async () => { const content = '\n\n\n\n'; const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.simple, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created with correct content expect(fs.existsSync(testFiles.simple)).toBe(true); const fileContent = fs.readFileSync(testFiles.simple, 'utf-8'); expect(fileContent).toBe(content); }); it('should handle file with whitespace only', async () => { const content = ' \t\t \n \t\t '; const result = await client.callTool({ name: 'create_file', arguments: { file_path: testFiles.simple, contents: content } }); expect(result.isError).toBe(false); expect((result.content as any)[0].text).toMatch(/Successfully created file/); // Verify the file was created with correct content expect(fs.existsSync(testFiles.simple)).toBe(true); const fileContent = fs.readFileSync(testFiles.simple, 'utf-8'); expect(fileContent).toBe(content); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pwilkin/mcp-file-edit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server