ftp-mcp 1.3.0 → 1.3.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 +2 -1
- package/index.js +142 -96
- package/package.json +122 -122
package/README.md
CHANGED
|
@@ -9,7 +9,8 @@ An enterprise-grade Model Context Protocol (MCP) server providing sophisticated
|
|
|
9
9
|
- **Security & Authorization**: Native support for SSH Key exchanges (both direct and Agent-forwarding), Pass-phrase authentication, and explicit `readOnly: true` config profiling to sandbox dangerous modifications.
|
|
10
10
|
- **Smart Directory Syncing**: Deep hash-and-size sync algorithms for minimal network payload deployments, complete with `--dryRun` toggling that logs differences back to the LLM without modifying live directories.
|
|
11
11
|
- **Git & Node Aware**: Automatically unpacks `.gitignore` and `.ftpignore` environments. Semantically evaluates `package.json` for smart context summarization.
|
|
12
|
-
- **
|
|
12
|
+
- **AI-Guided Initialization**: A dedicated "AI-First" configuration track (`--init`) that provides highly verbose instruction context during setup, ensuring AI assistants absorb server capabilities and operational constraints directly into their working memory.
|
|
13
|
+
- **Interactive Initializer**: Simple scaffolding of configurations natively via the CLI for human users.
|
|
13
14
|
- **Audit Logging**: Robust instrumentation generating structured `.ftp-mcp-audit.log` traces on all filesystem mutations.
|
|
14
15
|
- **Comprehensive E2E Testing**: Guaranteed operational functionality validated continuously by Node-based MCP IO test orchestration.
|
|
15
16
|
|
package/index.js
CHANGED
|
@@ -26,7 +26,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
26
26
|
const __dirname = path.dirname(__filename);
|
|
27
27
|
|
|
28
28
|
// Read version from package.json to avoid version drift (CODE-1)
|
|
29
|
-
let SERVER_VERSION = "1.3.
|
|
29
|
+
let SERVER_VERSION = "1.3.1";
|
|
30
30
|
try {
|
|
31
31
|
const pkg = JSON.parse(readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
|
32
32
|
SERVER_VERSION = pkg.version || SERVER_VERSION;
|
|
@@ -42,27 +42,50 @@ if (process.argv.includes("--init")) {
|
|
|
42
42
|
|
|
43
43
|
intro('🚀 Welcome to FTP-MCP Initialization Wizard');
|
|
44
44
|
|
|
45
|
+
const setupType = await select({
|
|
46
|
+
message: 'Who is running this setup wizard?',
|
|
47
|
+
options: [
|
|
48
|
+
{ value: 'ai', label: '1. AI Agent Install (Provides verbose context on how to use the server)', hint: 'Detailed instructions for LLMs' },
|
|
49
|
+
{ value: 'human', label: '2. Human Install (Standard Setup)', hint: 'Concise standard setup for human users' }
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
if (isCancel(setupType)) { outro('Setup cancelled.'); process.exit(0); }
|
|
53
|
+
|
|
54
|
+
const isAI = setupType === 'ai';
|
|
55
|
+
|
|
45
56
|
const host = await text({
|
|
46
|
-
message:
|
|
57
|
+
message: isAI
|
|
58
|
+
? '[AI INSTRUCTION] Provide the remote FTP/SFTP Host address. (e.g. sftp://ftp.example.com or ftp://1.2.3.4). Note: This tool brokers remote filesystem access as an MCP server.'
|
|
59
|
+
: 'Enter your FTP/SFTP Host (e.g. sftp://ftp.example.com)',
|
|
47
60
|
placeholder: 'sftp://127.0.0.1',
|
|
48
|
-
validate: (val) => val.length === 0 ? "Host is required!" : undefined,
|
|
61
|
+
validate: (val) => (!val || val.length === 0) ? "Host is required!" : undefined,
|
|
49
62
|
});
|
|
50
63
|
if (isCancel(host)) { outro('Setup cancelled.'); process.exit(0); }
|
|
51
64
|
|
|
52
65
|
const user = await text({
|
|
53
|
-
message:
|
|
54
|
-
|
|
66
|
+
message: isAI
|
|
67
|
+
? '[AI INSTRUCTION] Provide the remote server username. This credential will be used for all subsequent tool calls in this session.'
|
|
68
|
+
: 'Enter your Username',
|
|
69
|
+
validate: (val) => (!val || val.length === 0) ? "User is required!" : undefined,
|
|
55
70
|
});
|
|
56
71
|
if (isCancel(user)) { outro('Setup cancelled.'); process.exit(0); }
|
|
57
72
|
|
|
58
73
|
const pass = await promptPassword({
|
|
59
|
-
message:
|
|
74
|
+
message: isAI
|
|
75
|
+
? '[AI INSTRUCTION] Provide the password for the connection. If you are using SSH key authentication for SFTP, you may leave this field empty.'
|
|
76
|
+
: 'Enter your Password (optional if using keys)',
|
|
60
77
|
});
|
|
61
78
|
if (isCancel(pass)) { outro('Setup cancelled.'); process.exit(0); }
|
|
62
79
|
|
|
63
80
|
const port = await text({
|
|
64
|
-
message:
|
|
65
|
-
|
|
81
|
+
message: isAI
|
|
82
|
+
? '[AI INSTRUCTION] Provide the specific port for the connection. Default is 21 for FTP and 22 for SFTP. If the user has not specified a custom port, you should leave this blank.'
|
|
83
|
+
: 'Enter port (optional, defaults to 21 for FTP, 22 for SFTP)',
|
|
84
|
+
placeholder: '22',
|
|
85
|
+
validate: (val) => {
|
|
86
|
+
if (val && isNaN(parseInt(val, 10))) return "Port must be a number!";
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
66
89
|
});
|
|
67
90
|
if (isCancel(port)) { outro('Setup cancelled.'); process.exit(0); }
|
|
68
91
|
|
|
@@ -70,10 +93,17 @@ if (process.argv.includes("--init")) {
|
|
|
70
93
|
let privateKey = '';
|
|
71
94
|
|
|
72
95
|
if (isSFTP) {
|
|
73
|
-
const usesKey = await confirm({
|
|
74
|
-
|
|
96
|
+
const usesKey = await confirm({
|
|
97
|
+
message: isAI
|
|
98
|
+
? '[AI INSTRUCTION] An SFTP protocol was detected. Is the user employing an SSH Private Key instead of a traditional password? (Recommended for production)'
|
|
99
|
+
: 'Are you using an SSH Private Key instead of a password?'
|
|
100
|
+
});
|
|
101
|
+
if (isCancel(usesKey)) { outro('Setup cancelled.'); process.exit(0); }
|
|
102
|
+
if (usesKey) {
|
|
75
103
|
privateKey = await text({
|
|
76
|
-
message:
|
|
104
|
+
message: isAI
|
|
105
|
+
? '[AI INSTRUCTION] Provide the absolute local filesystem path to the SSH private key (e.g. ~/.ssh/id_rsa). This path must be accessible from the environment where the MCP server is running.'
|
|
106
|
+
: 'Path to your private key (e.g. ~/.ssh/id_rsa)',
|
|
77
107
|
});
|
|
78
108
|
if (isCancel(privateKey)) { outro('Setup cancelled.'); process.exit(0); }
|
|
79
109
|
}
|
|
@@ -92,9 +122,26 @@ if (process.argv.includes("--init")) {
|
|
|
92
122
|
|
|
93
123
|
await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
|
|
94
124
|
|
|
95
|
-
|
|
125
|
+
if (isAI) {
|
|
126
|
+
note(
|
|
127
|
+
"AI CONTEXT ESTABLISHED: The `.ftpconfig` file has been generated.\n" +
|
|
128
|
+
"You now have access to this MCP server's tools.\n\n" +
|
|
129
|
+
"Important capabilities:\n" +
|
|
130
|
+
"- Content-rich operations: `ftp_list`, `ftp_download`, `ftp_upload`.\n" +
|
|
131
|
+
"- Batched operations: `ftp_batch_upload`, `ftp_batch_download` (Highly recommended for speed).\n" +
|
|
132
|
+
"- Safe regex searches: `ftp_search`.\n" +
|
|
133
|
+
"- Transparent paths: All remote operations are relative to the server root.\n\n" +
|
|
134
|
+
"You may now proceed with the user's tasks.",
|
|
135
|
+
"Configuration Success"
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
note(`✅ Successfully generated config file at:\n${CONFIG_FILE}`, 'Success');
|
|
139
|
+
}
|
|
96
140
|
|
|
97
|
-
outro(
|
|
141
|
+
outro(isAI
|
|
142
|
+
? "Deployment complete. You are now configured to manage the remote filesystem."
|
|
143
|
+
: "You're ready to deploy with MCP! Ask your AI to 'list remote files'"
|
|
144
|
+
);
|
|
98
145
|
} catch (err) {
|
|
99
146
|
console.error(`❌ Init failed: ${err.message}`);
|
|
100
147
|
}
|
|
@@ -753,17 +800,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
753
800
|
tools: [
|
|
754
801
|
{
|
|
755
802
|
name: "ftp_connect",
|
|
756
|
-
description: "
|
|
803
|
+
description: "Establish or switch the active connection to a specific remote server profile defined in your .ftpconfig (e.g., 'production', 'staging'). This is the first step before performing any remote operations.",
|
|
757
804
|
inputSchema: {
|
|
758
805
|
type: "object",
|
|
759
806
|
properties: {
|
|
760
807
|
profile: {
|
|
761
808
|
type: "string",
|
|
762
|
-
description: "
|
|
809
|
+
description: "The named profile key from your .ftpconfig file."
|
|
763
810
|
},
|
|
764
811
|
useEnv: {
|
|
765
812
|
type: "boolean",
|
|
766
|
-
description: "
|
|
813
|
+
description: "If true, bypasses .ftpconfig and connects using global environment variables (FTPMCP_HOST, etc.)",
|
|
767
814
|
default: false
|
|
768
815
|
}
|
|
769
816
|
}
|
|
@@ -771,13 +818,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
771
818
|
},
|
|
772
819
|
{
|
|
773
820
|
name: "ftp_deploy",
|
|
774
|
-
description: "
|
|
821
|
+
description: "Execute a pre-defined deployment preset from .ftpconfig. This typically maps a specific local folder to a remote target with pre-configured exclusion rules.",
|
|
775
822
|
inputSchema: {
|
|
776
823
|
type: "object",
|
|
777
824
|
properties: {
|
|
778
825
|
deployment: {
|
|
779
826
|
type: "string",
|
|
780
|
-
description: "
|
|
827
|
+
description: "The name of the deployment preset (e.g., 'web-app', 'api-server')."
|
|
781
828
|
}
|
|
782
829
|
},
|
|
783
830
|
required: ["deployment"]
|
|
@@ -793,23 +840,23 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
793
840
|
},
|
|
794
841
|
{
|
|
795
842
|
name: "ftp_list",
|
|
796
|
-
description: "List files and directories in a remote
|
|
843
|
+
description: "List files and directories in a remote path. Use 'limit' and 'offset' for pagination when dealing with directories containing hundreds of files to avoid context overflow.",
|
|
797
844
|
inputSchema: {
|
|
798
845
|
type: "object",
|
|
799
846
|
properties: {
|
|
800
847
|
path: {
|
|
801
848
|
type: "string",
|
|
802
|
-
description: "Remote path
|
|
849
|
+
description: "Remote directory path (defaults to current working directory).",
|
|
803
850
|
default: "."
|
|
804
851
|
},
|
|
805
852
|
limit: {
|
|
806
853
|
type: "number",
|
|
807
|
-
description: "Maximum
|
|
854
|
+
description: "Maximum results to return in this chunk.",
|
|
808
855
|
default: 100
|
|
809
856
|
},
|
|
810
857
|
offset: {
|
|
811
858
|
type: "number",
|
|
812
|
-
description: "
|
|
859
|
+
description: "Starting position in the file list for pagination.",
|
|
813
860
|
default: 0
|
|
814
861
|
}
|
|
815
862
|
}
|
|
@@ -817,21 +864,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
817
864
|
},
|
|
818
865
|
{
|
|
819
866
|
name: "ftp_get_contents",
|
|
820
|
-
description: "Read file
|
|
867
|
+
description: "Read the source text of a remote file. CRITICAL: For large files, use 'startLine' and 'endLine' to extract specific chunks and prevent hitting the LLM context limit.",
|
|
821
868
|
inputSchema: {
|
|
822
869
|
type: "object",
|
|
823
870
|
properties: {
|
|
824
871
|
path: {
|
|
825
872
|
type: "string",
|
|
826
|
-
description: "
|
|
873
|
+
description: "Absolute or relative remote path to the file."
|
|
827
874
|
},
|
|
828
875
|
startLine: {
|
|
829
876
|
type: "number",
|
|
830
|
-
description: "Optional
|
|
877
|
+
description: "Optional: The first line to include in the output (1-indexed)."
|
|
831
878
|
},
|
|
832
879
|
endLine: {
|
|
833
880
|
type: "number",
|
|
834
|
-
description: "Optional
|
|
881
|
+
description: "Optional: The last line to include (inclusive, 1-indexed)."
|
|
835
882
|
}
|
|
836
883
|
},
|
|
837
884
|
required: ["path"]
|
|
@@ -839,25 +886,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
839
886
|
},
|
|
840
887
|
{
|
|
841
888
|
name: "ftp_patch_file",
|
|
842
|
-
description: "Apply a Unified Diff patch to a remote file",
|
|
889
|
+
description: "Apply a Unified Diff patch to a remote file. RECOMMENDED: Use this instead of ftp_put_contents for updating existing files to minimize bandwidth and ensure atomic-like updates. For new files, use ftp_put_contents.",
|
|
843
890
|
inputSchema: {
|
|
844
891
|
type: "object",
|
|
845
892
|
properties: {
|
|
846
893
|
path: {
|
|
847
894
|
type: "string",
|
|
848
|
-
description: "Remote
|
|
895
|
+
description: "Remote path to the existing file to be patched."
|
|
849
896
|
},
|
|
850
897
|
patch: {
|
|
851
898
|
type: "string",
|
|
852
|
-
description: "Unified
|
|
899
|
+
description: "The Unified Diff formatted string containing your local changes."
|
|
853
900
|
},
|
|
854
901
|
expectedHash: {
|
|
855
902
|
type: "string",
|
|
856
|
-
description: "Optional
|
|
903
|
+
description: "Optional (but recommended): The SHA-256 hash of the remote file before patching to prevent race conditions (drift protection)."
|
|
857
904
|
},
|
|
858
905
|
createBackup: {
|
|
859
906
|
type: "boolean",
|
|
860
|
-
description: "
|
|
907
|
+
description: "Generate a .bak copy of the remote file before applying the changes.",
|
|
861
908
|
default: true
|
|
862
909
|
}
|
|
863
910
|
},
|
|
@@ -866,13 +913,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
866
913
|
},
|
|
867
914
|
{
|
|
868
915
|
name: "ftp_analyze_workspace",
|
|
869
|
-
description: "
|
|
916
|
+
description: "Introspect the remote directory to identify technical environments (e.g., Node.js, PHP, Python) and read dependency manifests. Use this to gain architectural context of a new codebase.",
|
|
870
917
|
inputSchema: {
|
|
871
918
|
type: "object",
|
|
872
919
|
properties: {
|
|
873
920
|
path: {
|
|
874
921
|
type: "string",
|
|
875
|
-
description: "Remote directory
|
|
922
|
+
description: "Remote directory to analyze (defaults to current server root).",
|
|
876
923
|
default: "."
|
|
877
924
|
}
|
|
878
925
|
}
|
|
@@ -880,17 +927,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
880
927
|
},
|
|
881
928
|
{
|
|
882
929
|
name: "ftp_put_contents",
|
|
883
|
-
description: "Write
|
|
930
|
+
description: "Write raw text directly to a remote destination. Best for creating NEW files. For modifying existing files, prefer ftp_patch_file.",
|
|
884
931
|
inputSchema: {
|
|
885
932
|
type: "object",
|
|
886
933
|
properties: {
|
|
887
934
|
path: {
|
|
888
935
|
type: "string",
|
|
889
|
-
description: "Remote
|
|
936
|
+
description: "Remote destination path."
|
|
890
937
|
},
|
|
891
938
|
content: {
|
|
892
939
|
type: "string",
|
|
893
|
-
description: "
|
|
940
|
+
description: "The full string content to write."
|
|
894
941
|
}
|
|
895
942
|
},
|
|
896
943
|
required: ["path", "content"]
|
|
@@ -898,13 +945,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
898
945
|
},
|
|
899
946
|
{
|
|
900
947
|
name: "ftp_stat",
|
|
901
|
-
description: "
|
|
948
|
+
description: "Retrieve comprehensive metadata for a remote property, including size, modification timestamps, and UNIX permissions.",
|
|
902
949
|
inputSchema: {
|
|
903
950
|
type: "object",
|
|
904
951
|
properties: {
|
|
905
952
|
path: {
|
|
906
953
|
type: "string",
|
|
907
|
-
description: "Remote file path"
|
|
954
|
+
description: "Remote file or directory path."
|
|
908
955
|
}
|
|
909
956
|
},
|
|
910
957
|
required: ["path"]
|
|
@@ -912,13 +959,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
912
959
|
},
|
|
913
960
|
{
|
|
914
961
|
name: "ftp_exists",
|
|
915
|
-
description: "Check
|
|
962
|
+
description: "Check for the existence of a file or folder without performing heavy file operations. Use this for conditional logic workflows.",
|
|
916
963
|
inputSchema: {
|
|
917
964
|
type: "object",
|
|
918
965
|
properties: {
|
|
919
966
|
path: {
|
|
920
967
|
type: "string",
|
|
921
|
-
description: "Remote path
|
|
968
|
+
description: "Remote target path."
|
|
922
969
|
}
|
|
923
970
|
},
|
|
924
971
|
required: ["path"]
|
|
@@ -926,18 +973,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
926
973
|
},
|
|
927
974
|
{
|
|
928
975
|
name: "ftp_tree",
|
|
929
|
-
description: "
|
|
976
|
+
description: "Generate a complete recursive directory map. Use this to visualize project structure, but be cautious with 'maxDepth' in very large remote repositories to avoid excessive network payload.",
|
|
930
977
|
inputSchema: {
|
|
931
978
|
type: "object",
|
|
932
979
|
properties: {
|
|
933
980
|
path: {
|
|
934
981
|
type: "string",
|
|
935
|
-
description: "Remote path to start
|
|
982
|
+
description: "Remote directory path to start mapping from (defaults to root).",
|
|
936
983
|
default: "."
|
|
937
984
|
},
|
|
938
985
|
maxDepth: {
|
|
939
986
|
type: "number",
|
|
940
|
-
description: "Maximum depth to
|
|
987
|
+
description: "Maximum recursion depth to prevent infinite loops or huge payloads.",
|
|
941
988
|
default: 10
|
|
942
989
|
}
|
|
943
990
|
}
|
|
@@ -945,40 +992,40 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
945
992
|
},
|
|
946
993
|
{
|
|
947
994
|
name: "ftp_search",
|
|
948
|
-
description: "Advanced remote search
|
|
995
|
+
description: "Advanced remote file search. Supports finding files by name (wildcards), extension, or content regex (grep-like). Use this to find specific code patterns across the remote workspace.",
|
|
949
996
|
inputSchema: {
|
|
950
997
|
type: "object",
|
|
951
998
|
properties: {
|
|
952
999
|
pattern: {
|
|
953
1000
|
type: "string",
|
|
954
|
-
description: "
|
|
1001
|
+
description: "File name pattern (e.g. `*.js`, `db_*`)."
|
|
955
1002
|
},
|
|
956
1003
|
contentPattern: {
|
|
957
1004
|
type: "string",
|
|
958
|
-
description: "Regex pattern to search inside file contents
|
|
1005
|
+
description: "Regex pattern to search inside file contents. Highly efficient for finding variable usage or specific logic."
|
|
959
1006
|
},
|
|
960
1007
|
extension: {
|
|
961
1008
|
type: "string",
|
|
962
|
-
description: "
|
|
1009
|
+
description: "Restrict search to specific file extensions (e.g. `.css`)."
|
|
963
1010
|
},
|
|
964
1011
|
findLikelyConfigs: {
|
|
965
1012
|
type: "boolean",
|
|
966
|
-
description: "
|
|
1013
|
+
description: "Prioritize searching for project manifests and config files (package.json, .env, etc.)",
|
|
967
1014
|
default: false
|
|
968
1015
|
},
|
|
969
1016
|
path: {
|
|
970
1017
|
type: "string",
|
|
971
|
-
description: "Remote
|
|
1018
|
+
description: "Remote directory to start the recursive search in.",
|
|
972
1019
|
default: "."
|
|
973
1020
|
},
|
|
974
1021
|
limit: {
|
|
975
1022
|
type: "number",
|
|
976
|
-
description: "Maximum
|
|
1023
|
+
description: "Maximum matches to return.",
|
|
977
1024
|
default: 50
|
|
978
1025
|
},
|
|
979
1026
|
offset: {
|
|
980
1027
|
type: "number",
|
|
981
|
-
description: "
|
|
1028
|
+
description: "Skip initial matches for pagination.",
|
|
982
1029
|
default: 0
|
|
983
1030
|
}
|
|
984
1031
|
}
|
|
@@ -986,17 +1033,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
986
1033
|
},
|
|
987
1034
|
{
|
|
988
1035
|
name: "ftp_copy",
|
|
989
|
-
description: "
|
|
1036
|
+
description: "Directly duplicate a file on the remote server without downloading and re-uploading. CRITICAL: Only supported on SFTP connections.",
|
|
990
1037
|
inputSchema: {
|
|
991
1038
|
type: "object",
|
|
992
1039
|
properties: {
|
|
993
1040
|
sourcePath: {
|
|
994
1041
|
type: "string",
|
|
995
|
-
description: "
|
|
1042
|
+
description: "Qualified remote source path."
|
|
996
1043
|
},
|
|
997
1044
|
destPath: {
|
|
998
1045
|
type: "string",
|
|
999
|
-
description: "
|
|
1046
|
+
description: "Target remote destination path."
|
|
1000
1047
|
}
|
|
1001
1048
|
},
|
|
1002
1049
|
required: ["sourcePath", "destPath"]
|
|
@@ -1004,18 +1051,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1004
1051
|
},
|
|
1005
1052
|
{
|
|
1006
1053
|
name: "ftp_batch_upload",
|
|
1007
|
-
description: "Upload multiple files
|
|
1054
|
+
description: "Upload a collection of local files to remote destinations in a single operation. HIGHLY RECOMMENDED for multiple files to minimize connection handshaking overhead and drastically improve performance.",
|
|
1008
1055
|
inputSchema: {
|
|
1009
1056
|
type: "object",
|
|
1010
1057
|
properties: {
|
|
1011
1058
|
files: {
|
|
1012
1059
|
type: "array",
|
|
1013
|
-
description: "
|
|
1060
|
+
description: "A list of objects, each defining a local source and a remote destination.",
|
|
1014
1061
|
items: {
|
|
1015
1062
|
type: "object",
|
|
1016
1063
|
properties: {
|
|
1017
|
-
localPath: { type: "string" },
|
|
1018
|
-
remotePath: { type: "string" }
|
|
1064
|
+
localPath: { type: "string", description: "Source path on your local machine." },
|
|
1065
|
+
remotePath: { type: "string", description: "Target path on the remote server." }
|
|
1019
1066
|
},
|
|
1020
1067
|
required: ["localPath", "remotePath"]
|
|
1021
1068
|
}
|
|
@@ -1026,18 +1073,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1026
1073
|
},
|
|
1027
1074
|
{
|
|
1028
1075
|
name: "ftp_batch_download",
|
|
1029
|
-
description: "Download
|
|
1076
|
+
description: "Download a selection of remote files to local destinations. HIGHLY RECOMMENDED for bulk downloads to leverage stable socket persistence.",
|
|
1030
1077
|
inputSchema: {
|
|
1031
1078
|
type: "object",
|
|
1032
1079
|
properties: {
|
|
1033
1080
|
files: {
|
|
1034
1081
|
type: "array",
|
|
1035
|
-
description: "
|
|
1082
|
+
description: "A list of objects mapping remote sources to local destinations.",
|
|
1036
1083
|
items: {
|
|
1037
1084
|
type: "object",
|
|
1038
1085
|
properties: {
|
|
1039
|
-
remotePath: { type: "string" },
|
|
1040
|
-
localPath: { type: "string" }
|
|
1086
|
+
remotePath: { type: "string", description: "Source path on the remote server." },
|
|
1087
|
+
localPath: { type: "string", description: "Destination path on your local machine." }
|
|
1041
1088
|
},
|
|
1042
1089
|
required: ["remotePath", "localPath"]
|
|
1043
1090
|
}
|
|
@@ -1048,33 +1095,32 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1048
1095
|
},
|
|
1049
1096
|
{
|
|
1050
1097
|
name: "ftp_sync",
|
|
1051
|
-
description: "
|
|
1098
|
+
description: "Deploy entire project folders using smart synchronization. Analyzes local and remote directory trees and only transfers files that have changed in size or modification date. Automatically respects .gitignore and .ftpignore.",
|
|
1052
1099
|
inputSchema: {
|
|
1053
1100
|
type: "object",
|
|
1054
1101
|
properties: {
|
|
1055
1102
|
localPath: {
|
|
1056
1103
|
type: "string",
|
|
1057
|
-
description: "
|
|
1104
|
+
description: "The source directory on your local machine."
|
|
1058
1105
|
},
|
|
1059
1106
|
remotePath: {
|
|
1060
1107
|
type: "string",
|
|
1061
|
-
description: "
|
|
1108
|
+
description: "The target destination directory on the remote server."
|
|
1062
1109
|
},
|
|
1063
1110
|
direction: {
|
|
1064
1111
|
type: "string",
|
|
1065
|
-
|
|
1066
|
-
description: "Sync direction: currently only 'upload' is supported",
|
|
1112
|
+
description: "Sync direction. Currently only 'upload' is implemented for safety.",
|
|
1067
1113
|
enum: ["upload"],
|
|
1068
1114
|
default: "upload"
|
|
1069
1115
|
},
|
|
1070
1116
|
dryRun: {
|
|
1071
1117
|
type: "boolean",
|
|
1072
|
-
description: "If true,
|
|
1118
|
+
description: "If true, logs exactly which files would be changed without performing any actual transfers.",
|
|
1073
1119
|
default: false
|
|
1074
1120
|
},
|
|
1075
1121
|
useManifest: {
|
|
1076
1122
|
type: "boolean",
|
|
1077
|
-
description: "
|
|
1123
|
+
description: "Enables the local manifest cache for extremely fast delta detection on subsequent syncs.",
|
|
1078
1124
|
default: true
|
|
1079
1125
|
}
|
|
1080
1126
|
},
|
|
@@ -1083,13 +1129,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1083
1129
|
},
|
|
1084
1130
|
{
|
|
1085
1131
|
name: "ftp_disk_space",
|
|
1086
|
-
description: "
|
|
1132
|
+
description: "Query the remote server for available disk space. CRITICAL: Only available on SFTP connections.",
|
|
1087
1133
|
inputSchema: {
|
|
1088
1134
|
type: "object",
|
|
1089
1135
|
properties: {
|
|
1090
1136
|
path: {
|
|
1091
1137
|
type: "string",
|
|
1092
|
-
description: "Remote path to check",
|
|
1138
|
+
description: "Remote filesystem path to check (defaults to server root).",
|
|
1093
1139
|
default: "."
|
|
1094
1140
|
}
|
|
1095
1141
|
}
|
|
@@ -1097,17 +1143,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1097
1143
|
},
|
|
1098
1144
|
{
|
|
1099
1145
|
name: "ftp_upload",
|
|
1100
|
-
description: "
|
|
1146
|
+
description: "Standard single-file transport to the remote server. For bulk transfers, favor ftp_batch_upload.",
|
|
1101
1147
|
inputSchema: {
|
|
1102
1148
|
type: "object",
|
|
1103
1149
|
properties: {
|
|
1104
1150
|
localPath: {
|
|
1105
1151
|
type: "string",
|
|
1106
|
-
description: "
|
|
1152
|
+
description: "Source path on your local machine."
|
|
1107
1153
|
},
|
|
1108
1154
|
remotePath: {
|
|
1109
1155
|
type: "string",
|
|
1110
|
-
description: "
|
|
1156
|
+
description: "Target location on the remote server."
|
|
1111
1157
|
}
|
|
1112
1158
|
},
|
|
1113
1159
|
required: ["localPath", "remotePath"]
|
|
@@ -1115,17 +1161,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1115
1161
|
},
|
|
1116
1162
|
{
|
|
1117
1163
|
name: "ftp_download",
|
|
1118
|
-
description: "
|
|
1164
|
+
description: "Standard single-file transport from the remote server. For bulk downloads, favor ftp_batch_download.",
|
|
1119
1165
|
inputSchema: {
|
|
1120
1166
|
type: "object",
|
|
1121
1167
|
properties: {
|
|
1122
1168
|
remotePath: {
|
|
1123
1169
|
type: "string",
|
|
1124
|
-
description: "
|
|
1170
|
+
description: "Source file location on the remote server."
|
|
1125
1171
|
},
|
|
1126
1172
|
localPath: {
|
|
1127
1173
|
type: "string",
|
|
1128
|
-
description: "
|
|
1174
|
+
description: "Destination location on your local machine."
|
|
1129
1175
|
}
|
|
1130
1176
|
},
|
|
1131
1177
|
required: ["remotePath", "localPath"]
|
|
@@ -1133,13 +1179,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1133
1179
|
},
|
|
1134
1180
|
{
|
|
1135
1181
|
name: "ftp_delete",
|
|
1136
|
-
description: "
|
|
1182
|
+
description: "Permanently remove a file from the remote server. Use with caution.",
|
|
1137
1183
|
inputSchema: {
|
|
1138
1184
|
type: "object",
|
|
1139
1185
|
properties: {
|
|
1140
1186
|
path: {
|
|
1141
1187
|
type: "string",
|
|
1142
|
-
description: "
|
|
1188
|
+
description: "The remote file path to be destroyed."
|
|
1143
1189
|
}
|
|
1144
1190
|
},
|
|
1145
1191
|
required: ["path"]
|
|
@@ -1147,13 +1193,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1147
1193
|
},
|
|
1148
1194
|
{
|
|
1149
1195
|
name: "ftp_mkdir",
|
|
1150
|
-
description: "Create a directory on the
|
|
1196
|
+
description: "Create a new directory structure on the remote server. Supports nested creation (mkdir -p).",
|
|
1151
1197
|
inputSchema: {
|
|
1152
1198
|
type: "object",
|
|
1153
1199
|
properties: {
|
|
1154
1200
|
path: {
|
|
1155
1201
|
type: "string",
|
|
1156
|
-
description: "
|
|
1202
|
+
description: "The remote directory path to create."
|
|
1157
1203
|
}
|
|
1158
1204
|
},
|
|
1159
1205
|
required: ["path"]
|
|
@@ -1161,17 +1207,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1161
1207
|
},
|
|
1162
1208
|
{
|
|
1163
1209
|
name: "ftp_rmdir",
|
|
1164
|
-
description: "
|
|
1210
|
+
description: "Delete a directory from the remote server.",
|
|
1165
1211
|
inputSchema: {
|
|
1166
1212
|
type: "object",
|
|
1167
1213
|
properties: {
|
|
1168
1214
|
path: {
|
|
1169
1215
|
type: "string",
|
|
1170
|
-
description: "
|
|
1216
|
+
description: "The remote directory path to remove."
|
|
1171
1217
|
},
|
|
1172
1218
|
recursive: {
|
|
1173
1219
|
type: "boolean",
|
|
1174
|
-
description: "
|
|
1220
|
+
description: "If true, deletes all files and subdirectories within the target directory.",
|
|
1175
1221
|
default: false
|
|
1176
1222
|
}
|
|
1177
1223
|
},
|
|
@@ -1180,17 +1226,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1180
1226
|
},
|
|
1181
1227
|
{
|
|
1182
1228
|
name: "ftp_chmod",
|
|
1183
|
-
description: "Change file permissions
|
|
1229
|
+
description: "Change remote file permissions. CRITICAL: Only supported on SFTP connections.",
|
|
1184
1230
|
inputSchema: {
|
|
1185
1231
|
type: "object",
|
|
1186
1232
|
properties: {
|
|
1187
1233
|
path: {
|
|
1188
1234
|
type: "string",
|
|
1189
|
-
description: "Remote file path"
|
|
1235
|
+
description: "Remote file path to modify."
|
|
1190
1236
|
},
|
|
1191
1237
|
mode: {
|
|
1192
1238
|
type: "string",
|
|
1193
|
-
description: "
|
|
1239
|
+
description: "Standard octal permission string (e.g., '755' for executable, '644' for read-write)."
|
|
1194
1240
|
}
|
|
1195
1241
|
},
|
|
1196
1242
|
required: ["path", "mode"]
|
|
@@ -1198,17 +1244,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1198
1244
|
},
|
|
1199
1245
|
{
|
|
1200
1246
|
name: "ftp_rename",
|
|
1201
|
-
description: "
|
|
1247
|
+
description: "Move or rename files and directories on the remote server.",
|
|
1202
1248
|
inputSchema: {
|
|
1203
1249
|
type: "object",
|
|
1204
1250
|
properties: {
|
|
1205
1251
|
oldPath: {
|
|
1206
1252
|
type: "string",
|
|
1207
|
-
description: "Current
|
|
1253
|
+
description: "Current remote location."
|
|
1208
1254
|
},
|
|
1209
1255
|
newPath: {
|
|
1210
1256
|
type: "string",
|
|
1211
|
-
description: "New
|
|
1257
|
+
description: "New desired remote location."
|
|
1212
1258
|
}
|
|
1213
1259
|
},
|
|
1214
1260
|
required: ["oldPath", "newPath"]
|
|
@@ -1216,13 +1262,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1216
1262
|
},
|
|
1217
1263
|
{
|
|
1218
1264
|
name: "ftp_rollback",
|
|
1219
|
-
description: "
|
|
1265
|
+
description: "Undo a previous file mutation by restoring it from a system-generated snapshot. This provides safety during complex refactoring tasks.",
|
|
1220
1266
|
inputSchema: {
|
|
1221
1267
|
type: "object",
|
|
1222
1268
|
properties: {
|
|
1223
1269
|
transactionId: {
|
|
1224
1270
|
type: "string",
|
|
1225
|
-
description: "
|
|
1271
|
+
description: "Specific ID associated with the snapshot (e.g., 'tx_12345'). Get this from ftp_list_transactions."
|
|
1226
1272
|
}
|
|
1227
1273
|
},
|
|
1228
1274
|
required: ["transactionId"]
|
|
@@ -1230,7 +1276,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1230
1276
|
},
|
|
1231
1277
|
{
|
|
1232
1278
|
name: "ftp_list_transactions",
|
|
1233
|
-
description: "
|
|
1279
|
+
description: "Expose all recent mutations currently stored in the system's SnapshotManager. Essential for planning rollbacks.",
|
|
1234
1280
|
inputSchema: {
|
|
1235
1281
|
type: "object",
|
|
1236
1282
|
properties: {}
|
|
@@ -1238,13 +1284,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1238
1284
|
},
|
|
1239
1285
|
{
|
|
1240
1286
|
name: "ftp_probe_capabilities",
|
|
1241
|
-
description: "
|
|
1287
|
+
description: "Scan the remote server to determine supported filesystem features (e.g., chmod availability, symlink support, disk space querying). Helpful for troubleshooting capabilities.",
|
|
1242
1288
|
inputSchema: {
|
|
1243
1289
|
type: "object",
|
|
1244
1290
|
properties: {
|
|
1245
1291
|
testPath: {
|
|
1246
1292
|
type: "string",
|
|
1247
|
-
description: "A safe
|
|
1293
|
+
description: "A safe, ephemeral directory to run capability benchmarks in.",
|
|
1248
1294
|
default: "."
|
|
1249
1295
|
}
|
|
1250
1296
|
}
|
|
@@ -1252,7 +1298,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1252
1298
|
},
|
|
1253
1299
|
{
|
|
1254
1300
|
name: "ftp_telemetry",
|
|
1255
|
-
description: "
|
|
1301
|
+
description: "Retrieve internal performance metrics, including average latency, connection pool health, and total processed bytes.",
|
|
1256
1302
|
inputSchema: {
|
|
1257
1303
|
type: "object",
|
|
1258
1304
|
properties: {}
|
package/package.json
CHANGED
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ftp-mcp",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Enterprise-grade MCP server providing heavily optimized FTP/SFTP operations with smart sync, patch/chunk streaming, caching, and explicit read-only security mappings for AI code assistants.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"ftp-mcp": "./index.js",
|
|
9
|
-
"ftp-mcp-server": "./index.js"
|
|
10
|
-
},
|
|
11
|
-
"files": [
|
|
12
|
-
"index.js",
|
|
13
|
-
"policy-engine.js",
|
|
14
|
-
"snapshot-manager.js",
|
|
15
|
-
"sync-manifest.js",
|
|
16
|
-
"README.md",
|
|
17
|
-
"LICENSE",
|
|
18
|
-
".ftpconfig.example"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"start": "node index.js",
|
|
22
|
-
"test": "vitest run"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"mcp",
|
|
26
|
-
"mcp-protocol",
|
|
27
|
-
"model-context-protocol",
|
|
28
|
-
"ftp",
|
|
29
|
-
"ftp-client",
|
|
30
|
-
"sftp",
|
|
31
|
-
"sftp-client",
|
|
32
|
-
"ssh",
|
|
33
|
-
"ssh2",
|
|
34
|
-
"scp",
|
|
35
|
-
"ssh-agent",
|
|
36
|
-
"rsync",
|
|
37
|
-
"file-transfer",
|
|
38
|
-
"file-manager",
|
|
39
|
-
"sync",
|
|
40
|
-
"diff",
|
|
41
|
-
"patch",
|
|
42
|
-
"git",
|
|
43
|
-
"gitignore",
|
|
44
|
-
"deploy",
|
|
45
|
-
"deployment",
|
|
46
|
-
"devops",
|
|
47
|
-
"continuous-deployment",
|
|
48
|
-
"automation",
|
|
49
|
-
"ai",
|
|
50
|
-
"ai-tools",
|
|
51
|
-
"llm",
|
|
52
|
-
"assistant",
|
|
53
|
-
"agentic",
|
|
54
|
-
"code-assistant",
|
|
55
|
-
"tool-call",
|
|
56
|
-
"json-rpc",
|
|
57
|
-
"server",
|
|
58
|
-
"tools",
|
|
59
|
-
"claude",
|
|
60
|
-
"claude-mcp",
|
|
61
|
-
"claude-ftp",
|
|
62
|
-
"cline",
|
|
63
|
-
"cline-mcp",
|
|
64
|
-
"cline-ftp",
|
|
65
|
-
"cursor",
|
|
66
|
-
"cursor-mcp",
|
|
67
|
-
"cursor-ftp",
|
|
68
|
-
"windsurf",
|
|
69
|
-
"windsurf-mcp",
|
|
70
|
-
"roo",
|
|
71
|
-
"roo-code",
|
|
72
|
-
"roo-mcp",
|
|
73
|
-
"copilot",
|
|
74
|
-
"github-copilot",
|
|
75
|
-
"amp",
|
|
76
|
-
"amp-mcp",
|
|
77
|
-
"openai",
|
|
78
|
-
"anthropic",
|
|
79
|
-
"gemini",
|
|
80
|
-
"gemini-mcp",
|
|
81
|
-
"mcp-server",
|
|
82
|
-
"mcp-tools",
|
|
83
|
-
"server-tool",
|
|
84
|
-
"remote",
|
|
85
|
-
"remote-fs",
|
|
86
|
-
"vfs"
|
|
87
|
-
],
|
|
88
|
-
"engines": {
|
|
89
|
-
"node": ">=18.0.0"
|
|
90
|
-
},
|
|
91
|
-
"author": {
|
|
92
|
-
"name": "Kynlo Akari",
|
|
93
|
-
"url": "https://github.com/Kynlos/"
|
|
94
|
-
},
|
|
95
|
-
"license": "MIT",
|
|
96
|
-
"repository": {
|
|
97
|
-
"type": "git",
|
|
98
|
-
"url": "https://github.com/Kynlos/ftp-mcp.git"
|
|
99
|
-
},
|
|
100
|
-
"homepage": "https://github.com/Kynlos/ftp-mcp#readme",
|
|
101
|
-
"bugs": {
|
|
102
|
-
"url": "https://github.com/Kynlos/ftp-mcp/issues"
|
|
103
|
-
},
|
|
104
|
-
"publishConfig": {
|
|
105
|
-
"access": "public"
|
|
106
|
-
},
|
|
107
|
-
"dependencies": {
|
|
108
|
-
"@clack/prompts": "^1.2.0",
|
|
109
|
-
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
110
|
-
"basic-ftp": "^5.0.5",
|
|
111
|
-
"diff": "^8.0.4",
|
|
112
|
-
"dotenv": "^17.4.0",
|
|
113
|
-
"ignore": "^7.0.5",
|
|
114
|
-
"minimatch": "^10.0.3",
|
|
115
|
-
"ssh2-sftp-client": "^11.0.0",
|
|
116
|
-
"zod": "^4.3.6"
|
|
117
|
-
},
|
|
118
|
-
"devDependencies": {
|
|
119
|
-
"ftp-srv": "^4.6.3",
|
|
120
|
-
"vitest": "^4.1.2"
|
|
121
|
-
}
|
|
122
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "ftp-mcp",
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "Enterprise-grade MCP server providing heavily optimized FTP/SFTP operations with smart sync, patch/chunk streaming, caching, and explicit read-only security mappings for AI code assistants.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ftp-mcp": "./index.js",
|
|
9
|
+
"ftp-mcp-server": "./index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"index.js",
|
|
13
|
+
"policy-engine.js",
|
|
14
|
+
"snapshot-manager.js",
|
|
15
|
+
"sync-manifest.js",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
".ftpconfig.example"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"start": "node index.js",
|
|
22
|
+
"test": "vitest run"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"mcp-protocol",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"ftp",
|
|
29
|
+
"ftp-client",
|
|
30
|
+
"sftp",
|
|
31
|
+
"sftp-client",
|
|
32
|
+
"ssh",
|
|
33
|
+
"ssh2",
|
|
34
|
+
"scp",
|
|
35
|
+
"ssh-agent",
|
|
36
|
+
"rsync",
|
|
37
|
+
"file-transfer",
|
|
38
|
+
"file-manager",
|
|
39
|
+
"sync",
|
|
40
|
+
"diff",
|
|
41
|
+
"patch",
|
|
42
|
+
"git",
|
|
43
|
+
"gitignore",
|
|
44
|
+
"deploy",
|
|
45
|
+
"deployment",
|
|
46
|
+
"devops",
|
|
47
|
+
"continuous-deployment",
|
|
48
|
+
"automation",
|
|
49
|
+
"ai",
|
|
50
|
+
"ai-tools",
|
|
51
|
+
"llm",
|
|
52
|
+
"assistant",
|
|
53
|
+
"agentic",
|
|
54
|
+
"code-assistant",
|
|
55
|
+
"tool-call",
|
|
56
|
+
"json-rpc",
|
|
57
|
+
"server",
|
|
58
|
+
"tools",
|
|
59
|
+
"claude",
|
|
60
|
+
"claude-mcp",
|
|
61
|
+
"claude-ftp",
|
|
62
|
+
"cline",
|
|
63
|
+
"cline-mcp",
|
|
64
|
+
"cline-ftp",
|
|
65
|
+
"cursor",
|
|
66
|
+
"cursor-mcp",
|
|
67
|
+
"cursor-ftp",
|
|
68
|
+
"windsurf",
|
|
69
|
+
"windsurf-mcp",
|
|
70
|
+
"roo",
|
|
71
|
+
"roo-code",
|
|
72
|
+
"roo-mcp",
|
|
73
|
+
"copilot",
|
|
74
|
+
"github-copilot",
|
|
75
|
+
"amp",
|
|
76
|
+
"amp-mcp",
|
|
77
|
+
"openai",
|
|
78
|
+
"anthropic",
|
|
79
|
+
"gemini",
|
|
80
|
+
"gemini-mcp",
|
|
81
|
+
"mcp-server",
|
|
82
|
+
"mcp-tools",
|
|
83
|
+
"server-tool",
|
|
84
|
+
"remote",
|
|
85
|
+
"remote-fs",
|
|
86
|
+
"vfs"
|
|
87
|
+
],
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": ">=18.0.0"
|
|
90
|
+
},
|
|
91
|
+
"author": {
|
|
92
|
+
"name": "Kynlo Akari",
|
|
93
|
+
"url": "https://github.com/Kynlos/"
|
|
94
|
+
},
|
|
95
|
+
"license": "MIT",
|
|
96
|
+
"repository": {
|
|
97
|
+
"type": "git",
|
|
98
|
+
"url": "https://github.com/Kynlos/ftp-mcp.git"
|
|
99
|
+
},
|
|
100
|
+
"homepage": "https://github.com/Kynlos/ftp-mcp#readme",
|
|
101
|
+
"bugs": {
|
|
102
|
+
"url": "https://github.com/Kynlos/ftp-mcp/issues"
|
|
103
|
+
},
|
|
104
|
+
"publishConfig": {
|
|
105
|
+
"access": "public"
|
|
106
|
+
},
|
|
107
|
+
"dependencies": {
|
|
108
|
+
"@clack/prompts": "^1.2.0",
|
|
109
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
110
|
+
"basic-ftp": "^5.0.5",
|
|
111
|
+
"diff": "^8.0.4",
|
|
112
|
+
"dotenv": "^17.4.0",
|
|
113
|
+
"ignore": "^7.0.5",
|
|
114
|
+
"minimatch": "^10.0.3",
|
|
115
|
+
"ssh2-sftp-client": "^11.0.0",
|
|
116
|
+
"zod": "^4.3.6"
|
|
117
|
+
},
|
|
118
|
+
"devDependencies": {
|
|
119
|
+
"ftp-srv": "^4.6.3",
|
|
120
|
+
"vitest": "^4.1.2"
|
|
121
|
+
}
|
|
122
|
+
}
|