Skip to main content
Glama
Egnyte Large File Manager

Egnyte Large File Manager

by hschickdevs
README.md
# Egnyte Large File Manager

A local [MCP](https://modelcontextprotocol.io) server that fills the **binary / large-file gap** in Egnyte's hosted MCP connector.

Egnyte's official connector only returns **extracted text** (`get_file_content`) into agent context — it never hands you the real file bytes. So you can't `pandas.read_excel()` / `openpyxl` a workbook, parse a native PDF, or re-package a `.msg`. This server adds the missing piece: **sign in with OAuth, then download the actual binary to local disk** (and chunk-upload large files back).

It is meant to run **alongside** the official Egnyte connector, not replace it:

| Use the official Egnyte MCP for | Use this server for |
| --- | --- |
| search, `list_filesystem`, text extraction, `ask_document`, metadata | downloading real file **binaries** to disk, chunked upload of large files |

> **Where it runs.** This is a **local stdio MCP server** (and `.mcpb` bundle). The download→disk→load flow only works where the MCP server shares a filesystem with code execution:
> - **Claude Code (CLI):** ✅ fully works — server and your code run on the same machine.
> - **Claude Cowork / sandboxes:** ⚠️ Cowork runs your code in an isolated VM whose filesystem is **separate** from the host where the MCP server runs, so a file the MCP downloads isn't visible to the VM's Python. Use the bundled **`python/egnyte_fetch.py`** *inside* the sandbox instead (see [Claude Cowork / cloud sandbox](#claude-cowork--cloud-sandbox)).
> - **claude.ai web chat:** ❌ remote connectors only; no local MCP, no Python filesystem.

## Tools

| Tool | Purpose | Returns |
| --- | --- | --- |
| `egnyte_download` | Download a file's real bytes to local disk by `path` or `group_id`. Streams — handles large files. | the local filesystem **path** (never the bytes) |
| `egnyte_upload` | Upload a local file to Egnyte. Automatically uses **chunked** upload above the size threshold. | entry/group id + checksum |
| `egnyte_stat` | Get file metadata (size, type, ids, checksum) — use to decide before downloading. | metadata object |
| `egnyte_login` | Force the OAuth browser sign-in (otherwise it happens lazily on first call). | sign-in status |

**The model gets a path, not the bytes** — so a 200 MB workbook never bloats the context. Your code then does `pd.read_excel("/path/from/tool")`.

## Auth — simple OAuth sign-in

Uses the **OAuth 2.0 authorization-code flow** over an **HTTPS localhost loopback redirect**. Egnyte does not support PKCE / public clients, so this is a confidential client: a `client_secret` is required and is stored as a sensitive config field (never logged).

1. On first tool call (or `egnyte_login`) the server opens your browser to Egnyte's sign-in page.
2. You log in **as yourself** — including via your company's SSO/SAML.
3. Egnyte redirects to `https://localhost:<port>/callback` (a self-signed loopback listener — accept the one-time browser cert warning); the server captures the code and exchanges it (with the `client_secret`) for a token.
4. The token is cached locally (`0600`-permission file in your config dir) and reused; it auto-refreshes, falling back to a browser re-auth only when the refresh token is gone.

Because you sign in as yourself, the server only sees what **your** Egnyte permissions allow — same access model as the official connector. No shared service account, no flattened ACLs.

**Headless / SSH:** set `EGNYTE_NO_BROWSER=1` — the server prints the authorize URL instead of launching a browser; open it on any machine that can reach your Egnyte domain, and it will redirect back to the loopback.

## Prerequisites

- **Node.js ≥ 18**
- An **Egnyte API key + secret**. Register an app at <https://developers.egnyte.com> → "Get an API Key". Register `https://localhost:53682/callback` as the allowed redirect (Egnyte requires HTTPS).
- Your **Egnyte domain** (e.g. `acme.egnyte.com`).

## Configure

**Local dev:** copy `.env.example` → `.env` and fill in `EGNYTE_DOMAIN`, `EGNYTE_CLIENT_ID`, and `EGNYTE_CLIENT_SECRET` (all required — Egnyte is a confidential client).

**Installed `.mcpb` bundle:** the host (Claude Desktop) prompts for these via the bundle's `user_config` — `client_secret` is stored as a sensitive field.

## Run / develop

```bash
npm install
npm run login     # one-time browser sign-in, caches token
npm run dev       # run the stdio server locally
npm run build     # compile to dist/
npm run pack      # build + package into egnyte-large-file-manager.mcpb
```

### Use with Claude Code

```bash
claude mcp add egnyte-large-file-manager --transport stdio -- node /abs/path/to/dist/server.js
```

(or install the packed `.mcpb` in Claude Desktop)

## Claude Cowork / cloud sandbox

In Cowork your code runs in an **isolated VM** whose filesystem is separate from the host where an MCP server runs — so the MCP's download wouldn't be visible to the VM's Python. For these environments use the bundled, dependency-free **`python/egnyte_fetch.py`**, which runs *inside* the sandbox and pulls bytes straight from the Egnyte API.

**1. Pre-seed a token** (interactive browser OAuth can't reach a headless VM):
- Run `npm run login` once on a machine with a browser, then inject the resulting token into the sandbox — either copy `~/.config/egnyte-mcp/tokens.json`, or set `EGNYTE_ACCESS_TOKEN` as a sandbox secret.
- Per-user ACLs are preserved **only if each user injects their own token** (not a shared one).

**2. Use it in the sandbox** (`EGNYTE_DOMAIN` + the token in env):
```bash
python egnyte_fetch.py download "/Shared/Docs/report.xlsx"   # prints {"path": "...", ...}
```
```python
from egnyte_fetch import download
import pandas as pd
path = download("/Shared/Docs/report.xlsx")["path"]
df = pd.read_excel(path, sheet_name=None)   # real binary, loaded in-VM
```

Same hardening as the MCP: `*.egnyte.com` host lock, `..` path rejection, download-dir confinement, SHA-512 verify, single + chunked upload.

## Security

- **Per-user OAuth** — no shared service token; Egnyte ACLs are enforced per signed-in user.
- **Client secret** — Egnyte requires a confidential client; the `client_secret` is stored as a sensitive config field and is never logged or returned to the model. OAuth `state` guards the callback against CSRF.
- **Token cache** is a `0600` file; it is git-ignored and must never be committed.
- **Least privilege** — request only the scopes you need (filesystem read; add write only if you upload).
- **Paths, not bytes** — file contents are written to disk and referenced by path, never echoed through the model.
- **Download confinement** — downloads are restricted to the configured download directory; a model-supplied `dest` cannot escape it (no `../` or absolute-path writes).
- **Host locked to `*.egnyte.com`** — the API host is validated, so a bad `EGNYTE_DOMAIN` can't exfiltrate the token/secret to another server. `..` segments in Egnyte paths are rejected.

## License

Apache-2.0. See [LICENSE](./LICENSE).

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct function: download, login, logout, stat, upload. No overlap in purpose.

Naming Consistency5/5

All tools follow a consistent 'egnyte_' prefix followed by a verb (download, login, logout, stat, upload), making them predictable.

Tool Count5/5

5 tools is well-scoped for a large file manager, covering authentication, metadata inspection, download, and upload without unnecessary extras.

Completeness4/5

Covers core operations for large files (login, stat, download, upload) but lacks delete, move, or list capabilities, which are minor gaps given the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo recent community issues