Multi-Volume Mount Transport.
mvmt exposes selected local folders through a small, permissioned tool API.
Mount folders into stable paths like /notes, /workspace, or /research,
then allow clients to search, list, read, write, or remove files within those
mounts. Clients never get full-computer access. They only see the mounts and
actions you allow.
client
|
v
mvmt
|
|-- /notes -> ~/Documents/Obsidian
|-- /workspace -> ~/code/mvmt
|-- /research -> ~/papersmvmt is not sync. mvmt is not cloud storage. mvmt is not a general-purpose filesystem server.
It is a local-first access layer for exposing specific parts of your machine through explicit mounts, narrow tools, and per-client permissions.
Many tools need controlled access to local files.
Giving a tool broad filesystem access is risky. Uploading everything into a cloud workspace is often unnecessary. Ad hoc local servers usually lack a clear permission model.
mvmt takes a narrower approach:
- Mount only the folders you want clients to see.
- Expose those folders through stable virtual paths.
- Give each client its own path/action permissions.
- Keep data on your machine.
- Audit what clients search, read, write, and remove.
Clients operate on virtual paths:
/notes
/workspace
/researchThey do not need to know where those folders live on disk.
Each mount maps a virtual path to a real local folder.
mounts:
- name: notes
path: /notes
root: /Users/you/Documents/Obsidian
writeAccess: falseDifferent clients can see different parts of the namespace.
clients:
- id: codex
permissions:
- path: /workspace/**
actions: [search, read, write]
- id: readonly-client
permissions:
- path: /notes/**
actions: [search, read]A write requires both:
- the client has
writepermission for the path; and - the mount has
writeAccess: true.
Protected paths such as .env, .claude/**, or other configured patterns
cannot be written or removed. mvmt also has a global secret-path deny list
for paths such as .mvmt/**, .ssh/**, .aws/**, .kube/**, and common
cloud/dev credential files. Those paths are blocked even if an older config
does not list them.
Run mvmt from this source checkout:
npm install
npm run build
npm link
mvmt serve -iThe current npm package named mvmt is not this CLI release yet. Until this
package is published with the mvmt executable, use the source install above.
On first run, mvmt creates:
~/.mvmt/config.yamlIt then walks through:
- adding local folder mounts;
- optionally enabling the pattern redactor;
- starting the MCP server.
For a one-off read-only folder without changing saved config:
mvmt serve --path ~/Documents -iAt least one enabled mount is required. If no mounts are configured, mvmt has no data to serve.
Add a read-only notes mount:
mvmt mounts add notes ~/Documents/Obsidian \
--mount-path /notes \
--read-only \
--description "Personal notes and project journals" \
--guidance "Search first. Read specific files before answering."Add a writable project mount:
mvmt mounts add workspace ~/code/mvmt \
--mount-path /workspace \
--write \
--protect ".env" \
--protect ".env.*" \
--protect ".claude/**" \
--description "mvmt source code and design docs" \
--guidance "Read README.md and docs before changing code."Then rebuild the index and serve:
mvmt reindex
mvmt serve -i| Area | Status |
|---|---|
| Local folder mounts | supported |
| Text index | supported as a JSON prototype index |
| MCP tools | search, list, read, write, remove |
| Mount management CLI | supported |
| API-token path permissions | supported via mvmt token add |
| Local Streamable HTTP | supported on 127.0.0.1 |
| Stdio mode | supported |
| OAuth/PKCE for web clients | supported, including Dynamic Client Registration |
| Tunnel mode | supported for personal remote access |
| Pattern redactor plugin | supported |
| Legacy proxy connector config | accepted by the schema for compatibility, ignored by the mount-only CLI runtime |
| Admin UI | not shipped |
| API-token issuance | supported for bearer-token clients |
| Remote mvmt mounts | not shipped |
| Binary/PDF/image indexing | not shipped |
mvmt can be used by MCP clients, local HTTP clients, and remote web clients through tunnel mode.
| Client | Transport | Status | Auth method | Notes |
|---|---|---|---|---|
| Claude Desktop | stdio | supported | process launch | Runs its own mvmt process from the client config |
| Claude Code | Streamable HTTP | supported | bearer token | Use a scoped API token from mvmt token add |
| Codex CLI | Streamable HTTP | supported | bearer token | Use a scoped API token from mvmt token add |
| Cursor | Streamable HTTP | expected | bearer token | Behavior depends on Cursor's MCP implementation |
| VS Code / Copilot | Streamable HTTP | expected | bearer token | Behavior depends on the MCP extension |
| claude.ai / ChatGPT web | public HTTPS tunnel | supported remote mode | OAuth/PKCE | Requires a reachable tunnel URL |
| Raw HTTP / curl | Streamable HTTP | debug only | bearer token | Must follow MCP session initialization rules |
Most local HTTP clients need:
URL: http://127.0.0.1:4141/mcp
Authorization: Bearer <token>In local legacy mode, <token> can be the internal session token from
mvmt token session. For normal scoped access, create an API token with
mvmt token add and use that token instead.
Remote web clients use the tunnel URL, usually ending in /mcp, and authorize
through OAuth 2.1 + PKCE.
mvmt supports RFC 7591 Dynamic Client Registration. Issued OAuth access tokens are audience-bound to the current mvmt resource, so a token minted for one mvmt instance cannot be replayed against another.
Claude Desktop is different: it launches mvmt over stdio, so there is no HTTP listener and no bearer token header.
When mounts[] is configured, mvmt exposes five MCP tools:
| Tool | Purpose | Required permission |
|---|---|---|
search |
Search indexed text chunks across permitted mounts | search |
list |
List visible mount roots or directories | read |
read |
Read one text file by virtual path | read |
write |
Create or overwrite one text file | write |
remove |
Delete one text file | write |
Important behavior:
list("/")returns visible mount roots with description, guidance, and write-access status.searchuses simple keyword scoring over indexed text chunks.readandwriteare text-only.writesupportsexpected_hashso clients can avoid overwriting stale reads.removedeletes files permanently. It does not remove directories.- Non-text files are hidden from
list, skipped by indexing, and rejected byread/write.
Supported text-like files include Markdown, plain text, JSON, YAML, TOML, CSV, logs, shell scripts, HTML/CSS/XML, and common source-code extensions.
Files over 2 MiB are skipped by the index and rejected by direct text reads.
The saved config lives at:
~/.mvmt/config.yamlInspect it:
mvmt configValidate it:
mvmt doctorManage mounts:
mvmt mounts list
mvmt mounts add
mvmt mounts edit
mvmt mounts removeMinimal config:
version: 1
server:
port: 4141
allowedOrigins: []
access: local
mounts:
- name: notes
type: local_folder
path: /notes
root: /Users/you/Documents/Obsidian
description: Personal notes and project journals.
guidance: Search first. Read specific files before answering.
exclude:
- .git/**
- node_modules/**
- .claude/**
- .mvmt/**
- .ssh/**
- .aws/**
protect:
- .env
- .env.*
- .claude/**
- .mvmt/**
- .ssh/**
- .aws/**
writeAccess: false
enabled: true
- name: workspace
type: local_folder
path: /workspace
root: /Users/you/code/mvmt
description: mvmt project source and design docs.
guidance: Read README.md and docs before changing code.
exclude:
- .git/**
- node_modules/**
- dist/**
protect:
- .env
- .env.*
- .claude/**
- .mvmt/**
- .ssh/**
- .aws/**
writeAccess: true
enabled: true
plugins:
- name: pattern-redactor
enabled: true
mode: redactMount fields:
| Field | Meaning |
|---|---|
name |
Stable lowercase mount id, such as notes |
path |
Virtual path visible to clients, such as /notes |
root |
Local folder on disk |
description |
Short summary returned from list("/") |
guidance |
Optional client-facing guidance returned from list("/") |
exclude |
Paths hidden from listing, reads, writes, removal, and indexing |
protect |
Paths that cannot be written or removed |
writeAccess |
Mount-level write gate; defaults to false |
enabled |
Whether the mount is active |
An Obsidian vault is just a local folder mount. There is no special Obsidian runtime connector in the current mount-only shape.
For local testing, mvmt keeps legacy behavior when no API tokens are configured:
the internal session bearer token can access all configured mounts. The session
token is stored at ~/.mvmt/.session-token with file mode 600. HTTP
mvmt serve creates it if it is missing.
For repeatable client access, create scoped API tokens:
mvmt token add codex --read /notes --ttl 7d
mvmt token add codex --write /workspace --ttl 30dmvmt token add prints the plaintext token once. mvmt stores only a scrypt
verifier in config. Tokens expire after 30 days by default; use values like
--ttl 30m, --ttl 7d, or --ttl never when creating or editing a token.
If a client asks for an authorization token, paste the printed mvmt_...
value. If a web client sends you through OAuth, paste the same token into the
mvmt approval page.
Once API tokens are present, /mcp becomes strict:
- bearer tokens must match a configured client
tokenHash; - OAuth access tokens inherit the API-token identity selected on the approval page;
- the session token no longer grants data-plane access;
- unknown OAuth clients are quarantined with zero permissions.
Tunnel mode can start with no API tokens, but MCP data access rejects the
legacy session token. Add API tokens to grant access. For temporary debugging
only, set MVMT_ALLOW_LEGACY_TUNNEL=1 to allow the legacy session token over a
tunnel.
API-token permissions are written against virtual paths, not local disk paths.
The underlying config field is currently named clients[].
clients:
- id: codex
name: Codex CLI
description: Local Codex token
expiresAt: "2026-05-06T12:00:00.000Z"
auth:
type: token
# Verifier for the client API key.
# Do not store the plaintext key.
tokenHash: "scrypt:v1:..."
rawToolsEnabled: false
permissions:
- path: /workspace/**
actions: [search, read, write]
- path: /notes/**
actions: [search, read]
- id: readonly-client
name: Read-only client
auth:
type: token
tokenHash: "scrypt:v1:..."
rawToolsEnabled: false
permissions:
- path: /notes/**
actions: [search, read]Policy is additive. A call succeeds only when the resolved API token has the required action for the target virtual path.
For writes, the mount itself must also have writeAccess: true, and the target
must not match protect.
| Command | Description |
|---|---|
mvmt serve |
Configure mvmt if needed, then start the MCP server |
mvmt serve -i |
Start with an interactive control prompt |
mvmt serve --path <dir> |
Temporarily serve one read-only folder |
mvmt reindex |
Rebuild the text index |
mvmt mounts |
List configured mounts |
mvmt mounts --json |
List configured mounts as JSON |
mvmt mounts add [name] [root] |
Add a local folder mount |
mvmt mounts edit [name] |
Edit a mount |
mvmt mounts remove [name] |
Remove a mount |
mvmt mounts remove [name] --yes |
Remove a mount without an interactive confirmation |
mvmt config |
Show the saved config summary |
mvmt config setup |
Rerun guided setup |
mvmt doctor |
Validate config and startup prerequisites |
mvmt token |
List scoped API tokens |
mvmt token add [id] |
Create or update a scoped API token |
mvmt token edit [id] |
Edit a scoped API token |
mvmt token rotate [id] |
Replace a scoped API token secret |
mvmt token remove [id] |
Remove a scoped API token |
mvmt token session |
Hidden compatibility command for the internal session token |
mvmt tunnel |
Show tunnel status |
mvmt tunnel config |
Choose and save a tunnel command |
mvmt tunnel start |
Start the configured tunnel |
mvmt tunnel refresh |
Restart the tunnel and print the new URL |
mvmt tunnel stop |
Stop public tunnel exposure |
mvmt tunnel disable |
Switch config back to local-only access |
mvmt tunnel logs |
Show recent tunnel output |
mvmt tunnel logs stream |
Stream live tunnel output |
mvmt --version |
Print version and check for updates |
Interactive mode accepts the same command groups:
> mounts
> mounts add
> mounts edit
> mounts remove
> config
> config setup
> token
> token add
> token edit
> token rotate
> token remove
> tunnel
> tunnel refreshOn mvmt serve, mvmt starts serving immediately and rebuilds the text index in
the background.
Search may return fewer results until the rebuild finishes.
Use:
mvmt reindexafter changing files outside mvmt or after editing mount configuration.
Writes and removes performed through mvmt rebuild the index automatically.
The current index is a JSON file beside the config file. SQLite and incremental file watching are planned but not shipped.
Every data operation is gated by path and action.
- HTTP mode binds to
127.0.0.1, not0.0.0.0. - HTTP
/mcpand/healthrequire authentication. - The session token is stored at
~/.mvmt/.session-tokenwith mode600. - Mount roots are resolved before access.
- Path traversal outside the mount root is rejected.
excludehides paths from listing, reading, writing, removal, and indexing.protectblocks write/remove for sensitive paths such as.envand.claude/**.- Global secret paths such as
.mvmt/**,.ssh/**,.aws/**,.kube/**, and common credential files are denied regardless of per-mount config. - Write operations require both client
writepermission and mountwriteAccess. - Unknown OAuth clients are quarantined once API-token/OAuth policy exists.
- Browser-origin checks block drive-by browser requests from non-local origins.
- The optional pattern redactor can warn, redact, or block configured regex matches before output reaches clients.
- Tool calls are appended to
~/.mvmt/audit.log.
Authentication controls who connects. Mounts and client policy control what they can access.
mvmt is local-first.
Remote clients cannot reach 127.0.0.1 directly, so tunnel mode can publish a
public HTTPS URL.
Remote access checklist:
- Mount only the folders the remote client needs.
- Prefer read-only mounts.
- Start the tunnel when ready. Without API tokens, the public endpoint is reachable but cannot read data.
- Create scoped API tokens with
mvmt token add. - Use
excludefor secrets that must not be read. - Use
protectfor files that must not be written or removed. - Watch
~/.mvmt/audit.logwhen testing a new remote client. - Use a stable tunnel URL for repeatable OAuth flows.
Quick tunnels are convenient but temporary.
- Local folders are the only shipped mount provider.
- mvmt currently runs as a single instance.
- Remote mvmt mounts are not shipped.
- The active CLI runtime is mount-only.
- Legacy proxy connector config still parses for compatibility, but proxy connectors are not loaded as runtime tools.
- Search is prototype keyword scoring, not semantic embedding search.
- PDFs, images, archives, and other binary files are skipped.
- There is no file watcher yet.
- API-token rotation is shipped. An admin UI is not shipped.
- mvmt does not sync, replicate, or resolve conflicts across machines.
Near-term:
- SQLite-backed text index.
- Incremental index updates.
- Better mount and API-token management commands.
- Admin UI for client keys, path permissions, audit, and mount visibility.
Later:
- Remote mvmt mounts.
- Multiple mount providers behind the same
search/list/read/write/removesurface. resolve(path) -> AccessPlanfor routing virtual paths to local or remote backends.
- Setup guide
- Client setup
- Text index prototype
- Remote access
- Audit log
- Threat model
- Troubleshooting
- Architecture
- Security policy
- Contributing
- Changelog
Contributions are welcome while the project is early.
Keep changes focused and security-conscious. Read CONTRIBUTING.md and report vulnerabilities through SECURITY.md.
MIT
