MCPとかTOONとか

いつもお世話になっております。わいとん(@ytnobody)です。

さて、ただいま宿泊先のホテルのロビーでほろ酔い気分でこのエントリを書いています。Perl Advent Calendar 2025のday 6となります。

みなさんはMCPサーバーというものを使ったことはありますでしょうか?AIにコードを書かせているような人は間違いなく使ったことがある側の人だとおもいます。

ではMCPサーバーを作ったことはありますか?私はこのエントリを書くまではまったくありませんでした。もっぱらMCPサーバーについては使うばかりでした。

しかし、なんとPerlでもMCPサーバーが書けるということらしいです。どうにか私もMCPサーバーをPerlで書きました。正確には私がAIに指示を出して書いてもらったのですが…

MCPサーバーをPerlで作るには

実はPerlでは非常に人気の高いWebフレームワークとしてMojoliciousが挙げられます。この作者であるSebastian Riedelさんによって、その名もずばりMCPというモジュールが作られています。

Mojoliciousで/mcpパスをMCPサーバーとして公開する場合、以下のようにすればよいようです(SYNOPSISそのまま)。

1
2
3
4
5
6
7
8
9
10
11
12
13
use Mojolicious::Lite -signatures;
use MCP::Server;
my $server = MCP::Server->new;
$server->tool(
name => 'echo',
description => 'Echo the input text',
input_schema => {type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']},
code => sub ($tool, $args) {
return "Echo: $args->{msg}";
}
);
any '/mcp' => $server->to_action;
app->start;

なんか思ったより簡単そう。でも、そもそもHTTPでの通信すら面倒だからSTDIO(標準入出力)でやり取りさせたい。という場合にはSTDIOトランスポートを使うとよいのだそう(SYNOPSISママ)。

1
2
3
4
5
6
7
8
9
10
11
12
use Mojo::Base -strict, -signatures;
use MCP::Server;
my $server = MCP::Server->new;
$server->tool(
name => 'echo',
description => 'Echo the input text',
input_schema => {type => 'object', properties => {msg => {type => 'string'}}, required => ['msg']},
code => sub ($tool, $args) {
return "Echo: $args->{msg}";
}
);
$server->to_stdio;

これならHTTPで公開するわけじゃないから、手元で試すのに便利そうです。

さて、これを参考にClaude Haiku 4.5にオレオレMCPサーバーを作ってもらうことにします(成果物はこのあと紹介)。

MCPクライアントはどうするか

色々調べてみたんですが、やれClineをつかえだの、やれClaude Codeがいいぞだの、色々あるっちゃああるんですよ。

でも、これもPerlで作ったらいいじゃないですか。雑なMCP ClientをPerlで作ってはいけないという決まりはありません。だいたい、ツールを増やしたいわけではなく、自作MCPサーバーとやり取りできるクライアントが欲しいだけなんです。無料でアカウントを作らせようとするおせっかいはここでは不要なんですよ。

で、MCP::Clientというモジュールもあるにはあるのですが、これはHTTPベースのトランスポートしかサポートしておらず、STDIOトランスポートは未サポート。

仕方がないので、これもClaude Haiku 4.5に作ってもらうことにしました(このあと成果物を紹介)。

そういえばちょっと前にTOONというものが話題になったな?

何週間か前くらいにTOON(Token Oriented Object Notation)というデータフォーマットがにわかに話題になっていました。

いわく、LLMのトークン削減に効果的な構造化データフォーマットだー、みたいなことが特徴らしいのですが、まあ良く見ると、なんとPerl向けモジュールがあるとのこと。

老後に趣味のPerlを盆栽のように楽しみたい者としてはニッコリな状況というわけですが、ああ思い出した、これは私が「Perlモジュールがない」という理由で高血圧をこじらせてしまいそうだったので、慌ててClaude haiku 4.5に作らせたのでした。ここでこのData::TOONを作っていなければ、大好きなサウナをまた我慢しなければならないところでした。

ちなみに使い方はこういう感じ(SYNOPSISママ)です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
use Data::TOON;
# Basic usage
my $data = { name => 'Alice', age => 30, active => 1 };
my $toon = Data::TOON->encode($data);
print $toon;
# Output:
# active: true
# age: 30
# name: Alice
my $decoded = Data::TOON->decode($toon);
# Tabular arrays
my $users = {
users => [
{ id => 1, name => 'Alice', role => 'admin' },
{ id => 2, name => 'Bob', role => 'user' }
]
};
print Data::TOON->encode($users);
# Output:
# users[2]{id,name,role}:
# 1,Alice,admin
# 2,Bob,user
# Alternative delimiters
my $encoder = Data::TOON::Encoder->new(delimiter => '|');
print $encoder->encode($users);
# Or with tabs:
my $tab_encoder = Data::TOON::Encoder->new(delimiter => "\t");
# Root primitives and arrays
print Data::TOON->encode(42); # Output: 42
print Data::TOON->encode('hello'); # Output: hello
print Data::TOON->encode([1, 2, 3]); # Output: [3]: 1,2,3

全部混ぜてつくってみた

という、ここまで紹介した要素を全部混ぜてつくってみたのがこちらのレポジトリです。
ざっくり箇条書きで説明するとこんな感じ。

  • MCP::Serverを使ったSTDIOトランスポートなMCPサーバー mcp_server.pl
    • MCPサーバーに必要な基礎機能を全部実装。
    • 足し算、エコー、pingをツールとして実装。
  • まあまあ自力(ではなくAIが全部)実装なMCPクライアント mcp_client.pl
    • クライアントと人間の間のデータ入出力インターフェースはTOONフォーマット。
    • MCPサーバーとのやり取りはただのJSONでやり取り(普通のMCP)。

TOONの意味ねえ!とか、ほかにもツッコミどころだらけではあるんですが、こういうこともできるんすよ、Perlで。って言いたいだけなんで、そこんとこよろしくお願いしたいところであります。

さいごに

MCPで肉体を若返らせることはできませんでしょうか?できませんか、そうですか…