MCPについてちょーーーーっとだけ勉強したので、まとめました。

## 注意事項
本記事は自身が学習した内容のアウトプットを目的としています。
そのため、表現や内容は個人の理解をもとに記載しているため、一部内容として誤りを含む部分もあるかもしれません。



## MCPについて
LLMは基本的に外部へのアクセス権限を持っていません。なので、回答を得る場合には基本的にはLLMが学習した時点の情報をもとに回答してくれます。

そのため、現在の天気や株価などを教えてくれることはありません。

MCPとはLLMが外部にアクセスするための共通プロトコルです。
つまり、どのLLMからでも同じように外部リソースを使えるようにしているというわけです。
LLMがMCPを使って、外部にアクセスするためにはMCPサーバというサーバを経由して、外部リソースにアクセスし、取得した情報をもとに、回答をすることが可能です。
つまり、MCPサーバはLLMが外部から情報を取得するためのゲートウェイ的な役割を担うサーバというイメージです。

ここでいう「外部」とは、インターネット上に公開されているAPIなどのリソースだけではなく、DBやローカルのファイルシステムなども含みます。

ローカル上に構築されているDBやファイルシステムについてもLLMからは直接アクセス権限はないため、外部にあたります。

## MCPサーバはどこに存在する？
MCPサーバは基本的に、LLMから接続可能なサーバとして存在します。
※LLMが直接接続できるわけではないですが、便宜上接続可能と記載しています。
それは、ローカル上に独自で立てたサーバであったり、第三者が個別のサーバとして立てたりすることがあります。

## クライアントからMCPサーバを用いて、LLMからの回答を受け取る流れ
LLMがMCPを用いて、回答を生成して我々に回答を返してくれる流れは基本的には下記の流れのイメージです。
※下記イメージはClaudeに作成してもらいましたので、LLMクライアントはClauide DesktopとなっていますがそのほかのLLMクライアントアプリでも基本的には同じ流れになると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3678389/ef499e1c-eb1c-4b7d-9dab-2bb380503235.png)


## MCPサーバを実装するためにはどのような機能を持たせるべきか
上記の図から大体イメージはつくかと思いますが、おおよそLLMからの外部リソース参照リクエストを受け取って、MCPサーバ上に実装されているtoolを用いて外部リソースにアクセスをします。

### 共通機能
* 外部へのアクセスに使う共通機能を実装します。
    * DBへのコネクションを貼ったり、データ取得先のAPIのURLを作成したりします。

まあ、ここは正直実装の問題になるので、共通機能という表現は適切ではないかもしれません。

### 個別機能
* LLMが利用するtoolなどを作成する必要があります。
    * このtoolなどの中でそれぞれ、ファイルを作成したり、DBへのクエリを実行したりするような実装が必要になります。

### LLMクライアントはどのように使用するツールを分けてくれるのか
ありがたいことに、利用できるtoolがLLMにわかれば、具体的にどのような操作をするかはLLMが判断してくれま
Claude Desktopにおいては使用するtoolに関しては使用前にユーザーに使用許可を求めてくるため、勝手な操作がされるわけではありません。
ただし、DBの場合は発行されるSQLまで詳細に表示はしてくれないので、注意が必要です。
大量データを一括で取得するようなSQLが発行された場合には、DBのリソース消費が激しくなるかもしれないです。

## MCPサーバを実装
ここでは具体的な実装はしませんが、上記で必要と記載した機能について、どのように実装をするのかをサンプルで記載します。
※Python SDKを利用

### 共通機能の実装
必要なパッケージやそのほかの詳細な使用方法については下記のMCP Python SDKのREADMEを参照ください。
参考：https://github.com/modelcontextprotocol/python-sdk


```python
from mcp.server.fastmcp import FastMCP

"""
下記から引用
https://github.com/modelcontextprotocol/python-sdk
"""

mcp = FastMCP("My App")

if __name__ == "__main__":
    mcp.run()

```

まずはMCPを使用するためにはMCPオブジェクトを作成する必要があります。

### 個別機能の実装
LLMがMCPを用いて使用できる機能は大きく３つあります。

* プロンプト(Pronpt)
* ツール(tool)
* リソース(resource)

### プロンプトの実装
その名の通りLLMにプロンプトを与えることができます。

```python
@mcp.pronpt()
def pls_reply_gals(message: str) -> str:
    f"ギャルっぽく教えて:\n\n{message}"
```

上記の実装では、MCP経由でLLMに教えてもらいたい内容と、それについてギャルっぽく回答してほしいというプロンプトを渡すことができます。
なので、クライアント側のメッセージに「ギャルっぽく教えて」と入力するのと同じ役割になります。
「@mcp.pronpt」とアノテーションをつけることでLLMはこれをプロンプトとして利用します。

### ツールの実装
ここでは外部APIを用いるtoolを作成するイメージです。
「@mcp.tool()」とアノテーションをつけることで、LLMはアノテーションが付与されている関数をtoolとして利用が可能です。
ここでは、APIのレスポンスをそのままreturnしていますので、APIのレスポンスをインプット情報としてLLMが回答を生成することが可能になります。
※下記コードは実際にそのまま使用できるわけではなく、あくまでもイメージとして記載しています。

```python
@mcp.tool()
async def use_api(request):
    API_URL = "https://api.hogehoge.com/v1"
    response = await mcp.client(API_URL).get(f"/{request}")
    
    return response
```

### リソースの実装
リソースはLLMにデータを提供することを目的としています。
MCPサーバで腹持ちしているデータをLLMに提供することが可能です。
※ここでDBに接続して、データを提供することも可能です。

公式のGitHubにも記載されていますが、REST APIを実装するイメージに近いです。

```python
import sqlite3

@mcp.resource("user://{hogehoge}")
async def db_handler(request):
    # DB接続とユーザーデータ取得
    conn = sqlite3.connect("mcp.db")
    cursor = conn.cursor()

    # ユーザー一覧取得
    cursor.execute("SELECT * FROM users")
    users = [{"id": row[0], "name": row[1]} for row in cursor.fetchall()]
    return {"users": users}
```

## 最後に
私が学習したMCPについてのまとめは以上になります。
上記で記載したソースコードは実際に使用できるレベルのものではないですが、なんとなーくのイメージを持ってもらえたら助かります。
（リソースの具体例でDBにアクセスするbについてはtoolの方がいい気がする。）

実際にLLMクライアントからMCPを使うためにはどうすればいいの？はMCPのGitHubに記載されているので割愛しますが、claude desktopの設定ファイル（JSON）に記載してもらえれば使えます。

記事内容に誤りがあればご指摘ください。
よろしくお願いします。