MastraとGeminiとMCPサーバでAIエージェントをサクッと作成する

以前の投稿 「[CJSでMCPサーバを作る](https://qiita.com/poruruba/items/b807a10cc755798b4eab)」 で、MCPサーバを作れるようになりました。
今回は、チャット画面風のAIエージェントを作成します。
最近は、ぞくぞくとAIエージェントクライアントがでてきていますが、Mastraが簡単そうで、MCPサーバにもつなぐことができそうだったので試してみました。

　AIエージェント：Mastra
　AIプロバイダ：Google Gemini
　外部ソース：MCP(ModelContextProtocol)

必要なファイルは以下に上げました

https://github.com/poruruba/AiChatAgent/tree/main

# 全体構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/86d13823-c4e9-4208-9d87-45e97ad1701a.png)

以下の構成からなります。

* MCPサーバ
生成 AI モデルと様々なデータソースやツールを標準化された方法(MCP)で接続するサーバ、StreamableHTTPで通信します。

* AIエージェント(Mastraサーバ)
生成AIを使って、チャットやタスクなどのAIアプリを構築するためのフレームワーク

* WebAPIサーバ
ブラウザからのリクエストを受け取って後続システムと連携して結果を返すためのサーバ

* Webページサーバ
ブラウザに表示されるWebコンテンツを提供し、WebAPIサーバと連携してWebアプリを提供する

以降から、MCPサーバ、AIエージェント、Webアプリの順に作っていきます。

[参考サイト]

https://github.com/modelcontextprotocol

https://mastra.ai/

https://ai.google.dev/gemini-api/docs?hl=ja

# 準備

node.jsがインストールされている前提です。

まずは、以下ダウンロードしておきます。
・AiChatAgent-main.zip

https://github.com/poruruba/AiChatAgent


# MCPサーバのインストール

まずは、MCPサーバを立ち上げます。
以下をダウンロードします。
・amplify_template-main.zip

https://github.com/poruruba/amplify_template


適当な場所に展開します。
例えば、フォルダに「chatagent_console」という名前を付けておきます。

必要なモジュールをインストールします。

```
> npm install
```

BraveSearch APIキーを取得します。

https://brave.com/ja/search/api/

GoogleMapAPIキーを取得します。

https://developers.google.com/maps/documentation/javascript/get-api-key?hl=ja

APIキーには以下の権限をつけておきます。
・Places API
・Geocoding API
・Distance Matrix API
・Maps Elevation API

```server/api/controllers```にある```bravesearch-mcp```と```googlemap-mcp```をchatagent_consoleの```api\controllers```にコピーします。
この2つがMCPサーバです。それぞれ以下のツールを提供しています。

BraveSearch(/mcp-bravesearch)
・brave_web_search
・brave_local_search

GoogleMap(/mcp-googlemap)
・maps_geocode
・maps_reverse_geocode
・maps_search_places
・maps_place_details
・maps_distance_matrix
・maps_elevation

```chatagent_console```フォルダに、ファイル```.env```を作成し、```.env```に以下のように取得しておいたAPIキーを追記します。

```.env
GOOGLEMAP_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
BRAVE_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

必要なモジュールをインストールします。

```
> npm install @modelcontextprotocol/sdk zod node-fetch@2.7.0
```

以下で起動できます。

```
> node app.js
```

デフォルトでポート番号30080で待ち受けます。

MCPサーバの動作確認のため、別のDOSプロントから以下を立ち上げます。

```
> npx @modelcontextprotocol/inspector
```

ポート番号6274でInspectorが待ち受けます。コンソールにブラウザから開く際のトークンが記載されています。

ブラウザから以下を開きます。
```http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX```

画面上で、以下指定します。

　Transport Type : Streamable HTTP
　URL :  http://localhost:30080/mcp-googlemap or http://localhost:30080/mcp-bravesearch

Connectボタンを押下すると、MCPサーバに接続します。
List Toolsをクリックすると、Tool名が表示されます。

[http://localhost:30080/mcp-googlemapの場合]
たとえば、maps_geocodeを選択し、addressに「鎌倉駅」と入力すると、その下のTotal Resultに、鎌倉駅の緯度経度が返ってきます。

[http://localhost:30080/mcp-bravesearchの場合]
たとえば、brave_web_searchを選択し、queryに「今日のニュースは？」と入力すると、その下のTotal Resultに結果が返ってきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/f5022e4d-24ac-430c-b6b7-aac2a48d4bf3.png)

これで、MCPサーバの動作が確認できました。

# AIエージェント(Mastraサーバ)のインストール

今度は、AIエージェントを立ち上げます。
GOOGLE_GENERATIVE_AI_API_KEYを取得します。

https://ai.google.dev/gemini-api/docs/api-key?hl=ja

以下を実行して、Mastraをセットアップします。
途中で、default providerを聞かれるので、今回はGoogleを選択し、取得しておいたGOOGLE_GENERATIVE_AI_API_KEYを入力します。

```
> npm create mastra@latest

Need to install the following packages:
create-mastra@0.10.2
Ok to proceed? (y)

> npx
> create-mastra

T   Mastra Create
|
o  What do you want to name your project?
|  mastra_chatagent
|
o  Project created
|
o  npm dependencies installed
|
o  mastra installed
|
o  Dependencies installed
|
o  .gitignore added
|
?  Project created successfully


T  Mastra Init
|
o  Where should we create the Mastra files? (default: src/)
|  src/
|
o  Choose components to install:
|  Agents
|
o  Add tools?
|  No
|
o  Select default provider:
|  Google
|
o  Enter your google API key?
|  Enter API key
|
o  Enter your API key:
|  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
o  Add example
|  No
|
o  Make your AI IDE into a Mastra expert? (installs Mastra docs MCP server)
|  Skip for now
|
o
|
o   ---------------------------------------+
|                                          |
|                                          |
|        Mastra initialized successfully!  |
|                                          |
|                                          |
+------------------------------------------+
|
?
   To start your project:

    cd mastra_chatagent
    npm run dev
```

次に以下を実行します。

```
> cd mastra_chatagent
```

STDIO形式で通信する場合は以下のモジュールも使うのでインストールします。

```
> npm install mcp-remote
```

```mastra/src```配下をmastra_chatagentにすべて上書きコピーします。

```
> npm run dev
```

ポート番号4111で待ち受けます。

ブラウザから開きます。
```http://localhost:4111```

画面上で、Chat Agentを選択し、Enter your messageのところに、「こんにちは」と入力すると「こんにちは！何かお手伝いできることはありますか？」と返ってきます。これは、Google Geminiによる応答です。
「鎌倉駅の緯度経度は？」と入力すると鎌倉駅の緯度経度が返ってきます。これは、MCPサーバ「/mcp-googlemap」との連携の結果です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/c4bc1a5a-a5d0-4b9f-95d1-d3ed7fdcc639.png)

# Webページのインストール

今度は、チャット風の画面からAIエージェントと連携するWebページを立ち上げます。
chatagent_consoleに戻ります。

Mastraと連携するため、クライアントライブラリをインストールします。

```
> npm install @mastra/client-js
```

```server/api/controllers```にある```mastra-api```フォルダをchatagent_consoleの```api\controllers```にコピーします。
```server/public```にある```chatagent```フォルダをchatagent_consoleの```public```にコピーします。

ブラウザから開きます。
```http://localhost:30080/chatagent/```

画面上で、APIキーとして 12345678 を指定
「こんにちは」と入力して送信すると「こんにちは！何かお手伝いできることはありますか？」と返ってきます。
同様に、「鎌倉駅の緯度経度は？」と入力すると鎌倉駅の緯度経度が返ってきます。

完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/5364318e-8b3d-41b3-aa9e-284e30bdc712.png)

# カスタマイズ

[既存のMCPサーバを増やしたい場合]
```chat-agent.ts```を修正します。

[新規にMCPサーバを立ち上げたい場合]
```bravesearch-mcp```や```googlemap-mcp```フォルダを参考にしてください。


# 参考

https://mastra.ai/ja/reference/client-js/agents
https://api-dashboard.search.brave.com/app/documentation/web-search/get-started
https://github.com/modelcontextprotocol/servers-archived/tree/main/src
https://github.com/modelcontextprotocol/typescript-sdk

以上