burnrate 0.1.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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +507 -0
  3. package/dist/cli/format.d.ts +13 -0
  4. package/dist/cli/format.js +319 -0
  5. package/dist/cli/index.d.ts +7 -0
  6. package/dist/cli/index.js +1121 -0
  7. package/dist/cli/setup.d.ts +8 -0
  8. package/dist/cli/setup.js +143 -0
  9. package/dist/core/async-engine.d.ts +411 -0
  10. package/dist/core/async-engine.js +2274 -0
  11. package/dist/core/async-worldgen.d.ts +19 -0
  12. package/dist/core/async-worldgen.js +221 -0
  13. package/dist/core/engine.d.ts +154 -0
  14. package/dist/core/engine.js +1104 -0
  15. package/dist/core/pathfinding.d.ts +38 -0
  16. package/dist/core/pathfinding.js +146 -0
  17. package/dist/core/types.d.ts +489 -0
  18. package/dist/core/types.js +359 -0
  19. package/dist/core/worldgen.d.ts +22 -0
  20. package/dist/core/worldgen.js +292 -0
  21. package/dist/db/database.d.ts +83 -0
  22. package/dist/db/database.js +829 -0
  23. package/dist/db/turso-database.d.ts +177 -0
  24. package/dist/db/turso-database.js +1586 -0
  25. package/dist/mcp/server.d.ts +7 -0
  26. package/dist/mcp/server.js +1877 -0
  27. package/dist/server/api.d.ts +8 -0
  28. package/dist/server/api.js +1234 -0
  29. package/dist/server/async-tick-server.d.ts +5 -0
  30. package/dist/server/async-tick-server.js +63 -0
  31. package/dist/server/errors.d.ts +78 -0
  32. package/dist/server/errors.js +156 -0
  33. package/dist/server/rate-limit.d.ts +22 -0
  34. package/dist/server/rate-limit.js +134 -0
  35. package/dist/server/tick-server.d.ts +9 -0
  36. package/dist/server/tick-server.js +114 -0
  37. package/dist/server/validation.d.ts +194 -0
  38. package/dist/server/validation.js +114 -0
  39. package/package.json +65 -0
@@ -0,0 +1,1877 @@
1
+ /**
2
+ * BURNRATE MCP Server
3
+ * Model Context Protocol server for Claude Code integration
4
+ *
5
+ * This runs locally and connects to the hosted game API
6
+ */
7
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
10
+ // API client for the hosted game server
11
+ class GameAPIClient {
12
+ baseUrl;
13
+ apiKey;
14
+ constructor(baseUrl, apiKey = null) {
15
+ this.baseUrl = baseUrl;
16
+ this.apiKey = apiKey;
17
+ }
18
+ setApiKey(key) {
19
+ this.apiKey = key;
20
+ }
21
+ async request(method, path, body, requiresAuth = true) {
22
+ const headers = {
23
+ 'Content-Type': 'application/json'
24
+ };
25
+ if (requiresAuth && this.apiKey) {
26
+ headers['X-API-Key'] = this.apiKey;
27
+ }
28
+ const response = await fetch(`${this.baseUrl}${path}`, {
29
+ method,
30
+ headers,
31
+ body: body ? JSON.stringify(body) : undefined
32
+ });
33
+ const data = await response.json();
34
+ if (!response.ok) {
35
+ throw new Error(data.error || `API error: ${response.status}`);
36
+ }
37
+ return data;
38
+ }
39
+ // Public endpoints
40
+ async getServerStatus() {
41
+ return this.request('GET', '/health', null, false);
42
+ }
43
+ async getWorldStatus() {
44
+ return this.request('GET', '/world/status', null, false);
45
+ }
46
+ async join(name) {
47
+ return this.request('POST', '/join', { name }, false);
48
+ }
49
+ // Authenticated endpoints
50
+ async getMe() {
51
+ return this.request('GET', '/me');
52
+ }
53
+ async getZones() {
54
+ return this.request('GET', '/world/zones');
55
+ }
56
+ async getZone(id) {
57
+ return this.request('GET', `/world/zones/${id}`);
58
+ }
59
+ async getRoutes(from) {
60
+ const query = from ? `?from=${from}` : '';
61
+ return this.request('GET', `/routes${query}`);
62
+ }
63
+ async travel(to) {
64
+ return this.request('POST', '/travel', { to });
65
+ }
66
+ async extract(quantity) {
67
+ return this.request('POST', '/extract', { quantity });
68
+ }
69
+ async produce(output, quantity) {
70
+ return this.request('POST', '/produce', { output, quantity });
71
+ }
72
+ async ship(type, path, cargo) {
73
+ return this.request('POST', '/ship', { type, path, cargo });
74
+ }
75
+ async getShipments() {
76
+ return this.request('GET', '/shipments');
77
+ }
78
+ async placeOrder(resource, side, price, quantity) {
79
+ return this.request('POST', '/market/order', { resource, side, price, quantity });
80
+ }
81
+ async getMarketOrders(resource) {
82
+ const query = resource ? `?resource=${resource}` : '';
83
+ return this.request('GET', `/market/orders${query}`);
84
+ }
85
+ async scan(targetType, targetId) {
86
+ return this.request('POST', '/scan', { targetType, targetId });
87
+ }
88
+ async supply(amount) {
89
+ return this.request('POST', '/supply', { amount });
90
+ }
91
+ async capture() {
92
+ return this.request('POST', '/capture');
93
+ }
94
+ async depositStockpile(resource, amount) {
95
+ return this.request('POST', '/stockpile', { resource, amount });
96
+ }
97
+ async getZoneEfficiency(zoneId) {
98
+ return this.request('GET', `/zone/${zoneId}/efficiency`);
99
+ }
100
+ async getUnits() {
101
+ return this.request('GET', '/units');
102
+ }
103
+ async assignEscort(unitId, shipmentId) {
104
+ return this.request('POST', `/units/${unitId}/escort`, { shipmentId });
105
+ }
106
+ async deployRaider(unitId, routeId) {
107
+ return this.request('POST', `/units/${unitId}/raider`, { routeId });
108
+ }
109
+ async listUnitForSale(unitId, price) {
110
+ return this.request('POST', `/units/${unitId}/sell`, { price });
111
+ }
112
+ async unlistUnit(unitId) {
113
+ return this.request('DELETE', `/units/${unitId}/sell`);
114
+ }
115
+ async hireUnit(unitId) {
116
+ return this.request('POST', `/hire/${unitId}`);
117
+ }
118
+ async getUnitsForSale() {
119
+ return this.request('GET', '/market/units');
120
+ }
121
+ async getFactions() {
122
+ return this.request('GET', '/factions');
123
+ }
124
+ async createFaction(name, tag) {
125
+ return this.request('POST', '/factions', { name, tag });
126
+ }
127
+ async joinFaction(factionId) {
128
+ return this.request('POST', `/factions/${factionId}/join`);
129
+ }
130
+ async leaveFaction() {
131
+ return this.request('POST', '/factions/leave');
132
+ }
133
+ async getFactionDetails() {
134
+ return this.request('GET', '/factions/mine');
135
+ }
136
+ async promoteFactionMember(playerId) {
137
+ return this.request('POST', `/factions/members/${playerId}/promote`, { rank: 'officer' });
138
+ }
139
+ async demoteFactionMember(playerId) {
140
+ return this.request('POST', `/factions/members/${playerId}/demote`, { rank: 'member' });
141
+ }
142
+ async kickFactionMember(playerId) {
143
+ return this.request('DELETE', `/factions/members/${playerId}`);
144
+ }
145
+ async transferFactionLeadership(playerId) {
146
+ return this.request('POST', '/factions/transfer-leadership', { targetPlayerId: playerId });
147
+ }
148
+ async depositToTreasury(resources) {
149
+ return this.request('POST', '/factions/treasury/deposit', { resources });
150
+ }
151
+ async withdrawFromTreasury(resources) {
152
+ return this.request('POST', '/factions/treasury/withdraw', { resources });
153
+ }
154
+ async getFactionIntel() {
155
+ return this.request('GET', '/factions/intel');
156
+ }
157
+ async getContracts() {
158
+ return this.request('GET', '/contracts');
159
+ }
160
+ async getMyContracts() {
161
+ return this.request('GET', '/contracts/mine');
162
+ }
163
+ async createContract(type, details, reward, deadline, bonus, bonusDeadline) {
164
+ return this.request('POST', '/contracts', {
165
+ type,
166
+ ...details,
167
+ reward,
168
+ deadline,
169
+ bonus,
170
+ bonusDeadline
171
+ });
172
+ }
173
+ async acceptContract(contractId) {
174
+ return this.request('POST', `/contracts/${contractId}/accept`);
175
+ }
176
+ async completeContract(contractId) {
177
+ return this.request('POST', `/contracts/${contractId}/complete`);
178
+ }
179
+ async cancelContract(contractId) {
180
+ return this.request('DELETE', `/contracts/${contractId}`);
181
+ }
182
+ async getIntel(limit) {
183
+ const query = limit ? `?limit=${limit}` : '';
184
+ return this.request('GET', `/intel${query}`);
185
+ }
186
+ async getTargetIntel(targetType, targetId) {
187
+ return this.request('GET', `/intel/${targetType}/${targetId}`);
188
+ }
189
+ async getSeasonStatus() {
190
+ return this.request('GET', '/season');
191
+ }
192
+ async getLeaderboard(season, type, limit) {
193
+ const params = new URLSearchParams();
194
+ if (season)
195
+ params.append('season', String(season));
196
+ if (type)
197
+ params.append('type', type);
198
+ if (limit)
199
+ params.append('limit', String(limit));
200
+ const query = params.toString() ? `?${params.toString()}` : '';
201
+ return this.request('GET', `/leaderboard${query}`);
202
+ }
203
+ async getSeasonScore(season) {
204
+ const query = season ? `?season=${season}` : '';
205
+ return this.request('GET', `/season/me${query}`);
206
+ }
207
+ async getEvents(type, limit) {
208
+ const params = new URLSearchParams();
209
+ if (type)
210
+ params.append('type', type);
211
+ if (limit)
212
+ params.append('limit', String(limit));
213
+ const query = params.toString() ? `?${params.toString()}` : '';
214
+ return this.request('GET', `/events${query}`);
215
+ }
216
+ async getReputation() {
217
+ return this.request('GET', '/reputation');
218
+ }
219
+ async getLicenses() {
220
+ return this.request('GET', '/licenses');
221
+ }
222
+ async unlockLicense(type) {
223
+ return this.request('POST', `/licenses/${type}/unlock`);
224
+ }
225
+ // Phase 2: Tutorial
226
+ async getTutorialStatus() {
227
+ return this.request('GET', '/tutorial');
228
+ }
229
+ async completeTutorialStep(step) {
230
+ return this.request('POST', '/tutorial/complete', { step });
231
+ }
232
+ // Phase 4: Subscription
233
+ async getSubscription() {
234
+ return this.request('GET', '/subscription');
235
+ }
236
+ async upgradeSubscription(tier) {
237
+ return this.request('POST', '/subscription/upgrade', { tier });
238
+ }
239
+ // Phase 5: Doctrines
240
+ async getDoctrines() {
241
+ return this.request('GET', '/doctrines');
242
+ }
243
+ async createDoctrine(title, content) {
244
+ return this.request('POST', '/doctrines', { title, content });
245
+ }
246
+ async updateDoctrine(id, content) {
247
+ return this.request('PUT', `/doctrines/${id}`, { content });
248
+ }
249
+ async deleteDoctrine(id) {
250
+ return this.request('DELETE', `/doctrines/${id}`);
251
+ }
252
+ // Phase 5: Advanced market orders
253
+ async createConditionalOrder(zoneId, resource, side, triggerPrice, quantity, condition) {
254
+ return this.request('POST', '/market/conditional', { zoneId, resource, side, triggerPrice, quantity, condition });
255
+ }
256
+ async createTimeWeightedOrder(zoneId, resource, side, price, totalQuantity, quantityPerTick) {
257
+ return this.request('POST', '/market/time-weighted', { zoneId, resource, side, price, totalQuantity, quantityPerTick });
258
+ }
259
+ // Phase 6: Webhooks
260
+ async getWebhooks() {
261
+ return this.request('GET', '/webhooks');
262
+ }
263
+ async registerWebhook(url, events) {
264
+ return this.request('POST', '/webhooks', { url, events });
265
+ }
266
+ async deleteWebhook(id) {
267
+ return this.request('DELETE', `/webhooks/${id}`);
268
+ }
269
+ // Phase 6: Data export
270
+ async exportData() {
271
+ return this.request('GET', '/me/export');
272
+ }
273
+ // Phase 6: Batch operations
274
+ async executeBatch(operations) {
275
+ return this.request('POST', '/batch', { operations });
276
+ }
277
+ // Phase 7: Faction analytics
278
+ async getFactionAnalytics() {
279
+ return this.request('GET', '/faction/analytics');
280
+ }
281
+ async getFactionAuditLogs(limit) {
282
+ const query = limit ? `?limit=${limit}` : '';
283
+ return this.request('GET', `/faction/audit${query}`);
284
+ }
285
+ }
286
+ // MCP Server
287
+ const API_URL = process.env.BURNRATE_API_URL || 'http://localhost:3000';
288
+ const client = new GameAPIClient(API_URL);
289
+ // Load API key from environment or config
290
+ if (process.env.BURNRATE_API_KEY) {
291
+ client.setApiKey(process.env.BURNRATE_API_KEY);
292
+ }
293
+ const server = new Server({
294
+ name: 'burnrate',
295
+ version: '1.0.0',
296
+ }, {
297
+ capabilities: {
298
+ tools: {},
299
+ resources: {},
300
+ prompts: {},
301
+ },
302
+ });
303
+ // ============================================================================
304
+ // TOOLS
305
+ // ============================================================================
306
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
307
+ return {
308
+ tools: [
309
+ {
310
+ name: 'burnrate_status',
311
+ description: 'Get your current player status including inventory, location, and stats',
312
+ inputSchema: { type: 'object', properties: {}, required: [] }
313
+ },
314
+ {
315
+ name: 'burnrate_join',
316
+ description: 'Join the BURNRATE game with a new character. Returns your API key.',
317
+ inputSchema: {
318
+ type: 'object',
319
+ properties: {
320
+ name: { type: 'string', description: 'Your player name (2-20 characters)' }
321
+ },
322
+ required: ['name']
323
+ }
324
+ },
325
+ {
326
+ name: 'burnrate_set_api_key',
327
+ description: 'Set your API key to authenticate with BURNRATE',
328
+ inputSchema: {
329
+ type: 'object',
330
+ properties: {
331
+ apiKey: { type: 'string', description: 'Your BURNRATE API key' }
332
+ },
333
+ required: ['apiKey']
334
+ }
335
+ },
336
+ {
337
+ name: 'burnrate_view',
338
+ description: 'View the world map or a specific zone',
339
+ inputSchema: {
340
+ type: 'object',
341
+ properties: {
342
+ zoneId: { type: 'string', description: 'Optional: specific zone ID to view details' }
343
+ },
344
+ required: []
345
+ }
346
+ },
347
+ {
348
+ name: 'burnrate_routes',
349
+ description: 'View available routes from your current location or a specified zone',
350
+ inputSchema: {
351
+ type: 'object',
352
+ properties: {
353
+ from: { type: 'string', description: 'Optional: zone ID to view routes from' }
354
+ },
355
+ required: []
356
+ }
357
+ },
358
+ {
359
+ name: 'burnrate_travel',
360
+ description: 'Travel to an adjacent zone',
361
+ inputSchema: {
362
+ type: 'object',
363
+ properties: {
364
+ to: { type: 'string', description: 'Zone ID to travel to' }
365
+ },
366
+ required: ['to']
367
+ }
368
+ },
369
+ {
370
+ name: 'burnrate_extract',
371
+ description: 'Extract raw resources at a Field. Costs 5 credits per unit.',
372
+ inputSchema: {
373
+ type: 'object',
374
+ properties: {
375
+ quantity: { type: 'number', description: 'Amount to extract' }
376
+ },
377
+ required: ['quantity']
378
+ }
379
+ },
380
+ {
381
+ name: 'burnrate_produce',
382
+ description: 'Produce resources or units at a Factory. Use recipe names: metal, chemicals, rations, textiles, ammo, medkits, parts, comms, escort, raider',
383
+ inputSchema: {
384
+ type: 'object',
385
+ properties: {
386
+ output: { type: 'string', description: 'What to produce' },
387
+ quantity: { type: 'number', description: 'Amount to produce' }
388
+ },
389
+ required: ['output', 'quantity']
390
+ }
391
+ },
392
+ {
393
+ name: 'burnrate_ship',
394
+ description: 'Send a shipment along a route. You must specify explicit waypoints.',
395
+ inputSchema: {
396
+ type: 'object',
397
+ properties: {
398
+ type: { type: 'string', enum: ['courier', 'freight', 'convoy'], description: 'Shipment type' },
399
+ path: { type: 'array', items: { type: 'string' }, description: 'Array of zone IDs forming the route' },
400
+ cargo: { type: 'object', description: 'Cargo as {resource: amount}' }
401
+ },
402
+ required: ['type', 'path', 'cargo']
403
+ }
404
+ },
405
+ {
406
+ name: 'burnrate_shipments',
407
+ description: 'View your active shipments',
408
+ inputSchema: { type: 'object', properties: {}, required: [] }
409
+ },
410
+ {
411
+ name: 'burnrate_market_buy',
412
+ description: 'Place a buy order on the market',
413
+ inputSchema: {
414
+ type: 'object',
415
+ properties: {
416
+ resource: { type: 'string', description: 'Resource to buy' },
417
+ price: { type: 'number', description: 'Max price per unit' },
418
+ quantity: { type: 'number', description: 'Amount to buy' }
419
+ },
420
+ required: ['resource', 'price', 'quantity']
421
+ }
422
+ },
423
+ {
424
+ name: 'burnrate_market_sell',
425
+ description: 'Place a sell order on the market',
426
+ inputSchema: {
427
+ type: 'object',
428
+ properties: {
429
+ resource: { type: 'string', description: 'Resource to sell' },
430
+ price: { type: 'number', description: 'Price per unit' },
431
+ quantity: { type: 'number', description: 'Amount to sell' }
432
+ },
433
+ required: ['resource', 'price', 'quantity']
434
+ }
435
+ },
436
+ {
437
+ name: 'burnrate_market_view',
438
+ description: 'View market orders at your current location',
439
+ inputSchema: {
440
+ type: 'object',
441
+ properties: {
442
+ resource: { type: 'string', description: 'Optional: filter by resource' }
443
+ },
444
+ required: []
445
+ }
446
+ },
447
+ {
448
+ name: 'burnrate_scan',
449
+ description: 'Gather intel on a zone or route. Intel is shared with your faction.',
450
+ inputSchema: {
451
+ type: 'object',
452
+ properties: {
453
+ targetType: { type: 'string', enum: ['zone', 'route'], description: 'What to scan' },
454
+ targetId: { type: 'string', description: 'Zone or route ID' }
455
+ },
456
+ required: ['targetType', 'targetId']
457
+ }
458
+ },
459
+ {
460
+ name: 'burnrate_supply',
461
+ description: 'Deposit Supply Units to a zone. Requires 2 rations + 1 fuel + 1 parts + 1 ammo per SU.',
462
+ inputSchema: {
463
+ type: 'object',
464
+ properties: {
465
+ amount: { type: 'number', description: 'Number of SU to deposit' }
466
+ },
467
+ required: ['amount']
468
+ }
469
+ },
470
+ {
471
+ name: 'burnrate_capture',
472
+ description: 'Capture your current zone for your faction. Zone must be neutral or collapsed.',
473
+ inputSchema: { type: 'object', properties: {}, required: [] }
474
+ },
475
+ {
476
+ name: 'burnrate_stockpile',
477
+ description: 'Deposit medkits or comms to your current zone stockpile. Medkits boost combat defense, comms degrade enemy scans.',
478
+ inputSchema: {
479
+ type: 'object',
480
+ properties: {
481
+ resource: { type: 'string', enum: ['medkits', 'comms'], description: 'Resource to stockpile' },
482
+ amount: { type: 'number', description: 'Amount to deposit' }
483
+ },
484
+ required: ['resource', 'amount']
485
+ }
486
+ },
487
+ {
488
+ name: 'burnrate_zone_efficiency',
489
+ description: 'View zone efficiency bonuses including raid resistance, capture defense, production bonus, medkit bonus, and comms defense.',
490
+ inputSchema: {
491
+ type: 'object',
492
+ properties: {
493
+ zoneId: { type: 'string', description: 'Zone ID to check' }
494
+ },
495
+ required: ['zoneId']
496
+ }
497
+ },
498
+ {
499
+ name: 'burnrate_units',
500
+ description: 'View your military units',
501
+ inputSchema: { type: 'object', properties: {}, required: [] }
502
+ },
503
+ {
504
+ name: 'burnrate_units_escort',
505
+ description: 'Assign an escort unit to protect a shipment',
506
+ inputSchema: {
507
+ type: 'object',
508
+ properties: {
509
+ unitId: { type: 'string', description: 'Escort unit ID' },
510
+ shipmentId: { type: 'string', description: 'Shipment ID to protect' }
511
+ },
512
+ required: ['unitId', 'shipmentId']
513
+ }
514
+ },
515
+ {
516
+ name: 'burnrate_units_raider',
517
+ description: 'Deploy a raider unit to interdict a route',
518
+ inputSchema: {
519
+ type: 'object',
520
+ properties: {
521
+ unitId: { type: 'string', description: 'Raider unit ID' },
522
+ routeId: { type: 'string', description: 'Route ID to interdict' }
523
+ },
524
+ required: ['unitId', 'routeId']
525
+ }
526
+ },
527
+ {
528
+ name: 'burnrate_units_sell',
529
+ description: 'List a unit for sale at a Hub',
530
+ inputSchema: {
531
+ type: 'object',
532
+ properties: {
533
+ unitId: { type: 'string', description: 'Unit ID to sell' },
534
+ price: { type: 'number', description: 'Sale price in credits' }
535
+ },
536
+ required: ['unitId', 'price']
537
+ }
538
+ },
539
+ {
540
+ name: 'burnrate_hire',
541
+ description: 'Buy a unit listed for sale at your current Hub',
542
+ inputSchema: {
543
+ type: 'object',
544
+ properties: {
545
+ unitId: { type: 'string', description: 'Unit ID to buy' }
546
+ },
547
+ required: ['unitId']
548
+ }
549
+ },
550
+ {
551
+ name: 'burnrate_faction_create',
552
+ description: 'Create a new faction',
553
+ inputSchema: {
554
+ type: 'object',
555
+ properties: {
556
+ name: { type: 'string', description: 'Faction name' },
557
+ tag: { type: 'string', description: 'Faction tag (2-5 characters)' }
558
+ },
559
+ required: ['name', 'tag']
560
+ }
561
+ },
562
+ {
563
+ name: 'burnrate_faction_join',
564
+ description: 'Join an existing faction',
565
+ inputSchema: {
566
+ type: 'object',
567
+ properties: {
568
+ factionId: { type: 'string', description: 'Faction ID to join' }
569
+ },
570
+ required: ['factionId']
571
+ }
572
+ },
573
+ {
574
+ name: 'burnrate_faction_leave',
575
+ description: 'Leave your current faction',
576
+ inputSchema: { type: 'object', properties: {}, required: [] }
577
+ },
578
+ {
579
+ name: 'burnrate_faction_intel',
580
+ description: 'View intel shared by your faction members',
581
+ inputSchema: { type: 'object', properties: {}, required: [] }
582
+ },
583
+ {
584
+ name: 'burnrate_factions',
585
+ description: 'List all factions',
586
+ inputSchema: { type: 'object', properties: {}, required: [] }
587
+ },
588
+ {
589
+ name: 'burnrate_faction_details',
590
+ description: 'Get detailed info about your faction including treasury, members, and controlled zones',
591
+ inputSchema: { type: 'object', properties: {}, required: [] }
592
+ },
593
+ {
594
+ name: 'burnrate_faction_promote',
595
+ description: 'Promote a faction member to officer (founder only)',
596
+ inputSchema: {
597
+ type: 'object',
598
+ properties: {
599
+ playerId: { type: 'string', description: 'Player ID to promote' }
600
+ },
601
+ required: ['playerId']
602
+ }
603
+ },
604
+ {
605
+ name: 'burnrate_faction_demote',
606
+ description: 'Demote a faction member to member (founder only)',
607
+ inputSchema: {
608
+ type: 'object',
609
+ properties: {
610
+ playerId: { type: 'string', description: 'Player ID to demote' }
611
+ },
612
+ required: ['playerId']
613
+ }
614
+ },
615
+ {
616
+ name: 'burnrate_faction_kick',
617
+ description: 'Kick a member from your faction (founder/officer)',
618
+ inputSchema: {
619
+ type: 'object',
620
+ properties: {
621
+ playerId: { type: 'string', description: 'Player ID to kick' }
622
+ },
623
+ required: ['playerId']
624
+ }
625
+ },
626
+ {
627
+ name: 'burnrate_faction_transfer',
628
+ description: 'Transfer faction leadership to another member (founder only)',
629
+ inputSchema: {
630
+ type: 'object',
631
+ properties: {
632
+ playerId: { type: 'string', description: 'Player ID to transfer leadership to' }
633
+ },
634
+ required: ['playerId']
635
+ }
636
+ },
637
+ {
638
+ name: 'burnrate_treasury_deposit',
639
+ description: 'Deposit resources to your faction treasury',
640
+ inputSchema: {
641
+ type: 'object',
642
+ properties: {
643
+ resources: { type: 'object', description: 'Resources to deposit as {resource: amount}' }
644
+ },
645
+ required: ['resources']
646
+ }
647
+ },
648
+ {
649
+ name: 'burnrate_treasury_withdraw',
650
+ description: 'Withdraw resources from faction treasury (founder/officer)',
651
+ inputSchema: {
652
+ type: 'object',
653
+ properties: {
654
+ resources: { type: 'object', description: 'Resources to withdraw as {resource: amount}' }
655
+ },
656
+ required: ['resources']
657
+ }
658
+ },
659
+ {
660
+ name: 'burnrate_contracts',
661
+ description: 'View available open contracts that you can accept',
662
+ inputSchema: { type: 'object', properties: {}, required: [] }
663
+ },
664
+ {
665
+ name: 'burnrate_contracts_mine',
666
+ description: 'View contracts you have posted or accepted',
667
+ inputSchema: { type: 'object', properties: {}, required: [] }
668
+ },
669
+ {
670
+ name: 'burnrate_contract_create',
671
+ description: 'Post a new contract. Types: haul (deliver cargo A->B), supply (deliver SU to zone), scout (gather intel on target). Reward credits are escrowed.',
672
+ inputSchema: {
673
+ type: 'object',
674
+ properties: {
675
+ type: { type: 'string', enum: ['haul', 'supply', 'scout'], description: 'Contract type' },
676
+ fromZoneId: { type: 'string', description: 'For haul: pickup zone' },
677
+ toZoneId: { type: 'string', description: 'For haul/supply: destination zone' },
678
+ resource: { type: 'string', description: 'For haul: resource type to deliver' },
679
+ quantity: { type: 'number', description: 'For haul/supply: amount to deliver' },
680
+ targetType: { type: 'string', enum: ['zone', 'route'], description: 'For scout: target type' },
681
+ targetId: { type: 'string', description: 'For scout: zone or route ID' },
682
+ reward: { type: 'number', description: 'Credits paid on completion' },
683
+ deadline: { type: 'number', description: 'Ticks until expiration' },
684
+ bonus: { type: 'number', description: 'Optional: bonus credits for early completion' },
685
+ bonusDeadline: { type: 'number', description: 'Optional: ticks until bonus expires' }
686
+ },
687
+ required: ['type', 'reward', 'deadline']
688
+ }
689
+ },
690
+ {
691
+ name: 'burnrate_contract_accept',
692
+ description: 'Accept a contract to work on it',
693
+ inputSchema: {
694
+ type: 'object',
695
+ properties: {
696
+ contractId: { type: 'string', description: 'Contract ID to accept' }
697
+ },
698
+ required: ['contractId']
699
+ }
700
+ },
701
+ {
702
+ name: 'burnrate_contract_complete',
703
+ description: 'Complete an accepted contract and receive the reward. Must have met all requirements.',
704
+ inputSchema: {
705
+ type: 'object',
706
+ properties: {
707
+ contractId: { type: 'string', description: 'Contract ID to complete' }
708
+ },
709
+ required: ['contractId']
710
+ }
711
+ },
712
+ {
713
+ name: 'burnrate_contract_cancel',
714
+ description: 'Cancel a contract you posted (only if not yet accepted). Refunds escrowed credits.',
715
+ inputSchema: {
716
+ type: 'object',
717
+ properties: {
718
+ contractId: { type: 'string', description: 'Contract ID to cancel' }
719
+ },
720
+ required: ['contractId']
721
+ }
722
+ },
723
+ {
724
+ name: 'burnrate_season',
725
+ description: 'View current season info including week number and time remaining',
726
+ inputSchema: { type: 'object', properties: {}, required: [] }
727
+ },
728
+ {
729
+ name: 'burnrate_leaderboard',
730
+ description: 'View season leaderboard rankings',
731
+ inputSchema: {
732
+ type: 'object',
733
+ properties: {
734
+ season: { type: 'number', description: 'Optional: season number (default: current)' },
735
+ type: { type: 'string', enum: ['player', 'faction'], description: 'Optional: filter by player or faction' },
736
+ limit: { type: 'number', description: 'Optional: max entries (default 50, max 100)' }
737
+ },
738
+ required: []
739
+ }
740
+ },
741
+ {
742
+ name: 'burnrate_season_score',
743
+ description: 'View your season score and ranking',
744
+ inputSchema: {
745
+ type: 'object',
746
+ properties: {
747
+ season: { type: 'number', description: 'Optional: season number (default: current)' }
748
+ },
749
+ required: []
750
+ }
751
+ },
752
+ {
753
+ name: 'burnrate_events',
754
+ description: 'View your event history. History depth depends on your tier (freelance: 200, operator: 10k, command: 100k)',
755
+ inputSchema: {
756
+ type: 'object',
757
+ properties: {
758
+ type: { type: 'string', description: 'Optional: filter by event type' },
759
+ limit: { type: 'number', description: 'Optional: max events to return (capped by tier)' }
760
+ },
761
+ required: []
762
+ }
763
+ },
764
+ {
765
+ name: 'burnrate_reputation',
766
+ description: 'View your reputation score, title, and progress to next title',
767
+ inputSchema: { type: 'object', properties: {}, required: [] }
768
+ },
769
+ {
770
+ name: 'burnrate_licenses',
771
+ description: 'View your license status and requirements for unlocking new shipment types',
772
+ inputSchema: { type: 'object', properties: {}, required: [] }
773
+ },
774
+ {
775
+ name: 'burnrate_license_unlock',
776
+ description: 'Unlock a shipment license. Requires reputation and credits.',
777
+ inputSchema: {
778
+ type: 'object',
779
+ properties: {
780
+ type: { type: 'string', enum: ['freight', 'convoy'], description: 'License type to unlock' }
781
+ },
782
+ required: ['type']
783
+ }
784
+ },
785
+ {
786
+ name: 'burnrate_intel',
787
+ description: 'View your gathered intel. Intel decays over time: fresh (<10 ticks), stale (10-50 ticks), or expired (>50 ticks). Stale intel has reduced accuracy; expired intel is unreliable.',
788
+ inputSchema: {
789
+ type: 'object',
790
+ properties: {
791
+ limit: { type: 'number', description: 'Max number of intel reports to return (default 100, max 500)' }
792
+ },
793
+ required: []
794
+ }
795
+ },
796
+ {
797
+ name: 'burnrate_intel_target',
798
+ description: 'Get your most recent intel on a specific zone or route. Shows freshness status and decayed data if intel is old.',
799
+ inputSchema: {
800
+ type: 'object',
801
+ properties: {
802
+ targetType: { type: 'string', enum: ['zone', 'route'], description: 'Type of target' },
803
+ targetId: { type: 'string', description: 'Zone or route ID' }
804
+ },
805
+ required: ['targetType', 'targetId']
806
+ }
807
+ },
808
+ // Phase 2: Tutorial
809
+ {
810
+ name: 'burnrate_tutorial',
811
+ description: 'View your tutorial progress and current step',
812
+ inputSchema: { type: 'object', properties: {}, required: [] }
813
+ },
814
+ {
815
+ name: 'burnrate_tutorial_complete',
816
+ description: 'Complete a tutorial step and receive rewards',
817
+ inputSchema: {
818
+ type: 'object',
819
+ properties: {
820
+ step: { type: 'number', description: 'Tutorial step to complete (1-5)' }
821
+ },
822
+ required: ['step']
823
+ }
824
+ },
825
+ // Phase 4: Subscription
826
+ {
827
+ name: 'burnrate_subscription',
828
+ description: 'View your subscription tier and limits',
829
+ inputSchema: { type: 'object', properties: {}, required: [] }
830
+ },
831
+ // Phase 5: Doctrines
832
+ {
833
+ name: 'burnrate_doctrines',
834
+ description: 'View your faction doctrines (strategy documents)',
835
+ inputSchema: { type: 'object', properties: {}, required: [] }
836
+ },
837
+ {
838
+ name: 'burnrate_doctrine_create',
839
+ description: 'Create a new faction doctrine (officer+ only)',
840
+ inputSchema: {
841
+ type: 'object',
842
+ properties: {
843
+ title: { type: 'string', description: 'Doctrine title' },
844
+ content: { type: 'string', description: 'Doctrine content (strategy, rules, etc.)' }
845
+ },
846
+ required: ['title', 'content']
847
+ }
848
+ },
849
+ {
850
+ name: 'burnrate_doctrine_update',
851
+ description: 'Update an existing faction doctrine (officer+ only)',
852
+ inputSchema: {
853
+ type: 'object',
854
+ properties: {
855
+ doctrineId: { type: 'string', description: 'Doctrine ID to update' },
856
+ content: { type: 'string', description: 'New content' }
857
+ },
858
+ required: ['doctrineId', 'content']
859
+ }
860
+ },
861
+ {
862
+ name: 'burnrate_doctrine_delete',
863
+ description: 'Delete a faction doctrine (officer+ only)',
864
+ inputSchema: {
865
+ type: 'object',
866
+ properties: {
867
+ doctrineId: { type: 'string', description: 'Doctrine ID to delete' }
868
+ },
869
+ required: ['doctrineId']
870
+ }
871
+ },
872
+ // Phase 5: Advanced market orders
873
+ {
874
+ name: 'burnrate_market_conditional',
875
+ description: 'Create a conditional market order that triggers when price crosses a threshold (Operator+ tier)',
876
+ inputSchema: {
877
+ type: 'object',
878
+ properties: {
879
+ zoneId: { type: 'string', description: 'Zone ID for the order' },
880
+ resource: { type: 'string', description: 'Resource to trade' },
881
+ side: { type: 'string', enum: ['buy', 'sell'], description: 'Buy or sell' },
882
+ triggerPrice: { type: 'number', description: 'Price threshold that triggers the order' },
883
+ quantity: { type: 'number', description: 'Amount to trade' },
884
+ condition: { type: 'string', enum: ['price_below', 'price_above'], description: 'Trigger when price goes below or above threshold' }
885
+ },
886
+ required: ['zoneId', 'resource', 'side', 'triggerPrice', 'quantity', 'condition']
887
+ }
888
+ },
889
+ {
890
+ name: 'burnrate_market_twap',
891
+ description: 'Create a time-weighted average price order that drip-feeds quantity over ticks (Command tier)',
892
+ inputSchema: {
893
+ type: 'object',
894
+ properties: {
895
+ zoneId: { type: 'string', description: 'Zone ID for the order' },
896
+ resource: { type: 'string', description: 'Resource to trade' },
897
+ side: { type: 'string', enum: ['buy', 'sell'], description: 'Buy or sell' },
898
+ price: { type: 'number', description: 'Price per unit' },
899
+ totalQuantity: { type: 'number', description: 'Total amount to trade' },
900
+ quantityPerTick: { type: 'number', description: 'Amount to release per tick' }
901
+ },
902
+ required: ['zoneId', 'resource', 'side', 'price', 'totalQuantity', 'quantityPerTick']
903
+ }
904
+ },
905
+ // Phase 6: Webhooks
906
+ {
907
+ name: 'burnrate_webhooks',
908
+ description: 'List your registered webhooks',
909
+ inputSchema: { type: 'object', properties: {}, required: [] }
910
+ },
911
+ {
912
+ name: 'burnrate_webhook_register',
913
+ description: 'Register a webhook to receive game event notifications (Operator+ tier, HTTPS only)',
914
+ inputSchema: {
915
+ type: 'object',
916
+ properties: {
917
+ url: { type: 'string', description: 'HTTPS webhook URL' },
918
+ events: {
919
+ type: 'array',
920
+ items: { type: 'string' },
921
+ description: 'Event types to subscribe to (e.g. shipment_delivered, zone_captured, combat)'
922
+ }
923
+ },
924
+ required: ['url', 'events']
925
+ }
926
+ },
927
+ {
928
+ name: 'burnrate_webhook_delete',
929
+ description: 'Delete a registered webhook',
930
+ inputSchema: {
931
+ type: 'object',
932
+ properties: {
933
+ webhookId: { type: 'string', description: 'Webhook ID to delete' }
934
+ },
935
+ required: ['webhookId']
936
+ }
937
+ },
938
+ // Phase 6: Data export & batch
939
+ {
940
+ name: 'burnrate_export',
941
+ description: 'Export all your game data (player, units, shipments, contracts, intel, events)',
942
+ inputSchema: { type: 'object', properties: {}, required: [] }
943
+ },
944
+ {
945
+ name: 'burnrate_batch',
946
+ description: 'Execute multiple game actions in a single batch (max 10). Actions: travel, extract, produce, placeOrder, depositSU, scan.',
947
+ inputSchema: {
948
+ type: 'object',
949
+ properties: {
950
+ operations: {
951
+ type: 'array',
952
+ items: {
953
+ type: 'object',
954
+ properties: {
955
+ action: { type: 'string', description: 'Action name' },
956
+ params: { type: 'object', description: 'Action parameters' }
957
+ },
958
+ required: ['action', 'params']
959
+ },
960
+ description: 'Array of operations to execute'
961
+ }
962
+ },
963
+ required: ['operations']
964
+ }
965
+ },
966
+ // Phase 7: Faction analytics & audit
967
+ {
968
+ name: 'burnrate_faction_analytics',
969
+ description: 'View faction analytics including member activity, zone control, and resource flows (Operator+ tier, officer+ rank)',
970
+ inputSchema: { type: 'object', properties: {}, required: [] }
971
+ },
972
+ {
973
+ name: 'burnrate_faction_audit',
974
+ description: 'View faction audit logs tracking all member actions (Command tier only)',
975
+ inputSchema: {
976
+ type: 'object',
977
+ properties: {
978
+ limit: { type: 'number', description: 'Max entries to return (default 100)' }
979
+ },
980
+ required: []
981
+ }
982
+ }
983
+ ]
984
+ };
985
+ });
986
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
987
+ const { name, arguments: args } = request.params;
988
+ try {
989
+ let result;
990
+ switch (name) {
991
+ case 'burnrate_status':
992
+ result = await client.getMe();
993
+ break;
994
+ case 'burnrate_join':
995
+ result = await client.join(args?.name);
996
+ if (result.apiKey) {
997
+ client.setApiKey(result.apiKey);
998
+ }
999
+ break;
1000
+ case 'burnrate_set_api_key':
1001
+ client.setApiKey(args?.apiKey);
1002
+ result = { success: true, message: 'API key set. Use burnrate_status to verify.' };
1003
+ break;
1004
+ case 'burnrate_view':
1005
+ if (args?.zoneId) {
1006
+ result = await client.getZone(args.zoneId);
1007
+ }
1008
+ else {
1009
+ result = await client.getZones();
1010
+ }
1011
+ break;
1012
+ case 'burnrate_routes':
1013
+ result = await client.getRoutes(args?.from);
1014
+ break;
1015
+ case 'burnrate_travel':
1016
+ result = await client.travel(args?.to);
1017
+ break;
1018
+ case 'burnrate_extract':
1019
+ result = await client.extract(args?.quantity);
1020
+ break;
1021
+ case 'burnrate_produce':
1022
+ result = await client.produce(args?.output, args?.quantity);
1023
+ break;
1024
+ case 'burnrate_ship':
1025
+ result = await client.ship(args?.type, args?.path, args?.cargo);
1026
+ break;
1027
+ case 'burnrate_shipments':
1028
+ result = await client.getShipments();
1029
+ break;
1030
+ case 'burnrate_market_buy':
1031
+ result = await client.placeOrder(args?.resource, 'buy', args?.price, args?.quantity);
1032
+ break;
1033
+ case 'burnrate_market_sell':
1034
+ result = await client.placeOrder(args?.resource, 'sell', args?.price, args?.quantity);
1035
+ break;
1036
+ case 'burnrate_market_view':
1037
+ result = await client.getMarketOrders(args?.resource);
1038
+ break;
1039
+ case 'burnrate_scan':
1040
+ result = await client.scan(args?.targetType, args?.targetId);
1041
+ break;
1042
+ case 'burnrate_supply':
1043
+ result = await client.supply(args?.amount);
1044
+ break;
1045
+ case 'burnrate_capture':
1046
+ result = await client.capture();
1047
+ break;
1048
+ case 'burnrate_stockpile':
1049
+ result = await client.depositStockpile(args?.resource, args?.amount);
1050
+ break;
1051
+ case 'burnrate_zone_efficiency':
1052
+ result = await client.getZoneEfficiency(args?.zoneId);
1053
+ break;
1054
+ case 'burnrate_units':
1055
+ result = await client.getUnits();
1056
+ break;
1057
+ case 'burnrate_units_escort':
1058
+ result = await client.assignEscort(args?.unitId, args?.shipmentId);
1059
+ break;
1060
+ case 'burnrate_units_raider':
1061
+ result = await client.deployRaider(args?.unitId, args?.routeId);
1062
+ break;
1063
+ case 'burnrate_units_sell':
1064
+ result = await client.listUnitForSale(args?.unitId, args?.price);
1065
+ break;
1066
+ case 'burnrate_hire':
1067
+ result = await client.hireUnit(args?.unitId);
1068
+ break;
1069
+ case 'burnrate_faction_create':
1070
+ result = await client.createFaction(args?.name, args?.tag);
1071
+ break;
1072
+ case 'burnrate_faction_join':
1073
+ result = await client.joinFaction(args?.factionId);
1074
+ break;
1075
+ case 'burnrate_faction_leave':
1076
+ result = await client.leaveFaction();
1077
+ break;
1078
+ case 'burnrate_faction_intel':
1079
+ result = await client.getFactionIntel();
1080
+ break;
1081
+ case 'burnrate_factions':
1082
+ result = await client.getFactions();
1083
+ break;
1084
+ case 'burnrate_faction_details':
1085
+ result = await client.getFactionDetails();
1086
+ break;
1087
+ case 'burnrate_faction_promote':
1088
+ result = await client.promoteFactionMember(args?.playerId);
1089
+ break;
1090
+ case 'burnrate_faction_demote':
1091
+ result = await client.demoteFactionMember(args?.playerId);
1092
+ break;
1093
+ case 'burnrate_faction_kick':
1094
+ result = await client.kickFactionMember(args?.playerId);
1095
+ break;
1096
+ case 'burnrate_faction_transfer':
1097
+ result = await client.transferFactionLeadership(args?.playerId);
1098
+ break;
1099
+ case 'burnrate_treasury_deposit':
1100
+ result = await client.depositToTreasury(args?.resources);
1101
+ break;
1102
+ case 'burnrate_treasury_withdraw':
1103
+ result = await client.withdrawFromTreasury(args?.resources);
1104
+ break;
1105
+ case 'burnrate_contracts':
1106
+ result = await client.getContracts();
1107
+ break;
1108
+ case 'burnrate_contracts_mine':
1109
+ result = await client.getMyContracts();
1110
+ break;
1111
+ case 'burnrate_contract_create':
1112
+ result = await client.createContract(args?.type, {
1113
+ fromZoneId: args?.fromZoneId,
1114
+ toZoneId: args?.toZoneId,
1115
+ resource: args?.resource,
1116
+ quantity: args?.quantity,
1117
+ targetType: args?.targetType,
1118
+ targetId: args?.targetId
1119
+ }, args?.reward, args?.deadline, args?.bonus, args?.bonusDeadline);
1120
+ break;
1121
+ case 'burnrate_contract_accept':
1122
+ result = await client.acceptContract(args?.contractId);
1123
+ break;
1124
+ case 'burnrate_contract_complete':
1125
+ result = await client.completeContract(args?.contractId);
1126
+ break;
1127
+ case 'burnrate_contract_cancel':
1128
+ result = await client.cancelContract(args?.contractId);
1129
+ break;
1130
+ case 'burnrate_intel':
1131
+ result = await client.getIntel(args?.limit);
1132
+ break;
1133
+ case 'burnrate_intel_target':
1134
+ result = await client.getTargetIntel(args?.targetType, args?.targetId);
1135
+ break;
1136
+ case 'burnrate_season':
1137
+ result = await client.getSeasonStatus();
1138
+ break;
1139
+ case 'burnrate_leaderboard':
1140
+ result = await client.getLeaderboard(args?.season, args?.type, args?.limit);
1141
+ break;
1142
+ case 'burnrate_season_score':
1143
+ result = await client.getSeasonScore(args?.season);
1144
+ break;
1145
+ case 'burnrate_events':
1146
+ result = await client.getEvents(args?.type, args?.limit);
1147
+ break;
1148
+ case 'burnrate_reputation':
1149
+ result = await client.getReputation();
1150
+ break;
1151
+ case 'burnrate_licenses':
1152
+ result = await client.getLicenses();
1153
+ break;
1154
+ case 'burnrate_license_unlock':
1155
+ result = await client.unlockLicense(args?.type);
1156
+ break;
1157
+ // Phase 2: Tutorial
1158
+ case 'burnrate_tutorial':
1159
+ result = await client.getTutorialStatus();
1160
+ break;
1161
+ case 'burnrate_tutorial_complete':
1162
+ result = await client.completeTutorialStep(args?.step);
1163
+ break;
1164
+ // Phase 4: Subscription
1165
+ case 'burnrate_subscription':
1166
+ result = await client.getSubscription();
1167
+ break;
1168
+ // Phase 5: Doctrines
1169
+ case 'burnrate_doctrines':
1170
+ result = await client.getDoctrines();
1171
+ break;
1172
+ case 'burnrate_doctrine_create':
1173
+ result = await client.createDoctrine(args?.title, args?.content);
1174
+ break;
1175
+ case 'burnrate_doctrine_update':
1176
+ result = await client.updateDoctrine(args?.doctrineId, args?.content);
1177
+ break;
1178
+ case 'burnrate_doctrine_delete':
1179
+ result = await client.deleteDoctrine(args?.doctrineId);
1180
+ break;
1181
+ // Phase 5: Advanced market orders
1182
+ case 'burnrate_market_conditional':
1183
+ result = await client.createConditionalOrder(args?.zoneId, args?.resource, args?.side, args?.triggerPrice, args?.quantity, args?.condition);
1184
+ break;
1185
+ case 'burnrate_market_twap':
1186
+ result = await client.createTimeWeightedOrder(args?.zoneId, args?.resource, args?.side, args?.price, args?.totalQuantity, args?.quantityPerTick);
1187
+ break;
1188
+ // Phase 6: Webhooks
1189
+ case 'burnrate_webhooks':
1190
+ result = await client.getWebhooks();
1191
+ break;
1192
+ case 'burnrate_webhook_register':
1193
+ result = await client.registerWebhook(args?.url, args?.events);
1194
+ break;
1195
+ case 'burnrate_webhook_delete':
1196
+ result = await client.deleteWebhook(args?.webhookId);
1197
+ break;
1198
+ // Phase 6: Export & Batch
1199
+ case 'burnrate_export':
1200
+ result = await client.exportData();
1201
+ break;
1202
+ case 'burnrate_batch':
1203
+ result = await client.executeBatch(args?.operations);
1204
+ break;
1205
+ // Phase 7: Faction analytics & audit
1206
+ case 'burnrate_faction_analytics':
1207
+ result = await client.getFactionAnalytics();
1208
+ break;
1209
+ case 'burnrate_faction_audit':
1210
+ result = await client.getFactionAuditLogs(args?.limit);
1211
+ break;
1212
+ default:
1213
+ throw new Error(`Unknown tool: ${name}`);
1214
+ }
1215
+ return {
1216
+ content: [
1217
+ {
1218
+ type: 'text',
1219
+ text: JSON.stringify(result, null, 2)
1220
+ }
1221
+ ]
1222
+ };
1223
+ }
1224
+ catch (error) {
1225
+ return {
1226
+ content: [
1227
+ {
1228
+ type: 'text',
1229
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
1230
+ }
1231
+ ],
1232
+ isError: true
1233
+ };
1234
+ }
1235
+ });
1236
+ // ============================================================================
1237
+ // RESOURCES
1238
+ // ============================================================================
1239
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
1240
+ return {
1241
+ resources: [
1242
+ {
1243
+ uri: 'burnrate://status',
1244
+ name: 'Player Status',
1245
+ description: 'Current player status, inventory, location, and stats',
1246
+ mimeType: 'application/json'
1247
+ },
1248
+ {
1249
+ uri: 'burnrate://world',
1250
+ name: 'World Status',
1251
+ description: 'Current world state including tick, season, and week',
1252
+ mimeType: 'application/json'
1253
+ },
1254
+ {
1255
+ uri: 'burnrate://zones',
1256
+ name: 'Zone Map',
1257
+ description: 'All zones with types, controllers, and supply levels',
1258
+ mimeType: 'application/json'
1259
+ },
1260
+ {
1261
+ uri: 'burnrate://routes',
1262
+ name: 'Route Network',
1263
+ description: 'All routes from your current location',
1264
+ mimeType: 'application/json'
1265
+ },
1266
+ {
1267
+ uri: 'burnrate://shipments',
1268
+ name: 'Active Shipments',
1269
+ description: 'Your shipments currently in transit',
1270
+ mimeType: 'application/json'
1271
+ },
1272
+ {
1273
+ uri: 'burnrate://units',
1274
+ name: 'Military Units',
1275
+ description: 'Your escort and raider units with their status',
1276
+ mimeType: 'application/json'
1277
+ },
1278
+ {
1279
+ uri: 'burnrate://market',
1280
+ name: 'Market Orders',
1281
+ description: 'Buy and sell orders at your current location',
1282
+ mimeType: 'application/json'
1283
+ },
1284
+ {
1285
+ uri: 'burnrate://contracts',
1286
+ name: 'Available Contracts',
1287
+ description: 'Open contracts you can accept',
1288
+ mimeType: 'application/json'
1289
+ },
1290
+ {
1291
+ uri: 'burnrate://intel',
1292
+ name: 'Intel Reports',
1293
+ description: 'Your gathered intelligence with freshness status',
1294
+ mimeType: 'application/json'
1295
+ },
1296
+ {
1297
+ uri: 'burnrate://faction',
1298
+ name: 'Faction Details',
1299
+ description: 'Your faction info including members and controlled zones',
1300
+ mimeType: 'application/json'
1301
+ },
1302
+ {
1303
+ uri: 'burnrate://leaderboard',
1304
+ name: 'Season Leaderboard',
1305
+ description: 'Current season rankings',
1306
+ mimeType: 'application/json'
1307
+ },
1308
+ {
1309
+ uri: 'burnrate://reputation',
1310
+ name: 'Reputation',
1311
+ description: 'Your reputation score, title, and progress',
1312
+ mimeType: 'application/json'
1313
+ },
1314
+ {
1315
+ uri: 'burnrate://licenses',
1316
+ name: 'License Status',
1317
+ description: 'Your shipment licenses and requirements to unlock more',
1318
+ mimeType: 'application/json'
1319
+ }
1320
+ ]
1321
+ };
1322
+ });
1323
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1324
+ const { uri } = request.params;
1325
+ try {
1326
+ let data;
1327
+ switch (uri) {
1328
+ case 'burnrate://status':
1329
+ data = await client.getMe();
1330
+ break;
1331
+ case 'burnrate://world':
1332
+ data = await client.getWorldStatus();
1333
+ break;
1334
+ case 'burnrate://zones':
1335
+ data = await client.getZones();
1336
+ break;
1337
+ case 'burnrate://routes':
1338
+ data = await client.getRoutes();
1339
+ break;
1340
+ case 'burnrate://shipments':
1341
+ data = await client.getShipments();
1342
+ break;
1343
+ case 'burnrate://units':
1344
+ data = await client.getUnits();
1345
+ break;
1346
+ case 'burnrate://market':
1347
+ data = await client.getMarketOrders();
1348
+ break;
1349
+ case 'burnrate://contracts':
1350
+ data = await client.getContracts();
1351
+ break;
1352
+ case 'burnrate://intel':
1353
+ data = await client.getIntel(100);
1354
+ break;
1355
+ case 'burnrate://faction':
1356
+ data = await client.getFactionDetails();
1357
+ break;
1358
+ case 'burnrate://leaderboard':
1359
+ data = await client.getLeaderboard();
1360
+ break;
1361
+ case 'burnrate://reputation':
1362
+ data = await client.getReputation();
1363
+ break;
1364
+ case 'burnrate://licenses':
1365
+ data = await client.getLicenses();
1366
+ break;
1367
+ default:
1368
+ throw new Error(`Unknown resource: ${uri}`);
1369
+ }
1370
+ return {
1371
+ contents: [
1372
+ {
1373
+ uri,
1374
+ mimeType: 'application/json',
1375
+ text: JSON.stringify(data, null, 2)
1376
+ }
1377
+ ]
1378
+ };
1379
+ }
1380
+ catch (error) {
1381
+ return {
1382
+ contents: [
1383
+ {
1384
+ uri,
1385
+ mimeType: 'text/plain',
1386
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
1387
+ }
1388
+ ]
1389
+ };
1390
+ }
1391
+ });
1392
+ // ============================================================================
1393
+ // PROMPTS
1394
+ // ============================================================================
1395
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
1396
+ return {
1397
+ prompts: [
1398
+ {
1399
+ name: 'situation_analysis',
1400
+ description: 'Analyze your current game situation and suggest immediate priorities',
1401
+ arguments: []
1402
+ },
1403
+ {
1404
+ name: 'route_planning',
1405
+ description: 'Find safe and profitable shipping routes from a zone',
1406
+ arguments: [
1407
+ {
1408
+ name: 'from',
1409
+ description: 'Starting zone ID (defaults to current location)',
1410
+ required: false
1411
+ },
1412
+ {
1413
+ name: 'destination',
1414
+ description: 'Target zone ID if you have a specific destination',
1415
+ required: false
1416
+ }
1417
+ ]
1418
+ },
1419
+ {
1420
+ name: 'threat_assessment',
1421
+ description: 'Assess threats in a zone or along a route using available intel',
1422
+ arguments: [
1423
+ {
1424
+ name: 'target',
1425
+ description: 'Zone ID or route ID to assess',
1426
+ required: true
1427
+ }
1428
+ ]
1429
+ },
1430
+ {
1431
+ name: 'trade_opportunities',
1432
+ description: 'Analyze market conditions to find profitable trades',
1433
+ arguments: [
1434
+ {
1435
+ name: 'resource',
1436
+ description: 'Specific resource to analyze (optional)',
1437
+ required: false
1438
+ }
1439
+ ]
1440
+ },
1441
+ {
1442
+ name: 'mission_briefing',
1443
+ description: 'Get a mission briefing for a specific task type',
1444
+ arguments: [
1445
+ {
1446
+ name: 'mission_type',
1447
+ description: 'Type of mission: extraction, production, shipping, capture, or contract',
1448
+ required: true
1449
+ }
1450
+ ]
1451
+ },
1452
+ {
1453
+ name: 'faction_strategy',
1454
+ description: 'Analyze faction standing and suggest strategic priorities',
1455
+ arguments: []
1456
+ },
1457
+ {
1458
+ name: 'season_progress',
1459
+ description: 'Review your season performance and suggest ways to climb the leaderboard',
1460
+ arguments: []
1461
+ },
1462
+ {
1463
+ name: 'game_overview',
1464
+ description: 'Learn the basics of BURNRATE. Perfect for new players or a refresher on game mechanics.',
1465
+ arguments: []
1466
+ }
1467
+ ]
1468
+ };
1469
+ });
1470
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
1471
+ const { name, arguments: args } = request.params;
1472
+ // Helper to safely fetch data with error handling
1473
+ const safeFetch = async (fn, fallback) => {
1474
+ try {
1475
+ return await fn();
1476
+ }
1477
+ catch {
1478
+ return fallback;
1479
+ }
1480
+ };
1481
+ try {
1482
+ switch (name) {
1483
+ case 'situation_analysis': {
1484
+ const [status, world, shipments, units, intel] = await Promise.all([
1485
+ safeFetch(() => client.getMe(), null),
1486
+ safeFetch(() => client.getWorldStatus(), null),
1487
+ safeFetch(() => client.getShipments(), { shipments: [] }),
1488
+ safeFetch(() => client.getUnits(), { units: [] }),
1489
+ safeFetch(() => client.getIntel(20), { intel: [] })
1490
+ ]);
1491
+ return {
1492
+ messages: [
1493
+ {
1494
+ role: 'user',
1495
+ content: {
1496
+ type: 'text',
1497
+ text: `Analyze my current BURNRATE situation and suggest immediate priorities.
1498
+
1499
+ ## My Status
1500
+ ${status ? JSON.stringify(status, null, 2) : 'Unable to fetch status - you may need to authenticate first'}
1501
+
1502
+ ## World State
1503
+ ${world ? JSON.stringify(world, null, 2) : 'Unable to fetch world state'}
1504
+
1505
+ ## Active Shipments
1506
+ ${JSON.stringify(shipments, null, 2)}
1507
+
1508
+ ## Military Units
1509
+ ${JSON.stringify(units, null, 2)}
1510
+
1511
+ ## Recent Intel (newest first)
1512
+ ${JSON.stringify(intel, null, 2)}
1513
+
1514
+ Based on this data:
1515
+ 1. What is my current situation? (resources, location, threats)
1516
+ 2. What are my most pressing needs?
1517
+ 3. What are 3 immediate actions I should take?
1518
+ 4. Any warnings or threats I should be aware of?`
1519
+ }
1520
+ }
1521
+ ]
1522
+ };
1523
+ }
1524
+ case 'route_planning': {
1525
+ const from = args?.from;
1526
+ const destination = args?.destination;
1527
+ const [status, routes, zones, intel] = await Promise.all([
1528
+ safeFetch(() => client.getMe(), null),
1529
+ safeFetch(() => client.getRoutes(from), { routes: [] }),
1530
+ safeFetch(() => client.getZones(), { zones: [] }),
1531
+ safeFetch(() => client.getIntel(50), { intel: [] })
1532
+ ]);
1533
+ const currentLocation = from || status?.location || 'unknown';
1534
+ return {
1535
+ messages: [
1536
+ {
1537
+ role: 'user',
1538
+ content: {
1539
+ type: 'text',
1540
+ text: `Help me plan shipping routes in BURNRATE.
1541
+
1542
+ ## Starting Point
1543
+ ${currentLocation}
1544
+ ${destination ? `\n## Desired Destination\n${destination}` : ''}
1545
+
1546
+ ## Available Routes from ${currentLocation}
1547
+ ${JSON.stringify(routes, null, 2)}
1548
+
1549
+ ## Zone Information
1550
+ ${JSON.stringify(zones, null, 2)}
1551
+
1552
+ ## Intel on Routes and Zones
1553
+ ${JSON.stringify(intel, null, 2)}
1554
+
1555
+ Analyze the routes and recommend:
1556
+ 1. Safest route (lowest raider activity)
1557
+ 2. Most profitable route (good trading opportunities)
1558
+ 3. Fastest route to a production hub
1559
+ 4. Any routes to avoid and why
1560
+ 5. Recommended cargo for each route based on destination zone needs`
1561
+ }
1562
+ }
1563
+ ]
1564
+ };
1565
+ }
1566
+ case 'threat_assessment': {
1567
+ const target = args?.target;
1568
+ if (!target) {
1569
+ throw new Error('Target zone or route ID is required');
1570
+ }
1571
+ const [intel, zones] = await Promise.all([
1572
+ safeFetch(() => client.getIntel(100), { intel: [] }),
1573
+ safeFetch(() => client.getZones(), { zones: [] })
1574
+ ]);
1575
+ // Filter intel relevant to the target
1576
+ const relevantIntel = intel.intel?.filter((i) => i.targetId === target || i.targetId?.includes(target)) || [];
1577
+ return {
1578
+ messages: [
1579
+ {
1580
+ role: 'user',
1581
+ content: {
1582
+ type: 'text',
1583
+ text: `Assess threats for target: ${target}
1584
+
1585
+ ## All Intel
1586
+ ${JSON.stringify(intel, null, 2)}
1587
+
1588
+ ## Relevant Intel for ${target}
1589
+ ${JSON.stringify(relevantIntel, null, 2)}
1590
+
1591
+ ## Zone Data
1592
+ ${JSON.stringify(zones, null, 2)}
1593
+
1594
+ Provide a threat assessment:
1595
+ 1. Threat level (low/medium/high/critical)
1596
+ 2. Known hostile units in the area
1597
+ 3. Recent hostile activity
1598
+ 4. Intel freshness (is our data reliable?)
1599
+ 5. Recommended precautions
1600
+ 6. Best time/approach for operations here`
1601
+ }
1602
+ }
1603
+ ]
1604
+ };
1605
+ }
1606
+ case 'trade_opportunities': {
1607
+ const resource = args?.resource;
1608
+ const [status, market, zones] = await Promise.all([
1609
+ safeFetch(() => client.getMe(), null),
1610
+ safeFetch(() => client.getMarketOrders(resource), { orders: [] }),
1611
+ safeFetch(() => client.getZones(), { zones: [] })
1612
+ ]);
1613
+ return {
1614
+ messages: [
1615
+ {
1616
+ role: 'user',
1617
+ content: {
1618
+ type: 'text',
1619
+ text: `Analyze trade opportunities${resource ? ` for ${resource}` : ''}.
1620
+
1621
+ ## My Status
1622
+ ${JSON.stringify(status, null, 2)}
1623
+
1624
+ ## Market Orders${resource ? ` (${resource})` : ''}
1625
+ ${JSON.stringify(market, null, 2)}
1626
+
1627
+ ## Zone Economy
1628
+ ${JSON.stringify(zones, null, 2)}
1629
+
1630
+ Find profitable trades:
1631
+ 1. Best buy opportunities (underpriced resources)
1632
+ 2. Best sell opportunities (high demand)
1633
+ 3. Arbitrage opportunities between zones
1634
+ 4. Resources I should stockpile
1635
+ 5. Market trends and predictions
1636
+ 6. Recommended trade routes`
1637
+ }
1638
+ }
1639
+ ]
1640
+ };
1641
+ }
1642
+ case 'mission_briefing': {
1643
+ const missionType = args?.mission_type;
1644
+ if (!missionType) {
1645
+ throw new Error('Mission type is required: extraction, production, shipping, capture, or contract');
1646
+ }
1647
+ const [status, zones, routes, contracts, licenses] = await Promise.all([
1648
+ safeFetch(() => client.getMe(), null),
1649
+ safeFetch(() => client.getZones(), { zones: [] }),
1650
+ safeFetch(() => client.getRoutes(), { routes: [] }),
1651
+ safeFetch(() => client.getContracts(), { contracts: [] }),
1652
+ safeFetch(() => client.getLicenses(), null)
1653
+ ]);
1654
+ const missionInstructions = {
1655
+ extraction: `EXTRACTION MISSION
1656
+ Goal: Gather raw resources from Field zones.
1657
+ Requirements: Be at a Field zone, have 5 credits per unit to extract.
1658
+ Process: Use burnrate_extract to gather raw materials.`,
1659
+ production: `PRODUCTION MISSION
1660
+ Goal: Convert resources into valuable goods or military units at Factories.
1661
+ Requirements: Be at a Factory zone, have required input resources.
1662
+ Process: Use burnrate_produce with recipe name and quantity.`,
1663
+ shipping: `SHIPPING MISSION
1664
+ Goal: Transport cargo safely between zones.
1665
+ Requirements: Licensed for shipment type, cargo in inventory, valid route.
1666
+ Process: Plan route, load cargo, use burnrate_ship, optionally assign escorts.`,
1667
+ capture: `CAPTURE MISSION
1668
+ Goal: Take control of a neutral or collapsed zone for your faction.
1669
+ Requirements: Be in faction, zone must be neutral/collapsed.
1670
+ Process: Travel to target, use burnrate_capture.`,
1671
+ contract: `CONTRACT MISSION
1672
+ Goal: Complete contracts for rewards.
1673
+ Types: haul (deliver cargo), supply (deliver SU), scout (gather intel).
1674
+ Process: Find contract with burnrate_contracts, accept it, complete requirements.`
1675
+ };
1676
+ return {
1677
+ messages: [
1678
+ {
1679
+ role: 'user',
1680
+ content: {
1681
+ type: 'text',
1682
+ text: `Mission Briefing: ${missionType.toUpperCase()}
1683
+
1684
+ ${missionInstructions[missionType] || 'Unknown mission type. Valid types: extraction, production, shipping, capture, contract'}
1685
+
1686
+ ## My Current Status
1687
+ ${JSON.stringify(status, null, 2)}
1688
+
1689
+ ## Zone Data
1690
+ ${JSON.stringify(zones, null, 2)}
1691
+
1692
+ ## Available Routes
1693
+ ${JSON.stringify(routes, null, 2)}
1694
+
1695
+ ${missionType === 'contract' ? `## Open Contracts\n${JSON.stringify(contracts, null, 2)}` : ''}
1696
+
1697
+ ${missionType === 'shipping' ? `## My Licenses\n${JSON.stringify(licenses, null, 2)}` : ''}
1698
+
1699
+ Provide a mission plan:
1700
+ 1. Am I ready for this mission? What do I need?
1701
+ 2. Best location/target for this mission
1702
+ 3. Step-by-step execution plan
1703
+ 4. Risks and mitigations
1704
+ 5. Expected rewards`
1705
+ }
1706
+ }
1707
+ ]
1708
+ };
1709
+ }
1710
+ case 'faction_strategy': {
1711
+ const [faction, zones, intel, leaderboard] = await Promise.all([
1712
+ safeFetch(() => client.getFactionDetails(), null),
1713
+ safeFetch(() => client.getZones(), { zones: [] }),
1714
+ safeFetch(() => client.getIntel(50), { intel: [] }),
1715
+ safeFetch(() => client.getLeaderboard(undefined, 'faction', 20), { leaderboard: [] })
1716
+ ]);
1717
+ return {
1718
+ messages: [
1719
+ {
1720
+ role: 'user',
1721
+ content: {
1722
+ type: 'text',
1723
+ text: `Analyze faction strategy and suggest priorities.
1724
+
1725
+ ## My Faction
1726
+ ${faction ? JSON.stringify(faction, null, 2) : 'Not in a faction'}
1727
+
1728
+ ## Territory Map
1729
+ ${JSON.stringify(zones, null, 2)}
1730
+
1731
+ ## Intel
1732
+ ${JSON.stringify(intel, null, 2)}
1733
+
1734
+ ## Faction Leaderboard
1735
+ ${JSON.stringify(leaderboard, null, 2)}
1736
+
1737
+ Provide strategic analysis:
1738
+ 1. Current faction strength and position
1739
+ 2. Vulnerable zones we control
1740
+ 3. Expansion opportunities
1741
+ 4. Threats from other factions
1742
+ 5. Resource priorities for faction growth
1743
+ 6. Recommended coordination with faction members`
1744
+ }
1745
+ }
1746
+ ]
1747
+ };
1748
+ }
1749
+ case 'season_progress': {
1750
+ const [score, leaderboard, reputation, season] = await Promise.all([
1751
+ safeFetch(() => client.getSeasonScore(), null),
1752
+ safeFetch(() => client.getLeaderboard(undefined, 'player', 50), { leaderboard: [] }),
1753
+ safeFetch(() => client.getReputation(), null),
1754
+ safeFetch(() => client.getSeasonStatus(), null)
1755
+ ]);
1756
+ return {
1757
+ messages: [
1758
+ {
1759
+ role: 'user',
1760
+ content: {
1761
+ type: 'text',
1762
+ text: `Review my season progress and suggest improvements.
1763
+
1764
+ ## Season Status
1765
+ ${JSON.stringify(season, null, 2)}
1766
+
1767
+ ## My Season Score
1768
+ ${JSON.stringify(score, null, 2)}
1769
+
1770
+ ## My Reputation
1771
+ ${JSON.stringify(reputation, null, 2)}
1772
+
1773
+ ## Player Leaderboard
1774
+ ${JSON.stringify(leaderboard, null, 2)}
1775
+
1776
+ Analyze my progress:
1777
+ 1. Current ranking and gap to top players
1778
+ 2. My strongest scoring categories
1779
+ 3. Categories where I'm underperforming
1780
+ 4. Specific actions to gain more points
1781
+ 5. Time remaining and realistic goals
1782
+ 6. Reputation grind progress`
1783
+ }
1784
+ }
1785
+ ]
1786
+ };
1787
+ }
1788
+ case 'game_overview': {
1789
+ const [status, tutorial] = await Promise.all([
1790
+ safeFetch(() => client.getMe(), null),
1791
+ safeFetch(() => client.getTutorialStatus(), null)
1792
+ ]);
1793
+ return {
1794
+ messages: [
1795
+ {
1796
+ role: 'user',
1797
+ content: {
1798
+ type: 'text',
1799
+ text: `Welcome to BURNRATE — a logistics war MMO played through Claude Code.
1800
+
1801
+ ## How It Works
1802
+ You control territory by keeping it supplied. Every zone burns Supply Units (SU) each tick. When supply runs out, the zone collapses. The best generals still lose if they can't feed the front.
1803
+
1804
+ ## Resource Chain
1805
+ Raw resources (T0) → Processed goods (T1) → Strategic materials (T2) → Supply Units
1806
+
1807
+ **T0 (Raw):** ore, fuel, grain, fiber — extract at Fields (5 credits/unit)
1808
+ **T1 (Processed):** metal, chemicals, rations, textiles — produce at Factories
1809
+ **T2 (Strategic):** ammo, medkits, parts, comms — produce at Factories
1810
+ **SU:** 2 rations + 1 fuel + 1 parts + 1 ammo → 1 Supply Unit
1811
+
1812
+ ## Zone Types
1813
+ - **Hubs** — Safe starting areas with marketplaces
1814
+ - **Fields** — Extract raw resources (T0)
1815
+ - **Factories** — Convert resources, produce units
1816
+ - **Junctions** — Crossroads, no burn cost
1817
+ - **Fronts** — Contested territory, high burn
1818
+ - **Strongholds** — Victory objectives, highest burn
1819
+
1820
+ ## Key Actions
1821
+ 1. **Extract** resources at Fields
1822
+ 2. **Produce** goods at Factories
1823
+ 3. **Ship** cargo between zones
1824
+ 4. **Trade** on zone markets
1825
+ 5. **Supply** zones with SU to hold territory
1826
+ 6. **Scan** zones/routes for intel
1827
+ 7. **Capture** neutral or collapsed zones
1828
+
1829
+ ## Military
1830
+ - **Escorts** protect shipments from raiders
1831
+ - **Raiders** interdict enemy routes
1832
+
1833
+ ## Progression
1834
+ Earn reputation through deliveries, contracts, and captures. Unlock freight and convoy licenses for bigger shipments.
1835
+
1836
+ ## Factions
1837
+ Join or create factions. Control territory together, share intel, and coordinate logistics.
1838
+
1839
+ ## Your Current Status
1840
+ ${status ? JSON.stringify(status, null, 2) : 'Not authenticated — use burnrate_join or burnrate_set_api_key to get started.'}
1841
+
1842
+ ## Tutorial Progress
1843
+ ${tutorial ? `Step ${tutorial.step || 0} of ${tutorial.total || 5}${tutorial.currentContract ? `\nNext: ${tutorial.currentContract.title} — ${tutorial.currentContract.description}` : '\nTutorial complete!'}` : 'Use burnrate_tutorial to check your progress.'}
1844
+
1845
+ Based on my current status, what should I do first? Walk me through getting started step by step.`
1846
+ }
1847
+ }
1848
+ ]
1849
+ };
1850
+ }
1851
+ default:
1852
+ throw new Error(`Unknown prompt: ${name}`);
1853
+ }
1854
+ }
1855
+ catch (error) {
1856
+ return {
1857
+ messages: [
1858
+ {
1859
+ role: 'user',
1860
+ content: {
1861
+ type: 'text',
1862
+ text: `Error generating prompt: ${error instanceof Error ? error.message : String(error)}`
1863
+ }
1864
+ }
1865
+ ]
1866
+ };
1867
+ }
1868
+ });
1869
+ // ============================================================================
1870
+ // START SERVER
1871
+ // ============================================================================
1872
+ async function main() {
1873
+ const transport = new StdioServerTransport();
1874
+ await server.connect(transport);
1875
+ console.error('BURNRATE MCP Server running');
1876
+ }
1877
+ main().catch(console.error);