Skip to main content
Glama
tony816

Obsidian MCP for ChatGPT

by tony816
README.md
# Obsidian MCP for ChatGPT Web

This project connects an Obsidian vault to a ChatGPT custom MCP app through Cloudflare.

The recommended always-on, no-domain setup keeps one fixed ChatGPT URL and
continues working while the Windows PC is off:

```text
ChatGPT web
  -> fixed Cloudflare Worker URL (*.workers.dev)
  -> current Cloudflare quick tunnel on an OCI Always Free VM
  -> filesystem MCP bridge on 127.0.0.1:8000
  -> rclone OneDrive mount
  -> OneDrive/Obsidian Vault
  -> Windows Obsidian when the PC is online
```

The random `trycloudflare.com` origin can change after a reboot. A systemd
supervisor publishes the new origin to the Worker, so the `workers.dev` URL
saved in ChatGPT does not change. The original Windows launcher remains a
manual fallback.

## Modes

| Mode | Public URL | Authentication | ChatGPT setting |
| --- | --- | --- | --- |
| `worker-proxy` (recommended, no domain) | Fixed `*.workers.dev` URL | 256-bit secret URL path | None |
| `quick-tunnel` (fallback) | Changing `*.trycloudflare.com` URL | 256-bit secret URL path | None |
| `named-tunnel` (domain required) | Fixed custom hostname | Cloudflare Access OAuth plus origin JWT validation | OAuth |

The primary MCP transport is **Streamable HTTP** at `/mcp`. Legacy GET SSE remains available, but quick tunnels buffer it, so ChatGPT must use the URL ending in `/mcp`.

## Security properties

- The bridge listens only on loopback. The OCI VM requires no public inbound
  application port; `cloudflared` makes an outbound-only connection.
- In `worker-proxy` and `quick-tunnel` modes, every MCP path is below `/t/<64-hex-secret>/`; other paths return `404`.
- The path comparison at the local bridge and the Worker administrator-token comparison are timing-safe.
- The Worker administrator route accepts only authenticated updates containing a valid `https://*.trycloudflare.com` origin.
- Local secrets are encrypted with Windows DPAPI in ignored
  `config.local.json`; Cloudflare stores the Worker administrator token as a
  Worker secret. On OCI, the two bridge environment files are root-owned,
  group-readable only by the dedicated service user, and excluded from Git.
- `/healthz` is local-only. The Worker does not forward it.

The full MCP URL is a credential. Anyone who obtains it can use the vault tools, including write tools. Do not share it or commit it.

## Prerequisites for the Windows fallback and one-time Worker setup

- Windows PowerShell 5.1 or PowerShell 7
- Python 3.11+ and [`uv`](https://docs.astral.sh/uv/)
- Node.js and npm (for one-time Worker deployment)
- Obsidian with the Local REST API plugin
- [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/)
- A free Cloudflare account; no purchased domain is required for `worker-proxy`

Install the Python dependencies:

```powershell
uv sync
```

## Always-on OCI Free Tier setup

The deployed Linux layout, systemd units, OneDrive mount, recovery commands,
and free-tier constraints are documented in
[`OCI_ALWAYS_FREE_SETUP.md`](OCI_ALWAYS_FREE_SETUP.md). The relevant source
files are:

- `src/obsidian_chatgpt_bridge/filesystem_server.py` - direct vault backend
  exposing the same 12 MCP tools without running the Obsidian desktop app.
- `deploy/oci/*.service` - OneDrive mount, MCP bridge, and tunnel units.
- `scripts/oci_tunnel_supervisor.py` - quick-tunnel restart and stable Worker
  origin update.

The Windows task `Obsidian MCP ChatGPT` must remain disabled while OCI is the
primary host. Otherwise a Windows login could replace the Worker origin with a
PC-local tunnel.

## Windows fallback setup without a domain

1. Install the Obsidian Local REST API plugin if needed:

   ```powershell
   .\scripts\install_obsidian_local_rest_api.ps1 -VaultPath "<VAULT_PATH>"
   ```

2. Deploy the stable Worker. The first run opens one Cloudflare authorization page:

   ```powershell
   .\scripts\setup_stable_worker_proxy.ps1
   ```

3. Start and verify the full route:

   ```powershell
   .\scripts\launch_servers.ps1
   ```

4. Optionally register automatic startup 30 seconds after Windows logon only
   when Windows is the primary host:

   ```powershell
   .\scripts\install_autostart_task.ps1
   ```

5. Create or update the ChatGPT custom app:

   - MCP URL: the value printed by the launcher and stored in `runtime\last_chatgpt_mcp_url.txt`
   - Authentication: **None**

The URL stays fixed across reboots. Do not enable the Windows logon task at the
same time as the OCI services.

## Status

```powershell
.\scripts\check_status.ps1
```

This checks the Windows fallback services, configured mode, fixed origin, and a
real public MCP initialize request. OCI service status is checked with the
commands in `OCI_ALWAYS_FREE_SETUP.md`.

## Other modes

For a temporary changing URL, set `mode` to `quick-tunnel` and run the launcher. After each tunnel restart, update ChatGPT from `runtime\last_chatgpt_mcp_url.txt`.

For a custom domain with per-user OAuth, follow [`CLOUDFLARE_ACCESS_SETUP.md`](CLOUDFLARE_ACCESS_SETUP.md), run `scripts\setup_cloudflare_access.ps1`, and set ChatGPT authentication to **OAuth**.

Never expose a bridge started with `-AuthMode disabled` through any public tunnel.

## Tests

```powershell
uv run python -m unittest discover -s tests -v
cd cloudflare\stable-proxy
npm test
npm run check
```

## Secret rotation

- Path secret: remove `pathSecretProtected` from `config.local.json`, switch temporarily to `quick-tunnel`, run the launcher once to generate a new secret, then rerun `setup_stable_worker_proxy.ps1`. Update ChatGPT with the new fixed URL path.
- Worker administrator token: rerun `setup_stable_worker_proxy.ps1`; the path secret is preserved and the administrator token is replaced.
- Named-tunnel credentials: rotate them in Cloudflare and rerun `setup_cloudflare_access.ps1`.