MCP を OpenAI Agents SDK で軽く試してみた時のメモ： OpenAI の SDK で エージェント ＋ MCP

## はじめて

この記事は、以下のポストなどで情報を見かけていた「OpenAI Agents SDK で MCP（Model Context Protocol）で使う」という話を軽く試してみた時のメモです。

https://x.com/OpenAIDevs/status/1904957755829481737

### 公式の情報

公式の OpenAI Agents SDK のドキュメントで、MCP について書かれたページとして以下があります。

●Model context protocol (MCP) - OpenAI Agents SDK
 https://openai.github.io/openai-agents-python/mcp/

そのドキュメントの中に「End-to-end examples」という項目があり、サンプルが置かれているページへのリンクがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/069dc906-f769-40d9-9751-1b67a8c01d3e.png)

今回の記事では、このサンプルを試してみることにします。


## サンプルの情報を見てみる

上記のページに書いていたサンプルのリンク先は以下です。
記事執筆時点では 3つのサンプルがあります。

●openai-agents-python/examples/mcp at main · openai/openai-agents-python
 https://github.com/openai/openai-agents-python/tree/main/examples/mcp

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c449a592-5f38-4bcf-aad0-9f913186c51c.png)

## サンプルのうちの 1つ

今回は、3つあるサンプルの中で「filesystem_example」を試してみます。

●openai-agents-python/examples/mcp/filesystem_example at main · openai/openai-agents-python
 https://github.com/openai/openai-agents-python/tree/main/examples/mcp/filesystem_example

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/f492a245-4544-4341-af04-08ceb273487f.png)


## サンプルを元にしたお試し

サンプルをローカルに持ってきて試してみます。

ローカルにもってきた後、[「openai-agents-python」のルートのフォルダ](https://github.com/openai/openai-agents-python/tree/main)で、コマンドを実行していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c56fd089-65c4-435a-9285-c2d046e28e2b.png)

### コマンドの実行

今回、自分の環境で実行するコマンドは以下の 2つです。

1. APIキーの設定
1. uvコマンドを使ったもの

今回のサンプルは、環境変数「OPENAI_API_KEY」に OpenAI の APIキーが設定されている前提になっているようでした。

#### OpenAI の APIキーを設定

とりあえず自分の場合は、一時的に APIキーが設定された状態になれば良かったので、zsh で以下のコマンドを実行して APIキーを設定しました。

```zsh
export OPENAI_API_KEY=【OpenAI の APIキー】
```


#### uvコマンドを使った main.py の実行

その次に実行するコマンドは、[公式の説明](https://github.com/openai/openai-agents-python/tree/main/examples/mcp/filesystem_example#mcp-filesystem-example)に書かれていた以下です。

```zsh
uv run python examples/mcp/filesystem_example/main.py
```

上記を実行するだけで、依存関係の解決もしてくれるため、手軽にお試しができます。

#### 【余談】

余談になりますが、当初、環境変数に OpenAI の APIキーを設定せずに上記の uvコマンドを使ったものを実行したため、以下のエラーが出ていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/8ae35327-e642-4247-bc11-3809c2922b5c.png)



### コマンドの実行結果

コマンドの実行結果は以下となりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3eea7bd1-a290-4a9b-9fcd-35925cbe5ac4.png)


`Running: Read the files and list them.` という行以降の内容を書き出してみます。

```txt
Running: Read the files and list them.
Here are the files in the directory:

1. `favorite_books.txt`
2. `favorite_cities.txt`
3. `favorite_songs.txt`

Running: What is my #1 favorite book?
Your #1 favorite book is "To Kill a Mockingbird" by Harper Lee.

Running: Look at my favorite songs. Suggest one new song that I might like.
Based on your favorite songs, you might like "Shallow" by Lady Gaga and Bradley Cooper. It has a great mix of emotion and melody, similar to the songs you enjoy.
```

ここで行われた内容は、以下となるようです。

1. 今回読みこむ 3つのテキストファイルをリストとして表示
1. 「favorite_books.txt」の #1 の内容を表示
1. 「favorite_songs.txt」に書かれた内容を見た上で、そこに書かれていない好みと考えられる曲を表示する


## サンプルで用意されているファイルなど

今回のエージェントの動作の元になったデータを知るために、今回のサンプルで用意されているファイルなどを少し見てみます。


### 3つのテキストファイル

[sample_files](https://github.com/openai/openai-agents-python/tree/main/examples/mcp/filesystem_example/sample_files) フォルダ内の 3つのテキストファイルの内容を見てみます。

```txt:favorite_books.txt
1. To Kill a Mockingbird – Harper Lee
2. Pride and Prejudice – Jane Austen
3. 1984 – George Orwell
4. The Hobbit – J.R.R. Tolkien
5. Harry Potter and the Sorcerer’s Stone – J.K. Rowling
6. The Great Gatsby – F. Scott Fitzgerald
7. Charlotte’s Web – E.B. White
8. Anne of Green Gables – Lucy Maud Montgomery
9. The Alchemist – Paulo Coelho
10. Little Women – Louisa May Alcott
11. The Catcher in the Rye – J.D. Salinger
12. Animal Farm – George Orwell
13. The Chronicles of Narnia: The Lion, the Witch, and the Wardrobe – C.S. Lewis
14. The Book Thief – Markus Zusak
15. A Wrinkle in Time – Madeleine L’Engle
16. The Secret Garden – Frances Hodgson Burnett
17. Moby-Dick – Herman Melville
18. Fahrenheit 451 – Ray Bradbury
19. Jane Eyre – Charlotte Brontë
20. The Little Prince – Antoine de Saint-Exupéry
```

```txt:favorite_cities.txt
- In the summer, I love visiting London.
- In the winter, Tokyo is great.
- In the spring, San Francisco.
- In the fall, New York is the best.
```

```txt:favorite_songs.txt
1. "Here Comes the Sun" – The Beatles
2. "Imagine" – John Lennon
3. "Bohemian Rhapsody" – Queen
4. "Shake It Off" – Taylor Swift
5. "Billie Jean" – Michael Jackson
6. "Uptown Funk" – Mark Ronson ft.  Bruno Mars
7. "Don’t Stop Believin’" – Journey
8. "Dancing Queen" – ABBA
9. "Happy" – Pharrell Williams
10. "Wonderwall" – Oasis
```

#### エージェントの動作に関わる部分

3つのファイル名以外で、今回のエージェントの動作に関わる部分を見てみます。

エージェントの出力 2つ目で、表示するよう求められていた #1 の本に該当する行は以下でした。

```txt:favorite_books.txt
1. To Kill a Mockingbird – Harper Lee
。。。
```

エージェントは `Your #1 favorite book is "To Kill a Mockingbird" by Harper Lee.` という回答だったので、元の記載と一致しているようです。

また、 `Based on your favorite songs, you might like "Shallow" by Lady Gaga and Bradley Cooper. It has a great mix of emotion and melody, similar to the songs you enjoy.` という回答で、好みと考えられる曲をオススメするための、もとになっている情報は以下だったようです。

```txt:favorite_songs.txt
1. "Here Comes the Sun" – The Beatles
2. "Imagine" – John Lennon
3. "Bohemian Rhapsody" – Queen
4. "Shake It Off" – Taylor Swift
5. "Billie Jean" – Michael Jackson
6. "Uptown Funk" – Mark Ronson ft.  Bruno Mars
7. "Don’t Stop Believin’" – Journey
8. "Dancing Queen" – ABBA
9. "Happy" – Pharrell Williams
10. "Wonderwall" – Oasis
```

自分がこれらの曲のほとんどをあまり知らないので、エージェントの出力が合っているかは判断はつきませんでした。これらのテキストを書きかえて、自分が分かる内容で試してみると良さそうに思いました。



### main.py

最後に main.py の内容を少し見てみます。

#### コードの内容

コードの内容は以下のとおりです。


```python: main.py
import asyncio
import os
import shutil

from agents import Agent, Runner, gen_trace_id, trace
from agents.mcp import MCPServer, MCPServerStdio


async def run(mcp_server: MCPServer):
    agent = Agent(
        name="Assistant",
        instructions="Use the tools to read the filesystem and answer questions based on those files.",
        mcp_servers=[mcp_server],
    )

    # List the files it can read
    message = "Read the files and list them."
    print(f"Running: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)

    # Ask about books
    message = "What is my #1 favorite book?"
    print(f"\n\nRunning: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)

    # Ask a question that reads then reasons.
    message = "Look at my favorite songs. Suggest one new song that I might like."
    print(f"\n\nRunning: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)


async def main():
    current_dir = os.path.dirname(os.path.abspath(__file__))
    samples_dir = os.path.join(current_dir, "sample_files")

    async with MCPServerStdio(
        name="Filesystem Server, via npx",
        params={
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir],
        },
    ) as server:
        trace_id = gen_trace_id()
        with trace(workflow_name="MCP Filesystem Example", trace_id=trace_id):
            print(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n")
            await run(server)


if __name__ == "__main__":
    # Let's make sure the user has npx installed
    if not shutil.which("npx"):
        raise RuntimeError("npx is not installed. Please install it with `npm install -g npx`.")

    asyncio.run(main())
```


エージェントの出力に関わる部分を少し見てみます。

#### インストラクション

インストラクションの部分で、 `"Use the tools to read the filesystem and answer questions based on those files."` と書かれています。

指定された場所にあるファイルを読みこみ、その内容をもとに回答するよう指示されています。

#### 3つの出力のもとになっている部分

今回、エージェントが回答していた 3つの内容に関し、そのもとになる処理を見てみます。

具体的には以下の部分です。

```python
    # List the files it can read
    message = "Read the files and list them."
    print(f"Running: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)

    # Ask about books
    message = "What is my #1 favorite book?"
    print(f"\n\nRunning: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)

    # Ask a question that reads then reasons.
    message = "Look at my favorite songs. Suggest one new song that I might like."
    print(f"\n\nRunning: {message}")
    result = await Runner.run(starting_agent=agent, input=message)
    print(result.final_output)
```


#### MCP

MCP関連の部分は以下になるようです。

```python
async def main():
    current_dir = os.path.dirname(os.path.abspath(__file__))
    samples_dir = os.path.join(current_dir, "sample_files")

    async with MCPServerStdio(
        name="Filesystem Server, via npx",
        params={
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir],
        },
    ) as server:
        trace_id = gen_trace_id()
        with trace(workflow_name="MCP Filesystem Example", trace_id=trace_id):
            print(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n")
            await run(server)
```

おおまかな処理の流れとしては、以下の内容になっているようです。

1. main.py が置かれた場所の絶対パスを取得
1. 取得した絶対パスに sample_filesフォルダを付与
1. sample_filesフォルダを付与した絶対パスを `@modelcontextprotocol/server-filesystem` に渡して、そのパスに該当するフォルダに置かれたファイルを処理対象とする

このようなファイルがもとになり、先ほど掲載していたエージェントの出力が得られたようです。


## その他

### 関連情報

以下は、今回の内容を進めるにあたって参照したものや、情報検索中に見かけて後で内容を見てみようと思っているものの雑多なリストです。

●複数の MCP サーバーを使った OpenAI Agents SDK コード例
 https://zenn.dev/openaidevs/articles/c17ad6a2c95bcb

●tegnike/openai-agents-sdk-mcp
 https://github.com/tegnike/openai-agents-sdk-mcp

https://x.com/tegnike/status/1905028022203240931

```python
import asyncio
import os
from agents import Agent
from agents import Runner
from agents.mcp import MCPServerStdio
from dotenv import load_dotenv

# .envファイルを読み込む
load_dotenv()


async def main():
    async with MCPServerStdio(
        params={
            "command": "npx",  # Linux環境用
            # "command": "/Users/user/.volta/bin/npx",  # MacOS環境用（volta利用時）
            # "command": "C:\\Program Files\\nodejs\\npx.cmd",  # Windows環境用
            "args": ["-y", "@modelcontextprotocol/server-brave-search"],
            "env": {"BRAVE_API_KEY": os.getenv("BRAVE_API_KEY")},
        }
    ) as server:
        # サーバーからツールリストを取得
        await server.list_tools()

        # Agentの作成とMCPサーバーの設定
        agent = Agent(
            name="検索アシスタント",
            instructions="あなたは検索アシスタントです。ユーザーの質問に対して、"
            "Brave検索を使用して情報を調査し、日本語で分かりやすく回答してください。"
            "情報源も明記してください。",
            mcp_servers=[server],
        )

        # Agentの実行例
        result = await Runner.run(
            agent, "2025年にされたOpenAIの発表について教えて下さい"
        )
        print(result.final_output)


if __name__ == "__main__":
    asyncio.run(main())
```


#### 続きのお試しをやってみました

上記の [tegnike/openai-agents-sdk-mcp](https://github.com/tegnike/openai-agents-sdk-mcp) を使ったお試しもやってみました。

●AIエージェント で MCP： OpenAI Agents SDK を使ったお試し【その2】 - Qiita
　https://qiita.com/youtoy/items/5f4e477500c23c7dfd56