Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ This project follows the spirit of Keep a Changelog and uses semantic versioning
- Build specs and `rules.md` removed from the public tracked surface.
- `mvmt start -i` interactive control prompt with token, status, URL, and live-log controls.
- Typed connector setup registry (`src/connectors/setup-registry.ts`) so each connector owns its own detection, prompting, and config application.
- Optional `clients[]` policy with per-client auth bindings, raw-tool visibility, and source/action permissions.
- Optional `semanticTools` config for `search_personal_context` and `read_context_item`.

### Changed

- Internal refactor: `src/cli/start.ts` split into focused modules (`connector-loader`, `interactive`, `tunnel-controller`). Per-connector setup extracted into `src/connectors/{filesystem,obsidian,mempalace}-setup.ts`. Shared `saveConfig()` consolidated on `src/config/loader.ts`.
- `PluginSchema` is now a single-variant `z.discriminatedUnion('name', ...)` so adding a second plugin is a schema addition rather than a structural refactor.
- OAuth `/authorize` now defaults a missing `resource` parameter to the instance's canonical `/mcp` resource for client compatibility, while preserving token audience binding and still rejecting explicit wrong resources.
- Tool listing, tool calls, health tool counts, and audit entries are now client-identity aware when `clients[]` is configured.

### Deprecated

Expand Down Expand Up @@ -58,5 +61,5 @@ This project follows the spirit of Keep a Changelog and uses semantic versioning

- Tunnel mode is experimental.
- OAuth/tunnel auth is not production-ready.
- No per-client connector scoping yet.
- No admin UI or token issuance CLI yet.
- No native Postgres, SQLite, or Git connector yet.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ For source installs, connector setup, client tokens, and troubleshooting, see th
| Interactive start mode | supported |
| Built-in pattern-based redactor plugin | supported, opt-in during `mvmt config setup` or first `mvmt serve` |
| Tunnel mode | supported for personal remote access; quick tunnel URLs are temporary |
| Managed remote relay / per-client remote access | not in v0 |
| HTTP proxy write gates | incomplete; advanced/manual config only |
| Per-client tool scopes | supported via config; admin UI and token issuance CLI are not yet shipped |
| High-level context tools | supported for configured search/read sources with keyword-union retrieval |
| Managed remote relay | not in v0 |
| HTTP proxy write gates | supported |

## Client Compatibility

Expand All @@ -66,13 +68,16 @@ Every file and data access in mvmt is gated. There is no open mode.
- HTTP mode binds to `127.0.0.1`, not `0.0.0.0`.
- HTTP requests to `/mcp` and `/health` require a bearer token.
- The bearer token is stored at `~/.mvmt/.session-token`, reused across restarts, and rotated explicitly with `mvmt token rotate`.
- Optional `clients[]` entries map local bearer tokens or OAuth client IDs to per-client tool permissions.
- Browser requests from non-localhost origins are rejected unless allowlisted.
- Write access is opt-in per connector.
- Raw tool visibility and calls are filtered by client/source/action policy when `clients[]` is configured.
- High-level `search_personal_context` and `read_context_item` tools can expose configured read/search sources without exposing raw connector tools.
- Stdio child processes receive a scrubbed environment.
- Optional pattern-based redactor can warn, redact, or block configured regex matches in tool results.
- Tool calls are appended to `~/.mvmt/audit.log`.

Not yet enforced: TLS on localhost, per-client tokens, rate limiting, and full write gates for HTTP proxy connectors.
Not yet shipped: admin UI, token issuance CLI, memory-write semantic tool, managed relay, and TLS on localhost.

## Project Docs

Expand Down Expand Up @@ -113,6 +118,8 @@ See [Client Setup](docs/client-setup.md) for step-by-step instructions for Claud
- **`server`** — port, allowed origins, and whether to start a tunnel for public access.
- **`proxy`** — external MCP servers that mvmt proxies (e.g. filesystem and MemPalace).
- **`obsidian`** — the native Obsidian vault connector.
- **`clients`** — optional per-client auth bindings and source/action permissions.
- **`semanticTools`** — optional high-level context tools backed by allowed sources.
- **`plugins`** — security plugins that inspect tool results before they reach clients (e.g. the pattern-based redactor).

You should not need to write this file by hand. To re-run setup, use `mvmt config setup`. To inspect it, run `mvmt config`. To validate it, run `mvmt doctor`.
Expand Down Expand Up @@ -322,10 +329,12 @@ Every file and data access in mvmt is gated. There is no open mode.
- **Origin allowlist** — browser requests from non-localhost origins are rejected unless explicitly allowed.
- **Environment scrubbing** — stdio child processes receive only an allowlist of env vars.
- **Write gates** — read-only by default per connector; write tools are hidden and rejected unless enabled.
- **Per-client policy** — optional `clients[]` entries filter raw tool visibility and calls by source/action permission. Unknown OAuth client IDs are rejected as quarantined when policy is configured.
- **Semantic context tools** — optional `search_personal_context` and `read_context_item` tools provide a smaller read/search surface for clients that should not see raw connector tools.
- **Pattern redactor** — opt-in regex scrubbing of tool results before they reach clients.
- **Audit log** — every tool call appended to `~/.mvmt/audit.log` as JSONL with mode `600`.

Not yet enforced: TLS on localhost, per-client connector scoping, and write gates for HTTP proxy connectors.
Not yet shipped: admin UI, token issuance CLI, memory-write semantic tool, managed relay, and TLS on localhost.

See [Security Memo](docs/security-memo.md) for design notes and [Audit Log](docs/audit-log.md) for log format and queries.

Expand Down Expand Up @@ -364,7 +373,8 @@ Planned work is focused on safer long-running use and better local data coverage

- Fast file indexer with Chroma's embedded JS/TS version.
- Full key management: named keys, rotation, revocation, expiration.
- Per-client permissions and connector scoping.
- Admin UI for client keys, permissions, and semantic tool mappings.
- `save_personal_memory` with explicit memory-write permission and audit visibility.
- Runtime permission changes for folders, vaults, and connector write access.
- Remote access hardening guides for Cloudflare Named Tunnels, Cloudflare Access, and rate limiting.
- SQLite connector with per-table read/write permissions.
Expand Down
58 changes: 37 additions & 21 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ It is not a connector registry, marketplace, or bundled catalog of third-party s
| | | - bearer token | ||
| | | - origin check | ||
| | | - OAuth/PKCE bridge | ||
| | | - client identity | ||
| | +----------+-----------+ ||
| | | ||
| | v ||
| | +----------------------+ ||
| | | Tool router | ||
| | | | ||
| | | namespaces tools | ||
| | | filters by policy | ||
| | | semantic tools | ||
| | | routes calls | ||
| | | applies plugins | ||
| | | writes audit log | ||
Expand Down Expand Up @@ -144,29 +147,29 @@ Tunnel mode provides public HTTPS access for cloud and web MCP clients. Quick tu

## Request Pipeline

Every tool call follows the same path.
Every tool list and tool call follows the same path.

```text
+---------+ +--------------+ +------------+ +-------------+ +----------+
| client | --> | auth/origin | --> | write gate | --> | tool router | --> | connector|
+---------+ +--------------+ +------------+ +------+------+ +----+-----+
^ |
| v
| +-------------+
| | raw result |
| +-------------+
| |
| v
| +-------------+
+-- | plugins |
| redactor |
+------+------+
|
v
+-------------+
| audit log |
| ~/.mvmt/ |
+-------------+
+---------+ +--------------+ +----------------+ +-------------+ +----------+
| client | --> | auth/origin | --> | client policy | --> | tool router | --> | connector|
+---------+ +--------------+ +----------------+ +------+------+ +----+-----+
^ |
| v
| +-------------+
| | raw result |
| +-------------+
| |
| v
| +-------------+
+-- | plugins |
| redactor |
+------+------+
|
v
+-------------+
| audit log |
| ~/.mvmt/ |
+-------------+
```

## Tool Names
Expand All @@ -184,6 +187,19 @@ mvmt namespaces tools by connector ID so different connectors can expose tools w
+--------------------+----------------------+--------------------------------+
```

When `semanticTools` is configured, mvmt also exposes high-level tools without connector prefixes:

```text
+-------------------------+------------------------------------------------+
| Tool | Purpose |
+-------------------------+------------------------------------------------+
| search_personal_context | Keyword-union retrieval across allowed sources |
| read_context_item | Read an item returned by search |
+-------------------------+------------------------------------------------+
```

These tools are policy-aware. A client can see and call them only for configured sources where its permissions include the required action.

## Shutdown

SIGINT or SIGTERM triggers shutdown. All cleanup tasks run in parallel:
Expand Down
3 changes: 3 additions & 0 deletions docs/audit-log.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Each tool call appends one JSON object:
"ts": "2026-04-14T14:23:01.442Z",
"connectorId": "obsidian",
"tool": "obsidian__search_notes",
"clientId": "chatgpt",
"argKeys": ["query", "maxResults"],
"argPreview": "{\"query\":\"meeting notes\",\"maxResults\":10}",
"redactions": [
Expand All @@ -34,10 +35,12 @@ Each tool call appends one JSON object:
| `ts` | ISO 8601 timestamp. |
| `connectorId` | Which connector handled the call (e.g. `obsidian`, `proxy_filesystem`). |
| `tool` | The namespaced tool name the MCP client used. |
| `clientId` | Present when HTTP auth resolved to a configured or legacy client identity. |
| `argKeys` | Argument key names, without values. |
| `argPreview` | Truncated JSON of the arguments (max 512 characters). Can contain values. |
| `redactions` | Present when `pattern-redactor` matched. Records the plugin, mode, pattern name, and match count. |
| `isError` | `true` if the connector returned an error or the call threw. |
| `deniedReason` | Present when mvmt denied a tool call before it reached a connector. |
| `durationMs` | Time from call start to result, in milliseconds. |

## Querying the log
Expand Down
4 changes: 3 additions & 1 deletion docs/client-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Most MCP clients let you add servers through their settings UI. You only need tw

Stdio mode (Claude Desktop) is the exception — it launches mvmt directly and does not need a token.

If `clients[]` is configured in `~/.mvmt/config.yaml`, HTTP clients should use their configured client token instead of the owner/session token. The owner/session token remains the legacy data-plane credential only when no `clients[]` policy exists.

## Remote OAuth clients

Web clients that connect through a public HTTPS tunnel use OAuth/PKCE instead of a bearer token. mvmt will only authorize a client if its exact callback URL is registered first.
Expand All @@ -38,7 +40,7 @@ curl -X POST https://your-public-mvmt-host/register \
}'
```

Use the same `client_id` and exact `redirect_uri` during `/authorize`.
Use the same `client_id` and exact `redirect_uri` during `/authorize`. When `clients[]` is configured, map that OAuth `client_id` to a named client before expecting access to tools; unknown OAuth client IDs are rejected as quarantined.

## Claude Desktop

Expand Down
68 changes: 63 additions & 5 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ server:
access: local

proxy:
- name: filesystem
source: manual
- id: workspace
name: filesystem
transport: stdio
command: npx
args:
Expand All @@ -27,8 +27,8 @@ proxy:
writeAccess: false
enabled: true

- name: mempalace
source: mempalace
- id: mempalace
name: mempalace
transport: stdio
command: /Users/you/.local/pipx/venvs/mempalace/bin/python
args:
Expand All @@ -45,6 +45,37 @@ obsidian:
enabled: true
writeAccess: false

clients:
- id: codex
name: Codex CLI
auth:
type: token
tokenHash: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
rawToolsEnabled: true
permissions:
- sourceId: workspace
actions: [search, read, write]
- sourceId: obsidian
actions: [search, read]

- id: chatgpt
name: ChatGPT
auth:
type: oauth
oauthClientIds: ["chatgpt-mvmt"]
rawToolsEnabled: false
permissions:
- sourceId: obsidian
actions: [search, read]

semanticTools:
searchPersonalContext:
enabled: true
sourceIds: [workspace, obsidian]
readContextItem:
enabled: true
sourceIds: [workspace, obsidian]

plugins:
- name: pattern-redactor
enabled: true
Expand Down Expand Up @@ -143,8 +174,9 @@ A list of external MCP servers that mvmt proxies. Each entry launches a child pr

| Field | Default | Description |
| --- | --- | --- |
| `id` | `name` | Stable source ID used by client permissions and semantic tools. |
| `name` | — | Identifier used in tool namespacing (e.g. `proxy_filesystem__read_file`). |
| `source` | — | Optional label for where this entry came from (e.g. `manual`). |
| `source` | — | Legacy setup-provenance label. Accepted for old configs but ignored at runtime. |
| `transport` | `stdio` | `stdio` spawns a child process. `http` connects to an existing HTTP MCP server. |
| `command` | — | Required for `stdio`. The command to run. |
| `args` | `[]` | Arguments passed to the command. |
Expand All @@ -169,6 +201,32 @@ Configures the native Obsidian vault connector. This connector reads markdown fi
| `enabled` | `true` | Set to `false` to disable the connector. |
| `writeAccess` | `false` | When `true`, exposes `append_to_daily` for writing to daily notes. |

The native Obsidian source ID is always `obsidian`.

### `clients`

Optional per-client policy. When omitted, mvmt preserves legacy single-token behavior: the owner/session token can use the configured tool surface. When present, `/mcp` requires a configured client token or mapped OAuth client ID, and the owner/session token is no longer a data-plane credential.

| Field | Description |
| --- | --- |
| `id` | Stable client ID used in audit and policy. Lowercase letters, numbers, `_`, and `-`. |
| `name` | Human-readable client name. |
| `auth.type` | `token` for local bearer-token clients, or `oauth` for web clients. |
| `auth.tokenHash` | SHA-256 hex hash of the client bearer token. Plaintext tokens are not stored. |
| `auth.oauthClientIds` | OAuth `client_id` values mapped to this client. Unknown OAuth client IDs are quarantined when clients are configured. |
| `rawToolsEnabled` | Whether raw connector tools are listed and callable for this client. |
| `permissions` | Source/action grants. Actions are `search`, `read`, `write`, and `memory_write`. |

### `semanticTools`

Optional high-level tools backed by configured sources. These tools are useful for clients that should search/read context without seeing raw connector tools.

| Field | Description |
| --- | --- |
| `searchPersonalContext` | Exposes `search_personal_context` for sources where the client has `search`. Retrieval is keyword union, not embedding ranking. |
| `readContextItem` | Exposes `read_context_item` for sources where the client has `read`. |
| `sourceIds` | Source IDs the semantic tool may use. The client must also have the matching source/action permission. |

### `plugins`

A list of plugins that inspect or transform tool results before they reach MCP clients. Currently the only built-in plugin is `pattern-redactor`.
Expand Down
3 changes: 2 additions & 1 deletion docs/connectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ Proxy connectors still need mvmt-side guardrails:

- Stdio children get scrubbed environment variables.
- Known write tools are hidden and rejected when `writeAccess: false`.
- Raw tool visibility and calls are filtered by per-client source/action policy when `clients[]` is configured.
- Tool calls still go through plugins and audit logging.

HTTP proxy write gates are not complete in v0. Treat HTTP proxy connectors as advanced/manual configuration.
HTTP proxy connectors use the same write-tool policy as stdio proxy connectors.

### MemPalace proxy setup

Expand Down
Loading
Loading