本文へスキップ / Skip to main content
KINTO Tech Blog

約17分で読めます

AI

【Spring AI/MCP】 Spring Boot製の社内CMDBをMCPサーバー化して、AIエージェントに社内のコンテキストを与える

【Spring AI/MCP】 Spring Boot製の社内CMDBをMCPサーバー化して、AIエージェントに社内のコンテキストを与える cover

この記事でわかること

  • MCPサーバーはPythonやTypeScriptだけでなく、Spring AIを使えばJava(Spring Boot)でも構築できる
  • MCPサーバー機能は、Spring AIの公式スターターを使えば簡単に既存のSpring Bootアプリに組み込める(サーバー設定はapplication.ymlのみ)
  • 既存アプリがSpring SecurityのOAuth2 Resource Serverで認証していれば、MCPの認可に必要なメタデータ公開(RFC 9728)も含めてSpring Securityの標準機能で対応できる
  • AIエージェントがCMDBの構成情報を自分で参照できるようになると、Atlassian MCPなど他のMCPとも組み合わさって、脆弱性対応やEOL対応といった業務がエージェントとの1つの会話で完結する

はじめに

こんにちは。KINTOテクノロジーズ(以下、KTC) プラットフォームグループ Platform Engineeringチームの山田です。普段は社内向けのCMDBを内製開発していて、ここ最近はCMDBと生成AIを組み合わせる取り組みを続けています。

CMDBそのものやSpring AIについては過去の記事で紹介しているので、あわせてご覧ください!(CMDBの記事は少し古いですが、雰囲気は伝わるかと思います)

https://blog.kinto-technologies.com/posts/2023-12-14-CMDB/

https://blog.kinto-technologies.com/posts/2025-06-11-springAI/

今回はその続きとして、CMDB本体(Spring Boot製)にMCPサーバー機能を追加し、AIエージェントから社内の構成情報を直接検索できるようにしました。

背景

Claude CodeなどのAIエージェントだけで業務を進める場面が、この1年で一気に増えてきていると思います。社内でも各種MCPサーバーやスキルなどの整備が進み、調査・実装・ドキュメント作成の多くをエージェントに任せられるようになっています。

一方で、困っていたのが、今回の主役であるCMDB (Configuration Management Database: 構成管理データベース) のデータです。CMDBは、プロダクト・チーム・GitHubリポジトリ・脆弱性・SBOMといった社内の構成情報を一元管理するデータベースで、KTCでは内製開発しています(詳しくは冒頭の過去記事をご覧ください)。せっかく構成情報を集約しているのに、これまでの参照手段はWebアプリだけでした。そのため、エージェントで作業をしていてCMDBのデータが必要になるたびに、以下の作業が発生していました。

  • CMDBのWebアプリを開いてキーワード検索する
  • 検索結果のテキストをコピーして、エージェントのプロンプトに貼り付ける

この間、エージェントの作業は止まり、人がWebアプリとエージェントの間でデータを受け渡すだけの作業に時間を取られます。せっかく構成情報を一元化したのに、AIエージェントからは参照できない状態でした。

この手作業での受け渡しをなくすため、CMDBをMCPサーバー化することにしました。

CMDBのMCPサーバーで何ができるようになったか

先に、できるようになったことの紹介です。

たとえば、あるライブラリに脆弱性が見つかったとします。SBOM・GitHubリポジトリ・プロダクト・チーム・ユーザーなどを管理するCMDBのMCPサーバーができたことで、こうした脆弱性対応をAIエージェントとの1つの会話の中で完結できるようになりました。具体的には、SBOM情報から脆弱性のあるバージョンのライブラリを使っているGitHubリポジトリを洗い出し、リポジトリに紐づくプロダクトと管理チーム・担当者を特定し、担当者向けのJiraチケットの起票、さらには脆弱性を解消するPRの作成まで進められます。

脆弱性対応のユースケースフロー

①〜③と⑤がCMDBのMCPツール、④はAtlassian MCP、⑥はエージェント自身のコーディング機能です。

ポイントは、CMDBのMCPサーバー単体で完結するのではなく、他のMCPやエージェントの機能と組み合わさることで業務が一気通貫になることです。AIエージェントは、参照できるコンテキストが増えるほど、対応できる業務の幅が広がります。CMDBにはエージェントが持っていない社内の構成情報が集まっています。これまで人が都度補っていたこれらの情報をMCPで提供することで、エージェントに任せられる範囲そのものを広げることができました。

脆弱性対応の他にも、たとえばEOL(サポート期限)対応にも同じ要領で使えます。期限切れが近いコンポーネントとそれを使っているプロダクトをCMDBのMCPツールで洗い出し、担当チームの特定からJiraチケットの起票までを、そのまま1つの会話で進められます。

MCPサーバーの実装にSpring AIを選んだ理由

MCPサーバーの構築というと、PythonやTypeScriptのイメージが強いかと思います。公式SDKの充実度やFastMCPのようなフレームワークの存在もあり、実装記事もその2つに偏っている印象です。

ただ、今回MCPサーバー化したい対象は、Spring Bootで実装済みの既存アプリでした。別プロセスでPythonやTypeScriptのMCPサーバーを立ててAPIを中継させる構成も考えられますが、Spring AIを使って既存アプリにMCPサーバー機能を組み込めば、以下の資産をそのまま使い回せます。

  • REST APIのために実装してきたビジネスロジック(service層)
  • Spring Securityを使った認証認可の仕組み
  • ECSへのデプロイや監視などの運用の仕組み

唯一の不安は「Entra IDを使った既存の認証認可が、AIエージェント相手でも同じように使えるのか」でした。MCPの認可仕様はOAuth 2.1ベースで比較的新しく、検証するまでは正直手探りでしたが、結論から言うとSpring Securityの標準機能で対応できました(詳細は実装の節でお話しします)。

もしSpring Bootでアプリケーションを開発・運用しているチームであれば、MCPサーバーの構築にSpring AIを選ぶメリットは大きいと思います。

技術スタック

  • Java 21
  • Spring Boot 4.0
  • Spring AI 2.0 (spring-ai-starter-mcp-server-webmvc)
  • Spring Security (OAuth2 Resource Server)
  • Microsoft Entra ID (認可サーバー)
  • AWS (CloudFront + ALB + ECS など)

システム構成

既存のCMDBバックエンド(Spring Boot)に、MCPエンドポイント /mcp を追加した構成です。MCPサーバーのために新しく追加したインフラはありません。なお、図はMCPサーバーに関係する部分に絞っており、フロントエンドの配信経路などは省略しています。

システム構成図

実装

ここからは実装内容を紹介します。なお、記事中のコードは一部、省略・編集しています。

依存関係の設定

build.gradleにSpring AIのBOMとMCPサーバー用スターターを追加します。追加する依存関係はこれだけです。

ext {
    set('springAiVersion', "2.0.0")
}

dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.ai:spring-ai-bom:${springAiVersion}"
    }
}

サーバー設定はapplication.ymlのみ

MCPサーバーとしての設定はapplication.ymlに書くだけで、Javaの設定クラスは1つも作っていません。あわせて、JWT検証(OAuth2 Resource Server)の設定も抜粋します。

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://login.microsoftonline.com/${TENANT_ID}/v2.0
  ai:
    mcp:
      server:
        name: cmdb-mcp
        version: 0.0.1
        instructions: >-
          CMDB は KINTO Technologies (略: KTC) 社内の構成管理データベースのこと。
          プロダクト・チーム・リポジトリ・脆弱性などの社内構成情報を検索できる。
        protocol: STATELESS
        type: SYNC
        stateless:
          mcp-endpoint: /mcp
        annotation-scanner:
          enabled: true

設定のポイントを2つ紹介します。

1つ目は instructions です。ここに書いた文章はMCPの初期化時に一度だけエージェントへ渡されます。「CMDBとは何か」のような前提知識をここに置いておくと、各ツールのdescriptionで同じ説明を繰り返さずに済み、ツール定義のトークンを節約できます。

2つ目は annotation-scanner です。これを有効にすると、後述する @McpTool の付いたメソッドが自動でツールとして登録されるため、ツール登録用のBean定義も不要になります。

@McpToolでツールの実装

ツールは @McpTool を付けたメソッドとして実装します。プロダクト検索ツールを例に、実装の全体像を紹介します。

@Component
public class ProductMcpTools {

    private final ProductService productService;

    public ProductMcpTools(ProductService productService) {
        this.productService = productService;
    }

    @McpTool(
        name = "searchProducts",
        description = """
            プロダクトを検索します。一覧・絞り込み・詳細取得はすべてこのツール\
            (productId 指定で1件の詳細、未指定で一覧)""",
        annotations = @McpTool.McpAnnotations(
            readOnlyHint = true,
            destructiveHint = false,
            idempotentHint = true,
            openWorldHint = false))
    public ProductSearchMcpResult searchProducts(
            @McpToolParam(description = "プロダクトID。指定すると1件の詳細を返す。一覧結果の productId を渡す", required = false)
            Integer productId,
            @McpToolParam(description = "プロダクトの所属部署(グループID)で絞り込み", required = false)
            String groupId,
            @McpToolParam(description = "true で削除済みプロダクトを検索。削除済みはこの指定時のみ取得可(既定: false)", required = false)
            Boolean deleteFlag) {

        SearchProductServiceParameter parameter = new SearchProductServiceParameter();
        parameter.setProductId(productId);
        parameter.setGroupId(groupId);
        parameter.setDeleteFlag(Boolean.TRUE.equals(deleteFlag));

        // 既存のREST API用serviceをそのまま呼び出す
        SearchProductServiceResult result = productService.searchProduct(parameter);

        return productId != null
                ? ProductSearchMcpResult.ofDetail(result)
                : ProductSearchMcpResult.ofList(result);
    }
}

このクラスの役割はControllerと同じです。引数を組み立てて既存のserviceを呼び、結果をエージェント向けに整形するだけで、ビジネスロジックは置きません。検索ロジック本体は、REST APIのために実装済みの ProductService をそのまま呼んでいます。

これだけでMCPサーバーのツールが実装できてしまいます。

今回実装した検索ツール12個のほとんどは、既存のservice層を変更することなく再利用できました。REST APIのために実装してきたservice層を、MCPツールからそのまま再利用できるのが、既存アプリに組み込む構成のいちばんのメリットだと思います。

ツール 概要
searchProducts プロダクトの一覧・詳細検索
searchGroups 部署(グループ)の一覧取得
searchTeams チームとメンバーの検索
searchUsers ユーザーの検索
searchDomains ドメインの検索
searchGithubRepositories GitHubリポジトリの検索
searchVulnerabilitySummaries 脆弱性サマリの横断検索
searchVulnerabilityDetails 脆弱性詳細の検索
searchSbom SBOM(ソフトウェア部品表)の検索
searchEol EOL(サポート期限)の検索
searchArn AWSリソース(ARN)の検索
searchSchedules 開発環境のコスト削減を目的とした、AWSリソース起動停止スケジュールの検索

実装にあたって、3点補足します。

1つ目はツールヒント(annotations)です。MCPの仕様では、ヒントが未指定のツールは readOnlyHint=falsedestructiveHint=true、つまり「破壊的な操作をするかもしれないツール」というデフォルトで扱われます。エージェントが検索ツールの利用をためらわないよう、読み取り専用であることをヒントで明示しています。

2つ目は引数の形です。引数は1つのオブジェクトにまとめず、フラットに並べています。Spring AIはメソッドの引数をそれぞれinputSchemaのプロパティに変換するため、REST APIのようにパラメータクラスへまとめると、エージェントから見えるJSONスキーマに余計な階層ができてしまいます。既存のパラメータクラスの流儀とは意図的に変えている部分です。

3つ目はレスポンスの件数です。CMDBは、SBOMのように件数が膨大なデータも持っています(執筆時点で50万件超)。こうしたデータをそのまま返すと、エージェントのコンテキストを圧迫し、MCPの結果サイズ上限にも引っかかります。件数の多いデータを扱うツールでは絞り込み条件を必須にし、1ページ50件のページングと総件数(totalCount)の返却をあわせて実装しています。ページを分けても、データが足りなければエージェントがpageを変えて自分でツールを呼び直してくれるため、複数回の呼び出しで必要なデータを集められます。

認証認可

一番不安だった認証認可ですが、結論としては自前の認可サーバーを実装する必要はなく、既存のEntra IDをそのまま認可サーバーとして使えました。MCPの認可仕様の登場人物と流れは以下のとおりです。

重要なのが③④のProtected Resource Metadata (RFC 9728)です。MCPサーバーは /.well-known/oauth-protected-resource でメタデータを公開し、「このサーバーの認可サーバーはどこか」をエージェントに教えます。エージェントはこれを読んで、自動的にEntra IDのログイン画面(ブラウザのSSO)へユーザーを誘導してくれます。

Spring側の実装は、ほぼ標準機能の組み合わせで済みました。

  • JWT検証: Spring SecurityのOAuth2 Resource Server。application.ymlの issuer-uri の設定だけで、Entra IDが発行したJWTの検証が動きます
  • メタデータの公開: Spring Securityが標準でRFC 9728をサポートしており(OAuth2ProtectedResourceMetadataFilter)、認可サーバーの場所などをJavaの設定コード数行のカスタマイズだけで公開できます

1点だけインフラ側の対応が必要でした。RFC 9728のメタデータはドメインルートの /.well-known/ 配下で公開する必要がありますが、バックエンドは /api のコンテキストパスで動いています。そこで、CloudFrontで /.well-known/oauth-protected-resource* へのリクエストをALB(オリジンパス /api)にルーティングして解決しました。

ちなみに、Spring AIのドキュメントには、MCPサーバーの認証認可をコミュニティモジュールの mcp-security で実現する方法も紹介されています。

なお、AIエージェントによってOAuth周りの実装には微妙に差があり、あるエージェントでは問題なく接続できても、別のエージェントではエラーになることがありました。MCPサーバーを社内に展開する場合は、利用が想定されるエージェントで早めに接続確認をしておくと安心です。

AOPによる利用状況ログ

社内展開後の利用状況を把握するため、ツール呼び出しのログも仕込みました。@McpTool アノテーションを対象にしたAOPのアスペクトを1つ書くだけで、ツールクラスが今後増えても自動でログ対象になります。ログにはツール名・ユーザーID(JWTのクレームから取得)・検索条件を構造化フィールドとして出力し、ダッシュボードで「誰がどのツールをどんな条件で使っているか」を集計できるようにしています。

実行結果

最後に、社内情報のためお見せできる部分が少なくなってしまいますが、実際の使用感をご紹介します。

接続 (Claude Codeの場合)

以下のコマンドでClaude CodeにCMDBのMCPを登録します。

claude mcp add --transport http cmdb-mcp https://xxxxx/api/mcp \
  --client-id xxx \
  --callback-port 29352

サーバー一覧でCMDBのMCPを選択し、認証を開始します。

Claude CodeのMCPサーバー一覧でcmdb-mcpを選択し認証を開始する画面

ブラウザで認証をします。
ブラウザで認証が完了し、Claude Codeへ戻るよう案内される画面

ツールを呼び出してみる

試しにSpring Bootで構築しているプロダクト一覧を出してみます。

「Spring Bootで構築しているプロダクトを洗い出して」と聞いてみると、CMDBのMCPサーバーにあるSBOM検索ツールをspring-boot-autoconfigureのコンポーネントを検索条件に入れて呼び出します。
エージェントがSBOM検索ツールをspring-boot-autoconfigureを条件に呼び出している画面

こちらがレスポンスの一部になります。全部で31プロダクトがSpring Bootを採用しているそうです。多いですね。
SBOM検索の結果から、Spring Boot採用プロダクトの一覧が表形式で出力された画面

次のステップ

  • 更新系ツールへの拡張: 現在は検索専用ですが、登録・更新系のツールも要望があります。誤操作のリスクが検索とは段違いなので、権限制御や実行前の確認の仕組みとセットで検討していきたいと思います

さいごに

今回は、Spring Boot製の社内CMDBをSpring AIでMCPサーバー化し、AIエージェントから社内の構成情報を検索できるようにした取り組みについてお話ししました。

MCPサーバーの構築はPythonやTypeScriptの情報が多いですが、既存のSpring Bootアプリを持っているなら、service層も認証もインフラもそのまま使い回せるSpring AIは十分有力な選択肢です。この記事が、JavaでのMCPサーバー構築を検討している方の参考になれば嬉しいです。

AIエージェントを中心とした働き方はまだまだ進化していくと思うので、キャッチアップと実践を繰り返しながら、Platform Engineeringチームとしてツールの整備を進めていきたいと思います。

Facebook

Follow Us

XConnpassWantedly

KINTOテクノロジーズの最新情報をSNSで発信中!イベント・テックブログ更新情報もお届けします。