kadins-personal-mcp 1.0.0 → 1.0.1
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.
- package/README.md +40 -6
- package/dist/{chunk-T6KZEVGN.js → chunk-IFFK3HCL.js} +4 -1
- package/dist/index.js +8 -22
- package/dist/toolLoader.js +1 -1
- package/package.json +12 -3
- package/tools/fileEdit.ts +71 -0
- package/tools/fileGlob.ts +45 -0
- package/tools/listFiles.ts +63 -0
- package/tools/readManyFiles.ts +57 -0
- package/tools/shellCommand.ts +57 -0
- package/tools/textSearch.ts +61 -0
- package/tools/webFetch.ts +50 -0
- package/tools/writeFile.ts +36 -0
- package/PUBLISHING.md +0 -43
- package/gitignore +0 -7
- package/src/index.ts +0 -63
- package/src/simple.test.ts +0 -9
- package/src/toolLoader.ts +0 -59
- package/tools/calculator.ts +0 -40
- package/tools/currentTime.ts +0 -11
- package/tools/directoryCreate.ts +0 -43
- package/tools/directoryList.ts +0 -70
- package/tools/echo.ts +0 -12
- package/tools/fileCopy.ts +0 -55
- package/tools/fileDelete.ts +0 -48
- package/tools/fileList.ts +0 -88
- package/tools/fileMove.ts +0 -62
- package/tools/filePermissions.ts +0 -50
- package/tools/fileSearch.ts +0 -88
- package/tools/fileWrite.ts +0 -50
- package/tools/readFile.ts +0 -39
- package/tools/runCommand.ts +0 -38
- package/tsconfig.json +0 -12
package/PUBLISHING.md
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Publishing Kadins Personal MCP
|
|
2
|
-
|
|
3
|
-
## Prerequisites
|
|
4
|
-
|
|
5
|
-
1. Make sure you have an npm account at https://www.npmjs.com/
|
|
6
|
-
2. Ensure you're logged in to npm: `npm login`
|
|
7
|
-
|
|
8
|
-
## To Publish
|
|
9
|
-
|
|
10
|
-
1. Update the version in package.json if needed: `npm version patch` (or minor/major)
|
|
11
|
-
2. Run tests to make sure everything works: `npm test`
|
|
12
|
-
3. Build the project: `npm run build`
|
|
13
|
-
4. Publish to npm: `npm publish`
|
|
14
|
-
|
|
15
|
-
## Local Installation for Testing
|
|
16
|
-
|
|
17
|
-
To install locally for testing:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install -g .
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Or to link for development:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm link
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
|
|
31
|
-
After publishing, you can install your package globally:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm install -g kadins-personal-mcp
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
And then run it:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
kadins-personal-mcp
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
The server will start and be available for MCP-compatible clients.
|
package/gitignore
DELETED
package/src/index.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { loadTools } from "./toolLoader.js";
|
|
7
|
-
|
|
8
|
-
const packageJson = require("../package.json") as any;
|
|
9
|
-
|
|
10
|
-
// Create a new MCP server
|
|
11
|
-
const server = new McpServer(
|
|
12
|
-
{
|
|
13
|
-
name: packageJson.name,
|
|
14
|
-
version: packageJson.version,
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
instructions:
|
|
18
|
-
"These tools communicate with a reference Model Context Protocol (MCP) server.",
|
|
19
|
-
}
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
// Implement the ping_pong tool
|
|
23
|
-
server.tool(
|
|
24
|
-
"ping_pong",
|
|
25
|
-
"Ping the server and receive a pong back",
|
|
26
|
-
{},
|
|
27
|
-
async () => {
|
|
28
|
-
return {
|
|
29
|
-
content: [{ type: "text", text: "pong" }],
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Implement the echo tool
|
|
35
|
-
server.tool(
|
|
36
|
-
"echo",
|
|
37
|
-
"Send a message to the server and receive the message back",
|
|
38
|
-
{ message: z.string() },
|
|
39
|
-
async (params) => {
|
|
40
|
-
return {
|
|
41
|
-
content: [{ type: "text", text: params.message }],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
// Start the server
|
|
47
|
-
async function run() {
|
|
48
|
-
try {
|
|
49
|
-
// Load tools from the tools directory
|
|
50
|
-
await loadTools(server);
|
|
51
|
-
|
|
52
|
-
// Use stdio for transport
|
|
53
|
-
const transport = new StdioServerTransport();
|
|
54
|
-
await server.connect(transport);
|
|
55
|
-
// Since stdout is used for MCP messages, use stderr for logging
|
|
56
|
-
console.error("MCP server connected via stdio");
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error("Error starting MCP server:", error);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
run();
|
package/src/simple.test.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { test } from '@jest/globals';
|
|
2
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
|
|
4
|
-
// Simple test to verify the tool loader can be imported without errors
|
|
5
|
-
test('toolLoader can be imported', async () => {
|
|
6
|
-
// We'll just check that the module can be imported without errors
|
|
7
|
-
// Since the actual loading depends on the file system, we'll do a basic import test
|
|
8
|
-
expect(typeof (await import('./toolLoader.js'))).toBe('object');
|
|
9
|
-
});
|
package/src/toolLoader.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
-
|
|
5
|
-
// Define the interface for tool files
|
|
6
|
-
interface ToolDefinition {
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
parameters: Record<string, any>;
|
|
10
|
-
handler: (params: any) => Promise<any>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Validates that a loaded module has the required tool properties
|
|
14
|
-
function isValidTool(module: any): module is ToolDefinition {
|
|
15
|
-
return (
|
|
16
|
-
typeof module.name === 'string' &&
|
|
17
|
-
typeof module.description === 'string' &&
|
|
18
|
-
typeof module.parameters === 'object' &&
|
|
19
|
-
typeof module.handler === 'function'
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Load and register all tools from the tools directory
|
|
24
|
-
export async function loadTools(server: McpServer) {
|
|
25
|
-
const toolsDir = path.join(process.cwd(), 'tools');
|
|
26
|
-
|
|
27
|
-
if (!fs.existsSync(toolsDir)) {
|
|
28
|
-
console.error(`Tools directory does not exist: ${toolsDir}`);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const files = fs.readdirSync(toolsDir);
|
|
33
|
-
|
|
34
|
-
for (const file of files) {
|
|
35
|
-
if (file.endsWith('.ts') || file.endsWith('.js')) {
|
|
36
|
-
try {
|
|
37
|
-
// Use dynamic import to load the tool file
|
|
38
|
-
const modulePath = path.join(toolsDir, file);
|
|
39
|
-
const module = await import(modulePath);
|
|
40
|
-
|
|
41
|
-
if (isValidTool(module)) {
|
|
42
|
-
// Register the tool with the MCP server
|
|
43
|
-
server.tool(
|
|
44
|
-
module.name,
|
|
45
|
-
module.description,
|
|
46
|
-
module.parameters,
|
|
47
|
-
module.handler
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
console.error(`Registered tool: ${module.name}`);
|
|
51
|
-
} else {
|
|
52
|
-
console.error(`Invalid tool format in file: ${file}. Required exports: name, description, parameters, handler`);
|
|
53
|
-
}
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error(`Error loading tool from file ${file}:`, error);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
package/tools/calculator.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "calculator";
|
|
4
|
-
export const description = "Perform basic mathematical calculations";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
operation: z.enum(["add", "subtract", "multiply", "divide"]).describe("The mathematical operation to perform"),
|
|
7
|
-
a: z.number().describe("The first operand"),
|
|
8
|
-
b: z.number().describe("The second operand")
|
|
9
|
-
};
|
|
10
|
-
export const handler = async (params: { operation: string; a: number; b: number }) => {
|
|
11
|
-
let result: number;
|
|
12
|
-
|
|
13
|
-
switch (params.operation) {
|
|
14
|
-
case "add":
|
|
15
|
-
result = params.a + params.b;
|
|
16
|
-
break;
|
|
17
|
-
case "subtract":
|
|
18
|
-
result = params.a - params.b;
|
|
19
|
-
break;
|
|
20
|
-
case "multiply":
|
|
21
|
-
result = params.a * params.b;
|
|
22
|
-
break;
|
|
23
|
-
case "divide":
|
|
24
|
-
if (params.b === 0) {
|
|
25
|
-
return {
|
|
26
|
-
content: [{ type: "text", text: "Error: Division by zero is not allowed" }]
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
result = params.a / params.b;
|
|
30
|
-
break;
|
|
31
|
-
default:
|
|
32
|
-
return {
|
|
33
|
-
content: [{ type: "text", text: `Error: Unknown operation ${params.operation}` }]
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
content: [{ type: "text", text: `Result: ${params.a} ${params.operation} ${params.b} = ${result}` }]
|
|
39
|
-
};
|
|
40
|
-
};
|
package/tools/currentTime.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "get_current_time";
|
|
4
|
-
export const description = "Get the current date and time";
|
|
5
|
-
export const parameters = {};
|
|
6
|
-
export const handler = async () => {
|
|
7
|
-
const now = new Date();
|
|
8
|
-
return {
|
|
9
|
-
content: [{ type: "text", text: `Current date and time: ${now.toString()}` }]
|
|
10
|
-
};
|
|
11
|
-
};
|
package/tools/directoryCreate.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "directory_create";
|
|
4
|
-
export const description = "Create a new directory";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
path: z.string().describe("The path to the directory to create"),
|
|
7
|
-
recursive: z.boolean().describe("Whether to create parent directories if they don't exist").optional().default(true)
|
|
8
|
-
};
|
|
9
|
-
export const handler = async (params: { path: string; recursive: boolean }) => {
|
|
10
|
-
try {
|
|
11
|
-
const fs = await import("fs");
|
|
12
|
-
const path = await import("path");
|
|
13
|
-
|
|
14
|
-
// Resolve the path relative to the current working directory
|
|
15
|
-
const resolvedPath = path.resolve(params.path);
|
|
16
|
-
|
|
17
|
-
// Check if the path is within the current working directory to prevent path traversal
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
if (!resolvedPath.startsWith(cwd)) {
|
|
20
|
-
return {
|
|
21
|
-
content: [{ type: "text", text: "Error: Path traversal is not allowed" }]
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Check if directory already exists
|
|
26
|
-
if (fs.existsSync(resolvedPath)) {
|
|
27
|
-
return {
|
|
28
|
-
content: [{ type: "text", text: `Error: Directory already exists: ${params.path}` }]
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Create the directory
|
|
33
|
-
fs.mkdirSync(resolvedPath, { recursive: params.recursive });
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
content: [{ type: "text", text: `Successfully created directory: ${params.path}` }]
|
|
37
|
-
};
|
|
38
|
-
} catch (error) {
|
|
39
|
-
return {
|
|
40
|
-
content: [{ type: "text", text: `Error creating directory: ${(error as Error).message}` }]
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
};
|
package/tools/directoryList.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "directory_list";
|
|
4
|
-
export const description = "List directory contents with details (size, type, etc.)";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
directory: z.string().describe("The directory to list").optional().default("."),
|
|
7
|
-
showHidden: z.boolean().describe("Whether to show hidden files/directories").optional().default(false)
|
|
8
|
-
};
|
|
9
|
-
export const handler = async (params: { directory: string; showHidden?: boolean }) => {
|
|
10
|
-
try {
|
|
11
|
-
const fs = await import("fs");
|
|
12
|
-
const path = await import("path");
|
|
13
|
-
|
|
14
|
-
const searchDir = params.directory || ".";
|
|
15
|
-
const resolvedDir = path.resolve(searchDir);
|
|
16
|
-
|
|
17
|
-
// Check if the directory is within the current working directory to prevent path traversal
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
if (!resolvedDir.startsWith(cwd)) {
|
|
20
|
-
return {
|
|
21
|
-
content: [{ type: "text", text: "Error: Directory traversal is not allowed" }]
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!fs.existsSync(resolvedDir)) {
|
|
26
|
-
return {
|
|
27
|
-
content: [{ type: "text", text: `Error: Directory does not exist: ${resolvedDir}` }]
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!fs.statSync(resolvedDir).isDirectory()) {
|
|
32
|
-
return {
|
|
33
|
-
content: [{ type: "text", text: `Error: Path is not a directory: ${resolvedDir}` }]
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const items = fs.readdirSync(resolvedDir);
|
|
38
|
-
const results: string[] = [];
|
|
39
|
-
|
|
40
|
-
for (const item of items) {
|
|
41
|
-
// Skip hidden files if showHidden is false
|
|
42
|
-
if (!params.showHidden && item.startsWith('.')) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const itemPath = path.join(resolvedDir, item);
|
|
47
|
-
const stat = fs.statSync(itemPath);
|
|
48
|
-
|
|
49
|
-
let type = stat.isDirectory() ? "DIR" : "FILE";
|
|
50
|
-
let size = stat.isDirectory() ? "-" : `${stat.size} bytes`;
|
|
51
|
-
let permissions = stat.mode.toString(8).slice(-3);
|
|
52
|
-
|
|
53
|
-
results.push(`${type} ${permissions} ${size} ${item}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (results.length === 0) {
|
|
57
|
-
return {
|
|
58
|
-
content: [{ type: "text", text: `Directory is empty: ${params.directory || "."}` }]
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
content: [{ type: "text", text: `Contents of ${params.directory || "."}:\n${results.join("\n")}` }]
|
|
64
|
-
};
|
|
65
|
-
} catch (error) {
|
|
66
|
-
return {
|
|
67
|
-
content: [{ type: "text", text: `Error listing directory: ${(error as Error).message}` }]
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
};
|
package/tools/echo.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_echo";
|
|
4
|
-
export const description = "Send a message to the server and receive the message back (file-based tool)";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
message: z.string().describe("The message to echo back")
|
|
7
|
-
};
|
|
8
|
-
export const handler = async (params: { message: string }) => {
|
|
9
|
-
return {
|
|
10
|
-
content: [{ type: "text", text: params.message }]
|
|
11
|
-
};
|
|
12
|
-
};
|
package/tools/fileCopy.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_copy";
|
|
4
|
-
export const description = "Copy a file from one location to another";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
source: z.string().describe("The path to the source file"),
|
|
7
|
-
destination: z.string().describe("The path to the destination file")
|
|
8
|
-
};
|
|
9
|
-
export const handler = async (params: { source: string; destination: string }) => {
|
|
10
|
-
try {
|
|
11
|
-
const fs = await import("fs");
|
|
12
|
-
const path = await import("path");
|
|
13
|
-
|
|
14
|
-
// Resolve paths relative to the current working directory
|
|
15
|
-
const resolvedSource = path.resolve(params.source);
|
|
16
|
-
const resolvedDestination = path.resolve(params.destination);
|
|
17
|
-
|
|
18
|
-
// Check if paths are within the current working directory to prevent path traversal
|
|
19
|
-
const cwd = process.cwd();
|
|
20
|
-
if (!resolvedSource.startsWith(cwd) || !resolvedDestination.startsWith(cwd)) {
|
|
21
|
-
return {
|
|
22
|
-
content: [{ type: "text", text: "Error: Path traversal is not allowed" }]
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!fs.existsSync(resolvedSource)) {
|
|
27
|
-
return {
|
|
28
|
-
content: [{ type: "text", text: `Error: Source file does not exist: ${params.source}` }]
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (fs.statSync(resolvedSource).isDirectory()) {
|
|
33
|
-
return {
|
|
34
|
-
content: [{ type: "text", text: `Error: Source path is a directory, not a file: ${params.source}` }]
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Create destination directory if it doesn't exist
|
|
39
|
-
const destDir = path.dirname(resolvedDestination);
|
|
40
|
-
if (!fs.existsSync(destDir)) {
|
|
41
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Copy the file
|
|
45
|
-
fs.copyFileSync(resolvedSource, resolvedDestination);
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
content: [{ type: "text", text: `Successfully copied file from ${params.source} to ${params.destination}` }]
|
|
49
|
-
};
|
|
50
|
-
} catch (error) {
|
|
51
|
-
return {
|
|
52
|
-
content: [{ type: "text", text: `Error copying file: ${(error as Error).message}` }]
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
};
|
package/tools/fileDelete.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_delete";
|
|
4
|
-
export const description = "Delete a specified file";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
path: z.string().describe("The path to the file to delete")
|
|
7
|
-
};
|
|
8
|
-
export const handler = async (params: { path: string }) => {
|
|
9
|
-
try {
|
|
10
|
-
const fs = await import("fs");
|
|
11
|
-
const path = await import("path");
|
|
12
|
-
|
|
13
|
-
// Resolve the path relative to the current working directory
|
|
14
|
-
const resolvedPath = path.resolve(params.path);
|
|
15
|
-
|
|
16
|
-
// Check if the path is within the current working directory to prevent path traversal
|
|
17
|
-
const cwd = process.cwd();
|
|
18
|
-
if (!resolvedPath.startsWith(cwd)) {
|
|
19
|
-
return {
|
|
20
|
-
content: [{ type: "text", text: "Error: Path traversal is not allowed" }]
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
25
|
-
return {
|
|
26
|
-
content: [{ type: "text", text: `Error: File does not exist: ${params.path}` }]
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const stat = fs.statSync(resolvedPath);
|
|
31
|
-
if (stat.isDirectory()) {
|
|
32
|
-
return {
|
|
33
|
-
content: [{ type: "text", text: `Error: Path is a directory, not a file: ${params.path}` }]
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Delete the file
|
|
38
|
-
fs.unlinkSync(resolvedPath);
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
content: [{ type: "text", text: `Successfully deleted file: ${params.path}` }]
|
|
42
|
-
};
|
|
43
|
-
} catch (error) {
|
|
44
|
-
return {
|
|
45
|
-
content: [{ type: "text", text: `Error deleting file: ${(error as Error).message}` }]
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
};
|
package/tools/fileList.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_list";
|
|
4
|
-
export const description = "List files in a directory with optional filtering";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
directory: z.string().describe("The directory to list").optional().default("."),
|
|
7
|
-
filter: z.string().describe("Optional filter pattern to match files").optional(),
|
|
8
|
-
recursive: z.boolean().describe("Whether to list files recursively").optional().default(false)
|
|
9
|
-
};
|
|
10
|
-
export const handler = async (params: { directory: string; filter?: string; recursive?: boolean }) => {
|
|
11
|
-
try {
|
|
12
|
-
const fs = await import("fs");
|
|
13
|
-
const path = await import("path");
|
|
14
|
-
|
|
15
|
-
const searchDir = params.directory || ".";
|
|
16
|
-
const resolvedDir = path.resolve(searchDir);
|
|
17
|
-
|
|
18
|
-
// Check if the directory is within the current working directory to prevent path traversal
|
|
19
|
-
const cwd = process.cwd();
|
|
20
|
-
if (!resolvedDir.startsWith(cwd)) {
|
|
21
|
-
return {
|
|
22
|
-
content: [{ type: "text", text: "Error: Directory traversal is not allowed" }]
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!fs.existsSync(resolvedDir)) {
|
|
27
|
-
return {
|
|
28
|
-
content: [{ type: "text", text: `Error: Directory does not exist: ${resolvedDir}` }]
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!fs.statSync(resolvedDir).isDirectory()) {
|
|
33
|
-
return {
|
|
34
|
-
content: [{ type: "text", text: `Error: Path is not a directory: ${resolvedDir}` }]
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const results: string[] = [];
|
|
39
|
-
|
|
40
|
-
function listDirectory(dir: string, isRoot: boolean = true) {
|
|
41
|
-
const items = fs.readdirSync(dir);
|
|
42
|
-
|
|
43
|
-
for (const item of items) {
|
|
44
|
-
const itemPath = path.join(dir, item);
|
|
45
|
-
const relativePath = path.relative(resolvedDir, itemPath);
|
|
46
|
-
|
|
47
|
-
// Apply filter if provided
|
|
48
|
-
if (params.filter && !item.includes(params.filter)) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Skip node_modules and other common directories when not in recursive mode
|
|
53
|
-
if (!params.recursive && !isRoot && (item === "node_modules" || item.startsWith("."))) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const stat = fs.statSync(itemPath);
|
|
58
|
-
|
|
59
|
-
if (stat.isDirectory()) {
|
|
60
|
-
if (params.recursive && item !== "node_modules" && !item.startsWith(".")) {
|
|
61
|
-
results.push(`${relativePath}/ (directory)`);
|
|
62
|
-
listDirectory(itemPath, false);
|
|
63
|
-
} else if (!params.recursive) {
|
|
64
|
-
results.push(`${relativePath}/ (directory)`);
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
results.push(`${relativePath} (${stat.size} bytes)`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
listDirectory(resolvedDir);
|
|
73
|
-
|
|
74
|
-
if (results.length === 0) {
|
|
75
|
-
return {
|
|
76
|
-
content: [{ type: "text", text: `No files found in directory: ${resolvedDir}` }]
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
content: [{ type: "text", text: `Files in ${params.directory || "."}:\n${results.join("\n")}` }]
|
|
82
|
-
};
|
|
83
|
-
} catch (error) {
|
|
84
|
-
return {
|
|
85
|
-
content: [{ type: "text", text: `Error listing files: ${(error as Error).message}` }]
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
};
|
package/tools/fileMove.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_move";
|
|
4
|
-
export const description = "Move/rename a file";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
source: z.string().describe("The path to the source file"),
|
|
7
|
-
destination: z.string().describe("The path to the destination file")
|
|
8
|
-
};
|
|
9
|
-
export const handler = async (params: { source: string; destination: string }) => {
|
|
10
|
-
try {
|
|
11
|
-
const fs = await import("fs");
|
|
12
|
-
const path = await import("path");
|
|
13
|
-
|
|
14
|
-
// Resolve paths relative to the current working directory
|
|
15
|
-
const resolvedSource = path.resolve(params.source);
|
|
16
|
-
const resolvedDestination = path.resolve(params.destination);
|
|
17
|
-
|
|
18
|
-
// Check if paths are within the current working directory to prevent path traversal
|
|
19
|
-
const cwd = process.cwd();
|
|
20
|
-
if (!resolvedSource.startsWith(cwd) || !resolvedDestination.startsWith(cwd)) {
|
|
21
|
-
return {
|
|
22
|
-
content: [{ type: "text", text: "Error: Path traversal is not allowed" }]
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!fs.existsSync(resolvedSource)) {
|
|
27
|
-
return {
|
|
28
|
-
content: [{ type: "text", text: `Error: Source file does not exist: ${params.source}` }]
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (fs.statSync(resolvedSource).isDirectory()) {
|
|
33
|
-
return {
|
|
34
|
-
content: [{ type: "text", text: `Error: Source path is a directory, not a file: ${params.source}` }]
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Check if destination already exists
|
|
39
|
-
if (fs.existsSync(resolvedDestination)) {
|
|
40
|
-
return {
|
|
41
|
-
content: [{ type: "text", text: `Error: Destination file already exists: ${params.destination}` }]
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Create destination directory if it doesn't exist
|
|
46
|
-
const destDir = path.dirname(resolvedDestination);
|
|
47
|
-
if (!fs.existsSync(destDir)) {
|
|
48
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Move the file (rename it)
|
|
52
|
-
fs.renameSync(resolvedSource, resolvedDestination);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
content: [{ type: "text", text: `Successfully moved file from ${params.source} to ${params.destination}` }]
|
|
56
|
-
};
|
|
57
|
-
} catch (error) {
|
|
58
|
-
return {
|
|
59
|
-
content: [{ type: "text", text: `Error moving file: ${(error as Error).message}` }]
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
};
|
package/tools/filePermissions.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const name = "file_permissions";
|
|
4
|
-
export const description = "Change file permissions";
|
|
5
|
-
export const parameters = {
|
|
6
|
-
path: z.string().describe("The path to the file"),
|
|
7
|
-
permissions: z.string().describe("The new permissions in octal format (e.g., '755', '644')")
|
|
8
|
-
};
|
|
9
|
-
export const handler = async (params: { path: string; permissions: string }) => {
|
|
10
|
-
try {
|
|
11
|
-
const fs = await import("fs");
|
|
12
|
-
const path = await import("path");
|
|
13
|
-
|
|
14
|
-
// Resolve the path relative to the current working directory
|
|
15
|
-
const resolvedPath = path.resolve(params.path);
|
|
16
|
-
|
|
17
|
-
// Check if the path is within the current working directory to prevent path traversal
|
|
18
|
-
const cwd = process.cwd();
|
|
19
|
-
if (!resolvedPath.startsWith(cwd)) {
|
|
20
|
-
return {
|
|
21
|
-
content: [{ type: "text", text: "Error: Path traversal is not allowed" }]
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
26
|
-
return {
|
|
27
|
-
content: [{ type: "text", text: `Error: File does not exist: ${params.path}` }]
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Validate permissions format (should be 3 or 4 digits)
|
|
32
|
-
if (!/^[0-7]{3,4}$/.test(params.permissions)) {
|
|
33
|
-
return {
|
|
34
|
-
content: [{ type: "text", text: `Error: Invalid permissions format. Use octal format like '755' or '644'.` }]
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Change file permissions
|
|
39
|
-
const permissionsNum = parseInt(params.permissions, 8);
|
|
40
|
-
fs.chmodSync(resolvedPath, permissionsNum);
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
content: [{ type: "text", text: `Successfully changed permissions of ${params.path} to ${params.permissions}` }]
|
|
44
|
-
};
|
|
45
|
-
} catch (error) {
|
|
46
|
-
return {
|
|
47
|
-
content: [{ type: "text", text: `Error changing permissions: ${(error as Error).message}` }]
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
};
|