IYT Test について
IYT Test は、Telegram ミニアプリ、ウェブサイトのコンテンツ、公開読み取り専用 MCP サーバーを通じて、セーリング資格や競技規則の学習を支援します。セーリング学習者や AI アシスタント向けに、問題集、理論記事、模擬試験、解答確認、図を英語とロシア語で提供します。
主な機能
- 01複数のセーリングレベルの問題集
- 02模擬試験と解答確認
- 03理論記事とセクション検索
- 04SVG のセーリング図
- 05英語とロシア語のコンテンツ
活用シーン
- 01セーリングレベル別の問題を練習
- 02資格試験の模擬試験を実施
- 03解答に関連する理論を復習
- 04学習用のセーリング図を取得
MCP 対応
公開リモート MCP サーバーは、読み取り専用ツールで問題集、理論記事、解答、試験、図を提供します。ログイン不要でユーザー状態を保存せず、`en` と `ru` の言語引数に対応します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://iyt.rycrentals.com/api/mcpclaude mcp add --transport http nikolai-shilin-iyt-test https://iyt.rycrentals.com/api/mcp{"mcpServers":{"nikolai-shilin-iyt-test":{"type":"http","url":"https://iyt.rycrentals.com/api/mcp"}}}Cursor で開く{"servers":{"nikolai-shilin-iyt-test":{"type":"http","url":"https://iyt.rycrentals.com/api/mcp"}}}VS Code で開く{"mcpServers":{"nikolai-shilin-iyt-test":{"type":"http","url":"https://iyt.rycrentals.com/api/mcp"}}}{"mcpServers":{"nikolai-shilin-iyt-test":{"serverUrl":"https://iyt.rycrentals.com/api/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
IYT テスト
IYT 認定レベル向けの練習問題です。Telegram ミニアプリとウェブサイトで提供します。各問題は「前方にこの標識が見えます。安全な水域はどこですか?」のような状況を示し、可能な場合は図で表します。選択肢は4つで、ルールを示す1行の注記が付きます。最初のレベルは Bareboat Skipper(100問、10トピック)です。
ステータス(2026-11-02):デザインと問題バンクが完成しました。Telegram ミニアプリ(練習、模擬試験、進捗、プロフィール)と小規模なボットを開発し、デプロイ済みです(Vercel)。ウェブサイトは未着手です。
リポジトリの内容
README.md this file
docs/
PLAN.md goal, decisions, next steps
question-bank.md JSON format of a bank, authoring rules, how to build it
figures.md the figure spec: every type, its fields, an example
figure-style.md the agreed look of the rendered figures (cameras, looks, own boat, lights, annotations)
design.md look & feel, components, the 21 screens, how to use the viewer
data-model.md proposed database (Supabase) and how progress is computed
theory.md the theory articles: format of an article, authoring rules, check and build
superpowers/plans/ implementation plans (theory articles: 2026-11-05-theory-articles.md)
design/
flows.html hi-fi user flows (viewer: pages / overview, day / night)
questions.html the whole bank as the student sees it, filter by topic
flows.css flows.js viewer + test UI pieces
app.css app tokens and base components (day and night)
test-icons.js the app's icon set (24 grid, 2 px line) + svg()/paintIcons(), shared by the viewer and the app
icons.html the icon sheet: every glyph at 24 px and in the topic circle, day / night
icons.js older base set (Telegram chrome in the mockups; a few basics follow Lucide)
figures.js figure generator (JSON spec → SVG)
figure-style-spike.html reference renderer for figure-style.md (three.js from a CDN; open over HTTP)
figure-schematic.js plan-view schematic renderer (the companion diagram to every realistic figure)
figure-style/ sample renders of the ten example questions; hires/ at 2560 × 1600, schematic/ their plan views
logo-black.svg RYC logo
data/
build_bank.py source of the Bareboat Skipper bank — edit here, then run
build_level.py builds the other levels from bank/<level>/<topic>.json (+ .ru.json)
bank/<level>/<topic>.json VHF Radio Operator, International Crew, Flotilla Skipper: 20 questions per topic; Charter Check-in: 50; Yachtmaster Coastal, Offshore and Ocean, Racing Rules of Sailing: 100
questions/<level>.json the built banks the apps read
questions/<level>.ru.json Russian translation of each bank (overlay)
i18n.py extract strings to translate / check an overlay
theory/<level>/<topic>.json theory articles, one per topic of every level (+ .ru.json): 90 in all, each with figures
check_theory.mjs checks the articles against docs/theory.md and the banks (npm run check:theory)
miniapp/
index.html app.js app.css the Telegram mini app (static, no framework, no backend)
build.mjs builds miniapp/dist (the folder to host): the app, design files, fonts and minified banks,
each linked file renamed after its content (h/…) so phones cache it for good, and the
list of banks written into index.html so only the current level's bank loads at start
fonts/ Merriweather and Carlito (woff2, Latin + Cyrillic, OFL), served with the app
pages.mjs site.css the site around the app: a page per level and per theory article (EN + RU), sitemap, llms.txt
site.mjs the public address, the bot and the IndexNow key
indexnow.mjs npm run seo:ping: tells Bing and Yandex which pages changed
bot/
core.mjs the bot's replies: /start /exam /progress /settings open the app, /daily asks a question
daily.mjs the daily question of the day to everyone who has it on
bot.mjs runs core.mjs by long polling (local testing)
scripts/setup.mjs sets the bot's name, descriptions, commands and menu button
scripts/webhook.mjs points Telegram at the Vercel webhook, or removes it
api/
telegram.mjs Vercel function: Telegram's webhook, runs core.mjs
daily.mjs Vercel cron (09:00 UTC daily): runs bot/daily.mjs
settings.mjs the app's question-of-the-day switch (users.daily_question), checked with Telegram initData
admin.mjs every student's results, flagged and reported questions (admins can take a flag off), joins/answers/wrong answers per hour and day for the admins (ADMINS in settings.mjs — @fullcrimp; ADMIN_USERNAMES adds more)
mcp.mjs the MCP server: the banks and the theory articles as tools for AI assistants (public, read-only)
ミニアプリ
npm run dev # http://localhost:5173 — works in a normal browser too
画面は docs/design/flows.html に従っています。A1–A9 は練習(設定シート、確認 → 解説 → 次へ、結果、間違えた問題)、B1–B5 は模擬試験(全トピックから出題される40問、アプリを閉じている間は一時停止するタイマー、フラグ+グリッド、合否)、C1 は進捗、C2 はプロフィール(テーマ、シャッフル、リセット)です。習熟度は同じ問題に2回連続で正解すると達成となります。進捗は Telegram CloudStorage(ブラウザーでは localStorage)にユーザーごとに保存されるため、現時点ではサーバーやデータベースはありません。Telegram 内ではネイティブの戻る、メイン、セカンダリボタンとハプティクスを使用し、Telegram の外では同じバーを描画します。
ディープリンク:?screen=exam|progress|profile|practice|level、または同じ値を指定した startapp=。
言語:英語とロシア語のインターフェースに対応しています(プロフィールで切り替えるまでは Telegram の言語設定に従います。選択した言語はテーマと同様に保存されます)。1000問すべてが data/questions/bareboat-skipper.ru.json に翻訳されています(用語についてはdocs/glossary-ru.mdを参照)。詳しくはdocs/question-bank.mdをご覧ください。
https://iyt.rycrentals.com で公開中で、@iyt_test_bot に接続されています。ボットのメニューボタンからアプリを開けます。また、ボット自体も同じ Vercel プロジェクト上のウェブフック(api/telegram.mjs)として動作します。最初から再設定するには、以下の手順を実行します。
.env.localにTELEGRAM_BOT_TOKEN、WEBAPP_URL、TELEGRAM_WEBHOOK_SECRET(openssl rand -hex 32)を設定し、Vercel プロジェクトの Production 環境にも同じ3つを設定します。npx vercel deploy --prodを実行します。miniapp/distをビルドし、ウェブフック関数も同じ場所にデプロイします。npm run bot:setupを実行します。名前、説明、コマンド、メニューボタン(アプリへのリンク)を設定します。 次に、@BotFather でボットを Main Mini App に設定します(Bot Settings → Configure Mini App → Enable Mini App、WEBAPP_URLを送信)。ボットのプロフィールに「開く」ボタンが表示され、t.me/iyt_test_bot?startapp=<screen>リンクからアプリを直接開けるようになります。Telegram にはこれを設定する API がありません。npm run bot:setup -- --checkを実行すると、有効になっているか確認できます。npm run bot:webhookを実行し、Telegram が更新をWEBAPP_URL/api/telegramに送信するよう設定します(-- --checkを付けると状態を確認できます)。
ボットの変更をローカルで試すには、npm run bot:webhook -- --delete を実行してから npm run bot(ロングポーリング)を実行します。終了後に再度 npm run bot:webhook を実行してください。Telegram はウェブフックまたはポーリングのいずれか一方にのみ配信します。
今日の問題
毎日(Vercel cron、UTC で 0 9 * * * — ドバイ時間 13:00、モスクワ時間 12:00)、ボットは有効にしている各ユーザーに、A〜D のボタン付きのテキスト問題を 1 問送信します。回答と解説は同じメッセージに返されます。その日に出題される問題は全員同じです。ボットは、メッセージを送信した各ユーザーを Supabase の users に保存します(daily_question はデフォルトで有効)。
- ユーザーごと:今日の問題の下、および
/settingsに切り替えボタンがあります(「今日の問題:オン/オフ」)。 - ボット全体:Vercel の環境変数で
DAILY_QUESTION=offにすると、全員への送信が停止します(ユーザー個別の設定はそのままです)。 - ボットをブロックしたユーザーにはその旨が記録され(
blocked_at)、再びメッセージを送信するまで配信対象から除外されます。
Vercel で必要なもの:SUPABASE_URL、SUPABASE_SECRET_KEY、CRON_SECRET(openssl rand -hex 32)、およびマイグレーション supabase/migrations/20261102150000_daily_question.sql。試すには、npm run bot:daily -- --to <your chat id> を実行します(ロシア語にするには --ru を追加)。今日の問題が指定したチャットに送信されます。npm run bot:daily -- --dry を実行すると、配信対象の人数を数えます。
このバージョンには含まれません(docs/data-model.md にある Supabase バックエンドが必要です):DE/ES、連続記録リマインダー、ウェブサイトとのデバイス間同期、理論解説、共有画像。
検索エンジンと AI アシスタント
検索エンジンや多くの AI クローラーは JavaScript を実行せずにページを読み込むため、ビルドではアプリに加えて、サイトをプレーンなページとして書き出します(miniapp/pages.mjs。アプリ独自の CSS に重ねて miniapp/site.css でスタイルを設定)。公開先は https://iyt.rycrentals.com です(miniapp/site.mjs の SITE)。
| アドレス | ページ |
|---|---|
/ | アプリ。<noscript> 内の Home のコピーから、すべてのレベルにリンクします |
/<level> | レベル:問題、トピック、模擬試験、および記事付きの全トピック |
/<level>/<topic> | トピックの理論記事と図、その後にサンプル問題(各セクションにつき 1 問。図がある場合は図付き)と、回答、解説、および説明セクションへのリンク |
/about | IYT Test の内容と対象外の内容、著者、MCP サーバー |
/ru、/ru/<level>、/ru/<level>/<topic>、/ru/about | 同じ内容のロシア語版。/ru にはレベルの一覧が表示されます |
各ページには専用のタイトルと説明、canonical リンク、別の言語版への hreflang リンク、リンクプレビュー用タグ、および構造化データ(パンくずリスト、トピックページの Article と Quiz)があります。手作業で記述するのは pages.mjs 内の文字列だけです。新しい記事やレベルを追加すると、次回のビルドでページが生成されます。各セクションの冒頭文(docs/theory.md の qa。学習者が尋ねそうな質問に 1、2 文で答えるもの)は、見出しの下と、検索エンジンや AI アシスタントが引用する文章を含むページの FAQPage データに追加されます。ビルドではさらに、robots.txt(AI クローラーを名指しして許可します。コンテンツは無料で、MCP サーバーも提供しているため、検索と学習の両方を許可します)、sitemap.xml(各ページと別言語版)、llms.txt(AI アシスタント向けのサイトマップ)、404.html、IndexNow キーファイル、pages.json(各アドレスとそのページのハッシュ)も書き出します。npm run dev は、Vercel と同様に(cleanUrls)、ページを拡張子なしのアドレスで配信します。
本番環境にデプロイした後:
npm run seo:pingを実行すると、前回の通知以降に新規作成、変更、削除されたページを Bing と Yandex に(IndexNow 経由で)通知します(公開中のpages.jsonと、git の対象外であるminiapp/.indexnow-sent.jsonを比較します)。-- --dryを付けると対象の一覧を表示し、-- --allを付けるとすべてのページを送信し、-- --checkを付けるとキーファイルが公開されているかだけを確認します。- 手動で一度だけ設定します(いずれも自分のアカウントが必要です):Google Search Console に
iyt.rycrentals.comを追加し、指定された DNS TXT レコードで確認します(rycrentals.comゾーンに設定)。その後、sitemap.xmlを送信します。次に、Bing Webmaster Tools で「Import from Google Search Console」を選択します。最後に、Yandex Webmaster でサイトを追加し、DNS またはメタタグで確認して、サイトマップを追加します。
MCP サーバー
api/mcp.mjs は、問題バンクと理論記事を AI アシスタント(Claude、ChatGPT、およびModel Context Protocolに対応するその他のもの)に提供します。学生は https://iyt.rycrentals.com/api/mcp をリモート MCP サーバー(カスタムコネクター)として追加し、自分のアシスタントで学習できます。これは公開されており、読み取り専用です。サインインは不要で、何も保存されず、アプリがすでに提供しているものだけを返します。
接続方法は https://iyt.rycrentals.com/mcp に記載されています(miniapp/pages.mjs の mcpBody にあり、ツール一覧もあります。ツールを追加したら、そこに行を追加してください)。アプリのホーム画面では、フィードバックカードの上にあるカードからこのページにリンクしています。
サイト、アプリ、ボット、サーバーがユーザーについて保存する情報は https://iyt.rycrentals.com/privacy に記載されています(miniapp/pages.mjs の文字列、privBody)。いずれかが新たな情報を保存するようになったら、ここを変更してください。
| ツール | 提供する内容 |
|---|---|
list_levels | レベル、トピック、試験の設定、記事があるトピック |
get_questions | レベル、トピック、難易度を指定したランダムな問題(答えは含まれません) |
check_answer | 正誤、正解の選択肢、注記、および解説が載っている理論セクション |
search_questions | 単語で検索した問題 |
start_mock_exam, grade_exam | トピック全体にわたる試験相当の問題セット。その後、得点、合格または不合格、間違えた問題、読むべき内容を返します |
question_of_the_day | その日にボットが送信する問題 |
list_theory, get_theory, search_theory | 記事とそのセクション。図へのリンク付きのテキストとして提供します |
explain_question | 答えと、その根拠となるセクションを含む問題 |
practice_section | 理論セクションで扱う問題 |
get_figure | SVG マークアップ形式の図 |
すべてのツールは lang(en または ru)を受け取ります。まだ翻訳されていない内容は英語で返されます。図にはそれぞれ専用のアドレスがあります。問題の図は /api/mcp?figure=bs-001、理論セクションの n 番目の図は /api/mcp?figure=<level>/<topic>/<section>/<n> です。図は docs/design/figures.js により、当日の色を指定して描画される SVG 画像です。カードの図(スクリプト、チェックリスト)はテキストとして提供されます。
依存関係も状態もありません。この関数は HTTP 経由で JSON-RPC(initialize、tools/list、tools/call)に応答し、同梱された問題バンク、記事、figures.js を読み込みます(vercel.json → includeFiles)。そのため、デプロイすると新しい記事がアシスタントに反映されます。デプロイに対して試すには、次を実行します。
curl -s https://iyt.rycrentals.com/api/mcp -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_questions","arguments":{"level":"bareboat-skipper","count":1}}}'
公式 MCP Registry には、server.json に基づいて io.github.nikolai-shilin/iyt-test として登録されています(Glama と PulseMCP はレジストリの内容を複製します)。新しいツールや変更した説明は、新しい version(api/mcp.mjs の serverInfo.version も同様)とともに公開します。公開済みのバージョンは変更できません。
brew install mcp-publisher
mcp-publisher validate
mcp-publisher login github # as nikolai-shilin: the name must start with io.github.<your GitHub login>/
mcp-publisher publish
表示する
画面を確認するには、docs/design/flows.html をブラウザーで直接開きます。questions.html は問題バンクの JSON を読み込むため、ローカルサーバーが必要です。
npx serve docs/design # then http://localhost:3000/questions.html
フロー内では矢印キーでページを移動します。#A4、#D1 は画面へのリンクです。「Overview」を選ぶと、すべてのレーンを一度に表示します。
問題を編集する
問題は data/build_bank.py に Python の呼び出しとして記述されています(問題、正解、3 つの誤答、注記、参照先、図の仕様)。これを実行すると、答えが A~D に均等に分散された JSON が再生成されます。
python3 data/build_bank.py
その後、questions.html を再読み込みして問題を確認します。形式とルールについては、docs/question-bank.md を参照してください。
図の種類については、docs/figures.md を参照してください。
レベル
| レベル | 問題数 | ステータス |
|---|---|---|
| VHF Radio Operator | 200 (10 トピック × 20) | 完了 — data/questions/vhf-radio-operator.json |
| International Crew | 200 (10 トピック × 20) | 完了 — data/questions/international-crew.json |
| Flotilla Skipper | 200 (10 トピック × 20) | 完了 — data/questions/flotilla-skipper.json |
| Bareboat Skipper | 1000 (10 トピック × 100) | 完了 — data/questions/bareboat-skipper.json |
| Racing Rules of Sailing (IYT のコースではありません) | 1000 (10 トピック × 100) | 完了 — data/questions/racing-rules.json |
| Charter Check-in (IYT のコースではありません) | 500 (10 トピック × 50) | 完了 — data/questions/charter-checkin.json |
| ICC (International Certificate of Competency) | — | 予定 |
| Yachtmaster Coastal | 1000 (10 トピック × 100) | 完了 — data/questions/yachtmaster-coastal.json |
| Yachtmaster Offshore | 1000 (10 トピック × 100) | 完了 — data/questions/yachtmaster-offshore.json |
| Yachtmaster Ocean | 1000 (10 トピック × 100) | 完了 — data/questions/yachtmaster-ocean.json |
順序は IYT のコース進行に沿っています。 Racing Rules of Sailing(World Sailing、2025–2028;Russian Sailing Federation によるロシア語版 ППГ-25)は、レースコース上の状況(優先権、マークルーム、スタート、ペナルティ、プロテスト)を扱うため、IYT のレベルの後に続きます。Charter Check-in は、ベースでの土曜日に行うチェックインです。書類と契約、艇の確認、セール、エンジン、電気系統、水とガス、計器、安全装備、アンカー関連装備とディンギー、備品、デポジット、金曜日のチェックアウトを扱います。
問題は学習用に作成されたもので、IYT の公式試験問題ではありません。模擬試験のデフォルト設定(Bareboat Skipper と Flotilla Skipper は 60 分で 40 問、Yachtmaster Coastal と Offshore は 90 分で 50 問、Yachtmaster Ocean は 120 分で 50 問、VHF と International Crew は 45 分で 30 問、合格点は 70 %)は、公開前に最新の IYT 試験に照らして確認する必要があります。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。