Skip to main content
Glama
tanongkiat

mcp-chatgpt-file-store

by tanongkiat

ChatGPT File Store — MCP Server

A Model Context Protocol server that lets ChatGPT (or any MCP client) save and manage files inside a sandboxed local folder on your Mac.

Everything ChatGPT does is confined to an allowed directory — it cannot read or write anywhere else on your machine.

What it does

ChatGPT gets these tools:

Tool

Purpose

list_allowed_directories

Shows where ChatGPT is allowed to save/read

list_directory

Lists files and folders in the store

read_file

Reads a text file

get_file_info

File metadata (size, modified time)

search_files

Finds files matching a pattern (*.md, *notes*)

get_knowledge

Returns the whole store as one body of knowledge — Markdown, or PlantUML when it describes a flow

write_file

Saves a file (creates folders automatically)

append_file

Appends to a running log/notes file

create_directory

Creates folders

move_file

Moves/renames files

delete_file

Deletes a file or folder

Related MCP server: Local Files MCP Server

Installation

Requirements: Node.js 18 or newer (node -v to check) and git.

# 1. Clone the repo
git clone https://github.com/tanongkiat/mcp-chatgpt-file-store.git
cd mcp-chatgpt-file-store

# 2. Install dependencies
npm install

# 3. Build (optional — dist/ is committed, so a fresh clone already runs)
npm run build

Verify the install by starting the server over HTTP and hitting the health endpoint from a second terminal:

npm run start:http
curl http://localhost:8080/health
# {"status":"ok","sessions":0}

Ctrl+C stops it, or npm run stop from another terminal.

That's the whole install. Next: pick your sandbox folder (Setup), then connect a client — ChatGPT or Claude. Exposing the server beyond localhost? Read Authentication first.

Folder layout

mcp-chatgpt-file-store/
├── src/
│   ├── index.ts             # entrypoint — stdio or HTTP mode
│   ├── http.ts              # Streamable HTTP server (stateful sessions)
│   ├── server.ts            # MCP server + tool registration
│   ├── filesystem.ts        # sandboxed file operations + path safety
│   └── knowledge.ts         # knowledge gathering + PlantUML flow extraction
├── scripts/
│   ├── generate-token.sh    # create + save an auth token
│   ├── start-with-auth.sh   # generate token and start the HTTP server
│   ├── start-daemon.sh      # start detached (nohup + disown), logs to logs/
│   ├── stop.sh              # stop the HTTP server by port
│   ├── setup-claude.sh      # register this server with Claude
│   └── test-auth.sh         # verify auth is enforced
├── dist/                    # compiled output (committed, so no build needed to run)
├── Storage/                 # default sandbox — <folder where server runs>/Storage
└── package.json

Documentation

Doc

Covers

GETTING_STARTED.md

First run, start to finish

QUICKSTART.md

Shortest path to an authenticated server

CLAUDE_SETUP.md

Registering the server with Claude

AUTH_FLOW.md

How token auth works end to end

TOKEN_SCRIPTS.md

What each script in scripts/ does

OAUTH_GUIDE.md

Full OAuth 2.0 for multi-user setups

SUMMARY.md

Project overview

Two ways to run it

The server supports two transports — pick whichever your client wants:

Mode

Command

Endpoint

stdio (default)

npm run start

n/a (local process)

Streamable HTTP

npm run start:http

http://localhost:8080/mcp

Setup

1. Choose where ChatGPT can save

By default the sandbox is <folder where the server runs>/Storage (i.e. the Storage/ folder inside this project). To use your own folder(s), set an environment variable:

export CHATGPT_FILE_STORE_DIRS="/path/to/my/notes,/path/to/another"
npm run inspect

This opens the MCP Inspector where you can call each tool before wiring it to ChatGPT.

3a. Connect over stdio

In ChatGPT, add a custom MCP server with this command:

node /absolute/path/to/mcp-chatgpt-file-store/dist/index.js

Tip: point the command at the built dist/index.js (not src), and use the absolute path. If you set CHATGPT_FILE_STORE_DIRS, make sure that environment variable is visible to the process ChatGPT launches.

3b. Connect over Streamable HTTP

Start the HTTP server (default port 8080):

npm run start:http

Or with a custom port/host:

node dist/index.js --http --port 9090 --host 0.0.0.0
# or via environment variables
MCP_HTTP_PORT=9090 MCP_HTTP=1 node dist/index.js

Via the npm script, pass flags after --:

npm run start:http -- --port 9090 --host 0.0.0.0

Then register http://localhost:8080/mcp as the MCP server URL in ChatGPT.

3c. Connect to Claude Desktop

Any MCP client works, not just ChatGPT. For Claude Desktop, run the interactive setup script — it resolves the absolute path to dist/index.js, asks which folder to sandbox, and writes the entry into claude_desktop_config.json:

./scripts/setup-claude.sh

Restart Claude Desktop afterwards, then confirm the server appears in its MCP server list. See CLAUDE_SETUP.md for the manual config.

For Claude Code, register it from the command line instead:

claude mcp add file-store -- node /absolute/path/to/mcp-chatgpt-file-store/dist/index.js

Set MCP_AUTH_TOKEN to require a Bearer token on every /mcp request:

MCP_AUTH_TOKEN=$(openssl rand -hex 32) node dist/index.js --http

The server accepts tokens via two methods:

  1. Authorization header (standard):

    curl -H "Authorization: Bearer <token>" http://localhost:8080/mcp
  2. Query parameter (convenient for some clients):

    curl http://localhost:8080/mcp?token=<token>

Both methods are validated using constant-time comparison for security. Requests without a valid token receive 401 Unauthorized. The /health endpoint stays open (no token needed) for liveness checks.

Query-parameter tokens land in browser history and proxy/nginx access logs in a way headers do not. Prefer the header wherever the client allows it.

Sessions

Streamable HTTP is session-based, so a URL alone is not a connection. POST /mcp with initialize mints a session and returns it in the Mcp-Session-Id response header; every later request must present that id, via the header or a ?session=<id> query parameter. GET /mcp only opens the SSE stream for an existing session — it is not how you call the server.

This is why pasting the /mcp URL into a browser returns Missing session: a browser sends a bare GET with no session, and it cannot send Accept: text/event-stream either. Use /health for a browser-friendly check, or drive the handshake with curl:

URL="http://localhost:8080/mcp?token=<token>"

SID=$(curl -s -D- -X POST "$URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' \
  -o /dev/null | grep -i '^mcp-session-id' | tr -d '\r' | awk '{print $2}')

curl -s -X POST "$URL&session=$SID" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

A real MCP client does all of this for you — you only give it the URL.

When registering the connector in ChatGPT, add the token as a custom header: Authorization: Bearer <token>.

If MCP_AUTH_TOKEN is not set, the server logs a startup warning and accepts unauthenticated requests — fine for quick local testing, not for anything reachable from the internet.

For full OAuth 2.0 implementation (multi-user scenarios), see OAUTH_GUIDE.md.

Quick Start with Authentication

For the easiest way to start with authentication:

# Auto-generate token and start server
npm run start:auth

This script will:

  • Generate a secure 64-character token

  • Save it to .mcp-token for reuse

  • Start the HTTP server with authentication

  • Display the token and usage examples

Or generate a token separately:

# Generate and save token
npm run generate-token

# Start server manually
source .env && npm run start:http

See QUICKSTART.md for more details.

Running detached (servers, remote hosts)

start:auth and start:http hold the terminal. To leave the server running after you log out — the usual case on a VPS:

npm run start:daemon

It reuses the token from .mcp-token, starts the server under nohup and disown so it survives SIGHUP, appends output to logs/mcp-server.log, and writes the PID to .mcp-server.pid. It refuses to start if the port is already taken, and reports the log tail if the server dies on startup instead of leaving you with a silent failure.

npm run start:daemon -- --port 9090 --host 127.0.0.1
tail -f logs/mcp-server.log
npm run stop

Both logs/ and .mcp-server.pid are gitignored.

For a machine that reboots, prefer a real supervisor (systemd on Linux, launchd on macOS) — nohup survives logout, not restarts.

Stopping the server

start:auth and start:http run in the foreground, so Ctrl+C stops them. If the server is running detached or in another terminal, stop it by port:

npm run stop                      # stops the server on port 8080
npm run stop -- --port 9090       # a different port
npm run stop -- --force           # SIGKILL if it ignores SIGTERM

It sends SIGTERM first, waits up to 5 seconds for the port to free, and exits 0 if nothing was listening.

HTTP Transport

The server implements the MCP Streamable HTTP transport:

  • POST /mcp — JSON-RPC requests (first call creates a session and returns a Mcp-Session-Id header; send it back on subsequent requests)

  • GET /mcp — SSE stream for server-initiated messages

  • DELETE /mcp — ends a session

  • GET /health — liveness check ({"status":"ok","sessions":N})

Web login + browse (/login/mcp/browse)

In addition to the JSON-RPC API, the HTTP server serves a small password-protected file browser so you can view /Storage from a normal web browser:

  • GET /login — login form (username + password)

  • POST /login — validates credentials, then sets an HttpOnly session cookie

  • GET /mcp/browse — the authenticated file browser for /Storage

  • GET /mcp/browse?path=docs — navigate into a subfolder

  • GET /mcp/browse?view=notes.md — view a file's contents

  • GET|POST /logout — clears the session cookie

Authentication is username/password (separate from the MCP bearer token), not OAuth. Sessions are HttpOnly, SameSite=Lax cookies signed with an HMAC key. Every path is still resolved through the same sandbox as the MCP tools, so an authenticated user can never read or navigate outside the allowed directories.

Configuration (all optional — sensible defaults apply):

Variable

Default

Notes

MCP_BROWSE_USER

admin

Login username

MCP_BROWSE_PASSWORD

falls back to MCP_AUTH_TOKEN

Login password

MCP_BROWSE_SECRET

falls back to MCP_AUTH_TOKEN (else random)

HMAC key for session cookies

If neither MCP_BROWSE_PASSWORD nor MCP_AUTH_TOKEN is configured, web login is disabled (the server logs a warning). When using start:auth or start:daemon, MCP_AUTH_TOKEN is already exported, so you can log in with username admin and your bearer token as the password.

# Quick manual start with explicit credentials
MCP_BROWSE_USER=admin MCP_BROWSE_PASSWORD=secret \
  node dist/index.js --http --port 8080
# Then open http://localhost:8080/mcp/browse

Knowledge retrieval

get_knowledge reads everything in the store at once, rather than making the model open files one by one:

get_knowledge({
  "query": "auth",        // optional: only docs whose path or text matches
  "format": "auto",       // "auto" | "markdown" | "plantuml"
  "max_bytes": 100000     // budget across all documents
})

Formats:

  • markdown — every document concatenated under ## path/to/file.md headings.

  • plantuml — diagrams only. A document yields a diagram three ways: an existing @startuml block or ```plantuml fence is passed through unchanged; two or more A -> B: label lines become a sequence diagram; two or more numbered steps become an activity diagram.

  • auto (default) — Markdown, with a PlantUML section prepended when any document describes a flow.

So 1. User submits the form / 2. Service validates the email turns into:

@startuml
start
:User submits the form;
:Service validates the email;
stop
@enduml

Binary files and unknown extensions are skipped, and files are read through the same sandbox checks as every other tool.

The extraction is deterministic pattern-matching, not interpretation — it finds flows that are already written as diagrams, arrows, or numbered steps. For prose that merely implies a process, use format: "markdown" and let the model author the diagram.

Example usage

Once connected, you can tell ChatGPT things like:

  • "Save the summary of our conversation to notes/summary.md"

  • "Append today's ideas to ideas.md"

  • "List everything in the projects folder"

  • "Search for files containing draft in the name"

Security notes

  • Every path is resolved and checked against the allowed roots before any operation.

  • .. traversal and paths outside the roots are rejected with an error.

  • In stdio mode the server exposes no network port at all.

  • In HTTP mode the server binds to 0.0.0.0:8080 by default — use --host 127.0.0.1 to restrict it to localhost only. Sessions are tracked by random UUID. Set MCP_AUTH_TOKEN (see Authentication above) before exposing this server beyond localhost — without it, anyone who finds the URL can read/write files in the sandbox.

  • Only the configured directory is readable/writable — treat the sandbox as not secret (ChatGPT content is processed by the model provider).

Commands

npm run build          # compile TypeScript
npm run watch          # recompile on change
npm run start          # run compiled server over stdio
npm run start:http     # run compiled server over Streamable HTTP (port 8080)
npm run start:auth     # generate a token and start the HTTP server with auth
npm run start:daemon   # start detached (survives logout), logs to logs/
npm run stop           # stop the HTTP server (SIGTERM, then --force for SIGKILL)
npm run generate-token # create a token and save it to .mcp-token
npm run dev            # run stdio mode with tsx (no build step)
npm run dev:http       # run HTTP mode with tsx (no build step)
npm run inspect        # open MCP Inspector UI
Install Server
F
license - not found
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personal…

  • MCP server for freefirecommunity documentation, generated by doc2mcp.

  • MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tanongkiat/mcp-chatgpt-file-store'

If you have feedback or need assistance with the MCP directory API, please join our Discord server