arcane-assets-mcp 0.2.1

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.
@@ -0,0 +1,284 @@
1
+ # Usage Example
2
+
3
+ This document demonstrates how an agent would use the `arcane-assets` MCP server to discover and download game assets.
4
+
5
+ ## Scenario: Building a Platformer Game
6
+
7
+ An agent is tasked with creating a platformer demo and needs assets.
8
+
9
+ ### Step 1: Discover Available Assets
10
+
11
+ **Agent searches for platformer assets:**
12
+
13
+ ```typescript
14
+ // MCP Tool Call
15
+ search_kenney_assets({
16
+ query: "platformer",
17
+ type: "2d-sprites"
18
+ })
19
+ ```
20
+
21
+ **Result:**
22
+ ```json
23
+ {
24
+ "packs": [
25
+ {
26
+ "id": "platformer-pack-redux",
27
+ "name": "Platformer Pack Redux (360 assets)",
28
+ "description": "Complete platformer art pack with characters, tiles, items, and enemies",
29
+ "type": ["2d-sprites", "tilesets"],
30
+ "license": "CC0",
31
+ "tags": ["platformer", "character", "tiles", "pixel-art"]
32
+ },
33
+ {
34
+ "id": "pixel-platformer",
35
+ "name": "Pixel Platformer (220 assets)",
36
+ "description": "Pixel art platformer pack with characters, tiles, and decorations",
37
+ "type": ["2d-sprites", "tilesets"],
38
+ "license": "CC0",
39
+ "tags": ["platformer", "pixel-art", "retro"]
40
+ },
41
+ {
42
+ "id": "abstract-platformer",
43
+ "name": "Abstract Platformer (250 assets)",
44
+ "description": "Colorful abstract shapes for platformer games",
45
+ "type": ["2d-sprites"],
46
+ "license": "CC0",
47
+ "tags": ["platformer", "abstract", "shapes"]
48
+ }
49
+ ],
50
+ "total": 3
51
+ }
52
+ ```
53
+
54
+ ### Step 2: Get Detailed Information
55
+
56
+ **Agent examines the top result:**
57
+
58
+ ```typescript
59
+ // MCP Tool Call
60
+ get_kenney_asset({
61
+ id: "platformer-pack-redux"
62
+ })
63
+ ```
64
+
65
+ **Result:**
66
+ ```json
67
+ {
68
+ "id": "platformer-pack-redux",
69
+ "name": "Platformer Pack Redux (360 assets)",
70
+ "description": "Complete platformer art pack with characters, tiles, items, and enemies",
71
+ "source": "kenney",
72
+ "type": ["2d-sprites", "tilesets"],
73
+ "license": "CC0",
74
+ "url": "https://kenney.nl/assets/platformer-pack-redux",
75
+ "downloadUrl": "https://kenney.nl/content/3-assets/145-platformer-pack-redux/platformerpackredux.zip",
76
+ "tags": ["platformer", "character", "tiles", "pixel-art"]
77
+ }
78
+ ```
79
+
80
+ ### Step 3: Download the Asset Pack
81
+
82
+ **Agent downloads to project assets directory:**
83
+
84
+ ```typescript
85
+ // MCP Tool Call
86
+ download_kenney_asset({
87
+ id: "platformer-pack-redux",
88
+ destination: "./demos/platformer/assets"
89
+ })
90
+ ```
91
+
92
+ **Result:**
93
+ ```json
94
+ {
95
+ "success": true,
96
+ "path": "./demos/platformer/assets/platformerpackredux.zip"
97
+ }
98
+ ```
99
+
100
+ ### Step 4: Extract and Organize
101
+
102
+ **Agent extracts the downloaded archive:**
103
+
104
+ ```bash
105
+ # Agent runs bash command
106
+ cd demos/platformer/assets
107
+ unzip platformerpackredux.zip
108
+ rm platformerpackredux.zip
109
+ ```
110
+
111
+ **Result structure:**
112
+ ```
113
+ demos/platformer/assets/
114
+ └── platformerpackredux/
115
+ ├── PNG/
116
+ │ ├── Players/
117
+ │ ├── Tiles/
118
+ │ ├── Items/
119
+ │ └── Enemies/
120
+ ├── Spritesheet/
121
+ │ └── spritesheet.png
122
+ └── License.txt
123
+ ```
124
+
125
+ ### Step 5: Integrate into Game Code
126
+
127
+ **Agent updates the platformer demo to use the assets:**
128
+
129
+ ```typescript
130
+ // demos/platformer/platformer-visual.ts
131
+ import { loadTexture } from "../../runtime/rendering/texture.ts";
132
+ import { drawSprite } from "../../runtime/rendering/sprites.ts";
133
+
134
+ // Load sprite sheet
135
+ const spriteSheet = loadTexture("./assets/platformerpackredux/Spritesheet/spritesheet.png");
136
+
137
+ // Use in game
138
+ function renderPlayer(state: GameState) {
139
+ const player = state.entities.player;
140
+
141
+ drawSprite({
142
+ textureId: spriteSheet,
143
+ x: player.position.x,
144
+ y: player.position.y,
145
+ width: 32,
146
+ height: 32,
147
+ // Calculate UV coordinates for player sprite in sheet
148
+ uvX: 0,
149
+ uvY: 0,
150
+ uvWidth: 32,
151
+ uvHeight: 32,
152
+ });
153
+ }
154
+ ```
155
+
156
+ ### Step 6: Add UI Assets
157
+
158
+ **Agent searches for UI elements:**
159
+
160
+ ```typescript
161
+ // MCP Tool Call
162
+ search_kenney_assets({
163
+ query: "ui",
164
+ type: "ui"
165
+ })
166
+ ```
167
+
168
+ **Agent downloads UI pack:**
169
+
170
+ ```typescript
171
+ // MCP Tool Call
172
+ download_kenney_asset({
173
+ id: "ui-pack",
174
+ destination: "./demos/platformer/assets"
175
+ })
176
+ ```
177
+
178
+ ### Step 7: Add Sound Effects
179
+
180
+ **Agent searches for audio:**
181
+
182
+ ```typescript
183
+ // MCP Tool Call
184
+ search_kenney_assets({
185
+ query: "impact",
186
+ type: "audio"
187
+ })
188
+ ```
189
+
190
+ **Agent downloads sound pack:**
191
+
192
+ ```typescript
193
+ // MCP Tool Call
194
+ download_kenney_asset({
195
+ id: "impact-sounds",
196
+ destination: "./demos/platformer/assets"
197
+ })
198
+ ```
199
+
200
+ ## Scenario: Building a Roguelike
201
+
202
+ An agent needs dungeon assets for a roguelike game.
203
+
204
+ ### Quick Search and Download
205
+
206
+ ```typescript
207
+ // Search for dungeon assets
208
+ search_kenney_assets({ query: "dungeon", type: "tilesets" })
209
+
210
+ // Results: tiny-dungeon, roguelike-rpg-pack, 1-bit-pack
211
+
212
+ // Download tiny-dungeon for minimal pixel art style
213
+ download_kenney_asset({
214
+ id: "tiny-dungeon",
215
+ destination: "./demos/roguelike/assets"
216
+ })
217
+ ```
218
+
219
+ ## Benefits for Agent Workflow
220
+
221
+ 1. **No manual browsing** - Agent searches programmatically
222
+ 2. **Metadata-driven decisions** - Agent evaluates options based on structured data
223
+ 3. **Automated downloads** - No copy-paste of URLs or manual clicks
224
+ 4. **Consistent organization** - Assets downloaded to specified directories
225
+ 5. **License-safe** - All Kenney assets are CC0, no attribution concerns
226
+
227
+ ## Interactive Discovery
228
+
229
+ **Agent can explore the catalog systematically:**
230
+
231
+ ```typescript
232
+ // List all available types
233
+ get_asset_types()
234
+ // Returns: ["2d-sprites", "3d-models", "audio", "fonts", "tilesets", "ui", "vfx"]
235
+
236
+ // List all searchable tags
237
+ get_tags()
238
+ // Returns: ["1-bit", "abstract", "audio", "blocks", "button", "dungeon", ...]
239
+
240
+ // Browse full catalog
241
+ list_kenney_assets()
242
+ // Returns: All 24 curated packs with metadata
243
+ ```
244
+
245
+ ## Error Handling
246
+
247
+ **If asset not found:**
248
+
249
+ ```typescript
250
+ get_kenney_asset({ id: "nonexistent-pack" })
251
+ ```
252
+
253
+ **Result:**
254
+ ```json
255
+ {
256
+ "content": [{ "type": "text", "text": "Asset pack 'nonexistent-pack' not found" }],
257
+ "isError": true
258
+ }
259
+ ```
260
+
261
+ **If download fails:**
262
+
263
+ ```typescript
264
+ download_kenney_asset({
265
+ id: "platformer-pack-redux",
266
+ destination: "/invalid/path"
267
+ })
268
+ ```
269
+
270
+ **Result:**
271
+ ```json
272
+ {
273
+ "success": false,
274
+ "error": "EACCES: permission denied, mkdir '/invalid/path'"
275
+ }
276
+ ```
277
+
278
+ ## Next Steps
279
+
280
+ 1. **Test the MCP server** - Use Claude Code to interact with the tools
281
+ 2. **Extend catalog** - Add more Kenney packs as needed
282
+ 3. **Add Freesound.org** - Integrate sound effects API
283
+ 4. **Add itch.io** - Connect to community asset marketplace
284
+ 5. **Create `/add-asset` skill** - Build interactive CLI skill using MCP tools
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { listKenneyAssets, searchKenneyAssets, getKenneyAsset, downloadKenneyAsset, getAssetTypes, getTags, } from "./kenney.js";
6
+ /**
7
+ * Arcane Assets MCP Server
8
+ *
9
+ * Provides tools for discovering and downloading game assets from:
10
+ * - Kenney.nl (CC0 assets)
11
+ * - Freesound.org (future)
12
+ * - itch.io (future)
13
+ */
14
+ const server = new Server({
15
+ name: "arcane-assets",
16
+ version: "0.1.0",
17
+ }, {
18
+ capabilities: {
19
+ tools: {},
20
+ },
21
+ });
22
+ /**
23
+ * Define available tools
24
+ */
25
+ const TOOLS = [
26
+ {
27
+ name: "list_kenney_assets",
28
+ description: "List all available Kenney.nl asset packs. Returns the full catalog with metadata for each pack.",
29
+ inputSchema: {
30
+ type: "object",
31
+ properties: {},
32
+ },
33
+ },
34
+ {
35
+ name: "search_kenney_assets",
36
+ description: "Search Kenney.nl asset packs by keyword. Searches across pack names, descriptions, and tags.",
37
+ inputSchema: {
38
+ type: "object",
39
+ properties: {
40
+ query: {
41
+ type: "string",
42
+ description: "Search query (e.g., 'platformer', 'dungeon', 'ui')",
43
+ },
44
+ type: {
45
+ type: "string",
46
+ enum: [
47
+ "2d-sprites",
48
+ "3d-models",
49
+ "ui",
50
+ "audio",
51
+ "fonts",
52
+ "vfx",
53
+ "tilesets",
54
+ "textures",
55
+ ],
56
+ description: "Optional: filter by asset type",
57
+ },
58
+ },
59
+ required: ["query"],
60
+ },
61
+ },
62
+ {
63
+ name: "get_kenney_asset",
64
+ description: "Get detailed information about a specific Kenney.nl asset pack by ID.",
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: {
68
+ id: {
69
+ type: "string",
70
+ description: "Asset pack ID (e.g., 'platformer-pack-redux', 'tiny-dungeon')",
71
+ },
72
+ },
73
+ required: ["id"],
74
+ },
75
+ },
76
+ {
77
+ name: "download_kenney_asset",
78
+ description: "Download a Kenney.nl asset pack to a local directory. Returns the path to the downloaded file.",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ id: {
83
+ type: "string",
84
+ description: "Asset pack ID (e.g., 'platformer-pack-redux', 'tiny-dungeon')",
85
+ },
86
+ destination: {
87
+ type: "string",
88
+ description: "Destination directory path (e.g., './assets', './downloads')",
89
+ },
90
+ },
91
+ required: ["id", "destination"],
92
+ },
93
+ },
94
+ {
95
+ name: "get_asset_types",
96
+ description: "Get a list of all asset types available in the Kenney catalog.",
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {},
100
+ },
101
+ },
102
+ {
103
+ name: "get_tags",
104
+ description: "Get a list of all tags used in the Kenney catalog. Useful for discovering search keywords.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: {},
108
+ },
109
+ },
110
+ ];
111
+ /**
112
+ * Handle list_tools request
113
+ */
114
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
115
+ return { tools: TOOLS };
116
+ });
117
+ /**
118
+ * Handle call_tool request
119
+ */
120
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
121
+ const { name, arguments: args } = request.params;
122
+ try {
123
+ switch (name) {
124
+ case "list_kenney_assets": {
125
+ const packs = listKenneyAssets();
126
+ return {
127
+ content: [
128
+ {
129
+ type: "text",
130
+ text: JSON.stringify(packs, null, 2),
131
+ },
132
+ ],
133
+ };
134
+ }
135
+ case "search_kenney_assets": {
136
+ const { query, type } = args;
137
+ const result = searchKenneyAssets(query, type);
138
+ let responseText = JSON.stringify(result, null, 2);
139
+ // Add helpful message if no results found
140
+ if (result.total === 0 && result.suggestions) {
141
+ responseText = `No results found for "${query}".\n\nSuggestions:\n${result.suggestions.map(s => ` • ${s}`).join('\n')}\n\n` + responseText;
142
+ }
143
+ return {
144
+ content: [
145
+ {
146
+ type: "text",
147
+ text: responseText,
148
+ },
149
+ ],
150
+ };
151
+ }
152
+ case "get_kenney_asset": {
153
+ const { id } = args;
154
+ const pack = getKenneyAsset(id);
155
+ if (!pack) {
156
+ return {
157
+ content: [
158
+ {
159
+ type: "text",
160
+ text: `Asset pack '${id}' not found`,
161
+ },
162
+ ],
163
+ isError: true,
164
+ };
165
+ }
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: JSON.stringify(pack, null, 2),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ case "download_kenney_asset": {
176
+ const { id, destination } = args;
177
+ const result = await downloadKenneyAsset(id, destination);
178
+ return {
179
+ content: [
180
+ {
181
+ type: "text",
182
+ text: JSON.stringify(result, null, 2),
183
+ },
184
+ ],
185
+ isError: !result.success,
186
+ };
187
+ }
188
+ case "get_asset_types": {
189
+ const types = getAssetTypes();
190
+ return {
191
+ content: [
192
+ {
193
+ type: "text",
194
+ text: JSON.stringify(types, null, 2),
195
+ },
196
+ ],
197
+ };
198
+ }
199
+ case "get_tags": {
200
+ const tags = getTags();
201
+ return {
202
+ content: [
203
+ {
204
+ type: "text",
205
+ text: JSON.stringify(tags, null, 2),
206
+ },
207
+ ],
208
+ };
209
+ }
210
+ default:
211
+ return {
212
+ content: [
213
+ {
214
+ type: "text",
215
+ text: `Unknown tool: ${name}`,
216
+ },
217
+ ],
218
+ isError: true,
219
+ };
220
+ }
221
+ }
222
+ catch (error) {
223
+ return {
224
+ content: [
225
+ {
226
+ type: "text",
227
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
228
+ },
229
+ ],
230
+ isError: true,
231
+ };
232
+ }
233
+ });
234
+ /**
235
+ * Start the server
236
+ */
237
+ async function main() {
238
+ const transport = new StdioServerTransport();
239
+ await server.connect(transport);
240
+ console.error("Arcane Assets MCP Server running on stdio");
241
+ }
242
+ main().catch((error) => {
243
+ console.error("Fatal error:", error);
244
+ process.exit(1);
245
+ });
@@ -0,0 +1,8 @@
1
+ import { AssetPack } from "./types.js";
2
+ /**
3
+ * Curated catalog of popular Kenney.nl asset packs
4
+ *
5
+ * All Kenney assets are CC0 (public domain) - no attribution required.
6
+ * Download URLs point to kenney.nl direct download links.
7
+ */
8
+ export declare const KENNEY_CATALOG: AssetPack[];