BacklogのMCPサーバーを作ってローカル動かしてみた

## はじめに
MCPサーバー便利だなーとWindsurf上から日々使っている私ですが、Issueの登録は簡単にGithubのMCPサーバーからできるのにBacklogの課題はブラウザに飛んで課題を登録してと往復しなくてはいけない点でBacklog用のMCPサーバー欲しいなーと思っていました。

## 公開されてるMCPサーバーあるのでは？

### 結論：あります。

## なぜわざわざ作る？

以下の記事を読みました。

https://zenn.dev/arrowkato/articles/mcp_security

そして、基本的には以下のAnthoropicが管理しているMCPサーバーのリポジトリにおいて認められているもの以外のセキュリティーの信頼性は低いとのことでしたので、業務でも使う以上自分で作ってローカルで動かして使用しています。

> 自分でソースコード読んで安全性が確認できればよかったのですが…

https://github.com/modelcontextprotocol/servers

あと、もし自分で作れるなら作ってみたいでしょう

## どうやって作った？

先ほど添付したリポジトリに、MCPのintroductionに飛べるリンクがありますので、introductionを確認します。

MCPってこういうものだよという説明があります。

https://modelcontextprotocol.io/introduction

そして、実際に天気のAPIを使用してClaude Desktopを通してMCPサーバーを使用するところまでの流れがありましたので一回さらいます。

> AIにリンクを与えて学習させてもいいと思います
>
> ただ、未知の技術を触る場合、基本AIに聞きながら作業していくことが多いと思いますが、ドキュメント見たら簡単に解決するようなことだったのにAIが修正の方向性を見失って時間が溶けるなんてことに遭遇したことがあると思います。
>
> なので全体のフローと、ここは気をつけないといけなさそうだなというところはふわっとでいいので押さえておくといいと思います。
>
> MCPサーバーという情報だけ与えたらMineCraftのサーバーだという前提で説明を開始されましたので、浸透し切っていなさそうな情報はより大切かと思います。

↓ 天気のAPIで実際に作成するページ

https://modelcontextprotocol.io/quickstart/server

## 流れがわかったら次は

### 差分を洗い出そう

上のを読むと大体のソースの枠組みと、APIを叩くだけで情報が取得できるAPIの場合のMCPサーバーの作成方法がわかったと思います。

では今回作成したいBacklogのAPIとは何が違うだろうと考えました。

- API Keyが必要
- APIの呼び出し方（必要なパラメータなど）
- mcp_config.jsonにどのように記述すれば読み取ってくれるか

私はパッと上の3つが思いついたので、差分を埋めていきたいと思います。

### 1. API Keyが必要

これは私がGithubのMCPサーバーを先に利用していたこともあって、mcp_config.jsonのenvで渡せばいいのかなと予想がついていました。

もし触ったことがない方でも、すでに公開されているMCPサーバーの中でAPIキーが公開されているものを実際に触ってみるか、READMEとソースコードを読めばなんとなくわかるかと思います。

じゃあ、mcp_config.jsonで設定した環境変数をどうやって読み込めばいいのかが分かれば問題は解決です。

先ほども言った通りGithubのMCPサーバーのソースを確認したり、AIに聞きながら探していってもいいと思います。
　

<details><summary>結局どうやるの？</summary>

普通に.envで宣言した時と同じように読み込めます。

https://github.com/search?q=repo:modelcontextprotocol/servers%20GITHUB_PERSONAL_ACCESS_TOKEN&type=code


```ts:utils.ts
  if (process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
    headers["Authorization"] = `Bearer ${process.env.GITHUB_PERSONAL_ACCESS_TOKEN}`;
  }
```

```py:index.py
load_dotenv()

BACKLOG_API_KEY = os.getenv("BACKLOG_API_KEY")
```
</details>

### 2. APIの呼び出し方（必要なパラメータなど）

まず、なんのAPIが必要なのかを整理します。

> 私の場合、課題（チケット）の起票ができれば他の機能は必要ないというスタンスで進めていきます。

当然天気のAPIとBacklogのAPIでは色々と違ってきますので、この差を埋めていきます。

BacklogのAPI情報をAIに与える方法として、自分でAPIを調べて伝えることも、APIをまとめているページがあればそのURLをAIに与えることも考えられましたが、今回の作業では、まずAPIの選定は私が行い、それをもとに実装する部分をAIに任せることにしました。

---

まず、課題（チケット）の起票に必要そうなIssue作成的なAPIの情報を見つけます。
↓
そうすると、Issue作成的なAPIを実行するためには、何のパラメータが必須とされているかが分かりますのでそれを取得できそうなAPIを集めます。
↓
必要になるAPIのPathと必要なパラメータの情報をまとめてくれているページがあるので、そのページのURLをAPIの役割と一緒に渡して実装してもらいます。

---

## 3. mcp_config.jsonにどのように記述すれば読み取ってくれるか

これは他のMCPサーバーのREADMEや、MCPのドキュメントを読みます。

繰り返しになりますが、私の場合はGithubのMCPサーバーの設定で環境変数の設定方法が何となくわかっていたので、天気の時のjsonの記述に環境変数を足すだけで済みました。

```json
{
    "mcpServers": {
        "weather": {
            "command": "uv",
            "args": [
                "--directory",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
                "run",
                "weather.py"
            ]
        }
    }
}
```
↓
```json
{
    "mcpServers": {
        "backlog": {
            "command": "uv",
            "args": [
                "--directory",
                "/ABSOLUTE/PATH/TO/PARENT/FOLDER/mcp-backlog",
                "run",
                "main.py"
            ],
            "env": {
                "BACKLOG_API_KEY": "API_KEY",
            }
        }
    }
}
```
あとは、実際にサーバーをローカルで起動して、課題を追加してもらうように依頼してみます。

:::note warn
注意事項
Windsurfはmcp_config.jsonを更新したらWindsurf自体を再起動しないといけないらしいので、色々やる中でなんか上手くいかないなという時は再起動してみましょう
:::

おそらくエラーが出る場合も多いと思いますが、今のAIの性能なら数回のやり取りで実際に動くようになるはずです。

> もし上手くいかない場合はintroductionのページのURLを与えたり、必要となりそうな情報を与えましょう

Backlogに限らず様々なAPIを提供しているサービスのMCPサーバーが構築可能かと思いますので、もしこのサービスのこの機能をエディターから実行できたら楽なのになと思っている方がいたら試してみてください！

## 実際に使ってみた

![スクリーンショット 2025-04-02 20.18.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734276/211111d2-3f1f-4752-97db-12d84831d695.png)

↓

![スクリーンショット 2025-04-02 20.21.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734276/1e28482d-0dc1-4cee-a94f-286f6f84e0a9.png)

現在は担当者を自分固定で、start_dateを当日とするように修正して使用しています。

## 自分がやってみた中でぶつかったエラーやメモ

### ◯ MCPサーバーのツール

MCPサーバーはツールを使用して、こちらが指定した目的を達成しようとするのですが、以下のように書くと、ツールとして関数が使えるようになります。

```py
@mcp.tool()
async def create_backlog_issue(
.
.
.
```

そして、Windsurfではmcp0_,mcp1_などの接頭辞が必要になります。
もし、MCPサーバーを通して何かしようとしたときにツールが見つかりませんと出てきた場合には促してみてください。（大体自分で気づいてくれます）

:::note warn
注意事項
こちら側で関数（ツール）の名称に接頭辞をつける必要はありません。
:::

### ◯ MCPの実行設定と注意点

AIにMCP関連の実装を依頼すると、意図しないソースの変更が生じてしまう可能性があります。

その時、私のようにあんまり深くは理解していない方はサーバー自体は立ち上がっているのになんで上手くいかないんだろうと思うことがあるかもしれません。

例えば、本来 Windsurf と標準入出力で連携させたいのに、AIが勝手にネットワークサーバーとして localhost で待ち受けるようなコードに変更してしまうケースがありました。

Windsurf など他のプロセスと正しくやりとりするためには、入出力設定が非常に重要らしいです。今回の場合、以下のように transport="stdio" を指定して、標準入出力を経由させる必要がありました。（天気のやつでそうなっているので変更されない場合は大丈夫です。）

```py
# Windsurfや他のプロセスと標準入出力で連携するための正しい設定
mcp.run(transport="stdio")
```

### ◯ いきなり依頼を投げると…

例えばですが、Githubに対してIssueをよく投げている時などに急に、こういう課題を登録してください。などと急に投げてみるとbacklogではなくGithubに対してIssueを作成しにいってしまいます。

このサービスに対してアクションを行ってほしいですよーとワンクッションを挟むと安定します。

### ◯ クレジット消費するくらいなら手でやるよ

分かります。私もクレジット難民なので、毎月末には残りのクレジットと睨めっこが始まります。

ですが、MCPサーバーはProブランに入っていると使える無料のモデルでも実行できるので、無料モデルで実行しましょう！

## まとめ

基本的には、個人的に利用するような場合は、すでに誰かが作ってくれているサービスを使うのが手軽だと思います。その際は、ご自身でソースコードを確認しつつ、AIにもダブルチェックしてもらうなど、安全性を確かめてから使用するのが良いと思います。

　
具体的なコードを何一つ出さずに恐縮ですが、ここまでの内容は、Backlog以外のサービスに対してもご自身でMCPサーバーを構築する際の手順に応用できるかと思います。もし利用しているサービスにMCPサーバー（公式）が無い場合には、ご自分の手で作ってみるのも良いかもしれません。

「まだMCPサーバー使ってみたことない！」という方も、使用自体は非常に簡単です。世の中にある記事などの情報通りに進めれば、数分で試せると思いますので、ぜひお試しください！