Skip to main content
Glama

Librarian MCP

An MCP server that lets an AI client browse, search and read files you mount into its Docker container, reached remotely through a tunnel.

Mount a folder on /data, start the container, and it serves that folder over MCP (Streamable HTTP with a bearer token). The image bundles cloudflared and opens the tunnel itself, so a single docker run gives you a public HTTPS endpoint.

Tools

Tool

What it does

list_directory

Entries of a directory with type, size, mode, owner and mtime

stat

Metadata for one path (symlinks are reported, not followed)

read_file

Read a file or a byte range, as UTF-8 or base64, paged by MAX_READ_BYTES

search_files

Find names matching a glob (*.log, nginx*.conf) under a directory

write_file, make_directory, move, delete

Only registered when WRITE_ENABLED=true

Clients see the mounted folder as /, so /reports/q3.csv is /data/reports/q3.csv in the container. Paths are resolved like a chroot: .. stops at that root, and symlinks, absolute or relative, are followed inside the mounted folder, never outside it.

Related MCP server: filezop

Quick start

docker build -t librarian-mcp .

# Serve a host folder, read-only
docker run -d --name librarian -v /path/to/files:/data:ro librarian-mcp
docker logs -f librarian

The logs print everything a client needs:

Librarian MCP is reachable at:
  URL:   https://<random-words>.trycloudflare.com/mcp
  Token: 3f1c…  (generated, set MCP_TOKEN to choose your own)

  Claude Code:
  claude mcp add --transport http librarian https://<random-words>.trycloudflare.com/mcp --header "Authorization: Bearer 3f1c…"

  Claude Desktop / claude.ai:
  Settings > Connectors > Add custom connector, URL https://<random-words>.trycloudflare.com/mcp
  then paste the token on the authorization page that opens.

Mount with :ro unless you also set WRITE_ENABLED=true. A named Docker volume works the same way (-v my-volume:/data).

The same setup as a compose file is in examples/docker-compose.yml.

Tunnel modes

  • Quick tunnel (default): no Cloudflare account needed. The URL is random and changes on every restart, and Cloudflare gives no uptime guarantee, so it is meant for ad hoc access.

  • Named tunnel: create a tunnel in the Cloudflare dashboard (Zero Trust → Networks → Tunnels), add a public hostname pointing to http://localhost:8787, and pass its token as CLOUDFLARE_TUNNEL_TOKEN. The endpoint is then https://<your-hostname>/mcp, stable across restarts, and you can put Cloudflare Access in front of it.

  • No tunnel: TUNNEL=none serves on 0.0.0.0:8787 only, for use with -p or your own tunnel (ngrok, Tailscale, ssh -R).

When a tunnel is on, the server listens on 127.0.0.1 only, so the tunnel is the only way in. If cloudflared stops, the container exits so its restart policy can bring both back.

Without Docker, npm run build && ROOT_DIR=/path/to/files MCP_TOKEN=… node dist/index.js serves a local folder (add --stdio for a local stdio client).

Client configuration

There are two ways to authenticate, and both use the same MCP_TOKEN:

  • Bearer token, for clients that let you set a header (Claude Code, most MCP configs).

  • OAuth, for Claude Desktop and claude.ai custom connectors, which only support OAuth. Add a custom connector with the /mcp URL and no client ID or secret. Claude identifies itself with its published client ID (a Client ID Metadata Document URL, which the server fetches and checks) or registers itself dynamically, then opens an authorization page served by Librarian MCP, and you paste MCP_TOKEN there once. Claude then gets its own access token (valid one hour) and refresh token (valid 30 days).

OAuth needs the server's public URL. It is detected automatically with a quick tunnel; with a named tunnel or your own tunnel, set PUBLIC_URL=https://<your-hostname>. Client registrations and tokens are encrypted with a key derived from MCP_TOKEN rather than stored, so they survive restarts, and changing MCP_TOKEN revokes all of them. With a quick tunnel the URL changes on every restart, so the connector has to be added again. The authorization page shows the host a published client ID comes from (for example claude.ai), since the client name itself is self-declared.

{
  "mcpServers": {
    "librarian": {
      "type": "http",
      "url": "https://<your-tunnel>/mcp",
      "headers": { "Authorization": "Bearer <MCP_TOKEN>" }
    }
  }
}

With Claude Code: claude mcp add --transport http librarian https://<your-tunnel>/mcp --header "Authorization: Bearer <MCP_TOKEN>".

Configuration

Variable

Default

Meaning

ROOT_DIR

/data in the image, / otherwise

Directory exposed to clients as /

TUNNEL

cloudflare in the image, none otherwise

cloudflare starts the bundled cloudflared, none disables it

CLOUDFLARE_TUNNEL_TOKEN

unset

Named tunnel token. Unset means a quick tunnel

MCP_TOKEN

generated with a tunnel, else required

Bearer token for /mcp. Without a tunnel the server refuses to start without it

MCP_ALLOW_NO_AUTH

false

Run without a token, only on a trusted network. Also disables OAuth

PUBLIC_URL

detected with a quick tunnel

Public base URL (https://…), required for OAuth with a named tunnel or no tunnel

WRITE_ENABLED

false

Register the write tools

MAX_READ_BYTES

1048576

Largest chunk read_file returns per call

HOST / PORT

127.0.0.1 with a tunnel, else 0.0.0.0 / 8787

HTTP listen address

CLOUDFLARED_PATH

cloudflared

cloudflared binary to run

MCP_TRANSPORT

http

stdio to serve over stdin/stdout (same as --stdio)

GET /healthz answers without auth, for tunnel and container health checks.

Security

A quick tunnel makes the server reachable from the whole internet, protected only by the token (directly, or through the OAuth authorization page, which locks for a minute after 5 wrong tokens), and the URL shows up in your container logs. Anyone holding the token can read every file in the mounted folder. Keep the server read-only unless you need writes, use a long random token, and prefer a tunnel that adds its own access control (Cloudflare Access, Tailscale). To read client ID metadata documents the server makes outbound HTTPS requests to the URL a client presents; it refuses non-public addresses, redirects, documents over 5 KB and slow hosts, and caches results for five minutes. Symlinks are re-resolved on each call, but something that swaps a path component for a symlink between resolution and use can race the check, so do not mount a folder that untrusted processes write to while it is being served.

Development

npm install
npm test          # vitest
npm run typecheck
npm run dev       # tsx src/index.ts, needs MCP_TOKEN or MCP_ALLOW_NO_AUTH=true

Releases

Every push to main runs semantic-release once CI is green. It reads the commits since the last tag, so commit messages must follow Conventional Commits (fix: makes a patch, feat: a minor, feat!: or a BREAKING CHANGE: footer a major; chore:, docs:, ci: and the like release nothing). Pull requests run commitlint to catch bad messages.

A release creates the vX.Y.Z tag and GitHub release, commits CHANGELOG.md, and pushes a multi-arch image (amd64, arm64) to the GitHub Container Registry, so you can skip the build:

docker run -d --name librarian -v /path/to/files:/data:ro ghcr.io/pierrickrouxel/librarian-mcp:latest

Tags: X.Y.Z, X.Y, X and latest. Nothing is published to npm, and package.json carries no version: the tag is the source of truth, and the image passes it to the server through LIBRARIAN_VERSION (local builds report 0.0.0-dev).

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides file system operations (list, read, write, search) via MCP, enabling an AI agent to manage files through natural language.
    2,430 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes file system operations to AI clients via MCP, enabling secure read, write, and management of files and folders.
    7 npm
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Enables accessing and managing files from configured folders with filtering and size limits, allowing listing, reading, and searching files via MCP tools and resources.
    3
    -