🕔

現在時刻を返すMCPサーバを作ってCursorと連携させてみる(Docker編)

に公開

はじめに

以下の記事に書かれていたAIの使い方がいいなと思ったので自分も真似しようとやっているのですが、現在時刻や日付をこちらの意図に沿わせるのがどうも難しいなと感じました。

そこで、現在時刻を返却するMCPサーバを立て、Cursorを当該MCPサーバと連携させることで日時の精度が上がるのではないかと考えました。
時刻に関するMCPサーバは記事執筆時点でも無数に存在していますが、MCPに関する学習も踏まえ、今回は自分でMCPサーバを実装し、それをCursorと連携させてみます。

この記事で達成したいこと

  • DockerコンテナとしてMCPサーバの実行環境を構築する
  • 現在時刻を返却するMCPサーバを実装する
  • 開発したMCPサーバとCursorを連携して日時の精度が上がるか検証する

前提条件

開発環境 / 動作環境

macOS
$ sw_vers
ProductName:		macOS
ProductVersion:		14.6.1
BuildVersion:		23G93
Docker
$ docker --version
Docker version 27.4.0, build bde2b89
Docker Compose
$ docker compose version
Docker Compose version v2.31.0-desktop.2
Cursor
$ brew info cursor
==> cursor: 0.49.6,0781e811de386a0c5bcb07ceb259df8ff8246a52 (auto_updates)
https://www.cursor.com/
Installed
/opt/homebrew/Caskroom/cursor/0.49.6,0781e811de386a0c5bcb07ceb259df8ff8246a52 (398.6MB)
  Installed using the formulae.brew.sh API on 2025-05-04 at 09:37:14
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/c/cursor.rb
==> Name
Cursor
==> Description
Write, edit, and chat about your code with AI
==> Artifacts
Cursor.app (App)
/Applications/Cursor.app/Contents/Resources/app/bin/code -> cursor (Binary)
==> Analytics
install: 10,769 (30 days), 34,399 (90 days), 68,970 (365 days)
Dockerコンテナ内
# Python
$ docker compose exec mcp-time sh -c "python --version"
Python 3.11.12

# poetry
$ docker compose exec mcp-time sh -c "poetry --version"
Poetry (version 2.1.3)

# FastMCP
$ docker compose exec mcp-time sh -c "poetry show | grep fastmcp"
fastmcp           2.2.8     The fast, Pythonic way to build MCP servers.

MCPサーバ連携前の状態

MCPサーバ連携前の振る舞いで顕著だったものを添付しました。
ちなみにこの日は2025年5月5日(時間は覚えていませんが9時ぴったりではなかったはず)でしたが、Agentの振る舞いを確認すると分かる通り、ファイル名が 20250505_log.yaml となって欲しいところが 20250503_log.yaml となっていたり、working_hours.start に書き込まれた値が 09:00 になっていたりして、こちらの意図通りの結果を生成できていません。
なお、何度か同様の指示を送りましたが、日付や時刻の生成結果はどれも不安定でした。

MCPサーバ連携前の振る舞い
左がRules定義、右がAgentの振る舞い

MCPサーバ導入

下準備

適当なディレクトリに今回のMCPサーバ用のプロジェクトを作成してください。

$ pwd
/Users/***/Work
$ mkdir mcp-time

各種ファイルを作成していきます。
今回はDockerを用いて仮想環境を作成しますが、uvを使ってホストマシン上にPythonの仮想環境を作成している例が多く見られました。
個人的にホストマシンに直接色々入れて汚すのはあまり好きではないという理由からDockerを採用したものの、手軽さで言えば後者だと思いますので、その辺りはお好みで選定するのが良いと思います。

./mcp-time/Dockerfile
FROM python:3.11-slim-bookworm

WORKDIR /app

RUN apt-get update && apt-get install -y tzdata \
    && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata

# Install poetry
RUN pip install --no-cache-dir \
    poetry
./mcp-time/docker-compose.yml
services:
  mcp-time:
    container_name: mcp-time
    build:
      context: .
      dockerfile: ./Dockerfile
    tty: true
    stdin_open: true
    volumes:
      - .:/app

Dockerfiledocker-compose.ymlの準備ができたらコンテナをビルドして起動します。
コンテナが起動したらpoetryコマンドでプロジェクトを作成し、pyproject.tomlを手直しします。

$ docker compose exec mcp-time sh

# コンテナ内で
$ poetry new mcp-time
./mcp-time/mcp-time/pyproject.toml
[project]
name = "mcp-time"
version = "0.1.0"
description = ""
authors = [
    {name = "Your Name",email = "you@example.com"}
]
readme = "README.md"
- requires-python = ">=3.11"
+ requires-python = ">=3.10,<4.0" # `fastmcp`パッケージをインストールできるように変更
dependencies = [
]

[tool.poetry]
packages = [{include = "mcp_time", from = "src"}]


[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

プロジェクトが作成できたら、今回はMCPサーバを実装するためにFastMCPを使うためpoetryでインストールします。

$ docker compose exec mcp-time sh

# コンテナ内で
$ cd mcp-time
$ poetry add fastmcp

最後に、今後の作業ディレクトリとしてはpoetryで作成したプロジェクト配下になるのでWORKDIRを変更してコンテナを再度ビルド&起動しておきます。

./mcp-time/Dockerfile
FROM python:3.11-slim-bookworm

- WORKDIR /app
+ WORKDIR /app/mcp-time

RUN apt-get update && apt-get install -y tzdata \
    && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata

# Install poetry
RUN pip install --no-cache-dir \
    poetry

これで下準備は終わりです。

MCPサーバ開発

それではMCPサーバの実装に入っていきます。
公式リファレンスを見るとMCPサーバとしてだけでも様々な機能がありますが、今回のユースケースだと「クライアントが現在時刻を要求したらそれに応じる関数」を公開できれば良さそうなので、ツールとして実装することになりそうです。

./mcp-time/mcp-time/src/main.py
from datetime import datetime
from fastmcp import FastMCP

mcp = FastMCP(name="TimeServer")

@mcp.tool()
def get_current_time() -> str:
    """return the current time."""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

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

めちゃくちゃ簡単ですね…
特に言うことはありませんが強いて言うなら、ツールとして関数を公開するためには@mcp.tool()を記述することを忘れないというところでしょうか。

Cursorと連携

MCPサーバの実装が終わったのでCursorと連携していきます。
Cursorのコマンドパレットを開きCursor Settingsと入力して設定画面を開きます。

Cursor Settings

MCP > Add new global MCP Server と進み、開いたmcp.jsonを以下のように編集します。
なお/Users/xxx/Work/mcp-time/docker-compose.ymlの部分は絶対パスを指定する必要があります。

mcp.json
{
  "mcpServers": {
+     "time": {
+       "command": "docker",
+       "args": ["compose", "-f", "/Users/xxx/Work/mcp-time/docker-compose.yml", "exec", "-i", "mcp-time", "poetry", "run", "python", "src/main.py"]
+     }
  }
}

設定画面に戻りMCPサーバと正常に接続されていればOKです。

Cursor Settings

いざ実行

まずは単純に現在時刻を問い合わせてみました。

現在時刻を問い合わせてみた結果
良い感じですね

次にMCPサーバ連携前と同じ指示を送り、振る舞いがどのように変わるか試してみました。
なお、試した日時としては2025年5月6日の20時過ぎです。
前回と異なりファイル名や書き込まれる値がちゃんと現在時刻を反映したものになっています。

MCPサーバ連携後の振る舞い

おわりに

今回の実装を通して、MCPサーバの実装方法、Cursorでの連携方法について学べました。
結果的にAIエージェントに想定どおりの振る舞いを与えることができるようになり、伴走者としての信頼性も少し増しました。
今回は現在時刻を返却するという簡単なものでしたが、ユースケースに合わせたMCPサーバを導入または自作することでAIエージェントに任せられる作業の範囲が大きく広がりそうだと感じています。

一方で、今回はPythonの実行環境をDockerコンテナとして構築しましたが、この構成は正直あまり良い開発者体験を生みませんでした。
元々はMCPサーバを実装後、動作確認のためにMCP Inspectorを使う予定でしたが「MCP Inspectorはコンテナ内、実際Cursorで使う時はコンテナ外」といった格好になってしまい検証としての効果が薄く使用を見送りました。
また、Dockerコンテナが起動しているか管理しないといけないという点も、普段使いするのであれば煩わしく感じてくるのではないかと思っています。
他にもmcp.jsonに記述するargsの値が無駄に長くなってしまう点もダサかったりします…

目的は達成できたものの課題も残る結果となったので、次はuvを使ってホストマシン上にPythonの仮想環境を作る構成でも試してみようと思います💪

Discussion