Skip to main content
Glama

nautobot-mcp

CI Python License

Nautobot 用の MCP サーバーです。API が大きすぎて列挙できないインスタンス向けに構築されています。Nautobot 3.2 は 477 パスにわたる 1,673 の REST オペレーションを提供し、インストールするアプリごとにさらに増えていきます。このサーバーはエンドポイントごとに 1 ツールではなく、15 のスキーマ駆動ツールを公開するため、コアもプラグインも含めた API 全体に、エージェントのコンテキストを圧迫することなくアクセスできます。

仕組み

実行時パースではなくビルドステップ。 Nautobot の OpenAPI ドキュメントは 18 MB、GraphQL introspection はさらに 10 MB あります。ビルドスクリプトがこれらを統合して、FTS5 検索テーブルを持つ約 1.1 MB の SQLite インデックスを生成します。サーバーはこれを読み取り専用で開き、ルックアップをマイクロ秒単位で応答します。起動は API のサイズに依存しません。

GraphQL から復元された外部キー。 OpenAPI だけでは Nautobot のリレーションシップを記述できません。すべての関連フィールドは同一の不透明なオブジェクトとしてシリアライズされるからです。

// dcim.device: device_type, role, status and location are indistinguishable here
"device_type": { "id": {...}, "object_type": {"pattern": "^[a-z]+\\.[a-z]+$"}, "url": {...} }

GraphQL の型システムはターゲットを直接命名するため(device_type → DeviceTypeType)、OpenAPI のコンポーネント名で両者を結合し、441 の型付き FK エッジを復元します。依存関係の計画を可能にしているのはこのグラフです。

フィルターの圧縮。 dcim.device は 250 のフィルターパラメーターを公開しますが、これは実際には約 74 の基本フィールドにルックアップ接尾辞のファミリー(__ic、__n、__isnull、__gte、…)を掛けたものです。インデックスは基本フィールドとその接尾辞セットを保存し、語彙を一度だけ記述します。

Related MCP server: mcp-graphql

インストール

uv venv && uv pip install -e ".[dev]"
cp .env.example .env        # then set NAUTOBOT_URL and NAUTOBOT_TOKEN
cp .mcp.json.example .mcp.json   # optional: for stdio-based clients
python -m nautobot_mcp.schema.build --probe

チェックアウトを完全にスキップしてコンテナで実行することもできます — Docker を参照してください。

ビルドステップはスキーマを取得して var/index.sqlite を書き込みます。Nautobot アプリのインストールまたはアップグレード後、あるいは nautobot_refresh_schema ツールを呼び出した後に再実行してください。

設定

変数

デフォルト

目的

NAUTOBOT_URL

—

ベース URL(例: http://nautobot.example.com:8080)

NAUTOBOT_TOKEN

—

API トークン

NAUTOBOT_ALLOW_WRITE

false

create/update/delete のマスターゲート

NAUTOBOT_VERIFY_SSL

true

TLS 検証

NAUTOBOT_TIMEOUT

30

リクエストごとのタイムアウト(秒)

NAUTOBOT_CACHE_DIR

./var

スキーマソースとインデックスの保存先

NAUTOBOT_MAX_PAGE

1000

fetch_all ページネーションの上限

サーバーではなくエントリポイントが読み取るコンテナ専用の設定:

変数

デフォルト

目的

MCP_TRANSPORT

streamable-http

コンテナが提供するトランスポート(クライアント起動コンテナでは stdio)

MCP_HOST

0.0.0.0

HTTP トランスポートのバインドアドレス

MCP_PORT

8000

HTTP トランスポートのバインドポート

NAUTOBOT_AUTO_INDEX

true

起動時にスキーマインデックスがなければ構築して実行を拒否しない

クライアントへの登録

{
  "mcpServers": {
    "nautobot": {
      "command": "/path/to/nautobot-mcp/.venv/bin/python",
      "args": ["-m", "nautobot_mcp"],
      "env": {
        "NAUTOBOT_URL": "http://nautobot.example.com:8080",
        "NAUTOBOT_TOKEN": "...",
        "NAUTOBOT_CACHE_DIR": "/path/to/nautobot-mcp/var"
      }
    }
  }
}

HTTP トランスポートも利用可能です: python -m nautobot_mcp --transport streamable-http --port 8000。

Docker

cp .env.example .env        # then set NAUTOBOT_URL and NAUTOBOT_TOKEN
docker compose up -d        # or: make docker-up

初回起動時にインスタンスに対してスキーマインデックスを構築し、index ボリュームに保存します。以降の起動ではそれを再利用します。サーバーは 127.0.0.1:8000/mcp で待ち受けます。

インデックスはイメージに焼き込まれておらず、焼き込むこともできません。特定の Nautobot インスタンスのスキーマ(そのインスタンスにインストールされているすべてのアプリを含む)から統合されるからです。アプリのインストールまたはアップグレード後に再構築してください — make docker-index、または同じボリュームに書き込む nautobot_refresh_schema ツールを使用します。

make docker-index                 # rebuild the index in place
make docker-logs                  # follow the server log
make docker-down                  # stop; VOLUMES=1 also drops the index
docker compose run --rm server index --offline   # rebuild from cached sources only

コンテナのクライアントへの登録

HTTP 経由では、公開されたポートをクライアントに指定します:

{
  "mcpServers": {
    "nautobot": { "url": "http://127.0.0.1:8000/mcp" }
  }
}

または、クライアントにセッションごとにコンテナを stdio 経由で起動させ、同じインデックスボリュームを再利用させます:

{
  "mcpServers": {
    "nautobot": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/path/to/nautobot-mcp/.env",
        "-e", "MCP_TRANSPORT=stdio",
        "-v", "nautobot-mcp_index:/data",
        "nautobot-mcp:latest"
      ]
    }
  }
}

イメージ名の後に渡されたものはすべてそのまま python -m nautobot_mcp に渡されるため、docker run ... nautobot-mcp:latest --transport sse --host 0.0.0.0 --port 8000 も動作します。

compose ファイルが前提としていること

  • ポートはループバックのみで公開されます。 セキュリティ セクションが完全に適用されます。これはあなたの権限を持つトークンを保持する認証なしのプロキシであるため、他のホストから到達可能にするということは、ポートマッピングを広げるのではなく、その前に認証を置くことを意味します。

  • .env に NAUTOBOT_ALLOW_WRITE=true がない限り、書き込みはオフのままです。

  • コンテナはデフォルトで堅牢化されています — 非 root(uid 1000)、読み取り専用のルートファイルシステム、すべてのケーパビリティを削除、no-new-privileges。書き込み可能なパスは /data ボリュームのみで、インデックスとキャッシュされたソースがそこに属します。

  • ヘルスチェックは TCP 接続であり、MCP リクエストではありません。 セッションなしの /mcp へのリクエストは、セッションマネージャーに誰も回収しないトランスポートを割り当てさせるため、30 秒ごとにプロトコルをプローブするとプローブごとにセッションがリークします。

  • .env は compose によってそのまま読み取られます。 コメントは独自の行に置いてください。末尾の # comment は値から確実に除去されません。

ツール

ツール

目的

nautobot_search_schema

名前、説明、フィールド名でモデルを検索

nautobot_describe_model

フィールド、必須フィールド、FK ターゲット、フィルター、アクション

nautobot_list_apps

アプリの名前空間(コアとプラグイン)、バージョン、インデックス状態

nautobot_plan_create

オブジェクト作成のための順序付き前提条件

nautobot_resolve

人間が読める名前 → UUID(参照元モデルにスコープ)

nautobot_list / nautobot_get

任意のモデルの読み取り(スリム化またはプロジェクション)

nautobot_create / nautobot_update / nautobot_delete

ゲート付き書き込み

nautobot_graphql

任意の GraphQL クエリ

nautobot_graphql_schema

型を 1 つずつ取得する introspection

nautobot_model_actions

CRUD 以外のエンドポイント(trace、napalm、notes、…)

nautobot_call

任意の REST エンドポイント — プラグイン、一括操作、カスタムアクション

nautobot_refresh_schema

スキーマの再取得とインデックスの再構築

モデル参照は寛容です: dcim.device、device、devices、Device、/dcim/devices/、DeviceType はすべて解決され、タイプミスには提案が表示されます(dvice → 「Did you mean: dcim.device?」)。

依存関係の計画

空のインスタンスで Device を作成するには、先に他の 4 つのオブジェクトを作成する必要があります。nautobot_plan_create("dcim.device") は FK グラフを辿り、ライブインスタンスに既に存在するものを確認し、順序どおりに返します:

dcim.manufacturer → dcim.devicetype → dcim.locationtype → dcim.location → extras.role → dcim.device

また、Nautobot の コンテンツタイプスコーピングも処理します。Role、Status、Tag は、content_types にリストされているモデルにのみ割り当て可能です。グローバルなカウントは間違った質問です — インスタンスは 20 個の Role を保持できますが、Device に適用されるものは ゼロ の場合があります:

{
  "model": "extras.role",
  "action": "create",                      // not "use_existing", despite 20 existing
  "content_type_scoped": true,
  "by_referrer": { "dcim.device": { "valid_count": 0 } },
  "note": "No extras.role is assignable to dcim.device yet. Create one with
           content_types including ['dcim.device'] ..."
}

どのモデルがこの方法でスコープされるかは、ハードコードではなく発見されます。content_types は LocationType では「ここに何が置けるか」を意味し、Role では「誰が私を参照できるか」を意味します。プランナーはスコープ付きクエリを試し、400 をスコーピングが適用されない証拠として扱います — そのためプラグインモデルは追加コードなしで正しく動作します。

書き込み

NAUTOBOT_ALLOW_WRITE=true になるまで書き込みはオフです。それでも、ミューテーションは 2 段階です。最初の呼び出しはプレビューと confirm_token を返し、そのトークンを使って呼び出しを繰り返すと適用されます。トークンはペイロードから導出されるため、あるボディに対して発行されたトークンを別のボディに対して再生することはできません。nautobot_update はフィールドレベルの差分をプレビューし、nautobot_delete はオブジェクトとそれを参照するすべてのものをプレビューします。

セキュリティ

このサーバーは Nautobot への認証なしの特権プロキシです。 API トークンを保持し、独自の認証は行いません。到達できるクライアントは、トークン自体を保持することなく、そのトークンの完全な権限で動作します。

デフォルトは意図的に安全です — --host は 127.0.0.1 にバインドされ、NAUTOBOT_ALLOW_WRITE は false です。危険な設定は、非ループバックバインドと書き込み有効化の組み合わせであり、ポートにルーティングできるあらゆるものに、ソース・オブ・トゥルースに対する認証なしの create/update/delete を許可します。

confirm-token フローは事故防止ガードであり、アクセス制御ではありません。任意のクライアントがプレビュー応答からトークンを読み取り、即座に確認できます。

サーバーを他のホストから到達可能にする必要がある場合は、その前に認証を置き(mTLS 付きリバースプロキシ、OAuth 対応ゲートウェイ、または SSH トンネル)、エージェントが必要とするものだけにスコープされた Nautobot トークンを付与してください。SECURITY.md を参照してください。

応答性

  • プールされた 1 つの HTTP/2 クライアントがツール間で共有され、プランナーは存在確認を並行してファンアウトします。

  • 応答はエージェントに到達する前にスリム化されます。Nautobot にはスパースフィールドセットのサポートがないため(?fields= は不明なフィルターとして拒否されます)、url、natural_slug、notes_url、タイムスタンプ、空のカスタムフィールドブロックはクライアント側で削除され、ネストされた関連オブジェクトは ID に縮小されます。プロジェクションには fields=[...] を、オプトアウトには full=true を渡してください。

拡張

各ツールセットは register(server, ctx) を公開するモジュールで、tools/__init__.py::TOOLSETS にリストされています。登録はラップされ、すべてのツールが例外を発生させる代わりに構造化エラーを返すようになっています。捕捉されない例外は、不透明な「Error executing tool X」としてエージェントに到達するからです。

プラグインのエンドポイントにはコードは不要です。/api/swagger.json に現れるため、インデックスを再構築すればすべてのツールで利用可能になります。

テスト

pytest

ライブスキーマから切り出したフィクスチャに対して 82 のテストが実行され、HTTP は respx でモックされます。これらは構築中に見つかった罠を固定化しています: virtualization.vminterface を DCIM の InterfaceType にマッピングするスラッグ衝突、静かに使えないプランを生成する content_types スコーピング、DynamicGroupMembership.group を extras.DynamicGroup ではなく Django の auth.Group に解決する FK ヒューリスティックです。

エージェント設定

AGENT.md には、このサーバーを駆動するエージェント向けのすぐ使えるシステムプロンプトとレジストリの説明が含まれています。書き込みプロトコルと、作成失敗の最も一般的な原因であるコンテンツタイプスコーピングルールも含まれます。

貢献

Issue とプルリクエストを歓迎します。pytest が成功し、ruff check / ruff format --check がクリーンである必要があります。CI は Python 3.11〜3.13 の両方でこれを強制します。スイートは Nautobot インスタンスもネットワークも必要としません — tests/fixtures のスキーマフィクスチャに対して respx による HTTP モックで実行されます。

ライセンス

Apache 2.0 — LICENSE を参照してください。

レイアウト

src/nautobot_mcp/
  schema/build.py     fuses OpenAPI + GraphQL + content types into the index
  schema/index.py     read-only query layer (lookup, FTS search, graph)
  client.py           pooled async HTTP, slimming, error normalisation
  depgraph.py         creation planning and reference resolution
  safety.py           write gate, confirm tokens, diffs
  tools/              one module per toolset, registered through a guard
  server.py           MCP server assembly

Related MCP Connectors

Related MCP Servers