mcp-server-markview 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # mcp-server-markview
2
+
3
+ MCP (Model Context Protocol) server for [MarkView](https://github.com/paulhkang94/markview) — a native macOS Markdown previewer.
4
+
5
+ Lets AI assistants (Claude, etc.) preview Markdown files and open them in the MarkView app directly from the conversation.
6
+
7
+ ## Requirements
8
+
9
+ - macOS (arm64 or x86_64)
10
+ - Node.js 18+
11
+ - MarkView.app (auto-fetched on install, or install manually from [Releases](https://github.com/paulhkang94/markview/releases))
12
+
13
+ ## Quick Start
14
+
15
+ Run without installing:
16
+
17
+ ```bash
18
+ npx mcp-server-markview
19
+ ```
20
+
21
+ Or install globally:
22
+
23
+ ```bash
24
+ npm install -g mcp-server-markview
25
+ mcp-server-markview
26
+ ```
27
+
28
+ The binary is downloaded automatically during installation. If the download fails (e.g. offline install), the wrapper falls back to a locally installed MarkView.app at `/Applications` or `~/Applications`.
29
+
30
+ ## Claude Code Configuration
31
+
32
+ Add to your Claude Code MCP config (usually `~/.claude/mcp.json` or via `claude mcp add`):
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "markview": {
38
+ "command": "npx",
39
+ "args": ["-y", "mcp-server-markview"]
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ Or if you have installed it globally:
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "markview": {
51
+ "command": "mcp-server-markview"
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Using `claude mcp add`
58
+
59
+ ```bash
60
+ claude mcp add markview -- npx -y mcp-server-markview
61
+ ```
62
+
63
+ ## Available Tools
64
+
65
+ ### `preview_markdown`
66
+
67
+ Renders a Markdown string and opens a live preview in MarkView.
68
+
69
+ | Parameter | Type | Description |
70
+ |-----------|--------|---------------------------------|
71
+ | `content` | string | Markdown source text to preview |
72
+ | `title` | string | Optional window title |
73
+
74
+ ### `open_file`
75
+
76
+ Opens a Markdown file from disk in MarkView.
77
+
78
+ | Parameter | Type | Description |
79
+ |-----------|--------|--------------------------------------|
80
+ | `path` | string | Absolute path to the `.md` file |
81
+
82
+ ## Transport
83
+
84
+ The server uses **stdio transport** (JSON-RPC 2.0 over stdin/stdout), which is the standard MCP transport and compatible with all MCP clients.
85
+
86
+ ## How It Works
87
+
88
+ 1. `npm install` runs `scripts/postinstall.js`, which downloads the prebuilt `MarkView` release archive from GitHub and extracts the `markview-mcp-server` binary.
89
+ 2. The binary is placed at `bin/markview-mcp-server-binary` inside the package.
90
+ 3. `bin/mcp-server-markview` (the shell wrapper registered in `bin`) locates the binary and `exec`s it, preserving stdio.
91
+
92
+ ## Troubleshooting
93
+
94
+ **Binary not found after install**
95
+
96
+ Re-run the postinstall script manually:
97
+
98
+ ```bash
99
+ node "$(npm root -g)/mcp-server-markview/scripts/postinstall.js"
100
+ ```
101
+
102
+ **Download failed (corporate proxy / offline)**
103
+
104
+ Install MarkView.app manually from the [Releases page](https://github.com/paulhkang94/markview/releases) and place it in `/Applications`. The wrapper will find it automatically.
105
+
106
+ **Permission denied**
107
+
108
+ ```bash
109
+ chmod +x "$(npm root -g)/mcp-server-markview/bin/markview-mcp-server-binary"
110
+ chmod +x "$(npm root -g)/mcp-server-markview/bin/mcp-server-markview"
111
+ ```
112
+
113
+ ## License
114
+
115
+ MIT — see [LICENSE](https://github.com/paulhkang94/markview/blob/main/LICENSE).
@@ -0,0 +1,70 @@
1
+ #!/bin/sh
2
+ # mcp-server-markview
3
+ #
4
+ # Shell wrapper that locates the MarkView MCP server binary and exec's it,
5
+ # passing through all arguments and preserving stdio (required for JSON-RPC
6
+ # over stdio transport).
7
+ #
8
+ # Resolution order:
9
+ # 1. Downloaded binary next to this script (placed by postinstall.js)
10
+ # 2. MarkView.app installed at /Applications (system install)
11
+ # 3. MarkView.app installed in ~/Applications (user install)
12
+
13
+ set -e
14
+
15
+ # Resolve the real directory of this script, following symlinks.
16
+ # This is important when the script is invoked via `npx` which may symlink bin/.
17
+ resolve_dir() {
18
+ local target="$1"
19
+ # Loop until target is not a symlink.
20
+ while [ -L "$target" ]; do
21
+ local link
22
+ link="$(readlink "$target")"
23
+ case "$link" in
24
+ /*) target="$link" ;;
25
+ *) target="$(dirname "$target")/$link" ;;
26
+ esac
27
+ done
28
+ dirname "$target"
29
+ }
30
+
31
+ SCRIPT_DIR="$(resolve_dir "$0")"
32
+
33
+ # --- Candidate 1: binary downloaded by postinstall ---
34
+ DOWNLOADED_BINARY="$SCRIPT_DIR/markview-mcp-server-binary"
35
+
36
+ if [ -x "$DOWNLOADED_BINARY" ]; then
37
+ exec "$DOWNLOADED_BINARY" "$@"
38
+ fi
39
+
40
+ # --- Candidate 2: /Applications (system-wide install) ---
41
+ SYSTEM_APP_BINARY="/Applications/MarkView.app/Contents/MacOS/markview-mcp-server"
42
+
43
+ if [ -x "$SYSTEM_APP_BINARY" ]; then
44
+ exec "$SYSTEM_APP_BINARY" "$@"
45
+ fi
46
+
47
+ # --- Candidate 3: ~/Applications (user install) ---
48
+ USER_APP_BINARY="$HOME/Applications/MarkView.app/Contents/MacOS/markview-mcp-server"
49
+
50
+ if [ -x "$USER_APP_BINARY" ]; then
51
+ exec "$USER_APP_BINARY" "$@"
52
+ fi
53
+
54
+ # --- Not found ---
55
+ cat >&2 <<'EOF'
56
+ mcp-server-markview: could not find the MarkView MCP server binary.
57
+
58
+ To fix this, try one of the following:
59
+
60
+ 1. Re-run postinstall to download the binary:
61
+ node "$(npm root -g)/mcp-server-markview/scripts/postinstall.js"
62
+
63
+ 2. Install MarkView.app from:
64
+ https://github.com/paulhkang94/markview/releases
65
+
66
+ 3. If postinstall failed during `npm install`, re-install the package:
67
+ npm install -g mcp-server-markview
68
+
69
+ EOF
70
+ exit 1
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "mcp-server-markview",
3
+ "version": "1.1.3",
4
+ "description": "MCP server for MarkView — preview Markdown files in a native macOS viewer",
5
+ "license": "MIT",
6
+ "author": "Paul Kang <contact@paulkang.dev>",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/paulhkang94/markview.git",
10
+ "directory": "npm"
11
+ },
12
+ "homepage": "https://github.com/paulhkang94/markview#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/paulhkang94/markview/issues"
15
+ },
16
+ "bin": {
17
+ "mcp-server-markview": "bin/mcp-server-markview"
18
+ },
19
+ "mcpName": "io.github.paulhkang94/markview",
20
+ "scripts": {
21
+ "postinstall": "node scripts/postinstall.js"
22
+ },
23
+ "files": [
24
+ "bin/",
25
+ "scripts/",
26
+ "README.md"
27
+ ],
28
+ "keywords": [
29
+ "mcp",
30
+ "mcp-server",
31
+ "model-context-protocol",
32
+ "markdown",
33
+ "markview",
34
+ "preview",
35
+ "macos",
36
+ "claude"
37
+ ],
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "os": [
42
+ "darwin"
43
+ ],
44
+ "cpu": [
45
+ "arm64",
46
+ "x64"
47
+ ]
48
+ }
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall.js
4
+ *
5
+ * Downloads the MarkView MCP server binary from GitHub Releases and places it
6
+ * at ./bin/markview-mcp-server-binary so the shell wrapper can find it.
7
+ *
8
+ * Uses only Node.js built-ins — zero runtime dependencies.
9
+ */
10
+
11
+ "use strict";
12
+
13
+ const https = require("https");
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+ const os = require("os");
17
+ const { execFileSync } = require("child_process");
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Configuration
21
+ // ---------------------------------------------------------------------------
22
+
23
+ const GITHUB_OWNER = "paulhkang94";
24
+ const GITHUB_REPO = "markview";
25
+ const VERSION = "1.1.3";
26
+ const ARCHIVE_NAME = `MarkView-${VERSION}.tar.gz`;
27
+ const DOWNLOAD_URL = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases/download/v${VERSION}/${ARCHIVE_NAME}`;
28
+
29
+ // Path inside the tar.gz where the MCP server binary lives
30
+ const BINARY_IN_ARCHIVE = `MarkView.app/Contents/MacOS/markview-mcp-server`;
31
+
32
+ // Destination: placed next to the shell wrapper in bin/
33
+ const PKG_ROOT = path.resolve(__dirname, "..");
34
+ const DEST_BINARY = path.join(PKG_ROOT, "bin", "markview-mcp-server-binary");
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Platform guard
38
+ // ---------------------------------------------------------------------------
39
+
40
+ if (process.platform !== "darwin") {
41
+ console.error(
42
+ "[mcp-server-markview] MarkView is a macOS-only application. " +
43
+ "This package is not supported on " +
44
+ process.platform +
45
+ ".",
46
+ );
47
+ // Exit 0 so npm install does not fail on non-macOS CI environments.
48
+ process.exit(0);
49
+ }
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Helpers
53
+ // ---------------------------------------------------------------------------
54
+
55
+ /**
56
+ * Follow HTTP redirects and return a Promise that resolves with the final
57
+ * IncomingMessage once we land on a non-redirect response.
58
+ */
59
+ function followRedirects(url, maxRedirects) {
60
+ maxRedirects = maxRedirects === undefined ? 10 : maxRedirects;
61
+
62
+ return new Promise((resolve, reject) => {
63
+ if (maxRedirects === 0) {
64
+ return reject(new Error("Too many redirects"));
65
+ }
66
+
67
+ https
68
+ .get(
69
+ url,
70
+ { headers: { "User-Agent": "mcp-server-markview-postinstall" } },
71
+ (res) => {
72
+ if (
73
+ res.statusCode >= 300 &&
74
+ res.statusCode < 400 &&
75
+ res.headers.location
76
+ ) {
77
+ res.resume(); // drain the response body so the socket is freed
78
+ resolve(followRedirects(res.headers.location, maxRedirects - 1));
79
+ } else {
80
+ resolve(res);
81
+ }
82
+ },
83
+ )
84
+ .on("error", reject);
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Download a URL to a local file. Returns a Promise.
90
+ */
91
+ function downloadFile(url, destPath) {
92
+ return new Promise((resolve, reject) => {
93
+ followRedirects(url)
94
+ .then((res) => {
95
+ if (res.statusCode !== 200) {
96
+ res.resume();
97
+ return reject(new Error(`HTTP ${res.statusCode} downloading ${url}`));
98
+ }
99
+
100
+ const total = parseInt(res.headers["content-length"] || "0", 10);
101
+ let received = 0;
102
+ let lastPct = -1;
103
+
104
+ const out = fs.createWriteStream(destPath);
105
+
106
+ res.on("data", (chunk) => {
107
+ received += chunk.length;
108
+ if (total > 0) {
109
+ const pct = Math.floor((received / total) * 100);
110
+ if (pct !== lastPct && pct % 10 === 0) {
111
+ process.stdout.write(`\r ${pct}%`);
112
+ lastPct = pct;
113
+ }
114
+ }
115
+ });
116
+
117
+ res.pipe(out);
118
+
119
+ out.on("finish", () => {
120
+ process.stdout.write("\r \r"); // clear progress line
121
+ resolve();
122
+ });
123
+
124
+ out.on("error", reject);
125
+ res.on("error", reject);
126
+ })
127
+ .catch(reject);
128
+ });
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Main
133
+ // ---------------------------------------------------------------------------
134
+
135
+ async function main() {
136
+ // Skip if the binary is already present (e.g. re-running postinstall).
137
+ if (fs.existsSync(DEST_BINARY)) {
138
+ console.log(
139
+ "[mcp-server-markview] Binary already present, skipping download.",
140
+ );
141
+ return;
142
+ }
143
+
144
+ // Ensure the bin/ directory exists (it should, since it ships with the package).
145
+ fs.mkdirSync(path.dirname(DEST_BINARY), { recursive: true });
146
+
147
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-server-markview-"));
148
+ const archivePath = path.join(tmpDir, ARCHIVE_NAME);
149
+
150
+ try {
151
+ console.log(`[mcp-server-markview] Downloading MarkView v${VERSION}...`);
152
+ console.log(` ${DOWNLOAD_URL}`);
153
+
154
+ await downloadFile(DOWNLOAD_URL, archivePath);
155
+
156
+ console.log("[mcp-server-markview] Extracting MCP server binary...");
157
+
158
+ // Extract only the MCP server binary from the archive.
159
+ // Path is MarkView.app/Contents/MacOS/markview-mcp-server (3 dirs deep).
160
+ execFileSync(
161
+ "tar",
162
+ [
163
+ "-xzf",
164
+ archivePath,
165
+ "--strip-components=3",
166
+ "-C",
167
+ path.dirname(DEST_BINARY),
168
+ BINARY_IN_ARCHIVE,
169
+ ],
170
+ { stdio: "pipe" },
171
+ );
172
+
173
+ // The extracted file will be named "markview-mcp-server"; rename if needed.
174
+ const extractedName = path.join(
175
+ path.dirname(DEST_BINARY),
176
+ "markview-mcp-server",
177
+ );
178
+ if (fs.existsSync(extractedName) && extractedName !== DEST_BINARY) {
179
+ fs.renameSync(extractedName, DEST_BINARY);
180
+ }
181
+
182
+ // Make executable.
183
+ fs.chmodSync(DEST_BINARY, 0o755);
184
+
185
+ console.log("[mcp-server-markview] Binary installed successfully.");
186
+ console.log(` Location: ${DEST_BINARY}`);
187
+ } catch (err) {
188
+ console.error("[mcp-server-markview] Installation failed:", err.message);
189
+ console.error(
190
+ "\nYou can still use MarkView's MCP server if MarkView.app is installed at /Applications.\n" +
191
+ "Run `npx mcp-server-markview` and the wrapper will fall back to the app bundle automatically.",
192
+ );
193
+ // Exit 0 — a postinstall failure should not block npm install entirely.
194
+ process.exit(0);
195
+ } finally {
196
+ // Clean up temp directory.
197
+ try {
198
+ fs.rmSync(tmpDir, { recursive: true, force: true });
199
+ } catch (_) {
200
+ // Ignore cleanup errors.
201
+ }
202
+ }
203
+ }
204
+
205
+ main();