Shelem Scorekeeping について
Shelem Scorekeepingは、ペルシャのトリックテイキングゲームShelemの各ハンドを採点するローカルMCPサーバーです。会話からゲーム記録を行うAIアシスタント向けに、整数演算で採点し、不足や矛盾のある入力を拒否します。
主な機能
- 01各ハンドの得点変動を計算
- 02Mak、スイープ、Shelemのルールに対応
- 03入力を厳密に検証
- 04構造化された結果と説明を返却
- 05ネットワークやデータベースなしで状態を保持せず動作
活用シーン
- 01ハンドの説明からスコアを更新
- 021000点ルールと勝者判定を確認
- 03コマンドラインで1ハンドを採点
MCP 対応
ローカルMCPサーバーとして、STDIO経由でクライアントにcalculate_shelem_scoreツールを提供し、構造化された採点結果を返します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
1掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| bid | integer | はい | 勝ち取ったビッド:100、105、……、165。口頭での略称は先に展開してください("20" は 120 を意味します)。 |
| outcome | any | いいえ | "mak":宣言側がビッドとちょうど同じ点数を獲得した状態。"sweep":守備側が 1 点も獲得しなかった状態。点数フィールドの代わりに使うか、点数フィールドと矛盾しない形で併用してください。 |
| contract | any | いいえ | 165 未満の場合は省略します。ビッドが 165 の場合は必須です:"shelem"、"sare-shelem"、または "normal"(失敗時の採点が異なります)。 |
| hakem_team | any | いいえ | Hakem(宣言者)が所属するチーム:1 または 2。 |
| team1_score | integer | はい | このハンド開始前のチーム 1 の累計スコア。負の値も可。 |
| team2_score | integer | はい | このハンド開始前のチーム 2 の累計スコア。負の値も可。 |
| bidding_team | any | いいえ | ビッドに勝ったチーム:1 または 2。両方が指定される場合、hakem_team と一致する必要があります。どちらか一方は必須です。 |
| bid_successful | any | いいえ | 任意の照合用フラグです。成功 여부は獲得点で判定され、このフラグと一致しない場合はハンドが拒否されます。Mak は成功扱いです。 |
| declarer_points | any | いいえ | 宣言側チームが獲得した点数:0~165 の 5 の倍数。両方が指定される場合、defending_points との合計は 165 である必要があります。 |
| defending_points | any | いいえ | 防御側チームが獲得した点数:0~165 の 5 の倍数。 |
詳細
Shelem スコア記録 MCP サーバー
ペルシャのトリックテイキングカードゲーム、Shelem (شلم) のハンドを採点するローカルの Model Context Protocol サーバーです。AI アシスタントが会話からビッドと結果を読み取り、このサーバーがスコアの変更をすべて決定的な整数演算で行います。アシスタントが自分で計算する必要はありません。
このサーバーは STDIO 経由でお使いのマシン上で動作します。ネットワークアクセスもデータベースも状態もなく、ホスティングも不要です。
- PyPI パッケージ:
shelem-scorekeeping-mcp - MCP Registry 名:
io.github.khaleghika/shelem-scorekeeping(レジストリ検索) - ソース:github.com/khaleghika/shelem-mcp
機能
- 型付き入力と構造化出力を備えた、単一のツール
calculate_shelem_score。 - MCP から独立し、Python 標準ライブラリのみを使用し、浮動小数点演算を一切使わない採点エンジン(
shelem_mcp.scoring)。 - 厳密な検証。情報が欠けている、または矛盾しているハンドには、該当するフィールド名を示すエラーを返します。サーバーがスコアを推測することはありません。
- エンジンの結果から生成される、各ハンドの分かりやすい英語の
explanation。 - 診断情報は stderr のみに書き込まれます。stdout には MCP メッセージ以外は出力されません。
対応する Shelem のルール
ルールの矛盾点とそれぞれの解決方法を含む完全な仕様は、docs/scoring-rules.md に記載されています。同じ文書のペルシャ語版は docs/scoring-rules.fa.md です。
- 各ハンドの合計点は165点です。通常のビッドは100から165まで、5点刻みです。
- Hakem は宣言したチームです。
hakem_teamとbidding_teamは同じチームを指します。 - ビッド達成: Hakem がビッド以上の点を獲得すると、
+bidを獲得します。ディフェンダーは獲得した点数を得ます。 - Mak (مک): Hakem がビッドと同点を獲得した場合です。失敗ではなく、ビッド達成となります。
- スイープ: ディフェンダーが1点も獲得できなかった場合、Hakem は
+2 × bidを獲得します。 - ビッド失敗: Hakem の獲得点がビッド未満の場合、
−bidを獲得します。ディフェンダーが85点以上獲得した場合、Hakem は−2 × bidを獲得します。ディフェンダーは常に獲得した点数を得ます。 - Shelem/sar-shelem(すべての点を取るための165のビッド):成功時は
+330、ディフェンダーが5~80点を獲得した場合は−330、85点以上を獲得した場合は−660です。sar-shelem の得点は Shelem と同じです。 - 通常の165のビッドは通常のルールで採点されるため、ビッドが165の場合はコントラクトを明示する必要があります。
- 1000点ルール: ハンド開始前に1000点以上だったディフェンディングチームは、Hakem がビッドを達成すると0点を獲得します。ビッドが失敗した場合は、獲得した点数を得ます。Hakem であるチームが1000点以上の場合は、通常どおり採点されます。
- 勝利条件: いずれか一方のチームだけが 1165 点以上に達すると、ゲームは終了します。それより低い場合はゲームを続けます。スコアに上限はなく、マイナスの合計も認められます。タイブレークはないため、サーバーが独自にタイブレークを作ることはありません。
インストール
パッケージ名は shelem-scorekeeping-mcp で、インストールされるコマンドも同じ名前です。Python 3.10以降が必要です。
uvx を使用する(推奨)
uv がサーバーをダウンロードし、隔離された環境で実行するため、手動でインストールする必要はありません。
uvx shelem-scorekeeping-mcp --version
pip を使用する
pip install shelem-scorekeeping-mcp
shelem-scorekeeping-mcp --version
python -m shelem_mcp でもサーバーを起動できます。
ローカルのチェックアウトから(パッケージが PyPI に公開される前)
git clone https://github.com/khaleghika/shelem-mcp
cd shelem-mcp
uvx --from . shelem-scorekeeping-mcp --version
引数なしで実行すると、このコマンドは STDIO 上で MCP サーバーを起動し、クライアントを待ち受けます。通常は自分で実行する必要はありません。MCP クライアントが起動します。
オプション:
--log-level DEBUG|INFO|WARNING|ERROR|CRITICALは、stderr に書き込まれる診断情報のレベルを設定します。既定値はWARNINGです。SHELEM_MCP_LOG_LEVEL環境変数でも同じ設定ができます。--versionはバージョンを表示します。
MCP クライアントの設定
Claude Desktop
claude_desktop_config.json を編集します。macOS では ~/Library/Application Support/Claude/claude_desktop_config.json にあります。Windows では %APPDATA%\Claude\claude_desktop_config.json にあります。
{
"mcpServers": {
"shelem-scorekeeping": {
"command": "uvx",
"args": ["shelem-scorekeeping-mcp"]
}
}
}
その後、Claude Desktop を再起動します。pip でインストールした場合は、代わりに "command": "shelem-scorekeeping-mcp" と "args": [] を使用します。
Claude Code
claude mcp add shelem-scorekeeping -- uvx shelem-scorekeeping-mcp
すべてのプロジェクトで利用できるようにするには、--scope user を追加します。または、プロジェクトレベルの .mcp.json をコミットします。
{
"mcpServers": {
"shelem-scorekeeping": {
"type": "stdio",
"command": "uvx",
"args": ["shelem-scorekeeping-mcp"]
}
}
}
Cursor およびその他のクライアント
STDIO サーバーを起動するクライアントであれば、同じ command と args を使用できます。Cursor では、上記の Claude Desktop の設定ブロックを ~/.cursor/mcp.json またはプロジェクト内の .cursor/mcp.json に追加します。
使い方
ゲームの状況を自分の言葉でアシスタントに伝えます。たとえば、「両チームとも1000点です。チーム1がHakemで、入札は20、ちょうど達成しました(مک)。」 と伝えます。アシスタントは口頭での入札「20」を120に展開し、ツールを呼び出します。
{
"team1_score": 1000,
"team2_score": 1000,
"hakem_team": 1,
"bidding_team": 1,
"bid": 120,
"outcome": "mak"
}
サーバーは次の構造化された結果を返します。
{
"updated_team1_score": 1120,
"updated_team2_score": 1000,
"game_finished": false,
"winner": null,
"score_changes": {
"team1": 120,
"team2": 0
},
"explanation": "Team 1 (Hakem) declared a normal bid of 120. Team 1 captured 120 points and Team 2 captured 45. Team 1 captured exactly its bid (Mak), which is a made bid: +120. Team 2 had 1000 before the hand (1000 or more) and the bid was made, so its 45 captured points are withheld: +0. New totals: Team 1 1120, Team 2 1000. Neither team has reached 1165, so the game continues.",
"hand": {
"bid": 120,
"contract": "normal",
"bidding_team": 1,
"hakem_team": 1,
"defending_team": 2,
"declarer_points": 120,
"defending_points": 45,
"bid_successful": true,
"scoring_rule": "bid_made",
"thousand_point_rule_applied": true,
"scoring_note": null
}
}
サーバーはステートレスです。アシスタントが累計スコアを保持し、各ハンドの前のスコアを渡します。過去のハンドを修正する場合は、その時点以降のすべてのハンドを再採点します。
ツールのリファレンス:calculate_shelem_score
入力
| フィールド | 型 | 必須 | 意味 |
|---|---|---|---|
team1_score | integer | はい | ハンド開始前のチーム1の合計点。マイナスの場合もあります。 |
team2_score | integer | はい | ハンド開始前のチーム2の合計点。マイナスの場合もあります。 |
bid | integer | はい | 100、105、…、165。口頭での略称は先に展開する必要があります(「20」は120です)。 |
hakem_team | 1 or 2 | いずれか一方 | Hakem を務めるチーム。 |
bidding_team | 1 or 2 | いずれか一方 | 入札に勝ったチーム。両方が指定されている場合は、hakem_team と一致する必要があります。 |
outcome | "mak" or "sweep" | 3つのうちいずれか | mak:Hakem が入札した点数ちょうどを獲得しました。sweep:ディフェンダーが何も獲得しませんでした。 |
defending_points | integer | 3つのうちいずれか | ディフェンダーが獲得した点数。0~165の5の倍数です。 |
declarer_points | integer | 3つのうちいずれか | Hakem が獲得した点数。defending_points と合計して165になる必要があります。 |
contract | "normal", "shelem", "sare-shelem" | 入札が165の場合 | 165未満の場合は省略します。 |
bid_successful | boolean | いいえ | 照合用です。点数と一致しない場合、そのハンドは拒否されます。 |
「いずれか一方」および「3つのうちいずれか」は、そのグループ内のフィールドを少なくとも1つ指定する必要があることを意味します。複数指定する場合は、それらが一致している必要があります。
bid_successful だけではハンドを採点できません。Hakem の得点はディフェンダーが何も獲得しなかったか、85点以上を獲得したかによって決まり、ディフェンダーの得点は獲得した点数です。そのため、このツールには獲得点数、または outcome も必要です。
出力
| フィールド | 型 | 意味 |
|---|---|---|
updated_team1_score | integer | ハンド終了後のチーム1の合計点。 |
updated_team2_score | integer | ハンド終了後のチーム2の合計点。 |
game_finished | boolean | いずれか一方のチームが1165点以上に達した場合は true です。 |
winner | 1, 2 or null | ゲーム終了時にのみ設定されます。 |
score_changes | {team1, team2} | このハンドで各チームが獲得または失った点数。 |
explanation | string | 採点内容を平易な英語で説明します。 |
hand | object | 詳細:確定した入札、コントラクト、チーム、獲得点数、bid_successful、scoring_rule、thousand_point_rule_applied、scoring_note。 |
scoring_rule は sweep_double、bid_made、bid_failed、heavy_failure、shelem_made、shelem_failed、または shelem_heavy_failure のいずれかです。
エラー
入力が無効な場合は、isError: true を含むMCPツールの結果と、(field: <name>) で終わるメッセージが返されます。たとえば、次のとおりです。
bid must be from 100 through 165 in steps of 5. Abbreviated spoken bids are not accepted. (field: bid)
エラーが発生した場合、スコアは返されません。いずれかのチームがすでに1165点以上の場合、そのゲームは終了しているため、このツールはハンドの採点を拒否します。
MCP を使わずにエンジンを使用する
from shelem_mcp.scoring import calculate, explain
result = calculate({"team1_score": 0, "team2_score": 0, "bidding_team": 2, "bid": 135, "defending_points": 35})
print(result["team1_score"], result["team2_score"]) # 35 -135
print(explain(result))
python -m shelem_mcp.scoring < hand.json を実行すると、コマンドラインでJSONから1ハンドを採点できます。
開発とテスト
uv venv
uv pip install -e ".[dev]"
uv run pytest
テストでは、以下を確認します。
tests/test_scoring.pyではエンジン単体をテストします。ソースルールにあるすべての計算例、各境界値(999 と 1000、1160 と 1165、防御ポイントの 80 と 85)、Mak、スイープ、Shelem、検証、複数ハンドのゲーム、1000-1000 Mak の回帰テストを対象とします。tests/test_mcp_tools.pyでは MCP 層をテストします。ツールの検出とスキーマ、プロセス内および実際の STDIO サブプロセスでの呼び出し(従来のinitializeハンドシェイクと 2026-07-28 プロトコルの両方)、stdout にプロトコルメッセージのみが出力されることを確認する生の JSON-RPC、公式レジストリスキーマに照らしたserver.jsonの検証、この README の例と実際の出力との照合を対象とします。
配布物をビルドするには、次のコマンドを実行します。
uv build
uvx twine check dist/*
公開
server.json では、現行のレジストリスキーマ https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json を使用します。これは STDIO を使用するローカルの PyPI パッケージです。リモートエンドポイントはありません。このファイルの先頭にある mcp-name コメントは、PyPI の公開時に確認される所有権の証明です。
現行のレジストリガイドは以下のとおりです。
GitHub Actions
v0.1.0 などのタグをプッシュすると、.github/workflows/publish-mcp.yml が実行されます。タグ、パッケージのバージョン、server.json にある2つのバージョンフィールドは、すべて同じ値である必要があります。このワークフローはテストとビルドを実行し、PYPI_API_TOKEN という名前のリポジトリシークレットを使って shelem-scorekeeping-mcp を PyPI に公開した後、mcp-publisher v1.8.6 でこのリポジトリの server.json を公開します。バイナリは実行前に Sigstore バンドルで検証され、GitHub OIDC(login github-oidc)で認証されます。レジストリトークンはリポジトリに保存されません。
pypi.org/manage/account/token で PyPI トークンを作成します。プロジェクトが作成されるまではスコープに Entire account を選択し、作成後、GitHub Actions のシークレット PYPI_API_TOKEN として追加します。
git tag v0.1.0
git push origin v0.1.0
リリースを確認します。
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.khaleghika/shelem-scorekeeping"
手動での公開
クイックスタートから mcp-publisher をインストールし、まずパッケージを PyPI に公開してから、次を実行します。
mcp-publisher validate
mcp-publisher login github
mcp-publisher publish
validate は server.json を現在のレジストリに照らして検証しますが、公開はしません。
ライセンス
MIT。詳しくは LICENSE をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。