|
8 | 8 | } from "@modelcontextprotocol/sdk/types.js"; |
9 | 9 | import { randomBytes } from 'crypto'; |
10 | 10 | import { join } from 'path'; |
11 | | -import { mkdir, writeFile, appendFile, readFile, access, unlink } from 'fs/promises'; |
| 11 | +import { mkdir, writeFile, appendFile, readFile, access, unlink, readdir } from 'fs/promises'; |
12 | 12 | import { exec, ExecOptions } from 'child_process'; |
13 | 13 | import { promisify } from 'util'; |
14 | 14 | import { platform } from 'os'; |
@@ -323,6 +323,37 @@ async function readCodeFile(filePath: string) { |
323 | 323 | } |
324 | 324 | } |
325 | 325 |
|
| 326 | +/** |
| 327 | + * List files in the code storage directory (non-recursive). |
| 328 | + */ |
| 329 | +async function listCodeFiles() { |
| 330 | + try { |
| 331 | + const files = await readdir(CODE_STORAGE_DIR, { withFileTypes: false }); |
| 332 | + return makeResponse({ status: 'success', files }, false); |
| 333 | + } catch (error) { |
| 334 | + return makeResponse({ status: 'error', error: error instanceof Error ? error.message : String(error) }, true); |
| 335 | + } |
| 336 | +} |
| 337 | + |
| 338 | +/** |
| 339 | + * Delete a code file (best-effort, checks path) |
| 340 | + */ |
| 341 | +async function deleteCodeFile(filePath: string) { |
| 342 | + try { |
| 343 | + // Only allow deletion of files inside CODE_STORAGE_DIR for safety |
| 344 | + if (!filePath.startsWith(CODE_STORAGE_DIR)) { |
| 345 | + return makeResponse({ status: 'error', error: 'file_path must be inside CODE_STORAGE_DIR' }, true); |
| 346 | + } |
| 347 | + |
| 348 | + await access(filePath); |
| 349 | + await unlink(filePath); |
| 350 | + |
| 351 | + return makeResponse({ status: 'success', message: 'File deleted', file_path: filePath }, false); |
| 352 | + } catch (error) { |
| 353 | + return makeResponse({ status: 'error', error: error instanceof Error ? error.message : String(error), file_path: filePath }, true); |
| 354 | + } |
| 355 | +} |
| 356 | + |
326 | 357 | /** |
327 | 358 | * Install dependencies using the appropriate package manager |
328 | 359 | */ |
@@ -631,6 +662,28 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { |
631 | 662 | required: ["file_path"] |
632 | 663 | } |
633 | 664 | }, |
| 665 | + { |
| 666 | + name: "list_code_files", |
| 667 | + description: "List files in the code storage directory", |
| 668 | + inputSchema: { |
| 669 | + type: "object", |
| 670 | + properties: {} |
| 671 | + } |
| 672 | + }, |
| 673 | + { |
| 674 | + name: "delete_code_file", |
| 675 | + description: "Delete a code file from the storage directory (must be inside CODE_STORAGE_DIR)", |
| 676 | + inputSchema: { |
| 677 | + type: "object", |
| 678 | + properties: { |
| 679 | + file_path: { |
| 680 | + type: "string", |
| 681 | + description: "Full path to the file to delete" |
| 682 | + } |
| 683 | + }, |
| 684 | + required: ["file_path"] |
| 685 | + } |
| 686 | + }, |
634 | 687 |
|
635 | 688 | { |
636 | 689 | name: "install_dependencies", |
@@ -874,6 +927,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { |
874 | 927 | }] |
875 | 928 | }; |
876 | 929 | } |
| 930 | + |
| 931 | + case "list_code_files": { |
| 932 | + const result = await listCodeFiles(); |
| 933 | + return { |
| 934 | + content: [{ type: 'text', text: result.text, isError: result.isError }] |
| 935 | + }; |
| 936 | + } |
| 937 | + |
| 938 | + case "delete_code_file": { |
| 939 | + const args = request.params.arguments as { file_path?: string }; |
| 940 | + if (!args?.file_path) { |
| 941 | + throw new Error("File path is required"); |
| 942 | + } |
| 943 | + |
| 944 | + const result = await deleteCodeFile(args.file_path); |
| 945 | + return { |
| 946 | + content: [{ type: 'text', text: result.text, isError: result.isError }] |
| 947 | + }; |
| 948 | + } |
877 | 949 |
|
878 | 950 | case "install_dependencies": { |
879 | 951 | const args = request.params.arguments as InstallDependenciesArgs; |
|
0 commit comments