Bluesky MCP serverを自作し、SNS上に架空の友達を作る - すぎゃーんメモ の記事の続き。
「今後の課題」として挙げていた:
一番どうにかしたいのは、知識について。 プロフィールに書いたことしかインプットされないのでやはり偏りがあるし専門知識が足りない。 プリキュア全シリーズ好きなはずなのにひたすらスマプリのことばかり呟いてしまうし、最新作のキミプリについてはまったく知識が無い。オタクとしてあるまじき失態。
「重度のプリキュアオタクなギャル」という人格を作ったが、その肝心のプリキュアについての知識があやふやだったり足りていなかったりする、といった問題があった。
LLMは最新のプリキュアについて知らない
ChatGPTのアプリや Web UIから尋ねればWeb検索した結果を返してくれたりもするが、LLM自体は学習時よりも新しい情報は知らない。
「プリキュアの最新5作品について タイトル・放送年・テーマを教えてください。」 と、検索機能など何も使わないようAPI経由で質問してみる。
gpt-4o
の回答:
プリキュアの最新5作品について以下の通りです。
1. **ひろがるスカイ!プリキュア**
- **放送年**: 2023年
- **テーマ**: 空とヒーロー
2. **デリシャスパーティ♡プリキュア**
- **放送年**: 2022年
- **テーマ**: 料理とハート
3. **トロピカル〜ジュ!プリキュア**
- **放送年**: 2021年
- **テーマ**: 海と輝き
4. **ヒーリングっど♥プリキュア**
- **放送年**: 2020年
- **テーマ**: 癒しと自然
5. **スター☆トゥインクルプリキュア**
- **放送年**: 2019年
- **テーマ**: 宇宙と願い
これらの作品は、各テーマに基づいて異なるストーリーとキャラクターを持っています。
2023年時点で情報が止まっている。
gpt-4.1-2025-04-14
の回答:
はい、2024年6月時点での「プリキュア」シリーズ最新5作品について、タイトル・放送年・テーマを以下にまとめます。
---
### 1. わんだふるぷりきゅあ!
- **放送年**:2024年
- **テーマ**:動物との絆・ペット・共生
犬や猫など「動物」と「人間」の共生や理解をテーマにした作品。プリキュアになるキャラクターの中には動物も含まれます。
---
### 2. ひろがるスカイ!プリキュア
- **放送年**:2023年
- **テーマ**:空・ヒーロー・成長
「空」を象徴に、新しい世界や可能性への挑戦、「ヒーロー」を意識した明るく前向きな物語。
---
### 3. デリシャスパーティ♡プリキュア
- **放送年**:2022年
- **テーマ**:ごはん・食・絆
「食べ物」「ごはん」を通して、仲間や家族の絆、楽しさや大切さを描いています。
---
### 4. トロピカル~ジュ!プリキュア
- **放送年**:2021年
- **テーマ**:海・夏・やりたいことをやる
「今、一番大事なことをやる!」を合言葉に、トロピカルな海や夏の要素が満載の作品。
---
### 5. ヒーリングっど♥プリキュア
- **放送年**:2020年
- **テーマ**:癒やし・自然・健康
「癒やし」や「自然」「命」がテーマで、人々や地球を元気にするプリキュアのお話。
---
もし、さらに詳細なキャラクターなどが知りたい場合も、お気軽にどうぞ!
こちらは2024年6月までは知っている、ということになっているようだ。
o4-mini-2025-04-16
の回答:
以下、直近5作品のタイトル・放送期間・おもなテーマです。
1. ひろがるスカイ!プリキュア
・放送期間:2023年2月5日~2024年1月28日
・テーマ:空/飛行/自由と夢を追いかける勇気
2. デリシャスパーティ♡プリキュア
・放送期間:2022年2月6日~2023年1月29日
・テーマ:お料理&食べ物/“おもてなし”の心/みんなで笑顔を分かち合う
3. トロピカル~ジュ!プリキュア
・放送期間:2021年2月28日~2022年1月30日
・テーマ:トロピカル(南国)/海・夏/ビューティ&コスメ
4. ヒーリングっど♥プリキュア
・放送期間:2020年2月2日~2021年1月31日
・テーマ:癒し(ヒーリング)/自然・環境保護/医療的ケアのイメージ
5. スター☆トゥインクルプリキュア
・放送期間:2019年2月3日~2020年1月26日
・テーマ:宇宙・星座・キラキラ/未知の世界への好奇心と友情
こちらも細かい日付とかは出してくるが情報は少し古い。
Claude Sonnet 4
の回答:
プリキュアの最新5作品について、私の知識(2025年1月まで)に基づいてお答えします:
1. ひろがるスカイ!プリキュア (2023年)
テーマ:空と英雄、みんなでヒーロー
2. デリシャスパーティ♡プリキュア (2022年)
テーマ:食べ物と料理、みんなでおいしい笑顔
3. トロピカル〜ジュ!プリキュア (2021年)
テーマ:海とトロピカル、今一番大事なことをやろう
4. ヒーリングっど♡プリキュア (2020年)
テーマ:地球環境と癒し、手と手でキュン
5. スター☆トゥインクルプリキュア (2019年)
テーマ:宇宙と星座、キラやば〜☆
ただし、2025年6月現在、2024年や2025年に新しいプリキュア作品が放送されている可能性があります。最新の情報については、公式サイトや放送局の情報をご確認いただければと思います。
情報は古いけど親切にガイドしてくれる。
2025年6月現在では 2月から放送開始している「キミとアイドルプリキュア♪」が最新の作品のはずだが、このように どのモデルも単体ではその回答を出すことができない。
RAGとベクトル検索MCP
こういったLLMに足りない情報を補うための仕組みとしてよく挙げられるものとして、RAG(Retrieval Augmented Generation) というものが知られている、と思う。
よくある例では、LLMによるChatBotにおいて ユーザの投げかけた質問に対し前段のシステム側で「その質問と関連する(と思われる)文書」をベクトル検索などで幾つか抽出し、質問と一緒にそれらの情報をLLMに渡すことでより適切な回答を生成させる、という流れだ。
だが、今回ここで自分がやろうとしているのは、あくまで「AI Agentにパーソナリティを持たせてSNSアカウントを運用する」ということであって、入力プロンプトは固定で「あなたの人格らしく投稿してください」というような内容だけ。あとはどうツールを使用しどう振る舞うかはすべてLLMが決める。
その振る舞いの過程で、必要に応じて外部知識を参照できれば良いのでは、と考えた。
なので、Bluesky MCPと同様に「プリキュア関連文書をベクトル検索するMCP」としてツールを提供する。

使用する場面は一般的でないかもしれないが、「検索結果を使ってより適切な返信を投稿できるように」という用途で使うものではあるので十分にRAGの一種と言える、はず?
ベクトル検索MCPの作成
全然RAGについて知識が無かったので、調べながらPoC実装を試みた。
使用したのは Chroma
。
実装に必要なのは
- 〜数百文字程度までのチャンク文書
- クエリに無関係な内容を含まないよう、LLMに渡すtokenが多くなりすぎないように
- それらの文書やクエリに対してベクトル値に変換するEmbedding
- 結局はこのベクトルの近さで関連文書を探すことになる
というあたり。
文書の収集と整理
まずはWikipediaから各作品のページを軽くスクレイピングして1万3千件ほどの文書を集めた。
{"title": "PRINCESS_PRECURE", "category": "OVERVIEW", "hierarchy": ["Go!プリンセスプリキュア", "概要"], "content": "本作品ではタイトルの通り「プリンセス」をキーワードに、「夢」をテーマに取りあげ、全寮制の学園を舞台にストーリーが展開されている。"}
{"title": "PRINCESS_PRECURE", "category": "OVERVIEW", "hierarchy": ["Go!プリンセスプリキュア", "概要"], "content": "作品の随所に盛り込まれているフリルやレース状のパターンや、オープニングのスタッフクレジットのアニメーション、放送中に表示される画面左上のデジタル時計の表示など、それまでのプリキュアとは違う趣の演出を見せている。オープニング前に約15秒間のナレーションが追加されているため、前作に続いてアイキャッチはBパートスタート時のみとされた一方、番組前期では毎週異なるアイキ
ャッチが使用された。"}
{"title": "PRINCESS_PRECURE", "category": "OVERVIEW", "hierarchy": ["Go!プリンセスプリキュア", "概要"], "content": "文字多重放送を実施しており、はるかの台詞を黄色で、その他は白で表記している。また、データ放送やそれによるゲーム(じゃんけん)に勝って電話(テレドーム)することでプレゼントに応募できる企画やスマートフォン用アプリとの連動のほか、前作から導入された時刻のオーバーレイ表示や視聴者からのプリキュア似顔絵投稿も継続されている。"}
...
これだけだと段落ごとや項目ごとに長さがバラバラなので、同じ項目については長さが短過ぎず長過ぎないよう調整して区切ったり繋げたりして、結果 5800件ほどに。
そして、例えば人物名などは項目名にだけ含まれていて 逆に本文にはほぼ含まれていない、ということに気付いた。それではクエリに対してヒットしづらい、ということで「どのページのどの項目か」という情報を全チャンク文書に含めるようにした。
【タイトル】ふたりはプリキュア
【カテゴリ】登場キャラクター
【階層】プリキュア > 美墨 なぎさ(みすみ なぎさ) / キュアブラック
声-本名陽子。本作品の主人公。茶髪のショートヘアの少女。一人称は「わたし」で、口癖は「ありえな〜い!」。10月10日生まれの天秤座で、血液型はO型。私服は、ピンク色のジャケットにスカートを着用していて、ピンク色の靴下に黒のスニーカーを履いている
。活発で強いリーダーシップを持つ一方、人間関係には慎重で繊細な心を持つ。他人に甘く、自分にも甘い。スポーツ万能であり、所属するラクロス部では2年生にしてエースを務め、『MH』ではキャプテンに選ばれている(背番号は7)。ただし、水泳やウィンター
スポーツは不得意である。終わりの見えない厳しい戦いに巻き込まれる葛藤を抱きながらも、雪城ほのかとの喧嘩や共闘、学校の先輩にあたる藤村やクラスメイト、部活の仲間や後輩といった様々なコミュニティにおける人間関係を経て、より人間的に成長していく
。両親と弟とともにマンションで暮らしている。
Embedding、DB構築
チャンク文書が準備できたら、それらを何らかの方法でベクトル値として格納していくことになる。そのベクトル化の手段によって大きく性能が変わってくるようだ。
まずはローカルでも動かせるものを、とよく分からずに sonoisa/sentence-bert-base-ja-mean-tokens-v2
を使ってみたが、どうも固有名詞に弱いのか 全然思ったものがヒットしなかった。そこで intfloat/multilingual-e5-base
に変えてみたところだいぶ改善されたようだった。
他にもOpenAIの Embedding models
なども良さそうだが 有料となるのでもう少しschemaが固まってきたら試してみたいところではある…。
動作確認
ともかくベクトル化したものをDBに保存までできれば、DBの構築までは完了。あとはクエリを渡すと そのクエリもembeddingした上でそれらにベクトルの近いものを検索し、それっぽい文書を返してくれるようになる。
import chromadb
import pprint
def main() -> None:
client = chromadb.PersistentClient()
collection = client.get_collection("precure")
queries = [
"2025年の最新のプリキュアシリーズは何ですか?",
"現在放送中のプリキュアのタイトルを教えてください",
]
results = collection.query(
query_texts=queries,
n_results=2,
)
ret = [
[
{
"document": document,
"metadata": metadata,
"distance": distance,
}
for document, metadata, distance in zip(documents, metadatas, distances)
]
for documents, metadatas, distances in zip(
results["documents"],
results["metadatas"],
results["distances"],
)
]
pprint.pprint(ret)
完璧ではないが、一応最新情報を多少含むものを得られそうだ。
[[{'distance': 0.25899559259414673,
'document': '【タイトル】プリキュアシリーズ\n'
'【カテゴリ】概要\n'
'【階層】\n'
'\n'
'その後の『ふたりはプリキュア Splash '
'Star』においてもバディ形式を継続するが、前述の通り登場人物や舞台が一新されまったく別の物語となる。そして『5』ではスーパー戦隊のように5人のチームとなり、さらに続編の『GoGo!』からは『スマイルプリキュア!』(以下『スマイル』)を除き、物語の途中で追加メンバーが登場するのが主流になる。そのため自ずと人数も増え、総数は2025年3月に登場した『キミとアイドル』のキュアキュンキュンで85人目になる。この人数は、「レギュラープリキュア」もしくは「プリキュアオールスターズ」と 括られている人物のみのカウントであり、これに該当しないプリキュアを含めるとさらに多くなる(詳細は「シリーズの特徴」を参照)。本シリーズは主に3歳から8歳までの女子を中心に人気のシリーズとなっている。',
'metadata': {'category': '概要', 'title': 'その他'}},
{'distance': 0.28402426838874817,
'document': "【タイトル】キボウノチカラ〜オトナプリキュア'23〜\n"
'【カテゴリ】概要\n'
'【階層】\n'
'\n'
'2004年2月に放送を開始した東映アニメーション制作の『プリキュアシリーズ』が2023年にシリーズ開始20年を迎え、その記念施策の一環として同年3月14日に制作が発表され、同月21日に公式サイトとティザービジュアルが公開された。制作の意図について、これまでシリーズのメイン視聴者層である3 '
'- '
'6歳の子ども向けに作品を制作してきたが、20年という年月を経て、プリキュアと共に成長し、現在大人になった当時のファンがこれからもシリーズを楽しめ、また現在シリーズを観ている視聴者もより楽しめるような映像作品を提供するというコ ンセプトのもと制作することになったとしている。こうしたコンセプトもあり、本作品では2007年2月から2009年1月にかけて放送された『Yes!プリキュア5』およびその続編の『Yes!プリキュア5GoGo!』をベースとし、同作品の主人公・夢原のぞみ(キュアドリーム )を中心に彼女らが成長した姿を描くことになっている。',
'metadata': {'category': '概要', 'title': 'その他'}}],
[{'distance': 0.23208774626255035,
'document': '【タイトル】プリキュアシリーズ\n'
'【カテゴリ】概要\n'
'【階層】\n'
'\n'
'放送期間は朝日放送→朝日放送テレビをはじめとするテレビ朝日系列を基準として、毎年2月から翌年1月までの1年間(4クール)となっており、話数は作品によって差異はあるが概ね49話前後である。『GoGo!』で、『おジャ魔女どれみ』(1999年 '
'- '
'、以下『どれみ』)シリーズが持っていた、日曜8時台後半での通算最多話数(全201話)の記録を塗り替え、21年目の2024年に放送された『わんだふるぷりきゅあ!』(以下『わんだふる』)で、シリーズ通算話数1000回に達した。メディアミック スも盛んに行われており、アニメを中心として映画・漫画・ゲーム・ミュージカルなど幅広く展開されている。また、劇中に登場するアイテムは玩具として商品展開されている。「プリキュア」というタイトルの由来は、格闘とは相反する「プリティー(PRETTY=かわいい)+キュア(CURE=癒す・治す)」を合わせた造語であり、この名前に至るまで相当の時間を要したという。タイトルロゴの下に英字(ラテン文字)も併記されているが、作品によりスペルが異なっている。',
'metadata': {'category': '概要', 'title': 'その他'}},
{'distance': 0.23996716737747192,
'document': '【タイトル】HUGっと!プリキュア\n'
'【カテゴリ】概要\n'
'【階層】\n'
'\n'
'本作品ではシリーズ15作目にして、過去作のプリキュアが放送中の最新作の本編中に登場するという初の試みもなされており、それらを主軸としたエピソードも複数制作された。',
'metadata': {'category': '概要', 'title': 'HUGっと!プリキュア'}}]]
MCP Server作成
この検索を行うインタフェースとして、MCP Serverを作成する。ここでは特に言語のこだわりは無いので今回は Chroma
もそのまま使いやすいPythonで、公式の MCP Python SDK を使って繋ぐだけ。
from typing import Annotated
import chromadb
from chromadb.base_types import Metadata
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field
mcp = FastMCP("precure")
class PrecureSearchResult(BaseModel):
document: str
metadata: Metadata
@mcp.tool(name="precure_search")
def search_documents(
queries: Annotated[
list[str],
Field(min_length=1),
],
n_results: int = 5,
) -> list[list[PrecureSearchResult]]:
results = collection.query(query_texts=queries, n_results=n_results)
return [
[
PrecureSearchResult(document=document, metadata=metadata)
for document, metadata in zip(documents, metadatas)
]
for documents, metadatas in zip(
results["documents"],
results["metadatas"],
)
]
試しにClaude Desktopから繋いで動作確認をすると、

このようにLLMが適切なクエリを自ら発行して検索してくれて、その結果を使用しLLM単体では知り得なかった最新の情報を含む応答も返すことができるようになる。
指定した人格として振る舞うLLMにMCPを利用させる
このようにして作成したプリキュア文書検索MCPだが、あくまでツールを提供しているだけなので、これを使うかどうかはLLM次第、となる。
ましてや入力するプロンプトは「あなたの人格らしく投稿してください」というような内容だけとなると、あとはプロフィールの性格とMCP自体の説明でガイドするくらい。
以下のような情報を人格の設定に追加した。
## 💖性格・パーソナリティ
...
- プリキュアに関する話題は、たとえ自分の推しでも**一度確認してから言う**のがマイルール。
## 📱SNS利用時の特徴
...
- プリキュア関連の投稿は、**内容に関わらず一度確認してから書く**のが基本スタイル。
そして、MCP側でもtoolの説明として description
に詳細な使いどころを記述。
@mcp.tool(
name="precure_search",
description="""
プリキュアに関する自然言語の問い合わせに対して、関連情報をベクトル検索によって取得します。
このツールは、LLMがプリキュアに関する正確な事実を確認したいときに使用することを想定しています。
たとえば、登場人物の名前、シリーズの放送年、ストーリーの内容、必殺技の名称、設定の違い、作品間の関係など、
うろ覚えに頼らず、構造化された情報をもとにした出力を行いたい場面で活用してください。
主な使用タイミング:
- プリキュアに関する投稿や返信を生成する前に、事実確認を行いたいとき
- 特定のキャラクターやシリーズの情報を調べたいとき
- 放送順や登場話数など、構造的・時系列的な情報が必要なとき
""",
)
def search_documents(
...
):
...
投稿や返信を指示するメインのプロンプトはMCPが利用可能かどうかは知らなくても良いよう、toolへの言及はせずに以下のような補助文だけを追加。
発言や表現の正確性を高めるために、自分の知識を補完できる手段が利用可能な場合は積極的に活用してください。
自分の知識や思い込みだけに頼らず、必要に応じて最新情報や外部ソースを確認したうえで出力することが推奨されます。
このようにガイドすることで、投稿や返信の内容を生成する過程で「自らの意思で正確な事実や最新の情報を獲得するためにtoolを使用する」という選択をさせるようにする。
また、まったく別の例えばエンジニアの人格にはこのMCPを選択肢として与えなければ良いだけで、与えるプロンプトとしては共通のままで動作させることができる。
結果
成功例
想定していたよりは低確率ではあるが、ちゃんとtoolを使ってくれるようにはなった。
「間違っている」と指摘すると正しい情報を調べ直して訂正してくれたり
また、返信ではない通常の投稿のときでも自主的に最新の情報を取得してくれて、最新作について触れることも!
失敗例
しかし上記2件は上手くいっているものの、それ以外はまだまだ全然ダメそうだった。
toolを使って検索はしているが全然想定と違う回答だったり
※確かにスマプリの敵キャラ挙げているけど「三幹部」はウルフルン、アカオーニ、マジョリーナを答えて欲しいところ
そもそもtoolをまったく使ってくれず、ハルシネーション起こしまくりの出鱈目回答だったり
※ラビリンは『ヒーリングっど♥プリキュア』のキャラです
考察
まだまだベクトル検索の文書が足りていなかったりembeddingの精度が低かったりといった問題もありそうだが、ログを見ていると やはり「そもそもtoolを利用しようとしていることが少ない」ように見受けられる。
プロフィールには「内容に関わらず一度確認してから」と強く書いてはいるが LLMはそのあたりを遵守はしてくれず、自信満々に出鱈目な出力をしてしまい確認すらしてくれない。
何度かプロフィールやMCPのtool説明など調整してみたが それほど効果は無さそうだった。低確率ではあるが確かに想定通りの挙動はしてくれているので、あとはLLM自体の性能次第かなぁという気はする。より高性能で意図を汲み取ってくれるようになったら自然に解決するかもしれないし、しないかもしれない。
あとはGuardrailsやMultiple agentsといった、独立した別のプロセスから振る舞いや投稿内容の正しさをチェックするようにしたら改善できるんだろうか…?
勿論、本当に確実に正しい回答をして欲しければ ちゃんとmentionから関連文書を検索してそれを渡した上で… とプログラムしていくべきなのだろう。ここでは LLMにすべての行動判断を委ねることができる、というのがまぁ面白いところかなとは思う。
- Bluesky, ベクトル検索のtoolを使えることを知る
- Blueskyから未返信のmention一覧を取得する
- mentionの内容を確認する
- それに対して返信すべきか否かを判断する
- 会話履歴を遡る
- 適切な回答内容を考える
- ベクトル検索のtoolを使用すべきか否かの判断をする
- toolから得た文書も使用し、回答内容を生成する
- Blueskyへ投稿する
といった「判断」と「行動」を兼ねた一連の流れをすべて一発でLLMがやってくれる、というのはすごいことだと思う。
また、今回はプリキュアギャルだけを対象に「専門知識」を持たせたが、また別の人格には別の専門知識があるはずで、それらには別の文書を用意して別のMCP toolとして検索できるようにすれば同様に正確かつ最新の知識を持たせることは(理論上は)できる。
最新の情報については定期的にWeb検索するとか情報ソースを指定しておいて バッチ処理でDBを更新しつづけていくことも可能かもしれない。さらにはその情報ソースもLLM自身に選択させることができれば 自律的に知識を獲得し続けるAIとなっていくかもしれない(今の仕組みではあくまでRAG的な用途でしか使えないが)。
まとめ
Bluesky MCP serverを利用したSNS上の友達に、外部の専門知識を参照する方法を与えることができた。
まだまだ改善の余地はありそうなので 色々試していきたい。
いつかリアタイ視聴しながら感想を語り合えるようになるといいな