Cursorでテスト駆動でコードを書いて、MCPを使ってGitLabにMRを書いてもらうまで

# 背景

だいぶ二番煎じ感甚だしいのですが、今回もまた自分の理解を深めるために流行りのMCPの使い方を理解しようと思って書きます。

AIに仕事が奪われると言われる昨今ですが、個人的に感じるのはおそらく一定数エンジニアがAIに取って代わられるけれども、残ったエンジニアは例えば小規模プロジェクトの場合、今まで3人でやっていた仕事をプレイングマネージャー的な立ち位置で自分1人とAIでやるような世界になる気がしています。

さらに個人が捌くべきタスク量は増えるのでないかという気がしていて、少しでも自動化できるものは自動化して、AIに任せられるものはAIに任せて自分の頭で考えて鍛える時間を増やさねばと思う今日この頃です。

# やったこと

すごく初歩的な内容ですが備忘のため以下に書きます

* cursorを使って、MCPサーバーを設定
* cursorを使って、Agentモードでjestのインストール・設定、テストを書いて失敗させてから、コードを書いてPASSさせる
* cursorを使って、Agentモードで変更内容をcommit・pushし、MRを書いてもらう


## cursorを使って、MCPサーバーを設定

modelcontextprotocolのgithubにcursorでのサーバーの設定内容は書かれていないです。
cursorはVSCodeをforkして作ったものとのことなので、[Usage with VS Code](https://github.com/modelcontextprotocol/servers/tree/main/src/gitlab#docker-1)
でできるかなと思ったのですが、GitLabのMCP Serverの登録が上手くできませんでした。
mcpオブジェクトの中にserversを配置するのではなくmcpServersをトップレベルに配置すると上手くできました。


```mcp.json
{
  "mcpServers": {
    "gitlab": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "--env-file",
        ".env",
        "mcp/gitlab"
      ]
    }
  },
  "inputs": [
    {
      "type": "promptString",
      "id": "gitlab_token",
      "description": "GitLab Personal Access Token",
      "password": true
    },
    {
      "type": "promptString",
      "id": "gitlab_url",
      "description": "GitLab API URL",
      "default": "https://gitlab.com/api/v4"
    }
  ]
}
```
```.env
GITLAB_PERSONAL_ACCESS_TOKEN=xxxxxx
GITLAB_API_URL=http://host.docker.internal/api/v4 ⏎    
```
## cursorを使って、Agentモードでjestのインストール・設定、テストを書いて失敗させてから、コードを書いてPASSさせる

次のようなプロンプトを入力し、AIとのやりとりを行った結果(以下の内容はその抜粋)、無事AIにテストコード、ソースコードを書いてもらってテストをPASSさせ、commit, push, MRの作成まで行ってもらうことができました。

<details>
<summary>AIとのやりとり</summary>

```
私:
テスト駆動で失敗するテスト書いて、それを成功させるコードを書こうと思ってます。
まずjestをnpm installしてpackage.json及びpackage-lock.jsonを更新してもらえますか
```
```
AI:
...略...
これで以下のコマンドが使用可能になりました：
npm test: 全てのテストを実行
npm run test:watch: 監視モードでテストを実行
テストを書く準備が整いました。最初のテストファイルを作成しますか？
```
```
私:
その前に変更が出たファイルを適切なコメント共にコミットしてください
```
```
AI:
...略...
申し訳ありませんが、コマンドの実行に問題が発生しているようです。以下の手順で手動で実行することをお勧めします：
ターミナルで以下のコマンドを実行してください：
```
```bash
git add .
git commit -m "chore: migrate test framework from Mocha to Jest"
```
```
AI:
このコミットには以下の変更が含まれています：
テストフレームワークをMochaからJestに変更
テスト監視モード（test:watch）の追加
Jest設定の追加（テスト環境、カバレッジレポート等）
コミットが完了したら、次のテストファイルの作成に進むことができます。
```
```
私:
足し算をする関数addを作ろうと思います。第一引数と第二引数の和を返す関数ですが、
実装する前にテストコードを書いてください。
```
```
AI:
...略...
申し訳ありません。コマンドの実行に問題が発生しているようです。以下のコマンドを手動で実行することをお勧めします：
```
```bash
npm test
```
```
AI:
このコマンドを実行すると、以下のようなエラーが表示されるはずです：
add関数がundefinedなので、全てのテストが失敗
特に以下のテストケースが失敗：
正の整数の足し算（1 + 2 = 3）
負の整数の足し算（-1 + (-2) = -3）
小数の足し算（1.1 + 2.2 ≒ 3.3）
0との足し算（5 + 0 = 5）
引数のバリデーション（数値以外の引数）
これらのテストが失敗することを確認できたら、次は実装に進むことができます。実装を始めましょうか？
```
```
私:
(Line42-164を指定して)
npm testを実行すると上記の通り失敗します
```
```
AI:
はい、テストが失敗していることを確認できました。エラーメッセージを分析すると：
主なエラー：TypeError: add is not a function
これは現在addがundefinedとして定義されているためです
全てのテストケースが失敗：
正の整数の足し算
負の整数の足し算
小数の足し算
0との足し算
バリデーションテスト
では、これらのテストをパスするようにadd関数を実装しましょう：
...略...
```
```
私:
(Line166-202を指定して)
servers.test.jsがfailしてますね。こちらは要らないので消してください。
```
```
AI:
...略...
PASS  tests/add.test.js
-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |     100 |      100 |     100 |     100 |                   
 src/add.js      |     100 |      100 |     100 |     100 |                   
-----------------|---------|----------|---------|---------|-------------------
これでadd.test.jsのテストのみが実行され、全てのテストがパスしているはずです。また、コードカバレッジも100%となっているはずです。
変更をコミットしましょうか？
```
```
私:
はい。ただし、sever.test.jsの削除と他のコミットは分けてくださいね
```

</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244232/998f3843-800f-432a-ae29-53af1e49224e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244232/90727567-1571-4895-a712-e8eb29043445.png)

# 所感

* AIにコマンドを実行してもらうところでやたらともたついた
* 変更内容はテンプレート的な内容をrulesで縛るようにするのが良さそう
* レビュー機能を入れてCIでのlintや単体テストでチェックできない、コーディングルール、設計・実装のアンチパターンなどを入れてチェックできると良さそう
  * マジックナンバー使わない
  * 同じ処理を3回以上繰り返さない
  * 設計の対称性
  * 排他チェック
  * 割り込み関数で関数呼び出しまくる（アンチパターン）とか
  * etc...
* テスト駆動でAIとchatしながらコードを書くことができたが、効率が良いかは疑問。
* 自分で書いた方がいい場合とAIに書かせた方がいい場合の匙加減がありそう