Skip to main content
Glama

curseforge-ark-mcp

ARK: Survival Ascended 向け CurseForge の Mod キュレーション、発見、アップデート監視のための読み取り専用 MCP サーバー。

これは v0 です。ここにあるものは、実際のレスポンスに対して検証されていません。

CurseForge API キーはまだ存在しません。キーはセルフサービスではなく、Overwolf への申請によって付与されるため、このリポジトリから、誰によっても、いかなる時点でも、認証済みの呼び出しは行われていません。 すべてのフィクスチャとすべてのツール出力のフィールドパスは、公開されたスキーマから読み取った 仮説 です。

これは謙虚さではありません。兄弟リポジトリ nitrado-ark-mcp は同じ慎重な方法でドキュメントからフィクスチャを構築し、コミット 5481c04 では、実際のレスポンスと照合するまで間違っていた 3 つのフィールドパス が修正されました。このリポジトリにも、同様の誤りが 3 つ潜んでいると想定してください。

バージョン番号は 0.1.0 であり、これは検証ステータスに関する主張です。この README には 「実際のアカウントで検証済み」セクションはありません。その欠如は省略ではなく、正確な表現です。

今日検証されているのは、このリポジトリ自身の動作です。エンドポイント許可リスト、ホストの固定、パスの正規化、ページネーションの境界、エンベロープ処理、および 3 状態(不在/空/不明)の規律です。これらはすべて、キーもネットワークもない、注入された偽の fetch に対してテストされています。執筆時点で 146 テスト、0 失敗。

設計記録: docs/adr/ADR-002-endpoint-allow-list.md (ステータス: PROPOSED)。以下のすべてのセクション参照 (§1、§4.3、§14.3 …) はこれを指しています。


できること、そして意図的にできないこと

7 つのツール、すべて読み取り専用:

ツール

回答

search_mods

「この用語に一致する ASA Mod は?」

get_mod

「プロジェクト 777001 とは?」

list_mod_files

「この Mod はどのファイルを公開しているか?」

get_mod_file

「この特定のファイルとは?」

get_latest_file

「現在実行中のファイルよりも新しいファイルはこの Mod にあるか?」

resolve_mod_dependencies

「この Mod は何を引き込むか?」 (バッチ処理、ツリーレベルごとに 1 リクエスト)

get_api_diagnostics

「問題は私か、キーか、それとも CurseForge か?」 — そして「このビルドはどの程度正直か?」

できないこと:

  • 何もダウンロードまたはインストールしません。 GET /v1/mods/{modId}/files/{fileId}/download-url は文書化された読み取りであり、固定されたホスト上にありますが、拒否されます — エンドポイント許可リストにないためです (DEC-002 §11.3)。Nitrado は自身で Mod をインストールします。

  • どこにも何も書き込みません。 許可リストのエントリは、変更を伴うエンドポイントを指定していません。CurseForge は別のホスト上で変更を伴うアップロード API を運用していますが (§14.2)、ホストの固定により、独立した理由で二重に拒否されます。

  • Mod を公開または作成しません。 完全に拒否されます (DEC-002 裁定 2)。これは約束ではなく、起動時のアサーションによって強制されます。ティア 1 以外を宣言するツールを登録すると、プロセスは 起動を拒否します

  • Nitrado に触れません。 このリポジトリの設定画面には NITRADO_* 変数は存在せず、その欠如は制御です。このサーバーは Nitrado トークンを保持せず、Nitrado 設定も読み取りません。

  • タイマーで起動してサーバーを更新しません。 スケジューラ、ポーリングループ、永続化された「最終確認バージョン」状態はありません (§10)。監視とは、モデルが新しいバージョンを 観察 できることを意味します。行動を起こすことはできません。


隘路: メソッドチェックではなく、エンドポイント許可リスト

これは、コードに触れる前に読む価値のある唯一の設計上の決定です。

CurseForge は 読み取りに POST を使用しますPOST /v1/modsPOST /v1/mods/files は一括取得であり、これにより resolve_mod_dependencies はノードごとではなく、依存関係 レベル ごとに 1 リクエストで済みます。したがって、兄弟リポジトリの method !== "GET" → refuse は、ここでは最も高くつく方法で失敗します。それは動作するでしょう。 拒否し、自身のテストに合格し、静かにサーバーを仕事に適さないものにするでしょう。

そして、明白な修正はバグよりも悪いです:

allowed = { GET }          → the batch reads are refused (broken, loudly)
allowed = { GET, POST }    → every request this client can construct is allowed

文書化されたカタログ API には GETPOST しか含まれていません。両方を受け入れるゲートはすべてを受け入れます — 見た目はまともなまま。

そこで代わりに、すべての送信リクエストは、閉じた {method, path} ペアのリスト内の明示的なエントリと一致する必要があります。7 つのエントリ、src/allowlist.ts 内:

#

Method

Path

提供するもの

E1

GET

/v1/games

ゲーム ID 解決、get_api_diagnostics

E2

GET

/v1/mods/search

search_mods

E3

GET

/v1/mods/{modId}

get_modget_latest_file

E4

GET

/v1/mods/{modId}/files

list_mod_filesget_latest_file

E5

GET

/v1/mods/{modId}/files/{fileId}

get_mod_file

E6

POST

/v1/mods

resolve_mod_dependencies (一括読み取り)

E7

POST

/v1/mods/files

resolve_mod_dependencies (一括読み取り)

メカニズム:

  • {method, path} で共同で一致。 E3 は DELETE /v1/mods/123 を許可しません。E6 は POST /v1/mods/123 を許可しません。

  • ホストは固定 されて https://api.curseforge.com になり、その固定は他の名前付きオリジンを拒否するのではなく、1 つのオリジンを 許可 するものです。

  • ID セグメントは [0-9]+ にバインド され、[^/]+ ではありません。これは重要な意味を持ちます。寛容な {modId} は E3 が /v1/mods/search を飲み込んでしまいます。数値バインディングにより、その曖昧さはマッチ順序に依存するのではなく、構造的に不可能 になります。また、リスト全体を逆順にして、順序が救いではないことを証明するテストもあります。

  • チェックの前に 1 回の正規化 が行われ、URL はその出力から構築されます。パーセントデコードを 1 回行い、残った % を拒否し、バックスラッシュを折り畳み、...、空のセグメントを拒否します。

  • E6/E7 のみがボディを運ぶことができ、ディスパッチ前に形状チェックされます。GET エントリのボディは、ドロップされるのではなく拒否されます。

  • resolve_mod_dependencies のみが POST エントリに到達でき (§8)、トランスポートで強制されます。

障害モードは「一致しないリクエストは拒否される」であり、「認識されないリクエストが送信される」ではありません。 機能を追加することは、レビュー可能な 1 行の差分であり、そのレビューの質問 — 「このエンドポイントは読み取りか?」 — は人間が実際に答えられるものです。

それが許可リストであることを証明するテスト

GET /v1/mods/{modId}/files/{fileId}/download-url拒否されます。これは文書化された読み取りであり、GET であり、固定されたホスト上にあり、適切に形成された数値 ID を持っています。リストにないという理由 だけ で拒否されます。そのテストが他の理由 — ホスト固定の拒否、パスの拒否 — で合格した場合、そのプロパティは実装されていないため、テストは単に何かがスローされたことではなく、拒否の コードと詳細 をアサートします。

すべての拒否テストは、偽の fetch呼び出し回数 もアサートします。なぜなら、「リクエストが構築される前に拒否される」が実際の規定であり、ディスパッチ にスローされたエラーはより弱いアサーションを満たすからです。そして、拒否スイートの前には 原像 テストがあり、7 つのエントリすべてがディスパッチされることを証明します。何も送信できないクライアントに対する拒否スイートは完璧に合格し、何も証明しません。


まだ未検証

以下の各行は仮説です。 これらは ADR-002 の §14.3 を完全に再現したものです。フィールドパスは公開されたスキーマから読み取られており、これは兄弟リポジトリで 3 つの誤ったパスを生み出したのとまったく同じアーティファクトクラスです。

#

クレーム

根拠

なぜ重要か

U1

ASA gameId の値

キーなしでは発見不可能 (§5)

間違った値は、クリーンで空の、間違った検索結果を返す

U2

付与されたキーに対してASAがそもそも見えるかどうか

キーなしでは発見不可能

v1全体をブロックする可能性あり

U3

Mod フィールド: id, gameId, name, slug, latestFiles, latestFilesIndexes, dateModified, links, categories, allowModDistribution

公開スキーマ

すべてのツール出力

U4

File フィールド: id, modId, displayName, fileName, fileDate, gameVersions, sortableGameVersions, dependencies, releaseType, isAvailable

公開スキーマ

get_latest_file, list_mod_files

U5

FileDependency = { modId, relationType }

公開スキーマ

resolve_mod_dependencies トラバーサル

U6

FileRelationType 数値列挙型マッピング

未解決。 ドキュメントに対して3回試行。ページには relationType が公開された値テーブルのない裸の整数として表示されている。メモリ、ブログ、またはこのリポジトリからマッピングを取得しないでください

エッジが必須、オプション、ツール、または非互換のいずれであるか、つまりそれがまったくフォローされるかどうかを決定する。resolve_mod_dependencies はこれをブロックする。

U7

FileReleaseType 数値列挙型 (release/beta/alpha)

ドキュメントページからは未解決。部分的な裏付けのみ: アップロードAPIは名前 alpha, beta, release を使用する — これはセットをサポートするが、読み取りAPIの数値マッピングはサポートしない

get_latest_file フィルタリング。alpha を release として扱うことは間違ったアップデート推奨となる

U8

pagination がすべてのページネーション対応エンドポイントに存在するかどうか

文書化された形状。観測されたことはない

このクライアントは1ページを想定するのではなくエラーにする

U9

ASA MODが実際に dependencies, sortableGameVersions, latestFilesIndexes を設定するかどうか

スキーマは可能と言っている。ASA固有の動作は不明

常に空のフィールドはバグではなく機能ギャップであり、3状態ルールではそれらを区別する必要がある

U10

POST /v1/mods / POST /v1/mods/files ボディのID数上限

文書化されていない。 このクライアントの200 ID上限はベンダーではなく当社のもの

チャンク戦略

U11

CurseForge レート制限

文書化されていない。 公開された数値は見つからず

get_api_diagnostics は観測されたヘッダーまたは null を報告し、推測は決してしない

U12

index 0 以降の実際のページネーション動作、および10000上限での動作

文書化された制約のみ

§4.3 の切り捨て開示

U13

ベースURL https://api.curseforge.com

ドキュメント由来

ホストピンはこれに依存する

ツール出力で見られる2つの結果

relationTypereleaseType は生の整数として表示され、決してマッピングされません。 required/optional にも、release/beta/alpha にもマッピングされません。CurseForge はどちらに対しても値テーブルを公開しておらず、間違ったラベルは誰も確認しない方法で間違った依存関係リストまたはアップデート推奨を生成します。したがって、resolve_mod_dependenciesすべてのエッジをフォローし、そのように明示します。つまり、過剰収集し、その出力はそれを明白に述べます。広い網は少なくとも目に見えて広いのです。

get_latest_file では、「最新」の意味を指定する必要があります。 fileDate による最新、ゲームバージョンに一致する最新、特定の releaseType を持つ最新は異なる答えを返し、間違ったものに基づいたMODアップデートの決定は、このリポジトリが対策している自信過剰な間違いのクラスに正確に該当します。selection にはデフォルトがありません:

selection

追加で必要なもの

意味

newest_by_file_date

すべての候補ファイルの中で、fileDate による最新

newest_matching_game_version

game_version

そのゲームバージョンを宣言する最新のファイル

newest_with_release_type

release_type (生の整数)

そのリリースタイプ整数を持つ最新のファイル

名前付きの release/beta/alpha フィルターはありません。U7 が未解決であり、このサーバーはマッピングを発明しないからです。意図した整数を渡してください。

この定義は未解決の製品上の問題です。 ADR-002 の未解決質問2は、これが構築された時点では行われていなかった創設者の決定としてフラグを立てているため、ツールは意見を持つ代わりにパラメータ化されています。答えが到着したとき、それはデフォルトになるか、または1つ少ないバリエーションになります — 書き換えではなく小さな変更です。すべての答えは、使用した順序、フィルタリングした内容、考慮した候補の数、および候補の出所を再述します。


セットアップ

Node 20+ (22で開発)。設定するビルドステップはありません。npm test は最初にビルドします。

npm install
npm test          # builds, then runs the suite — no key, no network
npm run typecheck
npm run smoke     # refuses cleanly until a key exists, naming what it would probe

次に、キーを入手したら:

cp .env.example .env
# set CURSEFORGE_API_KEY, then:
npm run smoke

MCP クライアント設定 (stdio):

{
  "mcpServers": {
    "curseforge-ark": {
      "command": "node",
      "args": ["C:/path/to/curseforge-ark-mcp/dist/src/server.js"],
      "env": { "CURSEFORGE_API_KEY": "your-key" }
    }
  }
}

サーバーはキーなしでは起動を拒否し、検索した両方の場所、正確な変数、およびキーがセルフサービスではないという事実を報告します。クリーンに起動してから7つのツールすべてでエラーを投げる stdio MCP サーバーは、デバッグが悲惨です。

キーについて

APIキーは x-api-key リクエストヘッダーとして送信されます。これは Authorization: Bearer トークンではありません — それは兄弟リポジトリの Nitrado サーバーの方式であり、このリポジトリは意図的に両方をサポートしていません。両方をサポートすると、このコードが CurseForge が文書化したことのない形式で資格情報を送信する可能性があるからです。

キーは アプリケーションから Overwolf に付与され、譲渡不可です。 実用的な結果、そしてこの段落が存在する唯一の理由: 漏洩は失効と再申請を意味し、再申請はキューであり、セルフサービスのリセットではありません。 コーヒーを飲みながら再生成することはできず、他人のものを借りることもできません。それに応じて扱ってください — .env は gitignore されており、.env.example は変数名と空の値を運び、コミットされたファイルにキー値は表示されません。

このリポジトリにはスコープマトリックスはありません。それは見落としではありません: CurseForge は読み取り専用スコープもスコープ選択も公開していないため、マトリックス化するものは何もありません。このサーバーの読み取り専用プロパティは、より狭い資格情報ではなく、独自のエンドポイント許可リストに由来します。また、トークン漏洩のランブックもありません — 漏洩したキーは公開カタログへの読み取りアクセスとクォータ消費を許可します。これは現実的であり、兄弟リポジトリの Nitrado トークン(ゲームサーバーの完全制御と同等と文書化されている)と同じカテゴリではありません。その適正なサイズ設定は ADR-002 §12 で議論されており、反証可能にするためにそこに述べられた1つの主張に依存しています: CurseForge カタログデータは構造的に公開されています。

編集、すべて

一つのルール:APIキーを決してエコーしないこと。 一つの関数src/scrub.tsが、エラーメッセージと上流のボディスニペットに適用されます。リクエストヘッダーはエラーに決して現れません — キーも、編集されたキーも、ヘッダー名のリストも。get_api_diagnosticsはキーが設定されているかどうかを報告し、その値、プレフィックス、長さを決して報告しません


出力を読む前に知っておくべき動作

  • 空は不明ではない。 data: []はCurseForgeが「なし」と答えたことを意味します — 実際の回答であり、クエリがエコーされるため何が何も返さなかったかがわかります。存在しないフィールドはnullであり、決して 0""[]ではありません。完了しなかったリクエスト、または形状が間違っているレスポンスはエラーであり、値ではありません。

  • dataキーがないことはエラーであり、空の結果ではありません。 それを[]に強制すると、壊れた統合が「結果が見つかりません」になってしまいます。

  • ページネーションされたエンドポイントでpaginationがないこともエラーです。 1ページだけをツールが900のMODのうち50をすべてであるかのように報告する方法と仮定すること(U8はまさにこの未解決の問題です)。

  • pageSize > 50は拒否され、クランプされません。同様にindex + pageSize > 10000も拒否されます — そのインデックスでの最大有効ページサイズがメッセージに記載されます。200を要求して静かに50を受け取ったモデルは、ページをセットであるかのように推論します。

  • totalCountが10000を超える場合、ツール出力は末尾がUNREACHABLEであると述べ、その言葉で、ページングではなくフィルターを絞るようアドバイスします。

  • ASAのgameIdは実行時に発見されGET /v1/gamesから取得され、プロセスのライフタイム中キャッシュされます。ハードコードも推測もされません。解決できない場合、サーバーは大声で失敗し、何を検索したか、キーがいくつのゲームを見られるかを示します — gameId必須の検索フィルターであるため、間違ったものを指定するとエラーではなく、きれいで空で完全に間違った結果が返ります。組み込みの候補が間違っている場合はCURSEFORGE_GAME_SLUGを設定してください。

  • resolve_mod_dependenciesは制限されています 深さ4、ノード数400で、サイクル用の訪問済みセットがあります。制限に達すると、結果はtruncated(切り詰められた)として報告され、その言葉で、未探索のフロンティアがリストされます。


リポジトリ構成

src/
  allowlist.ts    THE CHOKEPOINT — seven entries, host pin, normalization, bounds, body checks
  client.ts       the single transport; the ONLY place x-api-key is attached; envelope unwrap
  config.ts       refuse-to-start; no NITRADO_*, no mode switch, no settable base URL
  coerce.ts       empty / absent / unknown, kept apart
  errors.ts       the error taxonomy
  game.ts         runtime gameId resolution (injected, process-lifetime cache)
  registry.ts     ToolDef + tier, and the boot assertion that refuses a non-tier-1 tool
  scrub.ts        never echo the key. That is the whole module.
  probe-plan.ts   one probe per unverified row, asserted complete by a test
  server.ts       stdio entry point
  smoke.ts        the key-arrival command
  tools/          the seven tools
test/             146 tests; fixtures are synthetic in content, structural in shape
scripts/          buildinfo generator, test enumerator

src/buildinfo.ts生成されgitignoreされています。コミットとdirtyフラグがtsc実行のたびにスタンプされ、get_api_diagnosticsによって表面化されます。dist/はgitignoreされており、サーバーはそこから長時間稼働プロセスとして実行されるため、「どのコードがその回答を生成したか?」は実行時にgitからは答えられません — アーティファクトとともに移動する必要があります。

兄弟リポジトリからの逸脱、意図的に記載

ADR-002の未解決質問7と8は、これらが発生する場所で名前を挙げるよう求めています:

  • 同じベースライン、意図的に。 Node ≥20、TypeScript 5.9.3、@modelcontextprotocol/sdk 1.30.0、zod 4.4.3、同じscripts/run-tests.mjs列挙子を介したnode:test。同じレビュアー、同じイディオム、両方を読むコストが低い。

  • @cfworker/json-schemaはここでは依存関係ではありません。 これは兄弟のcron式検証を支えていますが、ここには検証する書き込みパスはありません。

  • registry.tsは構造的に移植され、tierを保持しますが、モード/有効リスト機構は削除します — フィルタリングするものが何もないためです。すべてのツールはティア1であり、すべてのエンドポイントは読み取りです。背後に何もないモード変数は存在しないコントロールを宣伝します。1つの5行のブートアサーションがサブシステムを置き換えます。

  • redact.tsは移植されていません(§12.1)。上記の「編集、すべて」を参照。

  • UNKNOWN_OUTCOMEエラーコードはありません。 兄弟では、PUTへの応答が失われても世界が変わっている可能性があるため必要です。このクライアントが行えるすべてのリクエストは読み取りであるため、タイムアウトは本当に「発生しなかった」ことを意味し、再試行は安全です。

  • npm run smokeはキーがないために拒否した場合、終了コード0で終了します。 拒否は今日それを実行した場合の期待される結果であり、バナーはSMOKE NOT RUNと見逃せないように表示します。パイプラインをキーがない場合に失敗させたい場合は、この終了コードではなくキーでパイプラインをゲートしてください。


関連レコード

兄弟リポジトリnitrado-ark-mcpでは、ここからは読み取り専用 — そのリポジトリの何もこのリポジトリによって変更されていません:

  • docs/decisions/EXECUTIVE-BOARD-2026-08-16-curseforge-mods.md — このリポジトリが実行する理事会議事録(DEC-002)。その議長裁定は拘束力があります。

  • docs/decisions/decision-log.md — DEC-002、および§10が基づくスコープ分割のためのDEC-001。

  • docs/adr/ADR-001-write-path-enforcement.md — ADR-002が移植する形状、および正規化ルール、ブートチェックの推論、起動拒否の推論のソース。

2つのサーバーは独立しています。nitrado-ark-mcp*「これらのプロジェクトIDはactive-modsにあります」と答え、このリポジトリは「プロジェクトXの最新ファイルはv2.1です」*と答えます。モデルは両方を保持します。どちらのサーバーも他方を呼び出さず、どちらも他方の資格情報を保持しません。

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personal…

  • MCP server for doc2mcp documentation, generated by doc2mcp.

  • Official MCP server for Lovable, the AI-powered full-stack app builder.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JShort-bufr/curseforge-ark-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server