threenative-asset-mcp 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +441 -0
- package/dist/ambientcg/client.d.ts +61 -0
- package/dist/ambientcg/client.d.ts.map +1 -0
- package/dist/ambientcg/client.js +234 -0
- package/dist/ambientcg/client.js.map +1 -0
- package/dist/audio/catalog.d.ts +36 -0
- package/dist/audio/catalog.d.ts.map +1 -0
- package/dist/audio/catalog.js +169 -0
- package/dist/audio/catalog.js.map +1 -0
- package/dist/audio/client.d.ts +46 -0
- package/dist/audio/client.d.ts.map +1 -0
- package/dist/audio/client.js +196 -0
- package/dist/audio/client.js.map +1 -0
- package/dist/bundle/client.d.ts +89 -0
- package/dist/bundle/client.d.ts.map +1 -0
- package/dist/bundle/client.js +324 -0
- package/dist/bundle/client.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +130 -0
- package/dist/config.js.map +1 -0
- package/dist/download/direct-asset-downloader.d.ts +41 -0
- package/dist/download/direct-asset-downloader.d.ts.map +1 -0
- package/dist/download/direct-asset-downloader.js +232 -0
- package/dist/download/direct-asset-downloader.js.map +1 -0
- package/dist/fab/api-download.d.ts +30 -0
- package/dist/fab/api-download.d.ts.map +1 -0
- package/dist/fab/api-download.js +200 -0
- package/dist/fab/api-download.js.map +1 -0
- package/dist/fab/browser-transport.d.ts +79 -0
- package/dist/fab/browser-transport.d.ts.map +1 -0
- package/dist/fab/browser-transport.js +492 -0
- package/dist/fab/browser-transport.js.map +1 -0
- package/dist/fab/cache.d.ts +22 -0
- package/dist/fab/cache.d.ts.map +1 -0
- package/dist/fab/cache.js +55 -0
- package/dist/fab/cache.js.map +1 -0
- package/dist/fab/client.d.ts +61 -0
- package/dist/fab/client.d.ts.map +1 -0
- package/dist/fab/client.js +868 -0
- package/dist/fab/client.js.map +1 -0
- package/dist/fab/direct-transport.d.ts +68 -0
- package/dist/fab/direct-transport.d.ts.map +1 -0
- package/dist/fab/direct-transport.js +184 -0
- package/dist/fab/direct-transport.js.map +1 -0
- package/dist/fab/download-store.d.ts +21 -0
- package/dist/fab/download-store.d.ts.map +1 -0
- package/dist/fab/download-store.js +93 -0
- package/dist/fab/download-store.js.map +1 -0
- package/dist/fab/errors.d.ts +20 -0
- package/dist/fab/errors.d.ts.map +1 -0
- package/dist/fab/errors.js +65 -0
- package/dist/fab/errors.js.map +1 -0
- package/dist/fab/impersonate-fetch.d.ts +48 -0
- package/dist/fab/impersonate-fetch.d.ts.map +1 -0
- package/dist/fab/impersonate-fetch.js +228 -0
- package/dist/fab/impersonate-fetch.js.map +1 -0
- package/dist/fab/normalize.d.ts +3 -0
- package/dist/fab/normalize.d.ts.map +1 -0
- package/dist/fab/normalize.js +285 -0
- package/dist/fab/normalize.js.map +1 -0
- package/dist/fab/schemas.d.ts +10 -0
- package/dist/fab/schemas.d.ts.map +1 -0
- package/dist/fab/schemas.js +105 -0
- package/dist/fab/schemas.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/itch/catalog.d.ts +13 -0
- package/dist/itch/catalog.d.ts.map +1 -0
- package/dist/itch/catalog.js +50 -0
- package/dist/itch/catalog.js.map +1 -0
- package/dist/itch/client.d.ts +46 -0
- package/dist/itch/client.d.ts.map +1 -0
- package/dist/itch/client.js +175 -0
- package/dist/itch/client.js.map +1 -0
- package/dist/polyhaven/client.d.ts +55 -0
- package/dist/polyhaven/client.d.ts.map +1 -0
- package/dist/polyhaven/client.js +210 -0
- package/dist/polyhaven/client.js.map +1 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +448 -0
- package/dist/server.js.map +1 -0
- package/dist/sketchfab/client.d.ts +70 -0
- package/dist/sketchfab/client.d.ts.map +1 -0
- package/dist/sketchfab/client.js +255 -0
- package/dist/sketchfab/client.js.map +1 -0
- package/dist/smithsonian/client.d.ts +32 -0
- package/dist/smithsonian/client.d.ts.map +1 -0
- package/dist/smithsonian/client.js +142 -0
- package/dist/smithsonian/client.js.map +1 -0
- package/dist/tools/ambientcg.d.ts +296 -0
- package/dist/tools/ambientcg.d.ts.map +1 -0
- package/dist/tools/ambientcg.js +183 -0
- package/dist/tools/ambientcg.js.map +1 -0
- package/dist/tools/audio.d.ts +211 -0
- package/dist/tools/audio.d.ts.map +1 -0
- package/dist/tools/audio.js +156 -0
- package/dist/tools/audio.js.map +1 -0
- package/dist/tools/bundle.d.ts +237 -0
- package/dist/tools/bundle.d.ts.map +1 -0
- package/dist/tools/bundle.js +206 -0
- package/dist/tools/bundle.js.map +1 -0
- package/dist/tools/direct-download.d.ts +53 -0
- package/dist/tools/direct-download.d.ts.map +1 -0
- package/dist/tools/direct-download.js +68 -0
- package/dist/tools/direct-download.js.map +1 -0
- package/dist/tools/download-free-asset.d.ts +66 -0
- package/dist/tools/download-free-asset.d.ts.map +1 -0
- package/dist/tools/download-free-asset.js +60 -0
- package/dist/tools/download-free-asset.js.map +1 -0
- package/dist/tools/get-asset.d.ts +161 -0
- package/dist/tools/get-asset.d.ts.map +1 -0
- package/dist/tools/get-asset.js +131 -0
- package/dist/tools/get-asset.js.map +1 -0
- package/dist/tools/itch.d.ts +120 -0
- package/dist/tools/itch.d.ts.map +1 -0
- package/dist/tools/itch.js +120 -0
- package/dist/tools/itch.js.map +1 -0
- package/dist/tools/list-filters.d.ts +127 -0
- package/dist/tools/list-filters.d.ts.map +1 -0
- package/dist/tools/list-filters.js +68 -0
- package/dist/tools/list-filters.js.map +1 -0
- package/dist/tools/list-limited-time-free.d.ts +57 -0
- package/dist/tools/list-limited-time-free.d.ts.map +1 -0
- package/dist/tools/list-limited-time-free.js +47 -0
- package/dist/tools/list-limited-time-free.js.map +1 -0
- package/dist/tools/polyhaven.d.ts +266 -0
- package/dist/tools/polyhaven.d.ts.map +1 -0
- package/dist/tools/polyhaven.js +233 -0
- package/dist/tools/polyhaven.js.map +1 -0
- package/dist/tools/search-assets.d.ts +176 -0
- package/dist/tools/search-assets.d.ts.map +1 -0
- package/dist/tools/search-assets.js +172 -0
- package/dist/tools/search-assets.js.map +1 -0
- package/dist/tools/sketchfab.d.ts +325 -0
- package/dist/tools/sketchfab.d.ts.map +1 -0
- package/dist/tools/sketchfab.js +203 -0
- package/dist/tools/sketchfab.js.map +1 -0
- package/dist/tools/smithsonian.d.ts +189 -0
- package/dist/tools/smithsonian.d.ts.map +1 -0
- package/dist/tools/smithsonian.js +189 -0
- package/dist/tools/smithsonian.js.map +1 -0
- package/dist/tools/source-directory.d.ts +226 -0
- package/dist/tools/source-directory.d.ts.map +1 -0
- package/dist/tools/source-directory.js +583 -0
- package/dist/tools/source-directory.js.map +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# threenative-asset-mcp
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io/) server for finding
|
|
4
|
+
3D assets across [Fab](https://www.fab.com/),
|
|
5
|
+
[Poly Haven](https://polyhaven.com/), [ambientCG](https://ambientcg.com/),
|
|
6
|
+
[Smithsonian 3D](https://3d.si.edu/), [Sketchfab](https://sketchfab.com/), and a
|
|
7
|
+
curated game-audio catalog spanning Sonniss, Kenney, Tallbeard, Scott Buckley,
|
|
8
|
+
itch.io, Mixkit, Pixabay, Freesound, OpenGameArt, and Abstraction. It gives AI clients provider-scoped,
|
|
9
|
+
structured search, asset metadata, category/filter discovery, downloadable file
|
|
10
|
+
data, and guarded Fab downloads for directly available free files.
|
|
11
|
+
|
|
12
|
+
The audio tools separate **source discovery** from **verified direct downloads**.
|
|
13
|
+
All ten sources are described with license caveats and official browse pages;
|
|
14
|
+
only packs with stable official URLs and known license metadata appear in the
|
|
15
|
+
direct-download catalog. The initial downloadable set is Kenney Interface
|
|
16
|
+
Sounds, Kenney Music Jingles, and all five Sonniss GDC 2026 archives.
|
|
17
|
+
|
|
18
|
+
`fab_search_assets` defaults to free assets. This means Fab reported at least
|
|
19
|
+
one free or effectively free license; it does not imply every license tier is
|
|
20
|
+
free. Use `fab_get_asset` before making license or price claims.
|
|
21
|
+
|
|
22
|
+
Poly Haven results are CC0 and explicitly labelled `Powered by Poly Haven`.
|
|
23
|
+
`polyhaven_list_files` exposes official download URLs, hashes, sizes, and
|
|
24
|
+
dependency relationships with pagination and resolution/format filters.
|
|
25
|
+
|
|
26
|
+
> Status: experimental. Fab's `/i/*` JSON routes are undocumented and can
|
|
27
|
+
> change or restrict automated access. Poly Haven provides a documented public
|
|
28
|
+
> API, but clients must send a unique User-Agent and visibly credit Poly Haven.
|
|
29
|
+
> Sketchfab licenses vary per model and download URLs require a user API token.
|
|
30
|
+
> Review each provider's terms and each asset's license.
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js 20.19 or newer
|
|
35
|
+
- A local environment capable of running Playwright Chromium when Fab requests
|
|
36
|
+
browser verification
|
|
37
|
+
- No Epic or Fab login is required or automated
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
An MCP host can launch the published package with:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx -y threenative-asset-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For a local checkout:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm ci
|
|
51
|
+
npm run browser:install
|
|
52
|
+
npm run typecheck
|
|
53
|
+
npm test
|
|
54
|
+
npm run build
|
|
55
|
+
node dist/index.js
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Playwright does not download Chromium as part of a normal package install. Run
|
|
59
|
+
`npx -p playwright@1.62.0 playwright install chromium` once on the MCP host
|
|
60
|
+
before relying on the browser fallback.
|
|
61
|
+
|
|
62
|
+
## MCP host configuration
|
|
63
|
+
|
|
64
|
+
### Codex
|
|
65
|
+
|
|
66
|
+
Add this to `~/.codex/config.toml`:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[mcp_servers.assets]
|
|
70
|
+
command = "npx"
|
|
71
|
+
args = ["-y", "threenative-asset-mcp"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For a local build:
|
|
75
|
+
|
|
76
|
+
```toml
|
|
77
|
+
[mcp_servers.assets]
|
|
78
|
+
command = "node"
|
|
79
|
+
args = ["/absolute/path/to/threenative-asset-mcp/dist/index.js"]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Claude Desktop
|
|
83
|
+
|
|
84
|
+
Add a server entry to the Claude Desktop configuration:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"assets": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["-y", "threenative-asset-mcp"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### VS Code
|
|
98
|
+
|
|
99
|
+
Create `.vscode/mcp.json`:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"servers": {
|
|
104
|
+
"assets": {
|
|
105
|
+
"type": "stdio",
|
|
106
|
+
"command": "npx",
|
|
107
|
+
"args": ["-y", "threenative-asset-mcp"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Restart the MCP host after changing its configuration.
|
|
114
|
+
|
|
115
|
+
## MCP tools
|
|
116
|
+
|
|
117
|
+
Fab:
|
|
118
|
+
|
|
119
|
+
- `fab_search_assets` — searches public listings. `priceMode` defaults to
|
|
120
|
+
`free`; use `any` or `range` explicitly for paid results.
|
|
121
|
+
- `fab_get_asset` — returns normalized public listing details and per-license
|
|
122
|
+
effective prices.
|
|
123
|
+
- `fab_list_filters` — returns known public filter labels and slugs, including
|
|
124
|
+
an explicit warning when the versioned fallback is used.
|
|
125
|
+
- `fab_list_limited_time_free` — reads only a separately verified curated
|
|
126
|
+
promotion surface. In production it extracts canonical listing UUIDs from
|
|
127
|
+
Fab's public `/limited-time-free` page through the dedicated browser, then
|
|
128
|
+
resolves them through the normal detail client; it never substitutes general
|
|
129
|
+
`is_free=1` search.
|
|
130
|
+
- `fab_download_free_asset` — downloads one directly available free file into
|
|
131
|
+
the dedicated download directory after explicit Fab EULA acknowledgement. It
|
|
132
|
+
refuses purchase, acquisition, library-only, ambiguous, and unsafe-path
|
|
133
|
+
flows.
|
|
134
|
+
|
|
135
|
+
Poly Haven:
|
|
136
|
+
|
|
137
|
+
- `polyhaven_search_assets` — searches HDRIs, textures, and models by text,
|
|
138
|
+
type, and category, with relevance/popularity/date/name sorting and cursor
|
|
139
|
+
pagination.
|
|
140
|
+
- `polyhaven_get_asset` — returns normalized metadata, attributes, authors,
|
|
141
|
+
dimensions, resolution, and CC0 licensing for one asset.
|
|
142
|
+
- `polyhaven_list_categories` — returns category labels and counts for one
|
|
143
|
+
asset type.
|
|
144
|
+
- `polyhaven_list_files` — returns the official file URLs, sizes, MD5 hashes,
|
|
145
|
+
and dependency relationships. Use `resolution` and `format` to select usable
|
|
146
|
+
variants; follow `nextCursor` until absent to retrieve every matching file.
|
|
147
|
+
|
|
148
|
+
ambientCG:
|
|
149
|
+
|
|
150
|
+
- `ambientcg_search_assets` — searches CC0 materials, HDRIs, substances,
|
|
151
|
+
decals, atlases, 3D models, images, brushes, terrains, and HDRI elements.
|
|
152
|
+
- `ambientcg_get_asset` — returns metadata, maps, technique, dimensions,
|
|
153
|
+
statistics, and CC0 licensing.
|
|
154
|
+
- `ambientcg_list_categories` — lists typed categories and asset counts.
|
|
155
|
+
- `ambientcg_list_files` — returns official archives with variant attributes,
|
|
156
|
+
extensions, URLs, and byte sizes.
|
|
157
|
+
|
|
158
|
+
Smithsonian 3D:
|
|
159
|
+
|
|
160
|
+
- `smithsonian_search_assets` — searches Open Access models by text, format,
|
|
161
|
+
quality, owning unit, Draco compression, and glTF orientation compliance.
|
|
162
|
+
- `smithsonian_get_asset` — groups the file-centric API response into one model
|
|
163
|
+
summary.
|
|
164
|
+
- `smithsonian_list_files` — returns direct model files with format, quality,
|
|
165
|
+
compression, and orientation metadata.
|
|
166
|
+
|
|
167
|
+
Sketchfab:
|
|
168
|
+
|
|
169
|
+
- `sketchfab_search_models` — anonymously searches public models, defaulting to
|
|
170
|
+
downloadable results, and preserves author, geometry, archive, and license
|
|
171
|
+
metadata.
|
|
172
|
+
- `sketchfab_get_model` — returns public detail and explicit Creative Commons
|
|
173
|
+
requirements.
|
|
174
|
+
- `sketchfab_list_categories` — lists public category names and slugs.
|
|
175
|
+
- `sketchfab_get_downloads` — uses `SKETCHFAB_API_TOKEN` to retrieve temporary
|
|
176
|
+
download URLs. It never stores the token or returns it in tool output.
|
|
177
|
+
|
|
178
|
+
Game audio:
|
|
179
|
+
|
|
180
|
+
- `audio_list_sources` — lists the ten supported audio libraries, best uses,
|
|
181
|
+
official browse pages, license/attribution cautions, and honest download
|
|
182
|
+
capability (`curated-direct` or `provider-page`).
|
|
183
|
+
- `audio_search_assets` — searches only the curated packs with stable official
|
|
184
|
+
direct URLs. Results preserve license, commercial-use, attribution, source,
|
|
185
|
+
size (when known), and redistribution metadata.
|
|
186
|
+
- `audio_download_asset` — downloads a catalog asset by ID after
|
|
187
|
+
`acceptLicense: true`. It uses an HTTPS host allowlist, validates every
|
|
188
|
+
redirect, streams with a byte cap, writes atomically without overwrite, and
|
|
189
|
+
returns the local path, byte size, and SHA-256.
|
|
190
|
+
|
|
191
|
+
Curated itch.io packs:
|
|
192
|
+
|
|
193
|
+
- `itch_list_downloads` — resolves a fresh no-account download page and lists
|
|
194
|
+
upload IDs, filenames, sizes, CC0 terms, and pack-specific cautions without
|
|
195
|
+
exposing the signed page token.
|
|
196
|
+
- `itch_download_asset` — resolves a fresh 60-second signed file URL and streams
|
|
197
|
+
the selected upload into guarded storage after `acceptLicense: true`. Signed
|
|
198
|
+
URLs are not returned. The initial catalog covers Tallbeard Music Loop
|
|
199
|
+
Bundle, Quaternius Universal Animation Libraries 1 and 2, Brackeys VFX
|
|
200
|
+
Bundle, and KayKit Platformer.
|
|
201
|
+
- `asset_list_bundle_entries` — reads the remote ZIP directory with HTTP byte
|
|
202
|
+
ranges and returns individual paths and sizes without downloading the archive.
|
|
203
|
+
- `asset_download_bundle_entry` — range-fetches and extracts one selected file,
|
|
204
|
+
caches it with a SHA-256 sidecar, and never downloads unrelated bundle files.
|
|
205
|
+
- `asset_list_bundle_animations` — range-fetches only an aggregate GLB and lists
|
|
206
|
+
its named animation clips. For Quaternius, it automatically prefers the
|
|
207
|
+
standard non-root-motion GLB.
|
|
208
|
+
- `asset_download_bundle_animation` — exports one named animation as a valid
|
|
209
|
+
animation-only GLB, removing unrelated clips, meshes, materials, and textures.
|
|
210
|
+
The cached aggregate GLB is reused across requests.
|
|
211
|
+
|
|
212
|
+
Unified source and download routing:
|
|
213
|
+
|
|
214
|
+
- `asset_list_sources` — returns only **agent-ready sources by default** across
|
|
215
|
+
3D, textures, HDRIs, animations, VFX, 2D, UI, icons, fonts, and audio. An
|
|
216
|
+
agent-ready source has an MCP download tool and requires no manual browser,
|
|
217
|
+
login, checkout, donation prompt, or paywall. Pass `agentReadyOnly: false` to
|
|
218
|
+
inspect the broader research directory, including package-manager, Git, and
|
|
219
|
+
provider-page sources that are not yet integrated.
|
|
220
|
+
- `asset_search_sources` — filters that directory by text, category, access
|
|
221
|
+
mode, and license tag (`cc0`, `cc-by`, `mit`, and others), while preserving
|
|
222
|
+
the same agent-ready-only default.
|
|
223
|
+
- `asset_download_file` — streams a direct URL previously returned by
|
|
224
|
+
`polyhaven_list_files`, `ambientcg_list_files`, `smithsonian_list_files`, or
|
|
225
|
+
the Game-icons.net bulk archive or Kenney Particle Pack entry into guarded
|
|
226
|
+
local storage. Provider hosts and URL shapes are allowlisted, redirects are
|
|
227
|
+
revalidated, existing files are never overwritten, and the result includes
|
|
228
|
+
SHA-256.
|
|
229
|
+
|
|
230
|
+
Recommended agent flow:
|
|
231
|
+
|
|
232
|
+
1. Call `asset_search_sources` with the requested category/query. Its default
|
|
233
|
+
result set is guaranteed to contain only agent-ready sources.
|
|
234
|
+
2. Call the returned `searchTool` or `detailTool` when present.
|
|
235
|
+
3. Resolve variants with the returned `filesTool`.
|
|
236
|
+
4. Call the returned `downloadTool` with `acceptLicense: true`.
|
|
237
|
+
5. For aggregate Quaternius animation libraries, skip whole-pack download:
|
|
238
|
+
`itch_list_downloads` → `asset_list_bundle_animations` →
|
|
239
|
+
`asset_download_bundle_animation`.
|
|
240
|
+
|
|
241
|
+
This is intentionally a short MCP tool chain rather than a fake universal URL:
|
|
242
|
+
each provider keeps its real search/variant semantics, while source routing and
|
|
243
|
+
the no-manual-flow guarantee stay uniform.
|
|
244
|
+
|
|
245
|
+
All discovery tools are read-only. Download tools write only within their
|
|
246
|
+
dedicated local directories and never purchase, add to cart or library,
|
|
247
|
+
wishlist, sign in, or overwrite an existing download. Audio packs remain
|
|
248
|
+
subject to their source license; raw redistribution is not implied by download.
|
|
249
|
+
|
|
250
|
+
## Configuration
|
|
251
|
+
|
|
252
|
+
| Variable | Default | Purpose |
|
|
253
|
+
| ------------------------------- | -------------------------------------------------- | -------------------------------------------------------- |
|
|
254
|
+
| `FAB_DIRECT_TIMEOUT_MS` | `20000` | Direct JSON request timeout. |
|
|
255
|
+
| `FAB_BROWSER_TIMEOUT_MS` | `30000` | Dedicated browser request timeout. |
|
|
256
|
+
| `FAB_BROWSER_MANUAL_TIMEOUT_MS` | `10000` | Headed-mode grace period for visible verification. |
|
|
257
|
+
| `FAB_BROWSER_HEADLESS` | `true` | Set to `0` temporarily for manual verification. |
|
|
258
|
+
| `FAB_BROWSER_PROFILE_DIR` | OS state directory under `threenative-asset-mcp/fab-browser-profile` | MCP-owned Fab browser state. |
|
|
259
|
+
| `FAB_DOWNLOAD_DIR` | `~/Downloads/threenative-asset-mcp/fab` | Dedicated directory for Fab free-file downloads. |
|
|
260
|
+
| `FAB_MAX_DOWNLOAD_BYTES` | `2147483648` | Maximum accepted download size in bytes. |
|
|
261
|
+
| `FAB_DOWNLOAD_TIMEOUT_MS` | `600000` | Total timeout for one file download. |
|
|
262
|
+
| `FAB_CURL_IMPERSONATE` | auto-detected on `PATH` | curl-impersonate wrapper override; `0`/`off` disables. |
|
|
263
|
+
| `FAB_MIN_REQUEST_INTERVAL_MS` | `1000` | Minimum spacing between direct upstream requests. |
|
|
264
|
+
| `FAB_LOG_LEVEL` | `warn` | `debug`, `info`, `warn`, or `error`. |
|
|
265
|
+
| `FAB_LOG_QUERIES` | `false` | Set to `1` only if query text may be written to logs. |
|
|
266
|
+
| `SKETCHFAB_API_TOKEN` | unset | User token for temporary Sketchfab download URLs. |
|
|
267
|
+
| `AUDIO_DOWNLOAD_DIR` | `~/Downloads/threenative-asset-mcp/audio` | Dedicated directory for curated audio downloads. |
|
|
268
|
+
| `AUDIO_MAX_DOWNLOAD_BYTES` | `10737418240` | Maximum accepted bytes per audio archive (10 GiB). |
|
|
269
|
+
| `AUDIO_DOWNLOAD_TIMEOUT_MS` | `1800000` | Total timeout for one audio download (30 minutes). |
|
|
270
|
+
| `ASSET_DOWNLOAD_DIR` | `~/Downloads/threenative-asset-mcp/assets` | Dedicated directory for direct provider downloads. |
|
|
271
|
+
| `ASSET_MAX_DOWNLOAD_BYTES` | `10737418240` | Maximum accepted bytes per provider file (10 GiB). |
|
|
272
|
+
| `ASSET_DOWNLOAD_TIMEOUT_MS` | `1800000` | Total timeout for one provider download (30 minutes). |
|
|
273
|
+
|
|
274
|
+
Direct requests are spaced at least `FAB_MIN_REQUEST_INTERVAL_MS` apart. Only
|
|
275
|
+
HTTP 429, 502, 503, and 504 are retried, at most twice, with backoff and
|
|
276
|
+
`Retry-After` support. Challenges, access denial, invalid input, missing
|
|
277
|
+
listings, and schema drift are never retried by the transport; a
|
|
278
|
+
curl-impersonate challenge response is additionally retried inside the
|
|
279
|
+
impersonation wrapper with longer, jittered waits before the browser fallback
|
|
280
|
+
is engaged.
|
|
281
|
+
|
|
282
|
+
## Browser-fingerprint TLS (curl-impersonate)
|
|
283
|
+
|
|
284
|
+
Fab's `/i/*` JSON routes sit behind Cloudflare bot management that challenges
|
|
285
|
+
Node's default TLS fingerprint — including plain `fetch` from this MCP and
|
|
286
|
+
headless Chromium — while real browser fingerprints pass. When a
|
|
287
|
+
[curl-impersonate](https://github.com/lwthiker/curl-impersonate) wrapper (for
|
|
288
|
+
example `curl_chrome146`) is available on the host `PATH`, the server performs
|
|
289
|
+
all anonymous JSON reads through it and no browser is needed for search,
|
|
290
|
+
detail, or download resolution. Set `FAB_CURL_IMPERSONATE=0` to force the old
|
|
291
|
+
behavior (plain Node fetch plus the Playwright fallback), or point it at a
|
|
292
|
+
specific wrapper binary.
|
|
293
|
+
|
|
294
|
+
Downloads of free files resolve entirely through the anonymous JSON contract
|
|
295
|
+
when possible: listing detail → `asset-formats/{format}` file listing →
|
|
296
|
+
`download-info` signed URL → guarded file write. The signed distribution URL
|
|
297
|
+
is validated against an exact Epic distribution-host allowlist before use.
|
|
298
|
+
Only when the direct path is challenged does the server fall back to the
|
|
299
|
+
guarded browser click flow below.
|
|
300
|
+
|
|
301
|
+
Process-local cache TTLs are five minutes for search, fifteen minutes for
|
|
302
|
+
listing details, six hours for taxonomy data, and ten minutes for promotions.
|
|
303
|
+
The shared LRU is capped at 500 entries and is cleared on process exit.
|
|
304
|
+
|
|
305
|
+
## Poly Haven API behavior
|
|
306
|
+
|
|
307
|
+
Poly Haven requests go only to `https://api.polyhaven.com`, with the required
|
|
308
|
+
`threenative-asset-mcp` User-Agent. Asset lists are cached for 15 minutes and
|
|
309
|
+
details, categories, and file trees are cached for up to one hour. Returned file
|
|
310
|
+
URLs are accepted only from `https://dl.polyhaven.org`.
|
|
311
|
+
|
|
312
|
+
The live API is free for personal and commercial use, but use of the API
|
|
313
|
+
requires a visible Poly Haven credit. The assets themselves are CC0. This MCP
|
|
314
|
+
includes `provider`, `license`, and `attribution` fields so downstream clients
|
|
315
|
+
can preserve that distinction. See the
|
|
316
|
+
[official API page](https://polyhaven.com/our-api) and
|
|
317
|
+
[API documentation](https://api.polyhaven.com/).
|
|
318
|
+
|
|
319
|
+
## Other provider behavior
|
|
320
|
+
|
|
321
|
+
ambientCG uses its anonymous, read-only v3 API. Its files are CC0 and its API
|
|
322
|
+
exposes searchable metadata, categories, and downloadable variants.
|
|
323
|
+
|
|
324
|
+
Smithsonian uses the anonymous Smithsonian 3D file-search API. Files exposed by
|
|
325
|
+
that API are part of Smithsonian Open Access; the MCP retains direct source
|
|
326
|
+
URLs and format/quality metadata.
|
|
327
|
+
|
|
328
|
+
Sketchfab public search, categories, and model detail do not require a token.
|
|
329
|
+
The download endpoint requires a token belonging to the user, configured
|
|
330
|
+
through `SKETCHFAB_API_TOKEN`. The token is sent only in the Sketchfab
|
|
331
|
+
`Authorization` header, is never logged or persisted, and is not included in
|
|
332
|
+
MCP responses. Sketchfab models use different Creative Commons licenses; always
|
|
333
|
+
inspect `license.requirements` before use.
|
|
334
|
+
|
|
335
|
+
Audio direct downloads are catalog-ID based; the MCP does not accept arbitrary
|
|
336
|
+
URLs. Official Kenney downloads are restricted to `kenney.nl` and Sonniss GDC
|
|
337
|
+
downloads to `downloads.sonniss.com`, including redirect revalidation. Sources
|
|
338
|
+
without a stable, verified direct contract remain discoverable as
|
|
339
|
+
`provider-page` instead of being falsely presented as one-click downloads.
|
|
340
|
+
|
|
341
|
+
The generic direct downloader is intentionally narrower than an arbitrary URL
|
|
342
|
+
fetcher. It accepts only official Poly Haven, ambientCG, Smithsonian,
|
|
343
|
+
Game-icons.net, and curated Kenney URL contracts. The itch.io downloader uses
|
|
344
|
+
fresh signed mirror URLs internally but never exposes them. Sketchfab signed
|
|
345
|
+
downloads are exposed through `sketchfab_get_downloads` but are not persisted
|
|
346
|
+
by the generic downloader because their temporary CDN hosts vary and require
|
|
347
|
+
the user's token-backed session. Provider-page-only sources stay provider-page-only until a stable,
|
|
348
|
+
license-safe download contract is verified.
|
|
349
|
+
|
|
350
|
+
## Dedicated browser profile and privacy
|
|
351
|
+
|
|
352
|
+
When a direct anonymous request receives a Cloudflare challenge, the server may
|
|
353
|
+
open Playwright Chromium with a dedicated MCP-owned profile. It never attaches
|
|
354
|
+
to, copies, or reads the user's normal Chrome/Edge/Chromium profile, cookie
|
|
355
|
+
database, local storage, passwords, or Epic session.
|
|
356
|
+
|
|
357
|
+
If the tool returns `FAB_BROWSER_ATTENTION_REQUIRED`, run the same MCP command
|
|
358
|
+
once with `FAB_BROWSER_HEADLESS=0`. The MCP opens its dedicated Fab homepage at
|
|
359
|
+
startup, so complete any visible verification before calling the tool. A tool
|
|
360
|
+
call allows an additional `FAB_BROWSER_MANUAL_TIMEOUT_MS` grace period, then
|
|
361
|
+
returns `FAB_BROWSER_ATTENTION_REQUIRED` rather than exceeding typical MCP
|
|
362
|
+
client timeouts. Close the MCP process after verification and return to headless
|
|
363
|
+
mode. The server does not solve or bypass challenges.
|
|
364
|
+
|
|
365
|
+
Browser process startup is capped at ten seconds. On a host without a working
|
|
366
|
+
graphical session, headed mode returns `FAB_UPSTREAM_UNAVAILABLE` instead of
|
|
367
|
+
hanging an MCP call; run the manual release gate on a graphical host.
|
|
368
|
+
|
|
369
|
+
To clear browser-owned Fab state, stop every `threenative-asset-mcp` process and
|
|
370
|
+
move only the dedicated directory reported by your configuration out of
|
|
371
|
+
service. The default on Linux can be cleared recoverably with:
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
mv -- "${XDG_STATE_HOME:-$HOME/.local/state}/threenative-asset-mcp/fab-browser-profile" \
|
|
375
|
+
"${XDG_STATE_HOME:-$HOME/.local/state}/threenative-asset-mcp/fab-browser-profile.cleared"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Do not point `FAB_BROWSER_PROFILE_DIR` at a normal browser profile. The server
|
|
379
|
+
rejects known normal-profile locations.
|
|
380
|
+
|
|
381
|
+
The MCP has no analytics or remote telemetry. Application logs are structured
|
|
382
|
+
JSON written only to stderr; stdout is reserved for MCP JSON-RPC. Search query
|
|
383
|
+
text is omitted from logs unless `FAB_LOG_QUERIES=1`. Raw upstream bodies,
|
|
384
|
+
headers, cookies, tokens, stack traces, and browser profile paths are not logged
|
|
385
|
+
or returned to the model.
|
|
386
|
+
|
|
387
|
+
## Troubleshooting
|
|
388
|
+
|
|
389
|
+
`FAB_CHALLENGE` or `FAB_BROWSER_ATTENTION_REQUIRED`
|
|
390
|
+
: Fab asked for browser verification. First check whether a curl-impersonate
|
|
391
|
+
wrapper is installed (`FAB_LOG_LEVEL=info` logs `fab_impersonate_enabled`
|
|
392
|
+
when active). Otherwise use the headed dedicated-profile step above. If
|
|
393
|
+
verification continues to fail, stop; do not copy a signed-in browser
|
|
394
|
+
session.
|
|
395
|
+
|
|
396
|
+
`FAB_RATE_LIMITED`
|
|
397
|
+
: Wait for `retryAfterSeconds` when present. The MCP already applied its bounded
|
|
398
|
+
retries.
|
|
399
|
+
|
|
400
|
+
`FAB_UPSTREAM_CHANGED`
|
|
401
|
+
: Fab's undocumented response changed. Re-run the sanitized contract probe and
|
|
402
|
+
update normalization and fixtures before continuing.
|
|
403
|
+
|
|
404
|
+
`FAB_UPSTREAM_UNAVAILABLE`
|
|
405
|
+
: Fab is unavailable, or a currently unverified discovery contract was
|
|
406
|
+
intentionally disabled.
|
|
407
|
+
|
|
408
|
+
The MCP host shows no tools
|
|
409
|
+
: Build first, confirm the configured path is absolute, and run
|
|
410
|
+
`npm run inspect`. Logs belong on stderr; any non-JSON stdout is a bug.
|
|
411
|
+
|
|
412
|
+
## Verification
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
npm ci
|
|
416
|
+
npm run browser:install
|
|
417
|
+
npm run typecheck
|
|
418
|
+
npm test
|
|
419
|
+
npm run build
|
|
420
|
+
npm pack --dry-run
|
|
421
|
+
npm run inspect
|
|
422
|
+
npm run test:providers:live
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Live checks are opt-in because they contact Fab:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
npm run test:live
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
This runs the real anonymous search, cursor, detail, and dedicated-browser
|
|
432
|
+
contract probe. It exits nonzero when Fab challenges the clean browser or the
|
|
433
|
+
required contract cannot be verified. Live verification must remain anonymous,
|
|
434
|
+
concurrency-one, capped and paced. It must never acquire, purchase, wishlist,
|
|
435
|
+
download, or automatically solve a challenge.
|
|
436
|
+
|
|
437
|
+
`npm run test:providers:live` launches the compiled stdio MCP and exercises live
|
|
438
|
+
search, detail, categories, and file discovery for ambientCG, Smithsonian 3D,
|
|
439
|
+
and Sketchfab. If `SKETCHFAB_API_TOKEN` is configured it also verifies the
|
|
440
|
+
authenticated download endpoint; otherwise it verifies the explicit
|
|
441
|
+
authentication-required response.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare const AMBIENTCG_TYPES: readonly ["material", "hdri", "substance", "decal", "atlas", "3d-model", "plain-image", "brush", "terrain", "hdri-element"];
|
|
2
|
+
export type AmbientCgAssetType = (typeof AMBIENTCG_TYPES)[number];
|
|
3
|
+
export interface AmbientCgDownload {
|
|
4
|
+
attributes: string;
|
|
5
|
+
extension: string;
|
|
6
|
+
url: string;
|
|
7
|
+
sizeBytes: number;
|
|
8
|
+
}
|
|
9
|
+
export interface AmbientCgAsset {
|
|
10
|
+
id: string;
|
|
11
|
+
type: AmbientCgAssetType;
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
url: string;
|
|
15
|
+
tags: string[];
|
|
16
|
+
releaseDate?: string;
|
|
17
|
+
technique?: string;
|
|
18
|
+
dimensions?: {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
depth: number;
|
|
22
|
+
};
|
|
23
|
+
downloadCount?: number;
|
|
24
|
+
thumbnailUrl?: string;
|
|
25
|
+
maps: string[];
|
|
26
|
+
downloads: AmbientCgDownload[];
|
|
27
|
+
}
|
|
28
|
+
export interface AmbientCgSearchResult {
|
|
29
|
+
assets: AmbientCgAsset[];
|
|
30
|
+
total: number;
|
|
31
|
+
nextOffset?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AmbientCgCategory {
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
type: AmbientCgAssetType;
|
|
37
|
+
assetCount: number;
|
|
38
|
+
}
|
|
39
|
+
export declare class AmbientCgClientError extends Error {
|
|
40
|
+
readonly code: "AMBIENTCG_INVALID_INPUT" | "AMBIENTCG_NOT_FOUND" | "AMBIENTCG_RATE_LIMITED" | "AMBIENTCG_UPSTREAM_UNAVAILABLE" | "AMBIENTCG_UPSTREAM_CHANGED";
|
|
41
|
+
readonly retryable: boolean;
|
|
42
|
+
constructor(code: "AMBIENTCG_INVALID_INPUT" | "AMBIENTCG_NOT_FOUND" | "AMBIENTCG_RATE_LIMITED" | "AMBIENTCG_UPSTREAM_UNAVAILABLE" | "AMBIENTCG_UPSTREAM_CHANGED", message: string, retryable?: boolean);
|
|
43
|
+
}
|
|
44
|
+
type FetchLike = typeof fetch;
|
|
45
|
+
export declare class AmbientCgClient {
|
|
46
|
+
private readonly fetchImpl;
|
|
47
|
+
constructor(fetchImpl?: FetchLike);
|
|
48
|
+
private request;
|
|
49
|
+
search(input: {
|
|
50
|
+
query?: string;
|
|
51
|
+
type?: AmbientCgAssetType;
|
|
52
|
+
sort: "popular" | "latest" | "downloads" | "oldest" | "random" | "alphabet";
|
|
53
|
+
limit: number;
|
|
54
|
+
offset: number;
|
|
55
|
+
includeDownloads?: boolean;
|
|
56
|
+
}): Promise<AmbientCgSearchResult>;
|
|
57
|
+
getAsset(id: string): Promise<AmbientCgAsset>;
|
|
58
|
+
listCategories(): Promise<AmbientCgCategory[]>;
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ambientcg/client.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,YAC1B,UAAU,EACV,MAAM,EACN,WAAW,EACX,OAAO,EACP,OAAO,EACP,UAAU,EACV,aAAa,EACb,OAAO,EACP,SAAS,EACT,cAAc,CACN,CAAC;AACX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,kBAAkB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EACT,yBAAyB,GACzB,qBAAqB,GACrB,wBAAwB,GACxB,gCAAgC,GAChC,4BAA4B;IAEhC,QAAQ,CAAC,SAAS;IARpB,YACW,IAAI,EACT,yBAAyB,GACzB,qBAAqB,GACrB,wBAAwB,GACxB,gCAAgC,GAChC,4BAA4B,EAChC,OAAO,EAAE,MAAM,EACN,SAAS,UAAQ,EAI3B;CACF;AAED,KAAK,SAAS,GAAG,OAAO,KAAK,CAAC;AAuH9B,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAtC,YAA6B,SAAS,GAAE,SAAiB,EAAI;YAE/C,OAAO;IAyCf,MAAM,CAAC,KAAK,EAAE;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,kBAAkB,CAAC;QAC1B,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;QAC5E,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAwCjC;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgBlD;IAEK,cAAc,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkBnD;CACF"}
|