飼い主,MCPを遊ぶってよ

からあげさんのブログを出発点として真似してみる

おみくじを引く MCP を作ってみよう.
$ mkdir omikuji_mcp_julia
$ uv init
Initialized project `omikuji-mcp-julia`
$ uv run main.py
Using CPython 3.13.3 interpreter at: /opt/homebrew/opt/python@3.13/bin/python3.13
Creating virtual environment at: .venv
Hello from omikuji-mcp-julia!

modelcontextprotocol/python-sdk
の Python SDK を導入する.
$ uv add "mcp[cli]"

Quickstart の指示に従ってそのまま server.py
を作成する.
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
サーバを起動 インストールする.
$ uv run mcp install server.py
[05/10/25 14:18:28] INFO Added server claude.py:141
'Demo' to Claude
config
INFO Successfully cli.py:467
installed Demo in
Claude app

インストールされた MCP サーバを確認する.デスクトップアプリのClaudeを起動して下記のように Demo という場所が見える.
add
が見える. def add(a: int, b: int) -> int:
に対応するものだと思われる.

add(3, 4)
と命令(Prompt 入力欄に書き込みを)すると下記のように警告が出る.
ここでは Allow once を実行して実行を許可する.
下記のような thinking ログを残していたことがわかった.
{ `a`: 3, `b` : 4}

server.py を次のように書き換える.
# server.py
import random
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
FORTUNES = [
"大吉", "中吉", "小吉", "末吉",
]
@mcp.tool()
def omikuji() -> str:
return FORTUNES[random.randint(0, len(FORTUNES))]
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
下記のコマンドでインストールを開始する.
$ uv run mcp install server.py

Run omikuji
をプロンプトとして入力
下記のように "list index out of range" で怒られる.
random.randint
の仕様を勘違いしていた.end points も含むことに注意しなければいけない.
In [15]: ?random.randint
Signature: random.randint(a, b)
Docstring:
Return random integer in range [a, b], including both end points.
@mcp.tool()
def omikuji() -> str:
return FORTUNES[random.randint(0, len(FORTUNES)-1)]
↑のように書き直す

Claude を再起動して Run omikuji とか Draw again とか One more time で複数回行う.
小吉と中吉が出ている.とりあえず実行ごとに異なる答えが得られてるのがわかる.

画像データを返却できるらしいので試してみよう.
# server.py
import random
from mcp.server.fastmcp import FastMCP
import numpy as np
from PIL import Image
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
FORTUNES = [
"大吉", "中吉", "小吉", "末吉",
]
@mcp.tool()
def omikuji() -> str:
return FORTUNES[random.randint(0, len(FORTUNES)-1)]
@mcp.tool()
def create_image() -> Image.Image:
img = np.random.random((100, 100, 3))
return Image.fromarray((img * 255).astype(np.uint8))
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
下記のように --with pillow
オプションをつけておく
$ uv run mcp install server.py --with pillow --with numpy

Call create_image
というプロンプトを投げる.Claude app だと画像を表示してくれないっぽい.残念.

Python からJuliaを呼べるのでこんな感じのコードを作ってみる.
# server.py
import random
from mcp.server.fastmcp import FastMCP
import numpy as np
from PIL import Image
# ここで↓をロードするとMCPサーバが立ち上がらない.
#from juliacall import Main as jl
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
FORTUNES = [
"大吉", "中吉", "小吉", "末吉",
]
@mcp.tool()
def omikuji() -> str:
return FORTUNES[random.randint(0, len(FORTUNES)-1)]
@mcp.tool()
def create_image() -> Image.Image:
img = np.random.random((100, 100, 3))
return Image.fromarray((img * 255).astype(np.uint8))
@mcp.tool()
def call_julia(expression: str) -> str:
from juliacall import Main as jl
try:
out = str(jl.seval(expression))
return out
except Exception as e:
return str(e)
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
$ uv run mcp install server.py --with pillow --with numpy --with juliacall

おー.できた.

一応 Julia の式を評価してそれを返すようなものはできた.任意の指揮を評価するようになってるので注意が必要.

Cursor で遊ぶ場合
下記のような mcp.json
を記述
{
"mcpServers": {
"Demo": {
"command": "~/.local/bin/uv",
"args": [
"run",
"--with",
"juliacall",
"--with",
"mcp[cli]",
"--with",
"numpy",
"--with",
"pillow",
"mcp",
"run",
"~/work/omikuji_mcp_julia/server.py"
]
}
}
}
@
で呼び出すコマンド名が Python の関数名に対応しているようだ

相性問題かもしれないけれど,juliacall に関するコードを実行すると,一回は実行できるけれど次回以降,クライアントが止まる・・・.