routeros-command-tree について
RouterOS のコマンドツリーと `/console/inspect` REST エンドポイントを解説する技術スキルです。RouterOS 用ツールやスキーマ、コマンド検索機能を開発する人向けに、ツリー走査、バージョン差異、リスクのある構文要求への対処を説明します。
主な機能
- 01コマンドツリーのノード型を解説
- 02`/console/inspect` の要求を実行
- 03コマンドツリーの走査とキャッシュ
- 04CLI コマンドと REST 動詞の対応付け
- 05RAML と OpenAPI スキーマの生成
- 06危険なパスを保守的に処理
活用シーン
- 01RouterOS コマンド検索ツールの構築
- 02REST API スキーマの生成
- 03キャッシュ済みコマンドツリーのオフライン確認
MCP 対応
`rosetta` が MCP コマンド検索にコマンドツリーデータを利用する方法を説明します。MCP サーバーの実装については記載されていません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tikoci/ routeros-skills --skill routeros-command-treeインストール後、Claude Code で/routeros-command-treeを入力して読み込まれたか確認します。
詳細
RouterOS のコマンドツリーと /console/inspect
概要
RouterOS では、すべての設定とコマンドが階層型ツリーに整理されています。CLI の各パス
(/ip/address/add など)は、このツリー内のノードに対応します。/console/inspect REST エンドポイントを使うと、
ツリー全体をプログラムから探索できます。これは、restraml(RAML/OpenAPI
スキーマジェネレーター)や rosetta(MCP コマンド検索)などのツールがデータベースを構築する方法です。
コマンドツリーの構造
RouterOS のコマンド階層には、次の 4 種類のノードがあります。
| ノードの種類 | 意味 | 例 |
|---|---|---|
dir | ディレクトリ — 子パスを含みます | /ip、/system |
path | パス — 移動可能な階層です(コマンドを持つことがよくあります) | /ip/address、/interface/bridge |
cmd | コマンド — 実行可能な操作です | add、set、print、remove、get、export |
arg | 引数 — コマンドに渡すパラメーターです | address=、interface=、disabled= |
ツリーの例
/ (root dir)
├── ip/ (dir)
│ ├── address/ (path)
│ │ ├── add (cmd)
│ │ │ ├── address (arg) — "IP address"
│ │ │ ├── interface (arg) — "Interface name"
│ │ │ └── disabled (arg) — "yes | no"
│ │ ├── set (cmd)
│ │ ├── remove (cmd)
│ │ ├── get (cmd)
│ │ ├── print (cmd)
│ │ └── export (cmd)
│ ├── route/ (path)
│ │ └── ...
│ └── dns/ (path)
│ ├── set (cmd)
│ ├── cache/ (path)
│ │ ├── print (cmd)
│ │ └── flush (cmd)
│ └── ...
├── interface/ (dir)
│ └── ...
├── system/ (dir)
│ └── ...
└── ...
/console/inspect API
エンドポイント
POST /rest/console/inspect
基本認証が必要です。RouterOS 7.x のすべてのバージョンで利用できます。
リクエストの種類
| リクエスト | 目的 | 戻り値 |
|---|---|---|
child | パスの子要素を一覧表示します | {type: "child", name, "node-type"} の配列 |
syntax | ノードのヘルプテキストを取得します | {type: "syntax", text} の配列 |
highlight | 構文ハイライトのデータ | バイトごとのトークンクラス — routeros-syntax-inspection スキルを参照してください |
completion | タブ補完の候補 | 補完候補 — 有効性の確認については routeros-syntax-inspection を参照してください |
子要素の一覧表示
// List children of /ip
const children = await fetch(`${base}/console/inspect`, {
method: "POST",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify({
request: "child",
path: "ip",
}),
}).then(r => r.json());
// Response:
// [
// { "type": "child", "name": "address", "node-type": "path" },
// { "type": "child", "name": "arp", "node-type": "path" },
// { "type": "child", "name": "cloud", "node-type": "path" },
// { "type": "child", "name": "dhcp-client", "node-type": "path" },
// { "type": "child", "name": "dns", "node-type": "path" },
// { "type": "child", "name": "route", "node-type": "path" },
// ...
// ]
構文ヘルプの取得
// Get description for /ip/address/add → address argument
const syntax = await fetch(`${base}/console/inspect`, {
method: "POST",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify({
request: "syntax",
path: "ip,address,add,address", // comma-separated path
}),
}).then(r => r.json());
// Response:
// [{ "type": "syntax", "text": "IP address" }]
パスの形式
path フィールドでは、セグメントをスラッシュではなくカンマで区切ります。
- ルート:
""(空文字列) /ip:"ip"/ip/address:"ip,address"/ip/address/add:"ip,address,add"/ip/address/add → address arg:"ip,address,add,address"
JavaScript の Array.toString() メソッドを使うと、配列からこのカンマ区切り形式が
自動的に生成されます。["ip", "address", "add"].toString() → "ip,address,add"。
ツリーの走査パターン
ツリー全体を再帰的に走査するには、次のようにします。
async function walkTree(path = [], tree = {}) {
const children = await fetchInspect("child", path.toString());
for (const child of children) {
if (child.type !== "child") continue;
const childPath = [...path, child.name];
tree[child.name] = { _type: child["node-type"] };
// For args, fetch the syntax description — but NOT inside dangerous subtrees
if (child["node-type"] === "arg") {
if (DANGEROUS_PATHS.some(p => childPath.includes(p))) continue;
const syntax = await fetchInspect("syntax", childPath.toString());
if (syntax.length === 1 && syntax[0].text.length > 0) {
tree[child.name].desc = syntax[0].text;
}
}
// Recurse into this child (child enumeration is safe even in dangerous subtrees)
await walkTree(childPath, tree[child.name]);
}
return tree;
}
危険なパス — 保守的なスキップポリシー
古い RouterOS バージョンでは、スクリプト用キーワードを含むパスに対して
/console/inspect 経由で構文や補完を照会すると、REST サーバーがデッドロックすることがあります。クローラーでは保守的に、
次のいずれかの名前を含むサブツリー内での構文照会をスキップします。
where, do, else, rule, command, on-error
これらは RouterOS のスクリプト構文要素です。この 6 パスのリストは、時代を問わずクラッシュが発生することを示すものではなく、保守的なクローラーのスキップポリシーとして扱ってください。
tikoci/restraml での実機調査(MikroTik サポートケース SUP-127641)では、
デッドロックが発生すると確認されたのは RouterOS ≤7.20.8 で、request=syntax/completion を指定して
do 単体を照会した場合だけであり、ほかの 5 つのパスはその環境で瞬時に [] を返すことが判明しました。また、この問題は7.21.4 で修正されています。(元になった 6 パスの通説は、順番に照会した際に生まれたものです。do でサーバーがハングすると、その後にテストしたすべてのパスもクラッシュしたように見えてしまいます。)子要素の列挙(child リクエスト)は、テスト済みのすべてのバージョンで安全です。また、["do","command"] のようなネストされたパスも安全です。
上記の例で使っている保守的な方法では、祖先に危険なパスが含まれる場合、その引数全体をスキップし、古いバージョンまたは不明なバージョンでは、すべてのリクエストに短いタイムアウトを設定します。実際の rest2raml.js 実装も、このパターンに従っています。
const DANGEROUS_PATHS = ["where", "do", "else", "rule", "command", "on-error"];
CLI コマンドと REST 動詞の対応
RouterOS の CLI コマンドは、REST API では次の HTTP 動詞に対応します。
| CLI コマンド | HTTP 動詞 | REST URL パターン | 備考 |
|---|---|---|---|
get (print) | GET | /rest/ip/address | すべてのエントリーを配列で返します |
get (single) | GET | /rest/ip/address/*1 | ID で指定した単一のエントリー |
add | PUT | /rest/ip/address | 新しいエントリーを作成します(POST ではありません!) |
set | PATCH | /rest/ip/address/*1 | 既存のエントリーを更新します |
remove | DELETE | /rest/ip/address/*1 | ID でエントリーを削除します |
print | POST | /rest/ip/address/print | アクション形式(GET としても動作します) |
| その他のコマンド | POST | /rest/path/command | アクション(再起動、フラッシュなど) |
重要なポイント: REST の PUT は作成、PATCH は更新です。これは、PUT を冪等な更新、POST を作成に使う多くの REST API 規約とは逆です。
RAML/OpenAPI スキーマの生成
コマンドツリーから API スキーマを生成する場合:
- ツリーをたどり、すべてのパス、コマンド、引数を収集します
- 各
cmdノードについて:get→GET /path(一覧)とGET /path/{id}(単一)の両方を生成しますadd→ 引数に基づくリクエストボディを持つPUT /pathを生成しますset→ 引数に基づくリクエストボディを持つPATCH /path/{id}を生成しますremove→DELETE /path/{id}を生成します- その他のコマンド →
POST /path/commandを生成します
- コマンド配下の各
argについて、リクエストボディのプロパティまたはクエリパラメーターを生成します - 構文検索で得られる
descフィールドが説明になります
.proplist と .query パラメーター
POST ベースのコマンドエンドポイントは、すべて次の 2 つの特殊なパラメーターを受け付けます。
.proplist— 返すプロパティを選択します(SQL の SELECT のようなものです).query— フィルター式の配列です(SQL の WHERE のようなものです)
これらは RouterOS REST API の規約であり、標準的な REST パターンではありません。
出力形式
inspect ツリーは複数のスキーマ形式に変換できます。
inspect.json(生出力)
再帰的な /console/inspect 呼び出しで返される生のツリーです。各ノードには次の情報があります。
{
"address": {
"_type": "path",
"add": {
"_type": "cmd",
"address": { "_type": "arg", "desc": "IP address" },
"interface": { "_type": "arg", "desc": "Interface name" }
},
"set": { "_type": "cmd", ... },
"print": { "_type": "cmd", ... }
}
}
RAML 1.0(schema.raml)
RAML 1.0 のリソース/メソッド形式に変換されます。
/ip:
/address:
get:
queryParameters: ...
responses: ...
put:
body:
application/json:
properties:
address: { type: any, description: "IP address" }
/{id}:
get: ...
patch: ...
delete: ...
OpenAPI 3.0(openapi.json)
同じ inspect ツリーから生成される標準的な OpenAPI 3.0 スキーマです(7.21.1 以降)。
inspect.json データモデル
各バージョンの inspect.json は、その RouterOS バージョンのコマンドツリーにおける信頼できる唯一の情報源です。次の情報を記録します。
- CLI 階層内の移動可能なすべてのパス
- 各パス階層にある、実行可能なすべてのコマンド
- 各コマンドのすべての引数(パラメーター)
- 引数の構文説明
ルーターに接続しなくても、ツールで inspect.json をオフライン解析できます。INSPECTFILE 環境変数を設定すると、スキーマジェネレーターはルーターへの問い合わせの代わりにキャッシュ済みファイルを使用します。
ツリーを操作する際の一般的なパターン
パス上のコマンドを検索する
// Given an inspect.json node for /ip/address
const node = inspectData.ip.address;
// Commands are children with _type === "cmd"
const commands = Object.entries(node)
.filter(([key, val]) => val._type === "cmd")
.map(([key]) => key);
// → ["add", "set", "remove", "get", "print", "export", ...]
コマンドの引数を検索する
// Arguments of /ip/address/add
const addCmd = inspectData.ip.address.add;
const args = Object.entries(addCmd)
.filter(([key, val]) => val._type === "arg")
.map(([key, val]) => ({ name: key, description: val.desc }));
// → [{name: "address", description: "IP address"}, ...]
ディレクトリをたどる
// Directories and paths (navigable children)
const children = Object.entries(node)
.filter(([key, val]) => val._type === "dir" || val._type === "path")
.map(([key]) => key);
パフォーマンスに関する注意事項
- ライブのルーターに対するツリー全体の走査には数分かかります(数千件の HTTP リクエストが必要で、それぞれが
/console/inspectへの個別の POST です)。KVM アクセラレーションを使うと CHR は素早く応答しますが、逐次リクエストの数が多いため、合計時間は長くなります。 /console/inspectの呼び出しはそれぞれ個別の HTTP リクエストです。バッチ API はありません- ライブ環境への繰り返しの問い合わせを避けるため、開発/テストでは
INSPECTFILEを使用してください - ツリーはバージョン固有です。RouterOS のバージョンによってコマンドセットが異なります
- 追加パッケージ(container、iot、zerotier など)によって、コマンドツリーのブランチが追加されます
追加リソース
- MikroTik の新しいマニュアルサイトには、閲覧可能な CLI リファレンス があります。
https://manual.mikrotik.com/docs/CLI%20Reference/ では、パッケージ/パスごとにコマンドメニュー、
フラグ、引数名、型を確認できます(例:
/docs/CLI%20Reference/system/ip/address)。人が読みやすい/console/inspectの補助資料として扱ってください。稼働中のルーターと内容が異なる場合は、 そのルーターの/console/inspectを優先してください。 - REST API の詳細については、
routeros-fundamentalsスキル → REST API のパターンを参照してください - クエリを実行するための CHR の起動方法については、
routeros-qemu-chrスキルを参照してください - /app YAML 形式(7.22 以降のツリーで確認できる機能)については、
routeros-app-yamlスキルを参照してください