macos-mcp-server について
ローカルの Mac を操作する MCP サーバーです。アプリやウィンドウ、システム設定などを管理するエージェント向けで、オーディオ、ディスプレイ、スクリーンショット、Finder、通知、集中モードにも対応します。ホストには macOS が必要です。
主な機能
- 01アプリの起動、終了、非表示、表示
- 02ウィンドウの一覧表示、フォーカス、配置
- 03オーディオ設定の確認と変更
- 04ディスプレイと外観の管理
- 05スクリーンショットの撮影と Finder の操作
- 06通知の送信と集中モードの設定
活用シーン
- 01デスクトップのワークフローでアプリのウィンドウを配置
- 02オーディオデバイスの切り替えやシステム音量の調整
- 03ディスプレイ、アプリウィンドウ、画面領域を撮影
- 04システム情報の確認と集中モードの操作
MCP 対応
MCP クライアント向けに 13 個のツールと 3 つのリソースを公開し、STDIO または Streamable HTTP に対応します。ローカルの macOS ホストを操作するため、実用上は STDIO でのローカル実行を想定しています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y @cyanheads/macos-mcp-serverMACOS_SCREENSHOT_DIRDefault directory for screenshot files. Defaults to ~/Desktop when empty.MACOS_DISPLAY_LAYOUTSJSON object mapping layout names to displayplacer argument strings for apply_layout.MCP_LOG_LEVELMinimum log level for output: debug, info, notice, warning, error.MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEシークレットAuthentication mode: none, jwt, or oauth.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
13掲載時のツール一覧 · 今日に更新
このツールにパラメーターはありません。
詳細
@cyanheads/macos-mcp-server
MCP を介して macOS のシステム設定、アプリ、ウィンドウ、オーディオ、ディスプレイ、スクリーンショット、集中モードを操作します。STDIO または Streamable HTTP に対応しています。
macOS 専用です。 このサーバーはローカルの macOS システムを操作するため、ホストマシンで macOS が実行されている必要があります。HTTP トランスポートにも対応していますが、実用上は stdio での利用を想定しています。ローカルで実行し、MCP クライアントから接続してください。
概要
エージェントから Mac を操作できます。アプリやウィンドウの起動、終了、配置、オーディオやディスプレイデバイスの切り替え、スクリーンショットの撮影、Finder の操作、通知の送信、集中モードの切り替えが可能です。
ツール
| ツール | 説明 |
|---|---|
macos_get_info | システムのスナップショット:バッテリー残量と充電状態、電源、Wi-Fi の接続状態とネットワーク名、ホスト名、macOS のバージョン、稼働時間、ディスプレイ数を取得します。プローブに失敗した場合、そのフィールドは null となり、unavailable に名前が記載されます |
macos_check_permissions | Apple のプロンプト不要のチェックを使って、呼び出し元プロセスのアクセシビリティ、画面収録、オートメーション > Finder の状態を報告します。チェックで判定できない場合は、理由とともに null を返します |
macos_manage_apps | 実行中のアプリを一覧表示し、最前面のアプリを取得し、アプリケーションの起動、終了、強制終了、非表示、表示を行います |
macos_manage_windows | 表示中のすべてのアプリのウィンドウを一覧表示、フォーカス、移動、サイズ変更、移動とサイズ変更、最小化、フルスクリーン表示、または閉じます |
macos_control_volume | システムの出力音量(0~100)とミュート状態を取得または設定します |
macos_control_audio | オーディオデバイスを一覧表示し、現在のデフォルトを取得するか、デフォルトの入力/出力デバイスを切り替えます |
macos_control_appearance | ダーク/ライトモードを取得または設定します |
macos_control_system | 画面をロックするか、ディスプレイをスリープ状態にします |
macos_take_screenshot | メインディスプレイ、display_index で指定したディスプレイ、名前を指定したアプリのウィンドウ、またはピクセル領域をキャプチャします。overwrite が true の場合を除き、既存のファイルを置き換えずに PNG を保存します。JPEG プレビューは任意です |
macos_manage_displays | 接続されたディスプレイ(それぞれの index を含む)と設定済みレイアウト名を一覧表示し、名前を指定したディスプレイレイアウトのプリセットを適用します |
macos_send_notification | macOS の通知センターに通知を送信します |
macos_manage_focus | おやすみモード/集中モードを取得または設定します |
macos_manage_finder | 最前面のパス、現在の選択項目の取得、表示、アプリで開く、またはゴミ箱への移動を行います |
リソース
| リソース | 説明 |
|---|---|
macos://system/info | 現在の macOS システムのスナップショット:バッテリー、電源、Wi-Fi の接続状態とネットワーク名、ホスト名、バージョン、稼働時間、ディスプレイ数を取得します。プローブに失敗した場合、そのフィールドは null となり、unavailable に名前が記載されます |
macos://audio/devices | 現在のデフォルトデバイスを含む、すべてのオーディオ入力・出力デバイス。SwitchAudioSource CLI が必要です。 |
macos://displays | 永続 ID、インデックス(macos_take_screenshot と macos_manage_windows が使用する display_index)、種類、解像度、原点、回転、スケーリング、有効状態を含む、接続されたディスプレイの一覧。displayplacer CLI が必要です。 |
リソースのデータは、macos_get_info、macos_control_audio(action=list)、macos_manage_displays(action=list)からも取得できます。
機能リファレンス
macos_get_info tool
- バッテリー残量(0~100)、充電状態、電源(
AC、Battery、UPS)。バッテリーのないデスクトップではnullです。バッテリーが充電上限で維持されている場合(「AC 接続中、充電していません」)、chargingは false になり、充電完了に向けて充電中の場合は true になります - Wi-Fi デバイスのリンク状態から Wi-Fi の接続状態を取得します。macOS がネットワーク名の取得を制限している場合、接続中でもネットワーク名は
nullになります(取得にはホストアプリで位置情報サービスへのアクセスが必要です)。名前はcontent[]内でコードスパンとして表示されるため、名前に含まれる Markdown 文字もそのまま読み取れます - ホスト名と稼働時間(Node の
osモジュールから取得)、macOS のバージョン文字列(例:"15.1") - 接続されたディスプレイ数(ヘッドレス Mac では
0) - プローブに失敗した場合、そのフィールドは
nullとなり、unavailableに名前が記載されます。値がbattery: nullで、unavailableにbatteryが含まれていない場合、その Mac にバッテリーはありません - 権限は不要です
macos_check_permissions ツール
- Apple のプロンプトを表示しないチェック、
AXIsProcessTrusted、CGPreflightScreenCaptureAccess、およびプロンプト表示を無効にしたAEDeterminePermissionToAutomateTargetを使用して、アクセシビリティ(listを含むすべてのmacos_manage_windowsアクション、macos_manage_appsのhideとshow、window_titleのfrontmost読み取り、およびスクリーンセーバーにフォールバックする前に ⌃⌘Q キーストロークを送信するmacos_control_systemのlock)、画面収録(ウィンドウのスクリーンショット)、および オートメーション > Finder(macos_manage_finderのfrontmost_path、get_selection、trash)の権限を報告します - 各フィールドは
true、false、またはチェックで判定できない場合はnullです。unknown_reasonsには、各nullが不明である理由が示されます。macOS が同意を求めるまでは、また Finder が起動していない間は、オートメーション > Finder の値はnullです。通知は常にnullです。macOS にはプロンプトを表示しないチェック方法がありません - 呼び出し元のプロセス名(例:
"ghostty"、"node")を返すため、どのプロセスに権限を付与すべきかがわかります - 読み取り専用です。チェックによって他のアプリに Apple イベントが送信されたり、画面がキャプチャされたり、権限プロンプトが表示されたりすることはありません
- 他のツールが失敗する原因をデバッグする際は、まずこれを実行してください
macos_manage_apps ツール
list— 実行中のユーザー向けアプリを、名前、バンドル ID、PID、表示状態、最前面フラグとともに一覧表示しますfrontmost— アクティブなアプリの名前、バンドル ID、PID、最前面ウィンドウのタイトルlaunch—app_nameまたはbundle_idでアプリを開く、またはアクティブ化します。hidden=trueを指定するとバックグラウンドで起動しますquit(AppleScript による正常終了)とforce_quit(SIGKILL による終了。保存プロンプトは表示されません)hide/show— 表示状態を切り替えます。アクセシビリティが必要ですquit、force_quit、hide、showは、まずアプリが実行中かどうかを確認します。アプリケーション名はtell applicationと同じ方法で解決され("Visual Studio Code"からCodeプロセスが見つかります)、アプリは起動しません。実行中でない場合はnot_runningを返します- 型付きエラー:
app_not_found(インストールされていないアプリに対するlaunch)、no_frontmost_app(System Events が最前面のプロセスを報告しない場合)、not_running、accessibility_required
macos_manage_windows tool
list— アプリ全体で表示されているすべてのウィンドウを、位置、サイズ、minimizedとfullscreenの状態(それぞれウィンドウのAXMinimized/AXFullScreen属性から読み取り、読み取れない場合はnull)、およびdisplay_index(ウィンドウと最も重なるディスプレイ。インデックスはmacos_manage_displays action=listが報告するもの。ディスプレイのフレームを読み取れない場合、またはウィンドウと重なるディスプレイがない場合はnull)とともに一覧表示します。同じタイトルのウィンドウや、同じ名前の2つのプロセスが所有するウィンドウは、それぞれ個別に一覧表示されますfocus、move、resize、move_resize、minimize、fullscreen、close—window_title(大文字と小文字を区別しない完全一致で、すべてのアプリが対象。同じアプリに同じタイトルのウィンドウが2つある場合は、手前にあるウィンドウ)またはapp_name(そのアプリの手前にあるウィンドウ)で対象を指定します。window_titleが優先され、その場合app_nameは無視されますapp_nameは、アプリケーション名("Visual Studio Code")、ローカライズ名("Code")、またはプロセス名("firefox")で、実行中のアプリに大文字と小文字を区別せずに一致します。実行中のアプリ一覧から解決されるため、アプリの検索時にアプリを起動したり、Apple イベントを送信したりすることはありませんmoveにはx/yが必要です。resizeにはwidth/height(どちらも 0 より大きい値)が必要です。move_resizeには4つすべてが必要ですminimize—minimized: true(デフォルト)で最小化し、falseで復元します。ウィンドウがすでにその状態にある場合はAXMinimized属性を書き込まず、読み戻した状態が指定された状態になった場合にのみ成功しますfullscreen—fullscreen: trueで全画面表示にし、falseで解除します。省略するとウィンドウの現在の状態を切り替えます。状態が異なる場合は、focusと同様に対象のウィンドウを前面に表示し、そのAXFullScreen属性を設定します(キー入力は行わないため、キーボードフォーカスがあったウィンドウが切り替わることはありません)。ウィンドウの状態が指定された状態に読み戻されるまで、最大4秒待ちますlistを含むすべてのアクションは System Events をスクリプトで操作し、アクセシビリティの許可が必要です。許可されていない場合はaccessibility_requiredを返し、「ウィンドウなし」として読み取ることはありません。focusはウィンドウを前面に表示し、そのアプリを最前面にします。どのアクションもアプリを起動しません- 各書き込み処理では、1つのスクリプト内で同じウィンドウを見つけ、変更し、読み戻します。
window.appはウィンドウが見つかったプロセスです。closeはウィンドウを返しません - 型付きエラー:
not_running(app_nameに指定された名前のアプリが実行されていない)、window_not_found、accessibility_required、minimize_unsupported、fullscreen_unsupported(ウィンドウのAXMinimized/AXFullScreen属性が存在しない、設定できない、または4秒以内に指定された状態にならなかった場合)。osascript のタイムアウトまたは失敗は、window_not_foundとして読み替えず、固有のエラーを維持します
macos_control_volume tool
get— デフォルト出力の現在の音量(0~100)とミュート状態を取得します。ソフトウェアで音量を制御できない出力(多くの HDMI および DisplayPort ディスプレイなど)では、levelとmutedはnullになり、output_deviceにデバイス名が入ります(識別できない場合はnull)set—level(0~100)、muted、またはその両方が必要です。level=0ではミュートになりません。要求された値をソフトウェアで制御できない出力の場合、デバイス名を示すvolume_unsupportedで失敗し、変更は行いませんactionをそのまま含め、常に現在の状態を返します- 型付きエラー:
volume_unsupported。呼び出しがキャンセルされた場合、デバイスの検索を停止してキャンセルとして終了し、output_device: nullにはなりません
macos_control_audio tool
list— すべての入力/出力デバイスをis_defaultフラグ付きで一覧表示します。typeで絞り込めますcurrent— デフォルトの入力デバイス名と出力デバイス名を取得しますswitch_output/switch_input— 大文字と小文字を区別しない部分一致で名前を指定します("MacBook"は"MacBook Pro Microphone"に一致します)- 音量レベルは別のツールで制御します(
macos_control_volume) - SwitchAudioSource CLI が必要です(
brew install switchaudio-osx)。型付きエラー:device_not_found、switchaudio_unavailable
macos_control_appearance ツール
get—dark_mode: true/falseを返し、actionもそのまま返しますsetにはmode: "dark" | "light" | "toggle"が必要です —dark/lightは冪等で、toggleは呼び出すたびに切り替わります- System Events をスクリプトで操作します。Automation > System Events が拒否されると、型付きエラー
accessibility_requiredが発生します
macos_control_system ツール
lock— アクセシビリティ経由で ⌃⌘Q を実行します。アクセシビリティが許可されていない場合は、ScreenSaverEngine バイナリにフォールバックします(キャンセルされた呼び出しはフォールバックしません)sleep_display—pmset displaysleepnowを実行します。権限は不要です- どちらの操作も即座に実行され、任意の入力(スリープ解除/ロック解除)で元に戻せます
macos_take_screenshot ツール
target:screen(メニューバーがあるメインディスプレイのみ)、display(0 始まりの整数display_index。デフォルトは 0。macos_manage_displays action=listが報告するindex)、region(ピクセル単位の矩形。width/heightは 0 より大きい値)では、画面収録の許可は不要です。window(app_nameで指定。macos_manage_windowsと同様に、大文字と小文字を区別せず、アプリケーション名、ローカライズされた名前、またはプロセス名で照合し、そのアプリの画面上で最前面にあるウィンドウをキャプチャします)には画面収録の許可が必要です。画面収録の確認で判定できない場合もウィンドウのキャプチャは実行され、理由がnoticeに記載されます- 常にフル解像度の PNG を保存します。
pathを省略する(または""を渡す)と、MACOS_SCREENSHOT_DIR(未設定の場合は~/Desktop)に新しいscreenshot-<timestamp>.pngを保存します。既存ファイルは置き換えず、代わりに-2、-3、…を付加します。カスタムのpathは.pngで終わる必要があります(大文字と小文字は区別しません)。~/はホームディレクトリに展開されます。ディレクトリは存在している必要があり、シンボリックリンクを解決した後の場所がMACOS_SCREENSHOT_DIR、/tmp、またはホームディレクトリのいずれかの配下でなければなりません。返されるpathは解決済みのパスです(/tmpのパスは/private/tmp配下として報告されます) - 既存のエントリは置き換えません。パスがすでに存在する場合、
overwrite: trueが指定されていない限りpath_existsエラーになります。overwrite: trueが指定されている場合も、呼び出し時の確認でpathに見つかった通常の.pngファイルのみを置き換えます(シンボリックリンクやディレクトリは置き換えません)。確認後にpathに作成されたエントリや、そのファイルの代わりに置かれたエントリは置き換えず、path_existsエラーになります - すべての呼び出しは、開始から 55 秒以内に完了します。
app_nameの検索時間も含まれます。超過した場合はタイムアウト(-32004)として失敗し、何も書き込みません。キャンセルされたリクエストも何も書き込みません include_data=trueを指定すると、長辺が最大 1024 px(キャプチャがそれより小さい場合は元のサイズ)の JPEG プレビューを品質 70 で返します。これは最初のcontent[]ブロック(image/jpeg)として返され、structuredContent内では base64 のpreviewとpreview_width/preview_heightとしても返されますwidth/height(およびプレビューの寸法)は、画像ファイルのヘッダーから読み取られます- 型付きエラー:
screen_recording_required、window_not_found(アプリが起動していない場合、または画面上にウィンドウがない場合。ウィンドウ検索中に osascript がタイムアウトまたは失敗した場合は、独自のエラーが維持されます)、display_not_found、path_not_writable(解決または検索できないディレクトリも含みます。パスが長すぎる場合も含みます)、path_exists。.pngで終わらないpath、U+0000 を含むpath、またはファイル名や解決後のフルパスがファイルシステムの上限(名前あたり 255 バイト、パス全体で 1024 バイト)を超えるpathは、理由invalid_argumentsを伴う-32602として拒否されます
macos_manage_displays ツール
list— ディスプレイごとに、index(NSScreen.screens内の0始まりの位置。macos_take_screenshotとmacos_manage_windowsが使用するdisplay_index。無効化されたディスプレイなど、NSScreen エントリーがない場合はnull)、永続 ID、種類("MacBook built in screen"または"<N> inch external screen")、解像度、リフレッシュレート(macOS が報告しない場合は"N/A")、原点、回転、スケーリング、有効状態(別のディスプレイをミラーリングしている場合もtrue)を返します。さらに、現在の配置を再現する displayplacer コマンドであるcurrent_configと、MACOS_DISPLAY_LAYOUTSで設定された名前(設定がない場合は[])を示すlayoutsも返します。MACOS_DISPLAY_LAYOUTSが無効な場合でもlistは成功し、layoutsを省略して、noticeに変数名を示します。NSScreen の読み取りに失敗した場合はindexを省略し、その理由をnoticeに示します。これには、並行する System Events の列挙が完了するまで15秒待機した読み取りも含まれますapply_layout—MACOS_DISPLAY_LAYOUTSの名前付きプリセットを有効にします(listがlayoutsとして返す名前のいずれか)。呼び出し元から displayplacer の生の引数を受け付けることはありません。MACOS_DISPLAY_LAYOUTSが無効な場合、apply_layoutはlayouts_invalid(ConfigurationError)として失敗し、layout_not_foundにはなりません- displayplacer CLI が必要です(
brew install displayplacer)。型付きエラー:displayplacer_not_found、displayplacer_output_unrecognized、layout_not_found、layouts_invalid - displayplacer の実行に失敗した場合(終了コードが0以外、シグナル、タイムアウト)、出力内容を返すのではなく呼び出しが失敗します。ディスプレイブロックに、一覧表示で値を返す項目の行が欠けている場合、または一覧表示に配置コマンドがない場合は、
displayplacer_output_unrecognizedとして失敗します。displayplacer 1.3.0 と 1.4.0 の両方を読み取ります
macos_send_notification ツール
titleは必須です。body、subtitle、およびsound=true(デフォルトの通知音)は任意です- 呼び出すたびに新しい通知が作成されます(冪等ではありません)
- 通知の投稿に権限は必要ありません。おやすみモードなどの集中モードが有効な場合、そのモードで投稿アプリが許可されていない限り通知は無音になります
macos_manage_focus ツール
get— ベストエフォートで、~/Library/DoNotDisturb/DB/Assertions.jsonを読み取り、status: "active" | "inactive" | "unknown"を返します。このファイルを読み取れない、または解析できない場合(サーバープロセスに読み取りが許可されていない場合など)は、reasonを伴うunknownを返します。キャンセルされた呼び出しはキャンセルとして処理され、unknownにはなりませんset— Shortcuts ライブラリから"Set Focus"という名前のショートカットを実行し、JSON 入力として{"mode": …, "enabled": …}を渡します。このショートカットは組み込みではありません。Get Dictionary from Input の出力を Set Focus アクションにつなぐショートカットを作成してください。modeは設定済みの集中モード名と大文字小文字も含めて完全に一致する必要があります(例:"Do Not Disturb"、"Work")。enabledのデフォルトはtrueです。結果にはmodeとenabledがそのまま返されます。success: trueはショートカットがエラーなく完了したことを意味します(集中モードの状態は再読み取りされません)- 型付きエラー:
shortcuts_unavailable(shortcuts CLI が見つからない、または"Set Focus"という名前のショートカットがない)、shortcut_failed(ショートカットがエラーで終了し、エラーテキストを含む)。ショートカットの実行が15秒を過ぎても続いている場合は停止され、Timeoutエラーとして報告されます。呼び出しがキャンセルされた場合は実行を停止し、キャンセルとして処理されます
macos_manage_finder ツール
frontmost_path— アクティブな Finder ウィンドウの POSIX パス。ウィンドウが開いていない場合はnullです。キャンセルされた呼び出しはキャンセルとして処理され、nullにはなりませんget_selection— 選択した項目の POSIX パスreveal(open -R)、open_with(open -a <App>、またはapp_nameを省略した場合はデフォルトのアプリ)、trash(ゴミ箱に移動します。復元可能で、完全に削除されることはありません)open_withとtrashは、openまたは Finder を呼び出す前にパスの存在を確認しますfrontmost_path、get_selection、trashは Finder をスクリプトで操作するため、Automation > Finder の権限が必要です。revealとopen_withは権限を必要としません- 型付きエラー:
finder_not_open、path_not_found、app_not_found(open_withで指定したアプリが不明)、trash_refused(Finder が既存の項目を拒否した場合。ロック中、使用中、またはボリュームにゴミ箱がないなど)、accessibility_required
macos://system/info リソース
- 現在の macOS システムスナップショットを
application/jsonで返します。バッテリー、電源、Wi-Fi 接続とネットワーク名、ホスト名、バージョン、稼働時間、ディスプレイ数、unavailableが含まれます - 同じデータは
macos_get_infoからも取得できます
macos://audio/devices リソース
- 現在のデフォルトデバイスを含む、すべてのオーディオ入力・出力デバイスを
application/jsonで返します - SwitchAudioSource CLI が必要です
- 同じデータは
macos_control_audio(action=list)からも取得できます
macos://displays リソース
- 接続されているディスプレイの一覧を
application/jsonで返します。index、永続 ID、タイプ、解像度、原点、回転、スケーリング、有効状態、current_configが含まれます。NSScreen の読み取りに失敗した場合は、notice(およびindexなし)が含まれます - displayplacer CLI が必要です
- 同じデータは
macos_manage_displays(action=list)からも取得できます
機能
@cyanheads/mcp-ts-core を基盤としています。stdio および Streamable HTTP トランスポート、プラグイン可能な認証(none/jwt/oauth)、切り替え可能なストレージ(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1)、オプションの OpenTelemetry トレーシングに対応した構造化ロギングを備えています。
macOS 固有の機能:
- osascript サービスは、設定可能なタイムアウトで JXA(
runJxa)と AppleScript(runAppleScript)の両方を実行します - SwitchAudioSource と displayplacer の連携はオプションの依存関係です。呼び出しごとに PATH、
/opt/homebrew/bin、または/usr/local/binから検出されます。CLI が見つからない場所では、該当ツールはインストール手順とともにServiceUnavailableを返します - macOS のシステムバイナリ(osascript、screencapture、sips、pmset、networksetup、system_profiler など)は絶対パスで実行されるため、ホストの PATH によって実行されるバイナリが変わることはありません
- screencapture は保存先の隣にある非公開ディレクトリにファイルを書き込み、この呼び出しで確認していないファイルを置き換えることなく PNG を配置します。sips は JPEG プレビューを作成し、画像サイズは PNG/JPEG ヘッダーから取得します
- バッテリー情報には pmset、Wi-Fi には networksetup と ifconfig、バージョンには sw_vers、ディスプレイには
system_profiler -json SPDisplaysDataType、ホスト名と稼働時間には Node のosを使用します - 権限を優先する設計です。ツールが
Forbiddenを返す前に、macos_check_permissionsが、どのプロセスにどの権限が必要なのかを正確に報告します
エージェントに適した出力:
- 権限エラーには
accessibility_required理由と、実際に拒否された権限に対応する付与手順が含まれます。対象はPrivacy & Security > Accessibility、または名前が示されたアプリのPrivacy & Security > Automationです - アクションごとの必須引数が不足している場合(
modeを指定しないset、app_nameを指定しないquit)、または AppleScript リテラルで表現できないテキスト(U+0000、対応するサロゲートのないサロゲート)がある場合は、何も実行される前に拒否されます。この場合は-32602、理由invalid_arguments、送信すべき内容を示すヒントが返されます。各複数アクションツールのinputSchemaには、アクションごとの要件が示されています - エラーには失敗したプログラム自身のエラーテキストが含まれ、コマンドラインやスクリプトソースは含まれません
- オプションの CLI 依存関係がない場合、必要な
brew installコマンドを正確に示したServiceUnavailableが返されます macos_manage_windowsは各ウィンドウにdisplay_indexを報告します。これはウィンドウが最も大きく重なっているディスプレイを示し、不明な場合はnullとなります。これにより、エージェントは複数ディスプレイのレイアウトを把握できますmacos_take_screenshotは、フル解像度でのディスクへの書き込みとオプションのプレビューを分けています。プレビューは画像コンテンツブロックとして送信され、structuredContentには base64 として含まれるため、どちらの出力にも含まれます
はじめに
このサーバーはローカル専用で、実行されている macOS システムを操作します。MCP クライアントでは STDIO トランスポートを使用してください。
以下を MCP クライアントの設定ファイルに追加します。
{
"mcpServers": {
"macos-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/macos-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
または npx を使用します(Bun は不要です)。
{
"mcpServers": {
"macos-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/macos-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Streamable HTTP を使用する場合は、トランスポートを設定してサーバーを起動します。
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
前提条件
- macOS 13(Ventura)以降。
- Bun v1.4.0 以降(または Node.js v24 以降)。
- 任意:オーディオルーティング用の SwitchAudioSource(
brew install switchaudio-osx)。 - 任意:ディスプレイ管理用の displayplacer 1.3.0 または 1.4.0(
brew install displayplacer)。
どちらの任意の CLI も、Apple Silicon(/opt/homebrew/bin)または Intel(/usr/local/bin)の Homebrew から、あるいは PATH 上の任意の場所から使用できます。
一部のツールでは、ターミナルまたは MCP ホストアプリに macOS のアクセス許可が付与されている必要があります。
| アクセス許可 | 必要とする機能 |
|---|---|
| アクセシビリティ | macos_manage_windows(list を含むすべてのアクション)、macos_manage_apps(非表示/表示。frontmost はこれを使って window_title を読み取ります)、macos_control_system(ロックのキー入力。許可がない場合はスクリーンセーバーにフォールバックします) |
| 画面収録 | target=window を指定した macos_take_screenshot |
| オートメーション > Finder | action=frontmost_path、get_selection、または trash を指定した macos_manage_finder |
アクセス許可が必要な操作を実行する前に、macos_check_permissions で現在の状態を確認してください。
インストール
- リポジトリをクローンします:
git clone https://github.com/cyanheads/macos-mcp-server.git
- ディレクトリに移動します:
cd macos-mcp-server
- 依存関係をインストールします:
bun install
- 環境を設定します:
cp .env.example .env
# edit .env if you want to set MACOS_SCREENSHOT_DIR or MACOS_DISPLAY_LAYOUTS
設定
| 変数 | 説明 | デフォルト |
|---|---|---|
MACOS_SCREENSHOT_DIR | スクリーンショットファイルのデフォルトディレクトリ、およびカスタムの path が解決される可能性のあるディレクトリの一つです(/tmp とホームディレクトリも対象です)。~ とシンボリックリンクは解決されます。 | ~/Desktop |
MACOS_DISPLAY_LAYOUTS | レイアウト名を、空でない displayplacer 引数文字列に対応付ける JSON オブジェクトです。macos_manage_displays action=apply_layout で使用されます。action=list は名前を layouts として返します。値が無効な場合、apply_layout のみが失敗します。 | {} |
MCP_TRANSPORT_TYPE | トランスポート:stdio または http。 | stdio |
MCP_HTTP_PORT | HTTP サーバーのポート。 | 3010 |
MCP_AUTH_MODE | 認証モード:none、jwt、または oauth。 | none |
MCP_LOG_LEVEL | ログレベル。 | info |
MCP_SESSION_MODE | セッションストレージ:auto、stateful、または stateless(HTTP のみ)。このサーバーはセッションごとの状態を保持しないため、.env.example では stateless を明示的に設定しています。 | stateless(src/index.ts で宣言) |
OTEL_ENABLED | OpenTelemetry の計装を有効にします。 | false |
オプションの上書き設定の全一覧については、.env.example を参照してください。
ディスプレイレイアウトの例:
# Get the current displayplacer command for your setup:
displayplacer list
# Then configure named layouts in your env:
MACOS_DISPLAY_LAYOUTS='{"office":"\"id:1234 res:2560x1440 hz:60 color_depth:8 scaling:on origin:(0,0) degree:0\" \"id:5678 res:1920x1080 hz:60 color_depth:8 scaling:on origin:(2560,0) degree:0\""}'
各画面には、displayplacer list が配置を出力する形式の、引用符で囲まれた個別のセグメントが割り当てられます。レイアウト値に引用符で囲まれたセグメントがない場合、単一の引数として displayplacer に渡されます。macos_manage_displays action=list は、同じ画面ごとの引用符付きセグメントを含む current_config を返し、設定済みの名前を layouts として返します。
サーバーの実行
ローカル開発
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# Run checks
bun run devcheck # Lint, format, typecheck, security, changelog sync
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
プロジェクト構成
| ディレクトリ | 用途 |
|---|---|
src/index.ts | createApp() のエントリーポイント — ツール/リソースを登録し、サービスを初期化します |
src/config/server-config.ts | MACOS_SCREENSHOT_DIR と MACOS_DISPLAY_LAYOUTS の環境変数を解析します |
src/mcp-server/tools/definitions/ | 13 個のツール定義(macos-*.tool.ts) |
src/mcp-server/tools/action-requirements.ts | アクションごとの引数要件 — 入力スキーマで適用され、inputSchema で通知されます |
src/mcp-server/resources/definitions/ | 3 個のリソース定義(macos-*.resource.ts) |
src/services/osascript/ | タイムアウト設定と権限拒否の分類に対応した osascript JXA および AppleScript ランナー、呼び出し元のテキスト用 AppleScript 文字列リテラル、実行中のアプリ名の解決機能 |
src/utils/exec-failure.ts | CLI 呼び出し失敗時に呼び出し元へ返す安全なエラーテキスト(コマンドラインは含めません) |
src/services/binaries/binary-paths.ts | macOS システムバイナリの絶対パス、および呼び出しごとの PATH と displayplacer、SwitchAudioSource の Homebrew 検索 |
src/services/permissions/ | プロンプトを表示しないアクセシビリティ、画面収録、オートメーション > Finder のチェック |
src/services/audio/ | SwitchAudioSource によるデバイス一覧表示と切り替え |
src/services/display/ | displayplacer の一覧表示とレイアウト適用、および各ディスプレイのインデックスを取得する JXA NSScreen 読み取り |
src/services/screencapture/ | screencapture による PNG キャプチャ、パスチェックと上書きしない配置、sips による JPEG プレビュー |
src/services/system-info/ | pmset/networksetup/ifconfig/sw_vers/system_profiler によるバッテリー、Wi-Fi、バージョン、ディスプレイ数の取得、node:os によるホスト名と稼働時間の取得 |
tests/tools/ | ツール定義に対応するツールテスト |
開発ガイド
開発ガイドラインとアーキテクチャ上のルールについては、CLAUDE.md を参照してください。概要は次のとおりです。
- ハンドラーは例外をスローし、フレームワークが捕捉します — ツールのロジック内で
try/catchを使用しません - リクエスト単位のログには
ctx.logを使用し、consoleは呼び出しません - 実際のシステム/CLI の状態を読み取り、決して捏造しません — OS が回答できない場合(デスクトップでのバッテリー情報や、Focus の状態ファイルを読み取れない場合の Focus の状態など)は推測せず、
nullまたはunknownを返します - サービスは
createApp()でシングルトンとして初期化され、get*Service()アクセサーからアクセスします
貢献
Issue を歓迎します。提出前にチェックとテストを実行してください。
bun run devcheck
bun run test
ライセンス
Apache-2.0 — 詳細は LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。