@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 CHANGED
@@ -1,75 +1,9 @@
1
- # Storage4Everyone MCP server
1
+ # @storage4everyone/mcp
2
2
 
3
- `@storage4everyone/mcp` lets AI agents (Claude Code, Claude Desktop, Cursor and other [Model Context Protocol](https://modelcontextprotocol.io) clients) list, download, upload and delete files in your Storage4Everyone buckets.
3
+ A [Model Context Protocol](https://modelcontextprotocol.io) server for **Storage4Everyone (S4E)** cloud object storage.
4
4
 
5
- It runs on your own machine, started by the agent app, and calls the same API as the [JavaScript SDK](https://www.npmjs.com/package/@storage4everyone/sdk) with your API key. The key's scopes, bucket list, expiry, rate limits and quotas apply to everything the agent does.
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
- ## 1. Create a key for the agent
7
+ 📘 Full documentation: [docs.storage4everyone.com](https://docs.storage4everyone.com)
8
8
 
9
- In **Dashboard → API Keys**, create a separate key for each agent:
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('S4E_API_KEY is not set. Create an API key in the Storage4Everyone dashboard and pass it in the MCP server env.');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storage4everyone/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Model Context Protocol server that lets AI agents use Storage4Everyone buckets with your API key",
5
5
  "type": "module",
6
6
  "main": "./dist/server.js",