Repository navigation
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·431 lines (398 loc) · 12.8 KB
/
Copy pathsetup.sh
File metadata and controls
executable file
·431 lines (398 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
#!/usr/bin/env bash
#
# mcp-medium-reader — one-shot setup script.
#
# Installs the ZMediumToMarkdown Ruby gem (>= 3.5.2), the
# mcp-medium-reader npm package, and runs `mcp-medium-reader init`
# to bind the Ruby runtime and register with the four supported MCP
# clients (Claude Desktop, Claude Code, OpenAI Codex, Gemini CLI).
# It finishes with `doctor` so you see at a glance that everything is
# wired up.
#
# Usage:
# bash setup.sh
# bash <(curl -fsSL https://raw.githubusercontent.com/ZhgChgLi/mcp-medium-reader/main/setup.sh)
#
# Flags:
# --no-init Install dependencies only; skip the guided init.
# --no-gem Skip the ZMediumToMarkdown gem install.
# --no-npm Skip the mcp-medium-reader npm install.
# --no-auth Skip the interactive `ZMediumToMarkdown --auth` step.
# --yes Assume yes to every install prompt (Homebrew, etc.).
# --help Show this help.
#
# Platforms: macOS, Linux, and Windows via Git Bash / WSL. Native
# Windows users without bash can install components manually:
# gem install ZMediumToMarkdown
# npm install -g mcp-medium-reader
# mcp-medium-reader init
#
# After install, if you want paywalled access, run the gem standalone
# once to populate its cookie cache (the gem opens Chrome for sign-in
# and stores cookies at ~/.zmediumtomarkdown — mcp-medium-reader does
# not manage cookies):
# ZMediumToMarkdown --auth
#
set -euo pipefail
NO_INIT=0
NO_GEM=0
NO_NPM=0
NO_AUTH=0
ASSUME_YES=0
mcp_cmd=""
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
for arg in "$@"; do
case "$arg" in
--no-init) NO_INIT=1 ;;
--no-gem) NO_GEM=1 ;;
--no-npm) NO_NPM=1 ;;
--no-auth) NO_AUTH=1 ;;
--yes|-y) ASSUME_YES=1 ;;
--help|-h)
sed -n '3,34p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
printf 'Unknown flag: %s\n' "$arg" >&2
exit 1
;;
esac
done
if [ -t 1 ]; then
C_RED=$'\033[31m'
C_GREEN=$'\033[32m'
C_YELLOW=$'\033[33m'
C_BLUE=$'\033[34m'
C_BOLD=$'\033[1m'
C_RESET=$'\033[0m'
else
C_RED=''; C_GREEN=''; C_YELLOW=''; C_BLUE=''; C_BOLD=''; C_RESET=''
fi
step() { printf '%s%s==>%s %s\n' "$C_BOLD" "$C_BLUE" "$C_RESET" "$*"; }
ok() { printf '%s\xe2\x9c\x93%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
warn() { printf '%s\xe2\x9a\xa0%s %s\n' "$C_YELLOW" "$C_RESET" "$*"; }
fail() { printf '%s\xe2\x9c\x97%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; exit 1; }
confirm() {
local prompt="$1"
if [ "$ASSUME_YES" -eq 1 ]; then return 0; fi
if [ ! -t 0 ]; then return 1; fi
local ans
printf ' %s [y/N]: ' "$prompt"
read -r ans
case "${ans:-N}" in
[yY]*) return 0 ;;
*) return 1 ;;
esac
}
# Detect platform.
case "$(uname -s 2>/dev/null || echo unknown)" in
Darwin*) platform="macOS"; platform_kind=mac ;;
Linux*) platform="Linux"; platform_kind=linux ;;
MINGW*|MSYS*|CYGWIN*) platform="Windows (Git Bash)"; platform_kind=win ;;
*) platform="$(uname -s 2>/dev/null || echo unknown)"; platform_kind=unknown ;;
esac
step "mcp-medium-reader setup"
printf ' Platform: %s\n' "$platform"
printf ' Date: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')"
echo
# -------- helpers --------
read_ruby_version() {
ruby -e 'print RUBY_VERSION' 2>/dev/null
}
is_ruby_ok() {
local v_major v_minor
v_major=$(printf '%s' "$1" | awk -F. '{print $1}')
v_minor=$(printf '%s' "$1" | awk -F. '{print $2}')
[ "${v_major:-0}" -gt 3 ] && return 0
[ "${v_major:-0}" -eq 3 ] && [ "${v_minor:-0}" -ge 2 ] && return 0
return 1
}
adopt_brew_path() {
local brew_bin
for brew_bin in /opt/homebrew/bin /usr/local/bin; do
if [ -x "$brew_bin/brew" ]; then
case ":$PATH:" in
*:"$brew_bin":*) ;;
*) export PATH="$brew_bin:$PATH" ;;
esac
fi
done
}
adopt_brew_ruby_path() {
if ! command -v brew >/dev/null 2>&1; then return; fi
local ruby_prefix
ruby_prefix=$(brew --prefix ruby 2>/dev/null || true)
if [ -n "$ruby_prefix" ] && [ -d "$ruby_prefix/bin" ]; then
case ":$PATH:" in
*:"$ruby_prefix/bin":*) ;;
*) export PATH="$ruby_prefix/bin:$PATH" ;;
esac
local gem_user_bin
gem_user_bin=$(ruby -e 'require "rubygems"; print Gem.user_dir + "/bin"' 2>/dev/null || true)
if [ -n "$gem_user_bin" ] && [ -d "$gem_user_bin" ]; then
case ":$PATH:" in
*:"$gem_user_bin":*) ;;
*) export PATH="$gem_user_bin:$PATH" ;;
esac
fi
fi
}
resolve_mcp_medium_reader() {
if command -v mcp-medium-reader >/dev/null 2>&1; then
command -v mcp-medium-reader
return 0
fi
local npm_prefix npm_root candidate
npm_prefix=$(npm config get prefix 2>/dev/null || true)
case "$platform_kind" in
win)
candidate="${npm_prefix%/}/mcp-medium-reader"
if [ -n "$npm_prefix" ] && [ -x "$candidate" ]; then
printf '%s\n' "$candidate"; return 0
fi
candidate="${npm_prefix%/}/mcp-medium-reader.cmd"
if [ -n "$npm_prefix" ] && [ -f "$candidate" ]; then
printf '%s\n' "$candidate"; return 0
fi
;;
*)
candidate="${npm_prefix%/}/bin/mcp-medium-reader"
if [ -n "$npm_prefix" ] && [ -x "$candidate" ]; then
printf '%s\n' "$candidate"; return 0
fi
;;
esac
npm_root=$(npm root -g 2>/dev/null || true)
candidate="${npm_root%/}/mcp-medium-reader/bin/mcp-medium-reader.js"
if [ -f "$candidate" ]; then
printf 'node %s\n' "$candidate"
return 0
fi
return 1
}
install_mcp_medium_reader_from_dir() {
local source_dir tarball
source_dir="$1"
step "Packing mcp-medium-reader from source"
printf ' source dir: %s\n' "$source_dir"
tarball=$(cd "$source_dir" && npm pack | tail -n 1)
[ -n "$tarball" ] || fail "npm pack did not produce a tarball."
printf ' tarball: %s/%s\n' "$source_dir" "$tarball"
npm uninstall -g mcp-medium-reader >/dev/null 2>&1 || true
npm install -g "$source_dir/$tarball"
rm -f "$source_dir/$tarball"
}
# -------- Ruby --------
step "Checking Ruby (need >= 3.2)"
case "$platform_kind" in
mac) adopt_brew_path; adopt_brew_ruby_path ;;
esac
ruby_version=""
if command -v ruby >/dev/null 2>&1; then
ruby_version=$(read_ruby_version)
fi
if [ -z "$ruby_version" ] || ! is_ruby_ok "$ruby_version"; then
if [ -n "$ruby_version" ]; then
warn "Ruby $ruby_version is below 3.2"
else
warn "ruby not found"
fi
case "$platform_kind" in
mac)
if command -v brew >/dev/null 2>&1; then
if confirm "Install Ruby via \`brew install ruby\`?"; then
brew install ruby
adopt_brew_ruby_path
ruby_version=$(read_ruby_version)
fi
else
cat <<'HINT'
Install Homebrew first (https://brew.sh), or install Ruby some other way:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install ruby
Then re-run this script.
HINT
fi
;;
linux)
cat <<'HINT'
Install Ruby 3.2+ first:
Debian / Ubuntu: sudo apt install ruby ruby-dev (then verify version; if too old, use rbenv / asdf / a backports PPA)
Fedora / RHEL: sudo dnf install ruby ruby-devel
Arch: sudo pacman -S ruby
rbenv users: rbenv install 3.3.5 && rbenv global 3.3.5
HINT
;;
win)
cat <<'HINT'
Install Ruby 3.2+ via RubyInstaller-with-DevKit:
https://rubyinstaller.org/
HINT
;;
*)
cat <<'HINT'
Install Ruby 3.2+ for your platform, then re-run this script.
HINT
;;
esac
if [ -z "$ruby_version" ] || ! is_ruby_ok "$ruby_version"; then
fail "Ruby >= 3.2 is required."
fi
fi
ok "ruby $ruby_version"
# -------- Node --------
echo
step "Checking Node.js (need >= 18)"
node_version=""
if command -v node >/dev/null 2>&1; then
node_version=$(node --version)
fi
if [ -z "$node_version" ]; then
warn "node not found"
case "$platform_kind" in
mac)
if command -v brew >/dev/null 2>&1; then
if confirm "Install Node via \`brew install node\`?"; then
brew install node
adopt_brew_path
node_version=$(node --version 2>/dev/null || true)
fi
fi
;;
linux)
cat <<'HINT'
Install Node.js 18+ first:
NodeSource: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt install -y nodejs
Fedora: sudo dnf install -y nodejs
Arch: sudo pacman -S nodejs npm
fnm / nvm: https://github.com/Schniz/fnm / https://github.com/nvm-sh/nvm
HINT
;;
win)
cat <<'HINT'
Install Node.js 18+ from https://nodejs.org/, or via fnm / nvm-windows.
HINT
;;
*)
echo "Install Node 18+ for your platform and re-run."
;;
esac
fi
if [ -z "$node_version" ]; then
fail "Node.js >= 18 is required."
fi
node_major=$(printf '%s' "${node_version#v}" | awk -F. '{print $1}')
if [ "${node_major:-0}" -lt 18 ]; then
fail "Node $node_version is too old. Upgrade and re-run."
fi
ok "node $node_version"
if ! command -v npm >/dev/null 2>&1; then
fail "npm not found on PATH (Node is installed but npm isn't). Reinstall Node with npm bundled."
fi
# -------- ZMediumToMarkdown gem --------
echo
if [ "$NO_GEM" -eq 1 ]; then
step "Skipping gem install (--no-gem)"
else
step "Installing ZMediumToMarkdown gem"
if gem list -i ZMediumToMarkdown >/dev/null 2>&1; then
current=$(gem list ZMediumToMarkdown 2>/dev/null | sed -n 's/^ZMediumToMarkdown (\([^,)]*\).*/\1/p' | head -n 1)
printf ' existing version: %s\n' "${current:-unknown}"
printf ' upgrading to latest available...\n'
gem update ZMediumToMarkdown || gem install ZMediumToMarkdown
else
gem install ZMediumToMarkdown
fi
ok "gem ZMediumToMarkdown ready"
if ! command -v ZMediumToMarkdown >/dev/null 2>&1; then
warn "\`ZMediumToMarkdown\` is installed but not on PATH."
cat <<'HINT'
The gem bin directory might not be on PATH. Find it with:
ruby -e 'require "rubygems"; puts Gem.user_dir + "/bin"; puts Gem.dir + "/bin"'
Add the appropriate directory to PATH in your shell rc, then re-open the shell.
\`mcp-medium-reader init\` will still try to bind a stable runtime regardless.
HINT
fi
fi
# -------- mcp-medium-reader npm --------
echo
if [ "$NO_NPM" -eq 1 ]; then
step "Skipping npm install (--no-npm)"
else
if [ -f "$SCRIPT_DIR/package.json" ] && grep -q '"name":[[:space:]]*"mcp-medium-reader"' "$SCRIPT_DIR/package.json"; then
step "Installing mcp-medium-reader (from local checkout)"
install_mcp_medium_reader_from_dir "$SCRIPT_DIR"
else
step "Installing mcp-medium-reader (from GitHub)"
pkg_spec="github:ZhgChgLi/mcp-medium-reader"
printf ' spec: %s\n' "$pkg_spec"
npm uninstall -g mcp-medium-reader >/dev/null 2>&1 || true
npm install -g "$pkg_spec"
fi
ok "npm mcp-medium-reader ready"
mcp_cmd="$(resolve_mcp_medium_reader || true)"
if [ -z "$mcp_cmd" ]; then
warn "\`mcp-medium-reader\` installed but not resolvable from PATH or npm globals."
cat <<'HINT'
Run `npm config get prefix` and add `<prefix>/bin` (POSIX) or `<prefix>` (Windows) to PATH, then re-run.
HINT
fail "mcp-medium-reader could not be located; cannot run init."
fi
fi
# -------- init --------
echo
if [ "$NO_INIT" -eq 1 ]; then
step "Skipping init (--no-init)"
echo " Run 'mcp-medium-reader init' when ready, then 'mcp-medium-reader doctor' to verify."
exit 0
fi
if [ ! -t 0 ]; then
warn "stdin is not a TTY (looks like a curl-pipe-bash run); skipping interactive init."
cat <<'HINT'
Dependencies are installed. Open a terminal and run:
mcp-medium-reader init
mcp-medium-reader doctor
HINT
exit 0
fi
if [ -z "${mcp_cmd:-}" ]; then
mcp_cmd="$(resolve_mcp_medium_reader || true)"
fi
[ -n "${mcp_cmd:-}" ] || fail "mcp-medium-reader could not be resolved for init."
step "Running mcp-medium-reader init"
echo
${mcp_cmd} init
echo
step "Running mcp-medium-reader doctor"
echo
${mcp_cmd} doctor
echo
if [ "$NO_AUTH" -eq 1 ]; then
step "Skipping ZMediumToMarkdown --auth (--no-auth)"
cat <<'HINT'
When you want paywalled access, run the gem standalone once on a Terminal
where Chrome is available:
ZMediumToMarkdown --auth
The gem opens Chrome for sign-in / Cloudflare clearance and caches cookies at
~/.zmediumtomarkdown. mcp-medium-reader does not manage Medium cookies itself.
HINT
elif ! command -v ZMediumToMarkdown >/dev/null 2>&1; then
warn "ZMediumToMarkdown is not on PATH; cannot run --auth here."
cat <<'HINT'
Open a Terminal where the gem bin directory is on PATH and run:
ZMediumToMarkdown --auth
The gem opens Chrome for sign-in / Cloudflare clearance and caches cookies at
~/.zmediumtomarkdown.
HINT
else
step "Running ZMediumToMarkdown --auth (sign-in / Cloudflare clearance)"
cat <<'NOTE'
This opens Chrome so the gem can capture Medium login cookies and a fresh
cf_clearance, then caches them at ~/.zmediumtomarkdown. Skip with Ctrl-C
if you only ever read public posts.
NOTE
echo
if ! ZMediumToMarkdown --auth; then
warn "\`ZMediumToMarkdown --auth\` exited non-zero; you can re-run it later."
fi
fi