(本記事は OPTiM TECH BLOG Advent Calendar 2025 Day 23 の記事です。)
はじめに
こんにちは。サービス開発統括本部の三好です。
私はOPTiM BizというサービスのAndroidエージェント開発と問い合わせ業務を担当しています。
正直なところ、Android開発の経験はまだ浅く、adbコマンドを覚えるのに苦労していました。
そこで、近年話題のMCPサーバーを自作し、AIにadbコマンドの実行をお任せすることにしました。
この記事では、その実装手順から、Android Studioでの動作確認までを紹介します。
MCPサーバーとは
MCPサーバーは、AIに外部やローカルのデータ・機能を提供するための仕組みです。
通常、AIは学習済みの知識に依存しますが、MCPサーバーを介することで次のことが可能になります。
- 外部システムとの連携:データベースやWeb APIへのアクセス
- ローカルリソースの利用:ファイル、デバイス、アプリケーションへの操作
これにより、AIがより高度な応答やアクションを行えるようになります。
参考: https://cloud.google.com/discover/what-is-model-context-protocol
MCPサーバーを自作
使用するライブラリ
mark3labs/mcp-goを選定しました。
これはGo製MCP SDKの中で現在最もスター数が多く、活発にメンテナンスされているためです。
また、Go言語を採用した理由としては「クロスコンパイルの容易さ」にあります。
ランタイム不要でシングルバイナリを生成できるため、私のWindows環境でも同僚のMac環境でも手軽に配布・実行でき、運用コストを下げることができます。
実装
コード全体は下記の通りです。 重要な箇所をピックアップして解説します。
package main import ( "context" "fmt" "os/exec" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" ) func main() { s := server.NewMCPServer( "adb-mcp-server", "0.0.1", ) executeAdbTool := mcp.NewTool( "execute-adb", mcp.WithDescription("adbコマンドを実行します"), mcp.WithString( "subCommand", mcp.Required(), mcp.Description("adbコマンドで実行するサブコマンドです"), ), ) s.AddTool(executeAdbTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { subCommand, err := request.RequireString("subCommand") if err != nil { return mcp.NewToolResultError(err.Error()), nil } cmd := exec.Command("adb", subCommand) output, err := cmd.CombinedOutput() if err != nil { return mcp.NewToolResultError(err.Error()), nil } return mcp.NewToolResultText(string(output)), nil }) if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) } }
サーバーを生成
まずは server.NewMCPServer でサーバーのインスタンスを生成します。
ここで指定した名前(adb-mcp-server)とバージョンは、クライアント側がサーバーを識別するために使われます。
ツールを定義
次に、AIに提供する機能を「ツール」として定義します。
mcp.NewTool を使い、execute-adbという ツールを定義します。
重要なのは mcp.WithString の部分です。ここでAIに対して「subCommand という名前で、実行したいadbのサブコマンド(例: devices, shellなど)を文字列で渡してください」と定義しています。
ツールを実装
s.AddTool で、定義したツールが呼ばれた際の実際の処理を記述します。
1. request.RequireString("subCommand") でAIから送られてきた引数を取得し、
2. exec.Command("adb", subCommand) でOSの adb コマンドとして実行します。
3. cmd.CombinedOutput() で実行結果(標準出力と標準エラー出力)を取得し、それをテキストとしてAIに返却しています。
サーバーを起動
最後に server.ServeStdio(s) でサーバーを起動します。
MCPサーバーは標準入出力を通じてMCPクライアントと通信を行うため、待ち受け状態で起動します。
ビルド
私のPCはWindowsですがWSLで開発しているため、GOOSを指定しビルドを実行します。
$ GOOS=windows GOARCH=amd64 go build -o adb-mcp-server.exe
Android StudioのGemini Code Assistから使ってみる
準備
生成したバイナリをAndroid StudioのGemini Code AssistのMCPサーバーとして登録します。
「Setting」→「Tools」→「Gemini」→「MCP Servers」と遷移すると、設定用のjsonが表示されるので、以下の内容で修正してください。
{ "mcpServers": { "adb-mcp-server": { "command": "{{ ビルド済みexeファイルのパス }}", "args": [], "env": {} } } }
これで、Gemini Code Assistがadb-mcp-serverをツールとして認識してくれます。
手始めに
まずは簡単なコマンドで接続確認をしてみましょう。以下のようなプロンプトを入力します。
私: 「現在接続しているデバイスはありますか?」
すると、Geminiはexecute-adb ツールを選択し、サブコマンドに devices を指定して実行してくれます。
返答も期待通りの内容でした。

少し難しいお願い
次はアプリに付与されているランタイムパーミッションを取得してみたいと思います。
アプリは弊社のOPTiM Bizを指定し、以下のようなプロンプトを入力します。
私: 「jp.co.optim.bizagent.biz3.storeに付与されているランタイムパーミッションを列挙してください」
今回は、サブコマンドに shell dumpsys package jp.co.optim.bizagent.biz3.store を指定して実行してくれました。
dumpsysの出力をGeminiがいい感じに解釈してくれるので、自分で確認する手間が省けました。

まとめ
mark3labs/mcp-goを使って、少ないコードで実用的なMCPサーバーを構築できました。
ただし、現状の実装ではadbコマンドの実行に制限がなく、データ消去などのリスクが存在します。
そのために、ホワイトリスト方式で実行可能なコマンドを厳しく管理するなど、制御機構の導入が必要そうです。
今後は実際の運用を通じてフィードバックを集め、より安全で便利なものに改善していきたいです。
今回はMCPサーバーでadbコマンドを自動化しましたが、この他にもOPTiMでは様々な技術領域でAIの活用を推進しています。
あなたのアイデアと技術で、開発現場や社会に大きなインパクトを与えませんか?
少しでも興味をお持ちいただけたら、ぜひ採用ページをご覧ください。