From c9979be693c57ef17a7897910406223df68cc0cf Mon Sep 17 00:00:00 2001 From: elek-hmd Date: Fri, 4 Sep 2026 16:20:49 +0800 Subject: [PATCH] feat(mcp): connect via OAuth instead of API token Agents following this repo were still copying mcp-remote plus a Bearer token. Point .mcp.json at the hosted OAuth server and drop token setup from the MCP path. Co-authored-by: Cursor --- .cursor-plugin/plugin.json | 5 ++- .mcp.json | 10 +---- CHANGELOG.md | 6 +++ README.md | 84 ++++++++++++++------------------------ commands/setup-hackmd.md | 63 ++++++++-------------------- rules/hackmd-workflow.mdc | 17 ++++---- skills/hackmd-cli/SKILL.md | 2 +- 7 files changed, 68 insertions(+), 119 deletions(-) diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 994b86b..663f999 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "hackmd", - "version": "0.1.0", - "description": "Official HackMD plugin for Cursor with HackMD MCP setup, CLI skill, and guided setup workflow.", + "version": "0.2.0", + "description": "Official HackMD plugin for Cursor. Connects to HackMD through OAuth MCP; no API token for MCP.", "author": { "name": "HackMD" }, @@ -11,6 +11,7 @@ "hackmd", "cursor", "mcp", + "oauth", "notes", "documentation" ] diff --git a/.mcp.json b/.mcp.json index f4afd8c..233ec2b 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,13 +1,7 @@ { "mcpServers": { - "hackmd-mcp": { - "command": "npx", - "args": [ - "mcp-remote@0.1.38", - "https://mcp.hackmd.io/", - "--header", - "Authorization:Bearer ${env:HMD_API_ACCESS_TOKEN}" - ] + "hackmd": { + "url": "https://mcp.hackmd.io/" } } } diff --git a/CHANGELOG.md b/CHANGELOG.md index e44cc11..244c95a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on Keep a Changelog, and this project follows Semantic Versi ## [Unreleased] +### Changed + +- MCP connects to `https://mcp.hackmd.io/` with OAuth 2.1 (URL-only `.mcp.json`). No API token and no `mcp-remote` for MCP. +- README and `setup-hackmd` walk through the browser OAuth flow instead of `HMD_API_ACCESS_TOKEN` on the MCP path. +- CLI still uses `hackmd-cli login` or a personal API token; that token is independent of MCP OAuth. + ## [0.1.0] - 2026-03-31 ### Added diff --git a/README.md b/README.md index 0854106..56101a7 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ # HackMD Cursor Plugin -Official HackMD plugin scaffold for Cursor. +Official HackMD plugin scaffold for Cursor. Connects to HackMD through OAuth MCP. This plugin provides: - A repo-hosted `logo.png` wired into the plugin manifest -- A ready-to-configure `.mcp.json` entry for the HackMD MCP server -- A `hackmd-cli` skill adapted for Cursor plugin format +- A `.mcp.json` entry for the official remote MCP server (`https://mcp.hackmd.io/`, OAuth) +- A `hackmd-cli` skill for shell workflows - A `setup-hackmd` command for local setup and verification - A light HackMD workflow rule for note-related tasks +MCP does **not** use an API token. OAuth runs in the browser on first use. The REST API and CLI still use personal API tokens; those credentials do not belong in MCP config. + ## Repository Layout ```text @@ -61,7 +63,7 @@ Quit Cursor completely and reopen it (a window reload is not always enough). The - the `hackmd-cli` skill is available - the `setup-hackmd` command is available - the `hackmd-workflow` rule is discoverable -- the `.mcp.json` template is at the repo root for merging into your user MCP config (see [Setup](#2-configure-hackmd-mcp-safely)) +- Cursor has loaded the plugin MCP server `hackmd` ## Setup @@ -75,60 +77,32 @@ The plugin entrypoint is: .cursor-plugin/plugin.json ``` -### 2. Configure HackMD MCP safely - -Do not put API tokens inside `mcp.json`. In Cursor, `mcp.json` values support interpolation: strings like `${env:VAR}` are resolved from your environment when MCP loads. - -1. Copy the `hackmd-mcp` entry from this repo's `.mcp.json` -2. Paste it into your user-level Cursor MCP config at `~/.cursor/mcp.json` (or merge into an existing file) +### 2. Connect HackMD MCP (OAuth) -The header uses the same variable as the HackMD CLI: `HMD_API_ACCESS_TOKEN`. - -Example (no secrets in the file): +If Cursor does not pick up the plugin `.mcp.json` automatically, merge this into `~/.cursor/mcp.json`: ```json { "mcpServers": { - "hackmd-mcp": { - "command": "npx", - "args": [ - "mcp-remote@0.1.38", - "https://mcp.hackmd.io/", - "--header", - "Authorization:Bearer ${env:HMD_API_ACCESS_TOKEN}" - ] + "hackmd": { + "url": "https://mcp.hackmd.io/" } } } ``` -Cursor resolves `${env:HMD_API_ACCESS_TOKEN}` from the environment it inherits when it starts (not from secrets embedded in `mcp.json`). Set the variable in your **shell profile** (for example `~/.zshrc` or `~/.bashrc`) and fully restart Cursor, or define it in your **OS user / system environment** so GUI-launched Cursor sees it—same idea as Cursor’s MCP docs: use config interpolation in `mcp.json` and keep real values in the environment. Use the same token as in [Configure HackMD CLI authentication](#4-configure-hackmd-cli-authentication) below. +Fully restart Cursor, then invoke any HackMD tool (or ask Cursor to list your notes). Complete the browser OAuth prompt. Closing it leaves the client unauthorized. -To sanity-check the remote command from a terminal (shell variable, not Cursor interpolation): +Do not add `mcp-remote`, `Authorization` headers, or `HMD_API_ACCESS_TOKEN` to MCP config. Those are leftover from the token-era setup. -```bash -export HMD_API_ACCESS_TOKEN=YOUR_TOKEN -npx mcp-remote@0.1.38 https://mcp.hackmd.io/ --header "Authorization:Bearer $HMD_API_ACCESS_TOKEN" -``` +### 3. Optional: HackMD CLI -### 3. Install HackMD CLI +CLI is not required for MCP. Use it for shell scripting and export. ```bash npm install -g @hackmd/hackmd-cli -``` - -### 4. Configure HackMD CLI authentication - -Use either interactive login: - -```bash hackmd-cli login -``` - -or an environment variable: - -```bash -export HMD_API_ACCESS_TOKEN=YOUR_TOKEN +hackmd-cli whoami ``` For HackMD EE instances, also set: @@ -137,40 +111,42 @@ For HackMD EE instances, also set: export HMD_API_ENDPOINT_URL=https://your.hackmd-ee.endpoint ``` -### 5. Verify CLI and MCP access +### 4. Verify + +In Cursor, confirm the `hackmd` MCP server appears and a tool call succeeds after OAuth. + +If you installed the CLI: ```bash hackmd-cli whoami hackmd-cli notes ``` -In Cursor, confirm the `hackmd-mcp` server appears from your user MCP configuration. - ## Included Components ### Skill: `hackmd-cli` -Use this when working with HackMD notes via CLI, including personal notes, team notes, exports, and scripting workflows. +Use this when working with HackMD notes via CLI, including personal notes, team notes, exports, and scripting workflows. MCP OAuth does not replace CLI login. ### Command: `setup-hackmd` Use this command to guide users through: -- installing the HackMD CLI -- configuring authentication -- copying the MCP template into user-local Cursor config -- verifying CLI and MCP access +- installing the plugin +- connecting MCP with OAuth +- optionally installing and logging in to the HackMD CLI +- verifying MCP (and CLI, if installed) ### Rule: `hackmd-workflow` -Use this rule for HackMD-related work so Cursor prefers the HackMD CLI workflow, distinguishes personal notes from team notes, and keeps auth placeholders out of committed examples. +Use this rule for HackMD-related work so Cursor prefers MCP OAuth for chat-native notes, uses the CLI only for shell workflows, and never copies a CLI token into MCP config. ## Notes - The plugin manifest references the local `logo.png` asset. -- The repo `.mcp.json` is a template with `${env:HMD_API_ACCESS_TOKEN}` interpolation and a pinned `mcp-remote` version. -- Keep tokens in the environment, not in committed or pasted config files. +- The repo `.mcp.json` is URL-only: `https://mcp.hackmd.io/`. - The plugin keeps scope narrow so it can be extended safely later. -- The `hackmd-cli` skill adapts the upstream HackMD CLI guide for Cursor plugin packaging. -Upstream reference: [HackMD CLI skill](https://github.com/hackmdio/hackmd-cli/blob/develop/hackmd-cli/SKILL.md) +Setup guide: [HackMD MCP Server Setup](https://hackmd.io/@docs/mcp-server-setup) + +Upstream CLI skill: [HackMD CLI skill](https://github.com/hackmdio/hackmd-cli/blob/develop/hackmd-cli/SKILL.md) diff --git a/commands/setup-hackmd.md b/commands/setup-hackmd.md index 9d2c556..41a021a 100644 --- a/commands/setup-hackmd.md +++ b/commands/setup-hackmd.md @@ -1,70 +1,41 @@ --- name: setup-hackmd -description: Guide HackMD plugin setup, including CLI install, auth configuration, safe local MCP setup, and basic verification. +description: Guide HackMD plugin setup, including OAuth MCP, optional CLI install, and basic verification. --- # Setup HackMD -Help the user set up HackMD tooling in Cursor using this sequence: +Help the user set up HackMD tooling in Cursor using this sequence. -1. Confirm whether they need HackMD Cloud or HackMD EE setup. -1. Install the CLI if needed: +The MCP server (`mcp.hackmd.io`) authenticates with **OAuth 2.1**. The CLI continues to use interactive login or a personal API token. The two are independent — connecting MCP does not replace CLI credentials. -```bash -npm install -g @hackmd/hackmd-cli -``` - -1. Configure CLI auth with either: - -```bash -hackmd-cli login -``` - -or: - -```bash -export HMD_API_ACCESS_TOKEN=YOUR_TOKEN -``` - -1. If they use HackMD EE, also configure: - -```bash -export HMD_API_ENDPOINT_URL=https://your.hackmd-ee.endpoint -``` - -1. Copy the `hackmd-mcp` entry from the plugin `.mcp.json` into the user's local Cursor MCP config at `~/.cursor/mcp.json`. -1. Use a local config shaped like this (no token in the file; Cursor resolves `${env:HMD_API_ACCESS_TOKEN}`): +1. Confirm they have a HackMD account at [hackmd.io](https://hackmd.io). +2. Confirm the plugin is installed (this repo, or synced to `~/.cursor/plugins/local/hackmd/`). +3. Merge the plugin `.mcp.json` into the user's Cursor MCP config at `~/.cursor/mcp.json` (or confirm Cursor already loaded the plugin's MCP entry): ```json { "mcpServers": { - "hackmd-mcp": { - "command": "npx", - "args": [ - "mcp-remote@0.1.38", - "https://mcp.hackmd.io/", - "--header", - "Authorization:Bearer ${env:HMD_API_ACCESS_TOKEN}" - ] + "hackmd": { + "url": "https://mcp.hackmd.io/" } } } ``` -1. Ensure `HMD_API_ACCESS_TOKEN` is set in the environment Cursor uses (same as CLI), not inside `mcp.json`. Prefer a shell profile or OS user environment so Cursor inherits the variable on launch; `${env:...}` in `mcp.json` only references that external value. +Do **not** add `mcp-remote`, `Authorization` headers, or API tokens to this MCP config. MCP does not use `HMD_API_ACCESS_TOKEN`. -1. Verify CLI access: +4. Fully quit and reopen Cursor (a window reload is not enough). +5. Ask Cursor to list HackMD notes (or call any HackMD MCP tool). Complete the browser OAuth prompt. Closing it leaves the client unauthorized. +6. Optional: install the CLI for shell workflows (not required for MCP): ```bash +npm install -g @hackmd/hackmd-cli +hackmd-cli login hackmd-cli whoami -hackmd-cli notes ``` -1. Verify the MCP setup by confirming Cursor can see the configured `hackmd-mcp` server from the user's local MCP configuration. -1. If the user is scripting or automating content: - -- use `hackmd-cli notes` for personal notes -- use `hackmd-cli team-notes` for team content -- use JSON output for automation +`hackmd-cli login` is enough for most people. An API token is only for CLI/REST, never for MCP. -1. Never paste real secrets into docs, examples, commits, screenshots, or tracked plugin files. +7. Verify MCP: the `hackmd` server appears in Cursor's MCP list, and a tool call succeeds after OAuth. +8. Never paste real secrets into docs, examples, commits, screenshots, or tracked plugin files. diff --git a/rules/hackmd-workflow.mdc b/rules/hackmd-workflow.mdc index 119ce0e..3315ab8 100644 --- a/rules/hackmd-workflow.mdc +++ b/rules/hackmd-workflow.mdc @@ -1,5 +1,5 @@ --- -description: Prefer HackMD CLI and safe auth handling for HackMD-related note workflows. +description: Prefer HackMD MCP OAuth for chat-native note work; keep CLI credentials off the MCP path. alwaysApply: false --- @@ -7,10 +7,11 @@ alwaysApply: false When helping with HackMD tasks: -1. Prefer the `hackmd-cli` skill for creating, updating, exporting, and automating notes. -2. Distinguish personal notes (`hackmd-cli notes`) from team notes (`hackmd-cli team-notes --teamPath=...`). -3. Recommend `hackmd-cli login` or environment variables instead of embedding secrets directly in commands. -4. Keep token examples as placeholders in docs and configuration samples. -5. When scripting or inspection is needed, prefer machine-readable output such as `--output=json`. -6. **Verify login before API-backed CLI work** (listing or mutating notes, teams, history, export): run `hackmd-cli whoami`. If it errors or shows no user, have the user run `hackmd-cli login` or set `HMD_API_ACCESS_TOKEN` (and `HMD_API_ENDPOINT_URL` for HackMD EE), then re-run `whoami`. -7. **Optional `whoami` output tuning** (same table-style flags as other list commands): `--output=json|yaml|csv` for parsing; `-x` / `--extended` for extra columns; `--columns=...`, `--filter=...`, `--sort=...`, `--no-header`, `--no-truncate` as needed. +1. Prefer HackMD MCP (`https://mcp.hackmd.io/`) for reading and writing notes inside Cursor. Auth is OAuth in the browser — do not ask the user for an API token to connect MCP, and do not add `mcp-remote` or `Authorization: Bearer` to MCP config. +2. Prefer the `hackmd-cli` skill only for shell scripting, export, or EE endpoint work that MCP does not cover. +3. Distinguish personal notes from team notes (MCP team tools, or `hackmd-cli team-notes --teamPath=...`). +4. CLI credentials (`hackmd-cli login` or `HMD_API_ACCESS_TOKEN`) are independent of MCP OAuth. Do not copy a CLI token into `.mcp.json`. +5. Keep any CLI token examples as placeholders. Never commit real secrets. +6. When scripting the CLI, prefer machine-readable output such as `--output=json`. +7. **Verify MCP before chat-native note work:** the `hackmd` server should be present and OAuth completed. If tools return unauthorized, re-run the browser OAuth flow — do not fall back to pasting an API token into MCP config. +8. **Verify CLI before API-backed CLI work:** run `hackmd-cli whoami`. If it errors, have the user run `hackmd-cli login` (or set `HMD_API_ACCESS_TOKEN` and, for HackMD EE, `HMD_API_ENDPOINT_URL`), then re-run `whoami`. diff --git a/skills/hackmd-cli/SKILL.md b/skills/hackmd-cli/SKILL.md index 9f99ff0..5d9b9c7 100644 --- a/skills/hackmd-cli/SKILL.md +++ b/skills/hackmd-cli/SKILL.md @@ -5,7 +5,7 @@ description: Use HackMD CLI to create, read, update, delete, export, and automat # HackMD CLI -Use this skill when a user wants to manage HackMD content programmatically from Cursor. +Use this skill when a user wants to manage HackMD content from the **CLI** (shell, scripts, export). Chat-native read/write in Cursor should use HackMD MCP at `https://mcp.hackmd.io/` with **OAuth** — not this token, and not `mcp-remote`. ## What This Skill Covers