Game Asset Finder MCP
# Game Asset Finder MCP
[](https://github.com/sudoriaa/game-asset-finder-mcp/actions/workflows/ci.yml)
[](LICENSE)
一个面向游戏开发的“搜索优先”MCP 服务。它同时查询多个公开素材源和可选的本地素材库,把不同站点的结果统一成同一套字段,并做中文关键词扩展、许可证归一化、相关性排序、跨源去重、来源均衡、缓存和游标分页。
项目基于当前 MCP TypeScript SDK v2,使用 stdio 运行,适用于 Codex、ChatGPT 桌面端及其他支持本地 MCP 的客户端。
## 设计与优化
项目采用 provider 注册表和统一结果模型,并重点优化了跨来源搜索层:
- 单个来源失败不会拖垮全局搜索,响应会明确标记各来源状态。
- 关键词权重和中英文游戏术语扩展提升了中文查询的召回率。
- 加入 TTL/LRU 缓存、相同并发请求合并、provider 总时限、有限重试和 `Retry-After`。
- 加入统一许可证过滤、规范 URL 去重、镜像来源合并、稳定排序和来源多样化。
- 用 `limit + nextCursor` 分页,避免一次把大量结果塞进模型上下文。
- 本地索引采用增量扫描、SHA-256、原子写入、允许根目录约束和符号链接跳过。
- 工具面压缩为 4 个,降低代理选错工具的概率。
## 数据源
| id | 内容 | 凭据 | 许可证特点 |
| --- | --- | --- | --- |
| `kenney` | 2D、3D、UI、音频、字体素材包 | 无 | CC0 |
| `opengameart` | 2D、3D、音乐、音效 | 无 | 每个条目不同 |
| `itch` | 免费游戏素材列表 | 无 | 每个作者/页面不同 |
| `openverse` | 图片、纹理、图标参考 | 无 | CC / 公共领域 |
| `ambientcg` | PBR 材质、HDRI、3D | 无 | CC0 |
| `polyhaven` | 纹理、HDRI、3D | 无 | CC0 |
| `freesound` | 音效、录音 | `FREESOUND_API_KEY` | 每个条目不同 |
| `local` | 配置目录中的本地素材 | 本地目录 | 由 sidecar 描述 |
任何远程来源都可能临时超时或限流。返回值中的 `sourceStatuses` 会逐源给出 `ok / partial / disabled / timeout / rate_limited / error`;其他成功来源仍然返回结果。
## 安装
要求 Node.js 20.18.1 或更高版本。
```powershell
git clone https://github.com/sudoriaa/game-asset-finder-mcp.git
cd game-asset-finder-mcp
npm ci
npm run build
npm test
```
也可以执行:
```powershell
.\install.ps1
```
直接启动:
```powershell
node .\dist\index.js
```
stdio 的标准输出是 MCP JSON-RPC 通道,服务日志只写入标准错误。
## 接入 Codex
在 `~/.codex/config.toml` 或可信项目的 `.codex/config.toml` 中加入:
```toml
[mcp_servers.game_assets]
command = "node"
args = ["C:\\path\\to\\game-asset-finder-mcp\\dist\\index.js"]
cwd = "C:\\path\\to\\game-asset-finder-mcp"
startup_timeout_sec = 30
tool_timeout_sec = 90
enabled = true
[mcp_servers.game_assets.env]
GAME_ASSET_LOCAL_ROOTS = "D:\\GameAssets;E:\\SharedAssets"
GAME_ASSET_CACHE_TTL_SECONDS = "600"
```
如果启用 Freesound,建议从本机环境转发密钥,而不是把值写进配置:
```toml
[mcp_servers.game_assets]
env_vars = ["FREESOUND_API_KEY"]
```
也可以用 Codex CLI 添加 stdio server:
```powershell
codex mcp add game-assets -- node "C:\path\to\game-asset-finder-mcp\dist\index.js"
codex mcp list
```
保存配置后重启客户端,再用 `/mcp` 查看连接状态。仓库中的 [mcp-config.example.toml](mcp-config.example.toml) 可直接复制修改。
## MCP 工具
### `search_game_assets`
跨源搜索。主要参数:
```json
{
"query": "像素风地牢角色",
"types": ["sprite", "tileset"],
"sources": ["kenney", "opengameart", "itch"],
"formats": ["png"],
"tags": ["retro"],
"license_policy": "commercial",
"include_unknown_license": false,
"limit": 12,
"refresh": false
}
```
`license_policy` 可取:
- `any`:显示所有结果,并明确标记未知许可证。
- `commercial`:只保留已知可商用的许可证;可用 `include_unknown_license` 放回未知项。
- `cc0`:只保留 CC0 / Public Domain Mark。
- `no-attribution`:只保留已知可商用且无需署名的条目。
下一页把返回的 `nextCursor` 原样放进 `cursor`,其他查询参数保持不变。修改查询条件后继续使用旧游标会返回 `CURSOR_QUERY_MISMATCH`。
`hasMore` 表示当前缓存候选快照里还有下一页,不代表远端站点的全部历史结果都已抓取;需要更深结果时,优先缩小关键词、类型或来源范围并重新搜索。
### `get_game_asset`
读取刚刚搜索到的完整记录:
```json
{ "asset_id": "kenney:roguelike-characters" }
```
返回来源、作者、许可证、预览、文件变体、镜像来源、匹配原因和可直接加入 credits 的署名文本。远程条目先搜索后读取;本地条目也可从索引直接读取。
### `list_asset_sources`
列出所有 provider、启用状态、支持的素材类型、凭据要求、缓存配置和本地索引状态。
### `index_local_assets`
扫描 `GAME_ASSET_LOCAL_ROOTS`:
```json
{ "mode": "incremental", "max_files": 20000 }
```
`incremental` 会复用大小与修改时间未变化的 SHA-256;`rebuild` 会全部重算。索引写到 `GAME_ASSET_DATA_DIR/local-assets.json`,不会修改素材文件。
## 本地素材 sidecar
在 `hero.png` 旁放置 `hero.png.asset.json` 或 `hero.asset.json`:
```json
{
"title": "Azure Knight",
"description": "32x32 pixel hero with idle and run frames",
"type": "sprite",
"tags": ["player", "knight", "pixel-art"],
"author": "Studio Name",
"author_url": "https://example.com",
"license": "CC-BY-4.0",
"license_url": "https://creativecommons.org/licenses/by/4.0/",
"source_url": "https://example.com/azure-knight"
}
```
没有 sidecar 的本地文件仍可搜索,但许可证显示为未知。
## 环境变量
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `GAME_ASSET_LOCAL_ROOTS` | 空 | 本地素材根目录;Windows 用 `;`,macOS/Linux 用 `:` 分隔 |
| `GAME_ASSET_DATA_DIR` | 项目下 `data` | 本地索引目录 |
| `GAME_ASSET_CACHE_TTL_SECONDS` | `600` | 查询缓存秒数 |
| `GAME_ASSET_CACHE_MAX_ENTRIES` | `200` | 查询缓存最大条数 |
| `GAME_ASSET_PROVIDER_TIMEOUT_MS` | `15000` | 单一 provider 时限 |
| `GAME_ASSET_MAX_RESPONSE_BYTES` | `16777216` | 单次远程响应上限 |
| `GAME_ASSET_MAX_RETRIES` | `2` | 429/临时错误的重试次数 |
| `GAME_ASSET_MAX_LOCAL_FILES` | `20000` | 本地索引默认文件上限 |
| `GAME_ASSET_DISABLED_SOURCES` | 空 | 用逗号分隔的 provider id |
| `FREESOUND_API_KEY` | 空 | 可选 Freesound API key |
## 开发与验证
```powershell
npm run check
npm test
npm run test:unit
npm run test:mcp
```
测试覆盖中文查询扩展、类型识别、许可证策略、URL 规范化、去重、缓存击穿合并、局部 provider 失败、分页与游标、本地增量索引,以及真实 stdio MCP 客户端的 `tools/list` / `tools/call`。
## 结果使用提示
MCP 返回的是素材发现与许可证元数据,不替代来源页的最终条款。未知许可证会明确保留为 `id: null`;发布前可用 `commercial`、`cc0` 或 `no-attribution` 缩小范围,并在 `get_game_asset` 中保存来源与署名信息。
TDQS
Scored across 4 tools
Each tool has a distinct purpose: search, get details, list sources, and index. There is no overlap in functionality, making it easy for an agent to select the right tool.
All tool names follow a consistent verb_noun pattern in snake_case (get_game_asset, list_asset_sources, search_game_assets, index_local_assets). This predictable structure aids agent understanding.
Four tools cover the essential operations for a game asset finder: search, get detail, list sources, and index local assets. The count is well-scoped for the server's stated purpose.
The tools provide a complete workflow: index local assets, search across sources, retrieve detailed records, and list source info. No obvious gaps exist for the domain of finding and retrieving game assets.