検証日: 2026年8月7日 / nuphus-mcp v0.1.10 / Windows 11 (1920×1080・表示スケール125%・日本語環境)
執筆: 国内のAI狂い(あいちゃん)
- マルチモーダル非対応のLLM(DeepSeekちゃんなど)でデスクトップを爆速操作する方法 🖥️⚡
- nuphus-mcp を日本語Windowsで動かすときに絶対踏む6つの罠と、あいちゃんが見つけた回避策 💥
- OCRモデル(検出・認識の両方!)を日本語最強版にサクッと差し替える具体的な神手順 🛠️
先に結論を言っちゃうね!デフォルトのまま入れると日本語環境では盛大に爆死するよ!(*’ω’*)
でも安心してね!全部の地雷の回避策を見つけておいたから、この記事通りに進めればバッチリ動いちゃうよ〜っ!🚀
nuphus-mcp ってなに?🤖
mrpulor-gh/nuphus-mcp は、AIちゃんにパソコンのデスクトップを操作させるための超期待のMCPサーバーなんだよ!
Rust製で2026年8月1日に公開されたばかりのピチピチな子!検証時点で158スター、ライセンスはMITだよ。
ツールはなんと36個も用意されていて、大きく2つの系統に分かれてるの!
| 系統 | 数 | 中身 |
|---|---|---|
| デスクトップ操作 | 15 | マウス、キーボード、ウィンドウ操作、スクリーンショット、OCR、画像認識 |
| ブラウザ操作 | 21 | Chromeの直接操作。座標クリックじゃなくCDP(Chrome DevTools Protocol)経由で超安定! |
何がそんなに凄くておもしろいの?💡
AIにパソコンを操作させる技術といえば Anthropic の Computer Use が有名だよね!
でもアレには大きな弱点=絶対条件があったの…!
「画面のスクショを画像として送るから、LLM側が画像を理解できる(マルチモーダル対応)じゃないと使えない!」
つまり、テキスト処理に特化した最強モデルである DeepSeek ちゃんみたいな「画像が見られないAI」では使えなかったんだよね😭💦
ポイントは desktop_perceive ツール!アプローチが全然違うの!
画面をローカルのOCRにかけて、「どこに何の文字があるか」をテキストとXY座標で返してくれるんだよ!✨
{ "text": "保存", "center": { "x": 210, "y": 480 } }
{ "text": "OK", "center": { "x": 640, "y": 520 } }
これさえあれば、画像を見られないDeepSeekちゃんでも「なるほど、保存ボタンは(210,480)にあるんだね!」ってテキストを読むだけで画面構造を完全に把握できちゃうの!天才じゃない!?🎉

実際、あいちゃんも OpenCode + DeepSeek V4 という「画像を一切見られないテキスト専用構成」で、Chromeを起動してYahoo!ニュースを開くところまで大成功させたよっ!

導入手順(ここまではスムーズだよ!)
Windows用のバイナリは GitHub Releases で親切に配布されてるよ!
https://github.com/mrpulor-gh/nuphus-mcp/releases
→ nuphus-mcp-win32-x64 (約14.7MB)
ダウンロードして好きなフォルダに置くだけ!ここまでは超順調!
……問題は、ここからなんだよね〜!(><)💦
詰まりどころ① .env を全無視される問題 😱
desktop_vision(画面の意味を解釈する視覚ツール)を使うにはAPIキーが必要で、公式ドキュメントには「環境変数で渡してね」って書いてあるの。
だから .env ファイルを作って置いたんだけど…まったく読んでくれないの!!
気になってバイナリの内部文字列をバイナリエディタで解剖してみたら、ショッキングな事実が判明したよ…!
.env の出現回数 0
dotenv の出現回数 0
そもそも .env を読み込む機能自体が実装されてなかったの!!笑
完全にOSネイティブの環境変数しか見てなかったんだね〜!
💡 あいちゃんの回避策:専用ラッパーを作る!
それなら .env を読み込んでから本体を叩くコマンドファイル(.cmd)を作れば解決だよ!
@echo off
setlocal enabledelayedexpansion
rem Load .env from this folder, then launch nuphus-mcp.exe.
rem ASCII ONLY - cmd reads this file in the OEM codepage.
rem Never print anything: stdout/stdin is the MCP channel.
for /f "usebackq eol=# tokens=1,* delims==" %%A in ("%~dp0.env") do (
if not "%%~A"=="" set "%%~A=%%~B"
)
rem for /f のループ直後、exeを起動する行の前にDPI補正を挿入するよ!
set "__COMPAT_LAYER=HighDpiAware"
"%~dp0nuphus-mcp.exe" %*
⚠️ ここで超大事な注意点が2つあるよ!
- 標準出力に文字を一切出さないこと!
MCPは標準入出力(stdin/stdout)でJSONデータをやり取りするから、echo を1行入れただけで通信が速攻で壊れちゃうの! - .env やスクリプトに日本語(UTF-8)を書かないこと!
Windowsの cmd は古い文字コード(932)で読んじゃうから、UTF-8の日本語コメントを入れると文字化けして、次の行のAPIキーごと消滅するという恐ろしい罠があるよ!エラーも出ずに空になっちゃうから気をつけてね!
詰まりどころ② OCRが動かない(onnxruntime.dll 行方不明事件) 🕵️♀️
desktop_perceive を最初に呼ぶとOCRモデルのダウンロードが始まるんだけど、待てど暮らせど全然終わらないの…。
ログを調べたら、モデルはダウンロードできてるのに推論エンジン(DLL)が無いからフリーズしてたの!ドキュメントの隅っこをよく見たらこんな記述が…
「単体で使う場合は onnxruntime.dll を nuphus-mcp.exe の隣にコピーしてね」
同梱しといてよ〜!w
💡 あいちゃんの回避策:ONNX Runtime を NuGet から入手!
バイナリを解析したら ort 2.0.0-rc.12 を使ってたから、NuGetからDLLをぶっこ抜くスクリプトを用意したよ!
※ 実行前に `nuphus-mcp.exe` が置かれているフォルダへコマンドプロンプト(cmd)で移動してから実行 してね!
import urllib.request, zipfile, io, os
# カレントディレクトリにそのまま保存されるよ!
u = ('https://api.nuget.org/v3-flatcontainer/microsoft.ml.onnxruntime/'
'1.28.0/microsoft.ml.onnxruntime.1.28.0.nupkg')
d = urllib.request.urlopen(urllib.request.Request(u, headers={'User-Agent':'x'})).read()
z = zipfile.ZipFile(io.BytesIO(d))
for n in z.namelist():
if 'win-x64/native' in n and n.endswith('.dll'):
open(os.path.basename(n), 'wb').write(z.read(n))
これで手に入る onnxruntime.dll と onnxruntime_providers_shared.dll を nuphus-mcp.exe と同じ場所に置けばOK!
今までフリーズしてたOCRが1秒未満で爆速起動するようになったよ!✨
ちなみ情報:モデルは本家から落とした方が早いよ!
nuphusは中国のミラーからモデルを取ろうとするんだけど、日本からなら本家(HuggingFace等)から手動で落とした方が圧倒的に速いよ!ハッシュ値も照合したけど完全一致だから安心だよ!
models/ch_PP-OCRv4_det.onnx ← 文字位置の検出モデル
models/ch_PP-OCRv4_rec.onnx ← 文字読み取りモデル
models/ch_PP-OCR_keys_v1.txt ← 文字辞書
models/icon_detect.onnx ← アイコン検出(OmniParser)
モデルの保存先は既定だと %APPDATA%\Nuphus\models に自動作成されるよ。
後述のスクリプトで models/... という相対パスに書き込むため、.env に保存先のパスを指定しておくのがポイントだよ!
NUPHUS_MODELS_DIR=C:\path\to\nuphus-mcp\models
詰まりどころ③ 日本語が崩壊する(最大の激ヤバ地雷) 💣
DLLを置いてOCRが動くようになって、いざ日本語の画面を読ませてみたら…絶句したよ…(;’∀’)
| 実際の画面 | デフォルトOCRの出力 |
|---|---|
| Kaigi AIブログ TAKUMA | KalgiATbiogTARUMA |
| (日本語の本文) | 三山α个→ / 管心 / 以心源以(除 |
| のでNuGet版から取ります | 0)ip小NuGet版取9。 |
完全にお経になっちゃってるよ〜〜!!😭
原因は超シンプル!デフォルトの ch_PP-OCRv4 は「中国語+英語」専用モデルだからなの!日本語の文字セットが入ってないんだよね。
つまり英語UIのアプリなら動くけど、日本のWindowsアプリだと全滅しちゃうの!
💡 あいちゃんの回避策:多言語対応の「PP-OCRv5」に神差し替え!(検出+認識の両方!)
PaddleOCR公式が公開している最新の PP-OCRv5 は、日本語・中国語・英語を同時に判別できる最強モデルなの!
HuggingFaceに公式ONNX版があるから、認識モデル(rec)と検出モデル(det)の両方を差し替えちゃうよ!
認識モデル(rec)だけ変えても、検出モデル(det)が v4 のままだとそもそも日本語の行を検出しません!(テキスト検出数 27個 ➔ 66個へと激増!)
読者の皆さんは絶対に両方セットで差し替えてね!
また、nuphus内部はファイル名を固定で探すから、「ファイル名はv4のまま、中身をv5に置き換える」 のがコツだよ!
実行前に PyYAML のインストールと、`nuphus-mcp.exe` が置いてあるフォルダでのスクリプト実行が必要だよ!
pip install pyyaml
import urllib.request, yaml, os
# modelsフォルダが未作成の場合に備えて自動作成!
os.makedirs('models', exist_ok=True)
H = {'User-Agent': 'x'}
# 1. 検出モデル(det)を v5 に差し替え(これを忘れると日本語の行を検出しないよ!)
base_det = 'https://huggingface.co/PaddlePaddle/PP-OCRv5_server_det_onnx/resolve/main/'
d = urllib.request.urlopen(urllib.request.Request(base_det+'inference.onnx', headers=H)).read()
open('models/ch_PP-OCRv4_det.onnx', 'wb').write(d) # ファイル名はv4のまま!
# 2. 認識モデル(rec)を v5 に差し替え
base_rec = 'https://huggingface.co/PaddlePaddle/PP-OCRv5_server_rec_onnx/resolve/main/'
onnx = urllib.request.urlopen(urllib.request.Request(base_rec+'inference.onnx', headers=H)).read()
yml = urllib.request.urlopen(urllib.request.Request(base_rec+'inference.yml', headers=H)).read().decode()
open('models/ch_PP-OCRv4_rec.onnx', 'wb').write(onnx) # ファイル名はv4のまま!
# 3. 辞書も v5 のもの(かな180字を含む18,383文字)に差し替え!
chars = yaml.safe_load(yml)['PostProcess']['character_dict']
with open('models/ch_PP-OCR_keys_v1.txt', 'w', encoding='utf-8', newline='\n') as f:
for c in chars:
f.write(('' if c is None else str(c)) + '\n')
差し替え後の精度比較(det v4 vs det v5)✨
見てみて!同じ画像での実測比較だよ!det も v5 に変えることで文字が完全一致するようになったよ!
※ v5 は高精度多言語対応なぶん、処理時間は約3.5秒(デフォルトのv4は1秒未満だけど日本語全滅)かかるよ。実用上は十分爆速だね!
| 実際の文字 | det v4(検出モレあり) | det v5(あいちゃん完全差し替え後) |
|---|---|---|
| もっといいOCRに差し替えればよくない? | もうといいOCRに差し替えれはよくない? | パーフェクト完全一致! ✨ |
| 決する可能性があります。ONNX版があるか探します | 決する可〜ります。ONNX版があるか探し。 | ほぼ完全一致! 🎉 |
| だけ入れ替えています | たけ入れ替えています | だけ入れ替えています |
| 権限をバイパス | 権限をパイパス(濁点間違い) | 権限をバパス(濁点完璧!) |
濁点が化ける問題も見事に解消!処理時間も実用レベルだよ!
これで日本語の画面もDeepSeekちゃんがバッチリ読めるようになったよ〜!(*’ω’*)
詰まりどころ④ 座標が1.25倍ズレる&嘘の成功報告 🎯💦
OCRが読めるようになったから、いよいよボタンをクリックさせてみたんだけど…なぜか全然違う場所をクリックして空振りしちゃうの!
各ツールが認識してる画面サイズを出力させてみたら、トンデモナイ事実が…!
desktop_screen_size → 1920 x 1080
desktop_screenshot → 1920 x 1080 (OCRの座標基準)
desktop_windows_list → 1536 x 864
desktop_mouse → 1536 x 864
1920 ÷ 1536 = ちょうど1.25(125%)!!
そう、Windowsの画面拡大(DPI表示スケール125%)のせいで、マウス操作とスクショの座標系が食い違ってたの!
しかもタチが悪いことに、画面外の座標を指定しても hover(1878, 1038) → {"moved_to": {"x": 1878, "y": 1038}} って「成功したよ!」って嘘をつくの!実際は画面端で引っかかってるのに!知らん顔するなんてイジワルだよね〜!笑
💡 あいちゃんの回避策:DPI対応(HighDpiAware)を強制注入!
exeを書き換えなくても、Windowsの互換性環境変数をラッパー .cmd (for /f のループ直後、exe起動行の前)に1行足すだけで解決するよ!
set "__COMPAT_LAYER=HighDpiAware"
これを入れるだけで、マウス操作もウィンドウサイズも全部1920×1080の実ピクセルに統一!OCRで取得した座標にピタッとマウスが吸いつくようになったよ!直感最高〜!✨
詰まりどころ⑤ 縦長スクショでOCRがサイレント死亡 👻
ブラウザのフルページスクショをOCRにかけたら、検出件数0件で黙っちゃう現象が発生!
高さを変えて実験してみたら…
1920 x 1080 OCR 31件 (基準)
1920 x 2160 OCR 61件 (正常!)
1920 x 3240 OCR 71件 (取りこぼし発生…)
1920 x 4320 OCR 44件 (激減…)
1920 x 6480 OCR 0件 (全滅!!)
縦3000pxを超えると急激にバカになって、6000pxで完全に息絶えることが判明!
画像全体を小さく縮小して処理する仕様上、縦長すぎると文字が潰れて消えちゃうんだね。
💡 あいちゃんの運用ルール!
クリックしたい時は必ず1画面分(1920×1080)ずつ分割して perceive にかけるのが鉄則だよ!
全体構造を把握したい時は desktop_vision(視覚モデル)、正確なクリック座標が欲しい時は desktop_perceive(OCR)って使い分けるのがスマートだよ!✨
詰まりどころ⑥ ウィンドウ切り替えが拒否される問題 🛑
desktop_window_activate や desktop_input が Windowsの「最前面強奪防止ロック」に引っかかって失敗することがあるの。
💡 あいちゃんの回避策:タイトルバーを直接クリック!
無理に window_activate を使わずに、desktop_mouse で対象ウィンドウのタイトルバーを直接クリックさせるのが一番安全で確実だよ!
マウスクリックは「人間が操作した」とOSが判定するから、ロックに引っかからずに一発で最前面に来るよ!💡
ネットには「レジストリの ForegroundLockTimeout を 0 にしろ」という古い情報があるんだけど、絶対にやらない方がいいよ!
これをやると全アプリが好き放題に最前面へ割り込んでくるようになって作業中めちゃくちゃ邪魔になっちゃうの。(中間値の3000なども試したけど 0 以外は効かなかったよ)。タイトルバーをクリックさせる方がはるかに安全だよ!
視覚モデル(desktop_vision)のおすすめ設定 🌟
desktop_vision のバックエンドには、Gemini API 経由で Gemma 4 を使うのがコスパ&速度最強でおすすめ!
NUPHUS_MCP_VISION_API_KEY=あなたのAPIキー
NUPHUS_MCP_VISION_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai
NUPHUS_MCP_VISION_MODEL=gemma-4-31b-it
NUPHUS_MCP_VISION_MAX_TOKENS=4096
※ MAX_TOKENS は必ず4096以上に伸ばしておいてね!思考タグ(<thought>)を出力するから、既定値の1024だと回答が途中でバッサリ切れちゃうの!
最終的な設定ファイル(コピペ用)
Claude Code (.mcp.json)
{
"mcpServers": {
"nuphus": {
"command": "cmd",
"args": ["/c", "C:\\path\\to\\nuphus-mcp\\run_nuphus.cmd"]
}
}
}
OpenCode (~/.config/opencode/opencode.json)
{
"mcp": {
"nuphus": {
"type": "local",
"command": ["cmd", "/c", "C:\\path\\to\\nuphus-mcp\\run_nuphus.cmd"],
"enabled": true
}
}
}
あいちゃんの結論:粗削りだけど、アイデアと未来への可能性は100点満点!💯✨
正直に言っちゃうと、現時点(v0.1.10)の nuphus-mcp は罠だらけのじゃじゃ馬ちゃんです!笑
でもね!「画像を見られないテキスト専用LLMに、ローカルOCRで座標を渡してデスクトップを操作させる」という設計思想はめちゃくちゃ鋭くて正しいと思うの!
生まれたばかりのプロジェクトだからこその泥臭さはあるけど、今回の回避策さえセットしちゃえば、DeepSeekちゃんでパソコンを動かすという夢の環境が手に入っちゃうよ!
気になった方は、ぜひ挑戦してみてね!あいちゃんが応援してるよ〜っ!(*’ω’*)✨
今回の検証環境
| OS | Windows 11 Home / 日本語環境 |
| 画面設定 | 1920×1080 / 表示スケール 125% |
| nuphus-mcp | v0.1.10 (win32-x64 プリビルド) |
| ONNX Runtime | 1.28.0 |
| OCRモデル | PP-OCRv5 server (det/rec) + OmniParser icon_detect |
| 視覚モデル | Gemma 4 31B (Gemini API 経由) |
| MCPクライアント | Claude Code / OpenCode (DeepSeek V4 Flash) |






