NTT DATA TECH
🍔

@ITボツ原稿より。今ここに、MCPの秘密兵器mcpo復活

に公開

吾輩はボツである。名はmcpo

@ITで記事gpt-ossでMCP実践、Open WebUIとmcp-grafanaで障害解析AIエージェントを構築する方法を掲載したが、草稿を提出してから、Web校正を行うまでにOpen WebUIの仕様変更があり、当初mcpoを利用するはずだった記事からmcpoが抹消されてしまった。本稿では、@ITのボツ原稿からmcpoの紹介を行いたい。ボツ原稿からの復活なので、なにも期待せずに読むように。

ボツ記事の執筆と検証を手伝って頂いた、NTTドコモビジネスの多々納さんに感謝する。

MCPの秘密兵器mcpo

生成AIでの外部ツール利用を簡単にする今となってはAIエージェントに必須と言っても過言ではないMCP(Model Context Protocol)。登場当初は、stdioとSSEと呼ばれる二つのプロトコルで公開されたが、stdioはローカルのプロセス間通信のプロトコルであり、ネットワーク通信が可能なSSEもセッションを張ったままにするためロードバランサやプロキシとの相性が悪いなどの問題があり、簡単にWebサービスとしてMCPサーバーを公開する手段がなかった。

そんな背景もあって、MCPサーバーをOpenAPI(OpenAI APIではないので間違いないように!)で公開し、簡単にAIエージェントから使えるようにするmcpoが開発され、Open WebUIから使えるようになった。

これによりOpen WebUIは、MCPをサポートしたのだ。めでたしめでたし。

逆襲のMCPプロトコル

とはならなかったのだ。

MCPプロトコルの開発者達もSSEの問題に気がつき、Streamable HTTPと呼ばれる通信プロトコルを開発し、簡単にAIエージェント/AIクライアントからMCPサーバーへ通信できるようになった。そして、Open WebUIがStreamable HTTP対応を実装してしまったのだ。

不要となってしまったmcpo

こうしてOpen WebUIはmcpoを介さずとも、直接Streamable HTTPでMCPサーバーに接続できるようになったわけだが、そうなるとmcpoを利用する価値がなくなる。我々はmcpoを前提として記事を書き、編集部に草稿を送付した。しかしながら、Web校正時にはStreamable HTTPがサポートされており、mcpoは不要となった。

正確に言えば、mcpoは引き続き利用できたので、記事としては問題ないのだが、やはり読者には最新のベストプラクティスを伝えたい。そういう想いで、苦渋の決断でmcpoを記事からは切り捨てた。

復活のmcpo

とはいうものの、stdioのMCPサーバーをOpenAPIに変換するような用途ではまだ利用価値はあるので、ここにmcpoの使い方の復活を宣言する。

内容は、mcp-grafana(stdioプロトコル利用)をmcpoを利用してOpen APIで公開する、というものである。アーキテクチャのイメージは下記のような感じである。

@IT掲載原稿と比べると、mcpoが復活しているのが確認できるはずだ。

mcpoとmcp-grafanaが別サービスに見えるが、実際にはmcpoの中でmcp-grafanaがstdioモードで起動し、mcpoとプロセス間通信を行っている。

mcpoの設定ファイルの作成

下記のconfig.jsonを作成する。「取得したGrafanaのトークン」に取得したトークンを貼り付けておく。

config.json

{
  "mcpServers": {
    "time": {
      "command": "uvx",
      "args": ["mcp-server-time", "--local-timezone=Asia/Tokyo"]
    },
    "mcp-grafana": {
      "command": "mcp-grafana",
      "args": [
        "-debug",
        "--disable-oncall",
        "--disable-admin",
        "--disable-incident",
        "--disable-alerting",
        "--disable-sift",
        "--disable-pyroscope"
        ],
      "env": {
        "GRAFANA_URL": "http://lgtm-grafana.monitoring.svc.cluster.local:80",
        "GRAFANA_API_KEY": "[取得したGrafanaのトークン]"
      }
    }
  }
}

今回は、テスト用に時刻とタイムゾーンの変換機能を提供するTime MCPサーバも定義している。

mcpoのデプロイ

下記のmcpoをDeploymentとしてデプロイするマニフェストを作成する。

mcpo-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcpo-tools
  namespace: open-webui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mcpo-tools
  template:
    metadata:
      labels:
        app: mcpo-tools
    spec:
      # Init Containerでmcp-grafanaをインストール
      initContainers:
        - name: init-download-mcp-grafana
          image: alpine:latest
          command: ["/bin/sh", "-c"]
          args:
            - |
              apk add --no-cache curl tar && \
              curl -L -o /tmp/mcp-grafana.tar.gz https://github.com/grafana/mcp-grafana/releases/download/v0.6.3/mcp-grafana_Linux_x86_64.tar.gz && \
              mkdir -p /mcp-grafana-bin && \
              tar -xzvf /tmp/mcp-grafana.tar.gz -C /mcp-grafana-bin && \
              chmod +x /mcp-grafana-bin/mcp-grafana
          volumeMounts:
            - name: mcp-grafana-bin
              mountPath: /mcp-grafana-bin
      containers:
        - name: mcpo-tools
          image: ghcr.io/open-webui/mcpo:git-47d6f7a
          command: ["mcpo", "--config", "/app/config.json"]
          ports:
            - name: http-api
              containerPort: 8000
              protocol: TCP
          env:
            - name: PATH
              value: /mcp-grafana-bin:/app:/app/.venv/bin:/usr/bin
          volumeMounts:
            - name: mcpo-config
              mountPath: /app/config.json
              subPath: config.json
            - name: mcp-grafana-bin
              mountPath: /mcp-grafana-bin
      volumes:
        - name: mcpo-config
          secret:
            secretName: mcpo-configsecret
        - name: mcp-grafana-bin
          emptyDir: {}

mcpoのコンテナイメージには、mcp-grafanaを含んでいないので、mcp-grafanaをInit Containerでインストールするようにした。
なお、npxやuvxでインストールできるMCPサーバーはそのような面倒なことは不要である。uvxで一緒に設定したtime MCPサーバーの設定は何処にもdeploymentファイルに記載されていないことから分かると思う。

設定ファイルからSecretを作成する。

$ kubectl create secret generic mcpo-configsecret --from-file=./config.json -n open-webui
$ kubectl apply -f mcpo-deploy.yaml -n open-webui
$ kubectl get pod -n open-webui
NAME                                     READY   STATUS    RESTARTS   AGE
...
mcpo-tools-8747964f8-lzv98               2/2     Running   0          14d
...

ネットワークの設定

Kubernetesクラスタの外からアクセスできるようにネットワークの設定(Service)を行う。下記のmcpo-service.yamlを作成する。

mcpo-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mcpo-tools
  namespace: open-webui
spec:
  selector:
    app: mcpo-tools
  ports:
    - name: http-api
      port: 80
      targetPort: http-api
      protocol: TCP

Serviceを作成する。

$ kubectl apply -f mcpo-service.yaml

mcpoはOpen WebUIからアクセスされるので、Open WebUIのPodからアクセスできるかどうか確認する。

$ kubectl exec -it open-webui-0 -n open-webui -- bash
# curl http://mcpo-tools.open-webui.svc/mcp-grafana/openapi.json |jq
{
  "openapi": "3.1.0",
  "info": {
    "title": "mcp-grafana",
    "description": "\n\tThis server provides access to your Grafana instance and
...

上記のようなopenapiのレスポンスが返却されない場合、Serviceが正しく定義されているか、mcpo-tools Podが動作しているかどうか確認するとよい。

mcpoのツール登録

mcpoのツールサーバをOpen WebUIに登録する。

MCPサーバ URL
mcp-grafana http://mcpo-tools.open-webui.svc.cluster.local/mcp-grafana
time http://mcpo-tools.open-webui.svc.cluster.local/time

左下の「ユーザ名」(ここではadmin)>「管理者パネル」>「設定」>「ツールサーバの管理」から設定を行う。

ツールサーバの管理画面で「+」をクリックする。

openapi.jsonのURLを入力して、🔁をクリックする。

mcpoとの接続ができてれば、下図のようなポップアップが表示される。

mcp-grafana,timeに対してそれぞれ登録を行う。

動作確認

正しく動作していれば、Open WebUIのチャット画面のツールにtimeとmcp-grafanaが表示されているはずだ。

おわりに

以上、@ITのボツ記事からmcpoについてご紹介した。誰の得になるのか分からないが、このまま闇に葬り去るよりは、マシだと思い公開することにした。

また、MCPに纏わる一つの歴史的経緯としても貴重である(かもしれない)と考えている。

敢えて活用方法があるとすれば、MCPプロトコルに慣れていない開発者がOpenAPIでMCPツールを使いたいと場合、従来のOpenAPIを知っていればMCPサーバーを使いこなすことができるので、そういうユースケースでは利用価値はありそうだ。

mcpo...内容はともかく、その名前だけでも心の片隅にでも置いて頂ければ幸いである。

NTT DATA TECH
NTT DATA TECH
設定によりコメント欄が無効化されています