@storage4everyone/mcp 0.1.0 → 0.2.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.
- package/README.md +5 -71
- package/dist/env.d.ts +8 -0
- package/dist/env.js +51 -0
- package/dist/index.js +16 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,75 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @storage4everyone/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server for **Storage4Everyone (S4E)** cloud object storage.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Lets AI agents such as Claude Code, Claude Desktop and Cursor list, download, upload and delete files in your S4E buckets, using your own API key.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
📘 Full documentation: [docs.storage4everyone.com](https://docs.storage4everyone.com)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **Scopes:** `storage:read` only, unless the agent must upload or delete.
|
|
12
|
-
- **Buckets:** choose only the buckets the agent needs.
|
|
13
|
-
- **Expiry:** set one (for example 30 days).
|
|
14
|
-
|
|
15
|
-
Revoke the key in the dashboard to cut off the agent. Revocation takes effect within about a minute.
|
|
16
|
-
|
|
17
|
-
## 2. Add it to your agent
|
|
18
|
-
|
|
19
|
-
Claude Code:
|
|
20
|
-
|
|
21
|
-
```sh
|
|
22
|
-
claude mcp add s4e --env S4E_API_KEY=s4e_live_... --env S4E_BUCKET=bkt_... -- npx -y @storage4everyone/mcp
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Claude Desktop, Cursor and other clients use a JSON config like this:
|
|
26
|
-
|
|
27
|
-
```json
|
|
28
|
-
{
|
|
29
|
-
"mcpServers": {
|
|
30
|
-
"s4e": {
|
|
31
|
-
"command": "npx",
|
|
32
|
-
"args": ["-y", "@storage4everyone/mcp"],
|
|
33
|
-
"env": {
|
|
34
|
-
"S4E_API_KEY": "s4e_live_...",
|
|
35
|
-
"S4E_BUCKET": "bkt_...",
|
|
36
|
-
"S4E_MCP_ROOT": "/path/to/agent-files"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
On Windows, some clients need `"command": "cmd"` and `"args": ["/c", "npx", "-y", "@storage4everyone/mcp"]`.
|
|
44
|
-
|
|
45
|
-
## 3. Settings
|
|
46
|
-
|
|
47
|
-
| Variable | Required | Meaning |
|
|
48
|
-
| --- | --- | --- |
|
|
49
|
-
| `S4E_API_KEY` | Yes | The agent's API key. Read from the environment only; never passed as a tool argument. |
|
|
50
|
-
| `S4E_BUCKET` | No | Default bucket (`bkt_…`, name, or `s4e://workspace/bucket`) when the agent does not name one. |
|
|
51
|
-
| `S4E_MCP_ROOT` | No | The only local folder the server reads uploads from and writes downloads to. Defaults to the folder the agent app starts it in. Use a dedicated folder. |
|
|
52
|
-
| `S4E_MCP_ALLOW_WRITE` | No | Set to `true` to enable `upload_file` and `delete_object`. Off by default. |
|
|
53
|
-
|
|
54
|
-
## 4. Tools
|
|
55
|
-
|
|
56
|
-
| Tool | What it does | Needs |
|
|
57
|
-
| --- | --- | --- |
|
|
58
|
-
| `list_buckets` | Lists buckets the key can access | `storage:read` |
|
|
59
|
-
| `list_objects` | Lists files in a bucket (name, size, type, upload time); optional prefix; up to 500 per call | `storage:read` |
|
|
60
|
-
| `download_file` | Saves a file into `S4E_MCP_ROOT` and returns the saved path. Will not overwrite unless `overwrite: true` | `storage:read` |
|
|
61
|
-
| `upload_file` | Uploads a file from `S4E_MCP_ROOT` (up to 5 GiB; large files are sent in parts) | `storage:write` + `S4E_MCP_ALLOW_WRITE=true` |
|
|
62
|
-
| `delete_object` | Deletes a file (paid plans move it to the Trash Bin) | `storage:write` + `S4E_MCP_ALLOW_WRITE=true` |
|
|
63
|
-
|
|
64
|
-
The service may assign stored file names on upload; use the returned `fileName` afterwards.
|
|
65
|
-
|
|
66
|
-
Not included: share links, usage figures, creating buckets, client apps and browser sessions. These need the dashboard.
|
|
67
|
-
|
|
68
|
-
## 5. Security
|
|
69
|
-
|
|
70
|
-
- **The server decides what is allowed.** The MCP package adds no permissions. A read-only key cannot upload, even with `S4E_MCP_ALLOW_WRITE=true`.
|
|
71
|
-
- **Local folder sandbox.** Paths outside `S4E_MCP_ROOT` are refused, including `..`, other absolute paths, and symlinks or junctions that point outside it. This stops a misled agent from uploading files such as SSH keys or writing outside the folder.
|
|
72
|
-
- **No secrets in the agent's context.** Tool results never contain the API key or signed download URLs, and error messages are scrubbed of both. Downloads go to disk; file contents are not returned to the model.
|
|
73
|
-
- **File names are data.** Treat names in listings as untrusted text. Agents should not follow instructions found in file names or downloaded files.
|
|
74
|
-
- **Rate limits and quotas** are the same as for any API client. When a limit is hit, the agent gets the error code and the retry time; the server does not retry automatically.
|
|
75
|
-
- **Your agent provider sees tool results.** File names, sizes and bucket names returned to the agent are sent to whichever AI service runs it, under that service's terms.
|
|
9
|
+
License: Apache-2.0
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const ENV_FILES: string[];
|
|
2
|
+
/** Minimal dotenv parser: KEY=value, optional `export`, quotes, and trailing # comments. */
|
|
3
|
+
export declare function parseEnv(text: string): Record<string, string>;
|
|
4
|
+
/**
|
|
5
|
+
* Fills S4E_API_KEY and S4E_BUCKET from the project's .env files when the MCP config does
|
|
6
|
+
* not set them. Values already in `env` always win. Returns the files that supplied a value.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadEnvFiles(dir: string, env?: NodeJS.ProcessEnv): Promise<string[]>;
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
// Same order as Next.js and Vite in development: the first file that sets a value wins.
|
|
4
|
+
export const ENV_FILES = ['.env.development.local', '.env.local', '.env.development', '.env'];
|
|
5
|
+
// S4E_API_BASE and S4E_MCP_* are never read from files: a cloned project must not be able
|
|
6
|
+
// to send your key to another server or turn on write tools.
|
|
7
|
+
const FILE_KEYS = ['S4E_API_KEY', 'S4E_BUCKET'];
|
|
8
|
+
/** Minimal dotenv parser: KEY=value, optional `export`, quotes, and trailing # comments. */
|
|
9
|
+
export function parseEnv(text) {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const line of text.split(/\r?\n/)) {
|
|
12
|
+
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(line);
|
|
13
|
+
if (!match)
|
|
14
|
+
continue;
|
|
15
|
+
let value = match[2].trim();
|
|
16
|
+
const quote = value[0];
|
|
17
|
+
if ((quote === '"' || quote === "'") && value.lastIndexOf(quote) > 0)
|
|
18
|
+
value = value.slice(1, value.lastIndexOf(quote));
|
|
19
|
+
else
|
|
20
|
+
value = value.replace(/\s+#.*$/, '');
|
|
21
|
+
out[match[1]] = value;
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Fills S4E_API_KEY and S4E_BUCKET from the project's .env files when the MCP config does
|
|
27
|
+
* not set them. Values already in `env` always win. Returns the files that supplied a value.
|
|
28
|
+
*/
|
|
29
|
+
export async function loadEnvFiles(dir, env = process.env) {
|
|
30
|
+
const used = [];
|
|
31
|
+
for (const file of ENV_FILES) {
|
|
32
|
+
let text;
|
|
33
|
+
try {
|
|
34
|
+
text = await readFile(path.join(dir, file), 'utf8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const values = parseEnv(text);
|
|
40
|
+
let supplied = false;
|
|
41
|
+
for (const key of FILE_KEYS) {
|
|
42
|
+
if (!env[key] && values[key]) {
|
|
43
|
+
env[key] = values[key];
|
|
44
|
+
supplied = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (supplied)
|
|
48
|
+
used.push(file);
|
|
49
|
+
}
|
|
50
|
+
return used;
|
|
51
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,27 @@ import { realpath } from 'node:fs/promises';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { Storage4Everyone } from '@storage4everyone/sdk';
|
|
5
5
|
import { createServer } from './server.js';
|
|
6
|
+
import { loadEnvFiles } from './env.js';
|
|
6
7
|
// stdout carries the MCP protocol; all diagnostics go to stderr.
|
|
8
|
+
const rootSetting = process.env.S4E_MCP_ROOT || process.cwd();
|
|
9
|
+
let root;
|
|
10
|
+
try {
|
|
11
|
+
root = await realpath(rootSetting);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
console.error(`S4E_MCP_ROOT folder not found: ${rootSetting}. Create it or set S4E_MCP_ROOT to an existing folder.`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
// The agent app starts the server in the project folder, so its .env files can supply the key.
|
|
18
|
+
const project = process.cwd();
|
|
19
|
+
const envFiles = await loadEnvFiles(project);
|
|
7
20
|
if (!process.env.S4E_API_KEY) {
|
|
8
|
-
console.error(
|
|
21
|
+
console.error(`S4E_API_KEY is not set. Add S4E_API_KEY=s4e_live_... to .env.local in ${project}, or pass it in the MCP server env. ` +
|
|
22
|
+
'Create a key in the Storage4Everyone dashboard under API Keys.');
|
|
9
23
|
process.exit(1);
|
|
10
24
|
}
|
|
11
25
|
// No automatic retries: rate-limit errors go back to the agent with their retry time.
|
|
12
26
|
const client = new Storage4Everyone({ maxRetries: 0 });
|
|
13
|
-
const root = await realpath(process.env.S4E_MCP_ROOT || process.cwd());
|
|
14
27
|
const allowWrite = process.env.S4E_MCP_ALLOW_WRITE === 'true';
|
|
15
28
|
await createServer({ client, root, allowWrite }).connect(new StdioServerTransport());
|
|
16
|
-
console.error(`Storage4Everyone MCP server ready (folder: ${root}, write tools: ${allowWrite ? 'on' : 'off'}).`);
|
|
29
|
+
console.error(`Storage4Everyone MCP server ready (folder: ${root}, settings from: ${envFiles.length ? envFiles.join(', ') : 'MCP env'}, write tools: ${allowWrite ? 'on' : 'off'}).`);
|
package/package.json
CHANGED