Edge Case Museum について
Edge Case Museumは、実装内容に応じて厄介な入力例を探せる開発者向けのケース集です。実行済みのPython・JavaScript再現例を示し、自作関数向けのテストファイルも生成します。
主な機能
- 01実装内容に応じた境界ケース検索
- 02再現コード、出力、原因の確認
- 03修正方法と関連ケースの参照
- 04pytestまたはnode:testファイルの生成
- 05Unicode、日付、解析などの分類
活用シーン
- 01CSVパーサーの見落としやすい入力の調査
- 02金額や通貨の精度処理の確認
- 03ユーザー名のUnicode正規化のテスト
- 04関数向け境界値テストの生成
MCP 対応
ケース検索、個別ケースの確認、分類別表示、テストファイル生成のツールをMCPクライアントに提供します。Pipeworx経由で接続するほか、ローカルのstdio MCPサーバーとして実行できます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://gateway.pipeworx.io/edge-case-museum/mcpclaude mcp add --transport http pipeworx-io-edge-case-museum https://gateway.pipeworx.io/edge-case-museum/mcp{"mcpServers":{"pipeworx-io-edge-case-museum":{"type":"http","url":"https://gateway.pipeworx.io/edge-case-museum/mcp"}}}Cursor で開く{"servers":{"pipeworx-io-edge-case-museum":{"type":"http","url":"https://gateway.pipeworx.io/edge-case-museum/mcp"}}}VS Code で開く{"mcpServers":{"pipeworx-io-edge-case-museum":{"type":"http","url":"https://gateway.pipeworx.io/edge-case-museum/mcp"}}}{"mcpServers":{"pipeworx-io-edge-case-museum":{"serverUrl":"https://gateway.pipeworx.io/edge-case-museum/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
45| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| q | string | いいえ | question の別名。 |
| ask | string | いいえ | question の別名。 |
| text | string | いいえ | question の別名。 |
| input | string | いいえ | question の別名。 |
| packs | array | いいえ | 任意。ルーティング対象をこれらのパックスラッグに限定します(例:["sec-form-d","sec-13f"])。その場合、ルーターは該当パック内のツールのみを選択します。省略すると、デフォルトの全カタログへのルーティングになります。スラッグは list_packs / search_packs / https://pipeworx.io/directory から取得できます。リストにない、または不明なスラッグは無視され、_meta.pack_scope.ignored に記載されます。該当するスラッグが 1 つもない場合は、カタログ全体にルーティングし、_meta.pack_scope.full_catalog:true を設定します(空の回答にはなりません)。 |
| query | string | いいえ | question の別名。 |
| prompt | string | いいえ | question の別名。 |
| message | string | いいえ | question の別名。 |
| question | string | はい | 自然言語での質問またはリクエスト。query、q、prompt、text、input、ask、message をエイリアスとして使用できます。 |
詳細
edge-case-museum
コードは動きます。ただし、これらのとんでもない入力を除けば。
Pipeworx の一部です。AI エージェントを 1808 以上のライブデータソースに接続する MCP ゲートウェイです。これは独立した非公式の連携であり、上流プロバイダーとは提携関係になく、同社の承認を受けたものでも、同社が公開したものでもありません。
Pipeworx の開発元である Mojibake によるものです。
作成中のもの(「ユーザー名の一意性」「CSV アップロードの解析」「金額の保存と合計」「ユーザーのタイムゾーンでリマインダーを予約」など)を伝えると、その種のコードをひそかに壊す入力を返します。各入力が破る前提、正確なバイト列、何が起きるのか、その理由、より安全なパターン、そして実際に実行した出力を使った Python と JavaScript の再現例を示します。さらに、その入力を使って、あなた自身の関数を対象とするテストファイルを作成します。
3つの展示
以下の出力はすべて、コレクション全体を検証するものと同じハーネスでコードを実行して出力したものです(Python 3.14.2、Node.js v22.22.2)。
1. 1つの NaN でリストの残りがソートされないことがある
edge_case_get({ id: "nan-in-sort" })
nan = float("nan")
print(sorted([3, nan, 1]))
[3, nan, 1]
console.log([3, NaN, 1].sort((a, b) => a - b));
[ 3, NaN, 1 ]
「NaN が妙な場所に入る」というだけではありません。3 と 1 の順序が逆のままになります。NaN との比較はすべて false になるため、ソート処理は NaN がすべての値と等しいと見なします。これにより推移性が崩れます(3 は NaN と「等しく」、NaN は 1 と「等しい」ので、3 は 1 と「等しい」)。その結果、アルゴリズムはリストがすでにソート済みだと判断します。Python は、一貫性のない比較に対して何も保証しません。ECMAScript では順序は実装依存です。
2. Python では「01/01/68」は 2068 年、Node.js では 1968 年
edge_case_get({ id: "two-digit-year-century-pivot-mismatch" })
for s in ("01/01/49", "01/01/50", "01/01/68", "01/01/69"):
print(s, "->", datetime.strptime(s, "%m/%d/%y").year)
01/01/49 -> 2049
01/01/50 -> 2050
01/01/68 -> 2068
01/01/69 -> 1969
for (const s of ['01/01/49', '01/01/50', '01/01/68', '01/01/69'])
console.log(s, '->', new Date(s).getFullYear());
01/01/49 -> 2049
01/01/50 -> 1950
01/01/68 -> 1968
01/01/69 -> 1969
Python は 69 を境界とする POSIX の基準に従います。V8 の境界は 50 です。2桁の年は、50 から 68 までを除けば両者の結果は一致します。この範囲では世紀が1つずれます。いくつかの日付をテストしても、おそらく一度も遭遇しません。
3. Intl ではイラク・ディナールの小数桁数はゼロ。ISO 4217 では3桁です。
edge_cases_find({ context: "store and add up money amounts", language: "javascript" })
for (const c of ["USD", "JPY", "BHD", "KWD", "CLF", "IQD", "HUF"]) {
const digits = new Intl.NumberFormat("en-US", { style: "currency", currency: c })
.resolvedOptions().maximumFractionDigits;
console.log(c, digits);
}
USD 2
JPY 0
BHD 3
KWD 3
CLF 4
IQD 0
HUF 0
まず、amount * 100 は JPY では過剰請求(100倍)、BHD では過少請求(10分の1)になるため、誤りです。もう1つの問題は目立ちにくいものです。通貨の小数桁数を Intl に尋ねるという一見わかりやすい修正では、ISO 4217 ではなく CLDR の表示データが返されます。ISO 4217 では IQD は3桁、HUF は2桁ですが、Intl はどちらも0桁と報告します。決済プロセッサーが使う指数を保存してください。フォーマッターから導き出してはいけません。
そして、テストを作成します
edge_cases_test_file({ context: "parse a CSV upload", language: "python" }) は、7つの CSV 展示から8つのケースを含む pytest ファイルを返します。多くの人が最初に書くパーサー、list(csv.reader(io.StringIO(text))) を対象にすると、次のようになります。
PASSED test_edge_case[csv-formula-injection-excel]
PASSED test_edge_case[csv-crlf-trailing-blank-line0]
PASSED test_edge_case[csv-crlf-trailing-blank-line1]
PASSED test_edge_case[csv-quoted-field-with-newline]
PASSED test_edge_case[csv-doubled-quote-escaping]
PASSED test_edge_case[csv-quoted-field-with-comma]
FAILED test_edge_case[csv-utf8-bom-first-header]
FAILED test_edge_case[csv-semicolon-delimited-european-excel]
2 failed, 6 passed
実際に2つのバグがあります。Excel の「CSV UTF-8」として保存されたファイルでは、最初のヘッダーが "name" として返されます。また、小数点にカンマを使うロケールからのセミコロン区切りエクスポートは、1列として解析されます。それぞれの失敗には、原因を説明する展示が示されています。
内容
122 件のエッジケースがあり、すべて少なくとも 1 つの再現コードを実行済みです。
| カテゴリ | エッジケース | 例 |
|---|---|---|
| Unicode | 15 | NFC と NFD のユーザー名、トルコ語のドット付き I、ß の大文字・小文字変換、キリル文字の同形異字、ゼロ幅文字、Zalgo テキスト |
| 日付と時刻 | 18 | 夏時間の欠落時刻と重複時刻、ネパールの +05:45、サモアの存在しない日、うるう秒、2038 年問題、ISO 週年 |
| 浮動小数点数と金額 | 17 | round(2.675, 2)、(1.005).toFixed(2)、銀行家の丸め、通貨の最小単位、-0 の残高 |
| 並べ替えと比較 | 14 | 照合順序とコードポイント、z の後に来るスウェーデン語の å、[10, 9, 1].sort()、真偽値を返す比較関数 |
| ファイル名とパス | 15 | CON.txt、末尾のピリオド、絶対パスを含む os.path.join、NTFS ストリーム、255 バイトのファイル名 |
| 解析 | 15 | CSV の引用符と BOM、JSON の重複キーと 64 ビット ID、WHATWG のバックスラッシュ、有効なメールアドレスが拒否されるケース |
| 整数 | 14 | MAX_SAFE_INTEGER + 1 === MAX_SAFE_INTEGER + 2、parseInt(null, 36)、-7 % 2 |
| 名前と住所 | 14 | 姓に含まれる姓の前置要素、単名、「Null」という姓、先頭にゼロが付く郵便番号 |
ツール
edge_cases_find({ context, language?, limit? })— 実装する内容を平易な言葉で指定すると、関連するエッジケースを返します。それぞれに対象言語の再現コードと、対象を絞り込むためのrefine_tagsリストが付属します。edge_case_get({ id })— エッジケースの詳細を 1 件返します。実行結果とランタイムのバージョンを記録したすべての再現コード、その理由、修正方法、関連するエッジケース、出典が含まれます。edge_cases_browse({ category?, tag? })— カテゴリ(unicode、datetime、float-money、sorting、filenames、parsing、integers、names-addresses)またはタグ(username、csv、money、timezoneなど)でコレクションを閲覧します。edge_cases_test_file({ context, language })— 関連する入力をテストケースとしてまとめた、実行可能な pytest またはnode:testファイルを生成します。スタブを使ってそのまま実行できるので、TODO マークのあるスタブを自分の関数に置き換えると、失敗したテストから確認すべきエッジケースがわかります。
インストール
リモート(セットアップ不要)
{
"mcpServers": {
"edge-case-museum": {
"url": "https://gateway.pipeworx.io/edge-case-museum/mcp"
}
}
}
このエンドポイントでは、共有 Pipeworx ツール(ask_pipeworx、discover_tools など)も利用できます。
ローカル
{
"mcpServers": {
"edge-case-museum": {
"command": "npx",
"args": ["-y", "@pipeworx/mcp-edge-case-museum"]
}
}
}
コレクション全体がパッケージに含まれています。ネットワークへの接続もアカウントも不要です。
認証
キー不要です。
信頼できる理由
- 記憶を頼りに出力を記述していません。 Python と JavaScript の再現コードはすべて、コミット済みのハーネスで実行され、その実行結果が
expected_outputです。verified_withにはランタイム(例:Python 3.14.2、Node.js v22.22.2)を記載しています。動作がバージョンによって変わる場合があるため、どのバージョンで確認したかがわかります。 - ハーネスは失敗することがあり、実際に失敗しています。 期待される出力の文字を 1 つ変更するだけで、差分を示してテストが失敗します。コードまたは出力を変更した後に再実行していない再現コードは、パックに組み込めません。組み込み時にハーネスが記録したハッシュを検証するためです。
- 実行していない環境はその旨を明記しています。 Postgres、Windows、macOS のファイルシステムの動作は、検証済みとはせず、根拠となる情報源とともに
documentedとして記載しています。 - 各エッジケースに仕様またはドキュメントの出典を記載しています。 Unicode の付属書、RFC のセクション、ECMAScript 仕様、IEEE 754 の参考資料、ISO 4217、IANA tz、各言語のドキュメントを参照しています。説明は独自の言葉で記述しています。
データソース
- このコレクションのために Mojibake が作成したエッジケースです。それぞれに根拠とする標準規格またはドキュメントを記載しています。
- 一部の入力は Max Woolf による Big List of Naughty Strings(MIT ライセンス)に由来します。該当するエッジケースでは、出典にその旨を記載しています。
- 実在する人物の名前、住所、連絡先情報は一切含まれていません。名前と住所に関するエッジケースでは、架空の例を用い、命名および住所システムに関する事実を説明しています。
展示項目を追加する
src/exhibits/CATEGORY/ID.json にファイルを1つ追加します(形式を確認するため、既存の展示項目をコピーしてください)。再現例の code を記載し、expected_output は記載しないでください。
node src/harness.mjs --only ID --capture を実行します。各再現例を実行し、実際の出力をファイルに書き込んで記録します。キャプチャされた内容を確認してください。出力が説明の内容と異なる場合、説明が間違っています。
続いて node src/bake.mjs を実行し、プルリクエストを作成してください。ハーネスで実行されていない再現例を含む展示項目は、ベイクされません。
クイックスタート
MCP クライアント(Claude Desktop、Cursor、Windsurf など)に追加します。
{
"mcpServers": {
"edge-case-museum": {
"url": "https://gateway.pipeworx.io/edge-case-museum/mcp"
}
}
}
このエンドポイントが実際に提供するもの
https://gateway.pipeworx.io/edge-case-museum/mcp の tools/list は、上記の表にあるツールに加えて、共有 Pipeworx メタツール(ask_pipeworx、discover_tools、search_within、remember/recall など、ゲートウェイ全体で使えるツール群)も返します。そのため、表示されるツール数はこの表より多くなります。単一パックのエンドポイントには現在、そのパック固有のツールに加えて、約30個の共有ツールが一覧表示されます。接続の initialize 応答には正確な範囲が記載されており、その日の状況を確認する際の正式な情報源となります。
これは意図的な設計であり、偶然に多重化されているわけではありません。メタツールを使うと、このパックで扱っていない質問にも ask_pipeworx 経由でカタログ全体を検索して回答できるため、MCP サーバーをもう1つ追加する必要はありません。現時点では、メタツールなしでパックのエンドポイントをマウントする方法はありません。追加のスキーマによるコンテキストコストがルーティングの利点を上回る場合は、複数のパックエンドポイントではなく、フルゲートウェイに一度接続してください。
または、フル Pipeworx ゲートウェイに接続すると、このパックのツールだけでなく、すべてのパックのツールが直接一覧表示されます。
{
"mcpServers": {
"pipeworx": {
"url": "https://gateway.pipeworx.io/mcp"
}
}
}
どちらの URL も同じゲートウェイと同じ1808以上のデータソースに接続します。異なるのは、どのパックのツールが直接一覧表示されるかだけです。どちらを使っても、ask_pipeworx からすべてのツールにアクセスできます。
MCP クライアントがない場合:HTTP 経由で呼び出す
curl -X POST https://gateway.pipeworx.io/v1/tools/edge_cases_find \
-H 'Content-Type: application/json' \
-d '{"context":"username uniqueness","language":"python"}'
最初の呼び出しにはアカウントは不要です。任意のツールを確認するには、GET https://gateway.pipeworx.io/v1/tools/edge_cases_find を実行します。ツールを探すには、{"query":"..."} を指定して POST https://gateway.pipeworx.io/v1/tools/search_packs を実行します。
スタンドアロン(ゲートウェイアカウント不要)
このパッケージは、ローカルの stdio MCP サーバーとしても実行できます。Pipeworx アカウントも、ゲートウェイへの往復通信も不要です。
{
"mcpServers": {
"edge-case-museum": {
"command": "npx",
"args": ["-y", "@pipeworx/mcp-edge-case-museum"]
}
}
}
または、直接実行して起動することを確認できます。
npx -y @pipeworx/mcp-edge-case-museum
stdin/stdout 経由で MCP を使用し、initialize/tools/list/tools/call に応答します。対象はこのパックのツールのみで、上記のゲートウェイ接続で追加される共有メタツールは含まれません。同じソース、同じツールを使用しますが、ask_pipeworx によるルーティングはありません。
ask_pipeworx の使用
ツールを直接呼び出す代わりに、平易な英語で質問できます。これは、上記のパックエンドポイントとフルゲートウェイのどちらでも使えます。
ask_pipeworx({ question: "your question about Edge Case Museum data" })
ゲートウェイが適切なツールを選択し、引数を自動的に設定します。
詳細
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。