こんにちは。

今回はKlavisというMCP統合フレームワークを使って、GeminiでMCPサーバーを使って動かしてみたのでレビューします。

最近LLM界隈では猫も杓子も「MCP!MCP!」言ってます。

MCPって何なの?という方に、簡単に説明すると、LLMが外部のサービスやデータにアクセスしてその情報を扱えるようにするプロトコル(規格)みたいなものです。

少し前のエージェントでいえば、ファンクションコーリングやツールといったものに近いです。

LLMにGithubのソースコードを参照させたり、Slackのチャット内容を参照させたりできるようになるので、日々の業務に活用できるやないか!ということで皆さん盛り上がってるわけです。

しかしそのMCPサーバーをアプリとして組み込もうとすると、慣れてないと結構面倒というか難しく感じることが多いと思います。

そんな中、今回ご紹介する「Klavis」は、主要な様々なMCPをこれ一本で簡単に実装できます

でもそんな便利なもの、やっぱり使うとお高いんでしょ?と思いますよね。

私が紹介するということは、もちろん無料で使うことができます!

それでは早速紹介していきます!

Klavisとは?

主要なMCPツールを統合して簡単に使えるようにしてくれるフレームワークです。

使うためにはアカウントを作成してAPIキーを取得する必要があります。

無料プランもありますが、有料プランは99$/月とAIサービスとしてはやや高めです。(年契約で20%off)

無料プランにある3User Accountsというのは、MCPサーバーを立てられる数が3つまでということです。

このMCPサーバーの数については注意点があって、実装のところで解説します。

Python, TypeScriptだけでなく、幅広く言語に対応しています。

コードもとてもシンプルにかけそうです。

MCPをLLMアプリに使うためのコードを書くのは結構大変というか難しかったりします。

個人的にMCPも専用のフレームワークやツールが出てきて実装しやすくなることを期待していたので、Klavisはひとつの参考になりそうです。

さて最も気になるのは、セキュリティやプライバシーポリシーですね。

この辺もどこまで信用すべきかは毎度よくわかりませんが、概ねGoogleの規約に準拠しつつ、データを学習に使うことはないそうです。

この規約で「学習には使用しない」と書かれているだけで、アカウントでプライバシーモードなどの設定はありません。

利用規約もあるのでこちらも確認しましょう。

プライバシーポリシーと書いてることが矛盾してるように見えますね。。学習に使う可能性を示唆しています。

Googleアカウントに関するデータは使わないが、それ以外のデータは使うということかもしれません。

なので基本的にAIのどんなサービスにもいえることですが、不用意に重要なデータを突っ込むのはひかえましょう!

Githubは以下です。

まだ比較的新しいフレームワークですが、2.9Kスターを集めてるのはそれなりに評価が高そうです。

ライセンスはMITライセンスなので商用利用可能です。

PythonとTypeScriptがメインですね。

使えるMCPサーバーにはどのようなものがあるか。

YouTubeなどGoogle系のMCPは一通りあったり、GithubやSlack、Figmaなど主要なMCPは使えそうです。

その他詳細はKlavisのページからご確認ください。

概要としてはこんな感じです。

では早速実装して動かしてみましょう。

準備

今回の実装はGeminitとKlavisを使って動かします。

コードは以下のチュートリアルをベースに作成します。

なので必要なAPIキーとしては、GeminiとKlavisのAPIキーを用意しましょう。

GeminiのAPIキーは以下から取得します。

Klavisはアカウントを作成した後、Dashbordから「Get API keys」で作成します。

APIキーを取得したら.envファイルに保存しましょう。

GEMINI_API_KEY = "your api key"
KLAVIS_API_KEY = "your api key"

GeminiとKlavisの依存関係をお使いの開発環境に以下のpipコマンドでインストールしてください。

pip install google-genai klavis

この後ご紹介するコード一式をGithubリポジトリにまとめておいたので、よかったらこちらをgit cloneで使ってください。

Gemini × KlavisでYouTubeの要約をしてみた

ではまずはYouTubeのMCPで、ある動画をGeminiに要約させてみましょう。

要約する動画はこちら。

とりあえずリベ大の直近新しいのを持ってきました。

コードは以下です。

import os
from google import genai
from klavis import Klavis
from klavis.types import McpServerName, ToolFormat

YOUTUBE_VIDEO_URL = (
    "https://www.youtube.com/watch?v=_WMjnUpOUi8"  # pick a video you like!
)
SYSTEM_PROMPT = """あなたは、YouTube MCPツールを使用するAIアシスタントです。
利用可能なツールを使って、YouTube動画の情報を取得してください。

動画の要約を求められた場合は:
1. まず、動画のトランスクリプトや詳細情報を取得するツールを使用してください
2. 取得した情報を基に、動画の内容を要約してください

ツールの名前と機能を確認し、適切なツールを選択して使用してください。"""

klavis_api_key = os.environ["KLAVIS_API_KEY"]
klavis_client = Klavis(api_key=klavis_api_key)

google_api_key = os.environ["GEMINI_API_KEY"]
client = genai.Client(api_key=google_api_key)

youtube_mcp_instance = klavis_client.mcp_server.create_server_instance(
    server_name=McpServerName.YOUTUBE,
    user_id="1234",
    platform_name="Klavis",
)


def gemini_with_mcp_server(mcp_server_url: str, user_query: str):
    # Get tools from MCP server
    mcp_server_tools = klavis_client.mcp_server.list_tools(
        server_url=mcp_server_url,
        format=ToolFormat.GEMINI,
    )

    # Send initial message with tools
    response = client.models.generate_content(
        model="gemini-2.0-flash",
        contents=user_query,
        config=genai.types.GenerateContentConfig(
            tools=mcp_server_tools.tools,
            system_instruction=SYSTEM_PROMPT,
        ),
    )

    # Check if function call is requested
    if response.function_calls:
        function_call = response.function_calls[0]
        function_name = function_call.name
        function_args = dict(function_call.args)

        print(f"🔧 Calling: {function_name}, with args: {function_args}")

        # Call the MCP server tool
        result = klavis_client.mcp_server.call_tools(
            server_url=mcp_server_url,
            tool_name=function_name,
            tool_args=function_args,
        )

        function_response = genai.types.Part.from_function_response(
            name=function_call.name,
            response={"result": result.result.content[0]["text"]},
        )
        function_response_content = genai.types.Content(
            role="tool", parts=[function_response]
        )

        # Send function response back to model
        final_response = client.models.generate_content(
            model="gemini-2.0-flash",
            contents=[
                user_query,
                response.candidates[0].content,
                function_response_content,
            ],
            config=genai.types.GenerateContentConfig(
                tools=mcp_server_tools.tools,
            ),
        )
        return final_response.text
    else:
        return response.text


result = gemini_with_mcp_server(
    mcp_server_url=youtube_mcp_instance.server_url,
    user_query=f"このYouTube動画の内容を要約してください: {YOUTUBE_VIDEO_URL}",
)

print(result)

youtube_mcp_instanceというのが、MCPサーバーのインスタンスです。

user_idやplatform_nameは好きなものを設定して大丈夫ですが、このuser_idが冒頭で述べたユーザーアカウントです。

つまり無料プランなら3つまでしか設定できません。コロコロ変えてAPI叩くとあっという間に上限の3にあたってしまいますので注意が必要です。

しかもAPIコードから立ち上げたMCPサーバーは削除できないというちょっと残念な仕様になっているようです。

削除したい場合は、klavisのcontactから直接メールで依頼すると対応してくれます。

担当者によると、「近いうちにAPIで立ち上げたMCPサーバーについても、Klavisのダッシュボード上で管理できるようにする予定」とのことでしたので、続報を待ちましょう。

youtube_mcp_instanceにはserver_urlがあり、そのURLからtoolのリストを取得できるメソッドが用意されています。

あとはそのtool_listをGeminiに渡している流れになります。

Geminiの仕様として、function_callsの結果を再度抽出して回答を得るというちょっと面倒な書き方になっています。

この辺も近いうちに簡略化されそうな気はしますが、現状はこれで動きます。

では結果を見てみましょう。

大体2~3秒ぐらいで出力されます。

内容もあってますね。

このように、特定のYouTubeのURLを渡すだけで、動画の要約が一瞬でできてしまいます。

Gemini × KlavisでGmailを送ってみた

次はGeminiとKlavisを使って、Gmailに送信してみましょう。

import os
from google import genai
from klavis import Klavis
from klavis.types import McpServerName, ToolFormat
import webbrowser

SYSTEM_PROMPT = """あなたは、Gmail MCPツールを使用するAIアシスタントです。
利用可能なツールを使って、Gmailの情報を取得してください。"""

EMAIL_RECIPIENT = "your_email@gmail.com"  # Replace with your email
EMAIL_SUBJECT = "Test Gemini + Gmail MCP Server"
EMAIL_BODY = "Hello World from Gemini!"

klavis_api_key = os.environ["KLAVIS_API_KEY"]
klavis_client = Klavis(api_key=klavis_api_key)

google_api_key = os.environ["GEMINI_API_KEY"]
client = genai.Client(api_key=google_api_key)

# Create Gmail MCP server instance
gmail_mcp_server = klavis_client.mcp_server.create_server_instance(
    server_name=McpServerName.GMAIL,
    user_id="1234",
    platform_name="Klavis",
)

# Redirect to Gmail OAuth page for authorization
webbrowser.open(gmail_mcp_server.oauth_url)

print(
    f"🔐 Opening OAuth authorization for Gmail, if you are not redirected, please open the following URL in your browser: {gmail_mcp_server.oauth_url}"
)


def gemini_with_mcp_server(mcp_server_url: str, user_query: str):
    # Get tools from MCP server
    mcp_server_tools = klavis_client.mcp_server.list_tools(
        server_url=mcp_server_url,
        format=ToolFormat.GEMINI,
    )

    # Send initial message with tools
    response = client.models.generate_content(
        model="gemini-2.0-flash",
        contents=user_query,
        config=genai.types.GenerateContentConfig(
            tools=mcp_server_tools.tools,
            system_instruction=SYSTEM_PROMPT,
        ),
    )

    # Check if function call is requested
    if response.function_calls:
        function_call = response.function_calls[0]
        function_name = function_call.name
        function_args = dict(function_call.args)

        print(f"🔧 Calling: {function_name}, with args: {function_args}")

        # Call the MCP server tool
        result = klavis_client.mcp_server.call_tools(
            server_url=mcp_server_url,
            tool_name=function_name,
            tool_args=function_args,
        )

        function_response = genai.types.Part.from_function_response(
            name=function_call.name,
            response={"result": result.result.content[0]["text"]},
        )
        function_response_content = genai.types.Content(
            role="tool", parts=[function_response]
        )

        # Send function response back to model
        final_response = client.models.generate_content(
            model="gemini-2.0-flash",
            contents=[
                user_query,
                response.candidates[0].content,
                function_response_content,
            ],
            config=genai.types.GenerateContentConfig(
                tools=mcp_server_tools.tools,
            ),
        )
        return final_response.text
    else:
        return response.text


result = gemini_with_mcp_server(
    mcp_server_url=gmail_mcp_server.server_url,
    user_query=f"Please send an email to {EMAIL_RECIPIENT} with subject {EMAIL_SUBJECT} and body {EMAIL_BODY}",
)

print(result)

こちらも基本的には内容は一緒です。

MCPによらず、書きっぷりが大きく変わらない仕様はとてもいいですね!

EMAIL_RECIPIENTのところは、送りたいE-mailアドレスを設定しましょう。

今回は自分のGmailに送信します。

EMAIL_SUBJECTに件名、EMAIL_BODYに文章を設定します。

この辺の設定値を上手く使えば、業務のDXで自動化などの活用ができそうですね!

ここでOAuth認証が登場します。

OAuth認証についての詳細は割愛しますが、以下の記事がわかりやすかったので貼っておきます。

webbrowser.open(gmail_mcp_server.oauth_url)

一行でOAuth認証を実装できます!

ターミナル上でGmailのMCPサーバーの認証用URLが表示されるのでそちらをクリックしましょう。

すると以下のような画面が立ち上がります。

変更はGoogleアカウントからいつでもできますので、信頼できなくなったら以下で削除しましょう。

以下のような画面が表示されたらOAuth認証は完了です。

実行結果をみてみましょう。

こちらも体感2~3秒程度で完了しました。

件名も文章も正しく反映されていることを確認できました!

LLMがあなたにメールを送ってくる日もそう遠くないですね!

まとめ

今回はGeminiを使ってKlavisというMCPフレームワークについてご紹介しました。

とてもシンプルに主要なMCPを実装できるのが最大の魅力ですね!

これは私も独自MCPサーバーを作る際に、Klavisのコードを参考に作りたいと思いました。

マイナス面もあげると、有料プランで使うにはややコストが高めなのと、セキュリティやプライバシーポリシーにやや不安がある印象でした!

また実装後のMCPサーバーの管理面においても現状ほとんど何もできないですし、まだまだ開発途中なところが散見されるため、今後の改善に期待したいですね!

LLMがどんどん簡単かつ便利に使えるようになってきましたが、MCPが皆さんにとってなじみのあるものになりつつあります。

より快適な業務遂行のための道具として、LLMだけでなくMCPも活用していきましょう!

ここまでご覧いただきありがとうございました!