universalis-mcp-server 0.1.0 → 0.2.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 CHANGED
@@ -1,10 +1,10 @@
1
1
  # universalis-mcp-server
2
2
 
3
- MCP server for Universalis market data and XIVAPI item lookup.
3
+ MCP server for FFXIV market data via Universalis + Saddlebag Exchange, plus XIVAPI item lookup.
4
4
 
5
5
  ## Capabilities
6
6
 
7
- This MCP server exposes read-only tools for Universalis market data and XIVAPI item lookup.
7
+ This MCP server exposes read-only tools for Universalis market data, Saddlebag Exchange analytics, and XIVAPI item lookup.
8
8
  All tools support `response_format` as `markdown` or `json`.
9
9
 
10
10
  ### Market board data (Universalis)
@@ -16,7 +16,32 @@ All tools support `response_format` as `markdown` or `json`.
16
16
  ### Item lookup (XIVAPI)
17
17
 
18
18
  - `universalis_resolve_items_by_name`: Search items by name with `partial` or `exact` matching.
19
+ - `universalis_resolve_items_by_names`: Resolve multiple item names in one search query.
19
20
  - `universalis_get_item_by_id`: Fetch a single item row by ID.
21
+ - `universalis_get_items_by_ids`: Fetch multiple item rows by ID in one request.
22
+
23
+ ### Workflows
24
+
25
+ - `universalis_rank_items_by_profitability`: Resolve names, fetch aggregated data, and rank by demand and profit.
26
+
27
+ ### Market analytics (Saddlebag Exchange)
28
+
29
+ - `saddlebag_get_listing_metrics`: Listing competition metrics and current listings.
30
+ - `saddlebag_get_history_metrics`: Aggregated history metrics and price distributions.
31
+ - `saddlebag_get_raw_stats`: Daily snapshot stats (median, average, sales volume).
32
+ - `saddlebag_get_scrip_exchange`: Gil-per-scrip rankings.
33
+ - `saddlebag_get_shopping_list`: Crafting shopping list across servers (may return exception payloads).
34
+ - `saddlebag_get_export_prices`: Cross-world price comparison for export trading.
35
+ - `saddlebag_get_marketshare`: Marketshare leaderboard snapshot for a server.
36
+ - `saddlebag_get_reselling_scan`: Reselling opportunities (region/DC/vendor filters).
37
+ - `saddlebag_get_weekly_price_group_delta`: Weekly deltas for custom item groups.
38
+ - `saddlebag_get_price_check`: Price alert checks (user-supplied auctions).
39
+ - `saddlebag_get_quantity_check`: Quantity alert checks (user-supplied auctions).
40
+ - `saddlebag_get_sale_alert`: Sale alerts for retainer listings.
41
+ - `saddlebag_get_craftsim`: Crafting profitability scan (use `max_results` to limit payloads).
42
+ - `saddlebag_get_blog_description`: Item description text lookup.
43
+
44
+ Best-deals is excluded (premium gated + inconsistent API validation).
20
45
 
21
46
  ### Reference data (Universalis)
22
47
 
@@ -91,9 +116,11 @@ If you change code, re-run `pnpm build` and restart the MCP connection.
91
116
 
92
117
  - `UNIVERSALIS_BASE_URL`: Override Universalis base URL (default: `https://universalis.app/api/v2`).
93
118
  - `XIVAPI_BASE_URL`: Override XIVAPI base URL (default: `https://v2.xivapi.com/api`).
119
+ - `SADDLEBAG_BASE_URL`: Override Saddlebag base URL (default: `https://docs.saddlebagexchange.com/api`).
94
120
  - `UNIVERSALIS_MCP_USER_AGENT`: Custom User-Agent header.
95
121
  - `UNIVERSALIS_TIMEOUT_MS`: Request timeout for Universalis (default: 30000).
96
122
  - `XIVAPI_TIMEOUT_MS`: Request timeout for XIVAPI (default: 30000).
123
+ - `SADDLEBAG_TIMEOUT_MS`: Request timeout for Saddlebag (default: 30000).
97
124
  - `XIVAPI_LANGUAGE`: Default XIVAPI language (default: `en`).
98
125
  - `XIVAPI_VERSION`: Default XIVAPI version (default: `latest`).
99
126
 
@@ -101,3 +128,4 @@ If you change code, re-run `pnpm build` and restart the MCP connection.
101
128
 
102
129
  - Rate limits are enforced client-side for Universalis and XIVAPI.
103
130
  - Tools support `response_format` as `markdown` or `json`.
131
+ - Some Saddlebag endpoints proxy Universalis data; avoid excessive polling.
@@ -0,0 +1,347 @@
1
+ {
2
+ "generated_at": "2026-01-11T21:38:40.756Z",
3
+ "xivapi_version": "309a1e90d28b6bc6",
4
+ "categories": {
5
+ "combat": {
6
+ "I": [
7
+ "Aurelia Kiss Materia I",
8
+ "Battledance Materia I",
9
+ "Bison Hoof Materia I",
10
+ "Cactuar Foot Materia I",
11
+ "Chocobo Down Materia I",
12
+ "Coeurl Eye Materia I",
13
+ "Dexterity Materia I",
14
+ "Earth Materia I",
15
+ "Fire Materia I",
16
+ "Funguar Shriek Materia I",
17
+ "Heavens' Eye Materia I",
18
+ "Ice Materia I",
19
+ "Intelligence Materia I",
20
+ "Lightning Materia I",
21
+ "Mind Materia I",
22
+ "Piety Materia I",
23
+ "Quickarm Materia I",
24
+ "Quicktongue Materia I",
25
+ "Savage Aim Materia I",
26
+ "Savage Might Materia I",
27
+ "Strength Materia I",
28
+ "Treant Root Materia I",
29
+ "Vitality Materia I",
30
+ "Water Materia I",
31
+ "Wind Materia I"
32
+ ],
33
+ "II": [
34
+ "Battledance Materia II",
35
+ "Dexterity Materia II",
36
+ "Earth Materia II",
37
+ "Fire Materia II",
38
+ "Heavens' Eye Materia II",
39
+ "Ice Materia II",
40
+ "Intelligence Materia II",
41
+ "Lightning Materia II",
42
+ "Mind Materia II",
43
+ "Piety Materia II",
44
+ "Quickarm Materia II",
45
+ "Quicktongue Materia II",
46
+ "Savage Aim Materia II",
47
+ "Savage Might Materia II",
48
+ "Strength Materia II",
49
+ "Vitality Materia II",
50
+ "Water Materia II",
51
+ "Wind Materia II"
52
+ ],
53
+ "III": [
54
+ "Battledance Materia III",
55
+ "Dexterity Materia III",
56
+ "Earth Materia III",
57
+ "Fire Materia III",
58
+ "Heavens' Eye Materia III",
59
+ "Ice Materia III",
60
+ "Intelligence Materia III",
61
+ "Lightning Materia III",
62
+ "Mind Materia III",
63
+ "Piety Materia III",
64
+ "Quickarm Materia III",
65
+ "Quicktongue Materia III",
66
+ "Savage Aim Materia III",
67
+ "Savage Might Materia III",
68
+ "Strength Materia III",
69
+ "Vitality Materia III",
70
+ "Water Materia III",
71
+ "Wind Materia III"
72
+ ],
73
+ "IV": [
74
+ "Battledance Materia IV",
75
+ "Dexterity Materia IV",
76
+ "Earth Materia IV",
77
+ "Fire Materia IV",
78
+ "Heavens' Eye Materia IV",
79
+ "Ice Materia IV",
80
+ "Intelligence Materia IV",
81
+ "Lightning Materia IV",
82
+ "Mind Materia IV",
83
+ "Piety Materia IV",
84
+ "Quickarm Materia IV",
85
+ "Quicktongue Materia IV",
86
+ "Savage Aim Materia IV",
87
+ "Savage Might Materia IV",
88
+ "Strength Materia IV",
89
+ "Vitality Materia IV",
90
+ "Water Materia IV",
91
+ "Wind Materia IV"
92
+ ],
93
+ "V": [
94
+ "Battledance Materia V",
95
+ "Dexterity Materia V",
96
+ "Earth Materia V",
97
+ "Fire Materia V",
98
+ "Heavens' Eye Materia V",
99
+ "Ice Materia V",
100
+ "Intelligence Materia V",
101
+ "Lightning Materia V",
102
+ "Mind Materia V",
103
+ "Piety Materia V",
104
+ "Quickarm Materia V",
105
+ "Quicktongue Materia V",
106
+ "Savage Aim Materia V",
107
+ "Savage Might Materia V",
108
+ "Strength Materia V",
109
+ "Vitality Materia V",
110
+ "Water Materia V",
111
+ "Wind Materia V"
112
+ ],
113
+ "VI": [
114
+ "Battledance Materia VI",
115
+ "Dexterity Materia VI",
116
+ "Earth Materia VI",
117
+ "Fire Materia VI",
118
+ "Heavens' Eye Materia VI",
119
+ "Ice Materia VI",
120
+ "Intelligence Materia VI",
121
+ "Lightning Materia VI",
122
+ "Mind Materia VI",
123
+ "Piety Materia VI",
124
+ "Quickarm Materia VI",
125
+ "Quicktongue Materia VI",
126
+ "Savage Aim Materia VI",
127
+ "Savage Might Materia VI",
128
+ "Strength Materia VI",
129
+ "Vitality Materia VI",
130
+ "Water Materia VI",
131
+ "Wind Materia VI"
132
+ ],
133
+ "VII": [
134
+ "Battledance Materia VII",
135
+ "Heavens' Eye Materia VII",
136
+ "Piety Materia VII",
137
+ "Quickarm Materia VII",
138
+ "Quicktongue Materia VII",
139
+ "Savage Aim Materia VII",
140
+ "Savage Might Materia VII"
141
+ ],
142
+ "VIII": [
143
+ "Battledance Materia VIII",
144
+ "Heavens' Eye Materia VIII",
145
+ "Piety Materia VIII",
146
+ "Quickarm Materia VIII",
147
+ "Quicktongue Materia VIII",
148
+ "Savage Aim Materia VIII",
149
+ "Savage Might Materia VIII"
150
+ ],
151
+ "IX": [
152
+ "Battledance Materia IX",
153
+ "Heavens' Eye Materia IX",
154
+ "Piety Materia IX",
155
+ "Quickarm Materia IX",
156
+ "Quicktongue Materia IX",
157
+ "Savage Aim Materia IX",
158
+ "Savage Might Materia IX"
159
+ ],
160
+ "X": [
161
+ "Battledance Materia X",
162
+ "Heavens' Eye Materia X",
163
+ "Piety Materia X",
164
+ "Quickarm Materia X",
165
+ "Quicktongue Materia X",
166
+ "Savage Aim Materia X",
167
+ "Savage Might Materia X"
168
+ ],
169
+ "XI": [
170
+ "Battledance Materia XI",
171
+ "Heavens' Eye Materia XI",
172
+ "Piety Materia XI",
173
+ "Quickarm Materia XI",
174
+ "Quicktongue Materia XI",
175
+ "Savage Aim Materia XI",
176
+ "Savage Might Materia XI"
177
+ ],
178
+ "XII": [
179
+ "Battledance Materia XII",
180
+ "Heavens' Eye Materia XII",
181
+ "Piety Materia XII",
182
+ "Quickarm Materia XII",
183
+ "Quicktongue Materia XII",
184
+ "Savage Aim Materia XII",
185
+ "Savage Might Materia XII"
186
+ ]
187
+ },
188
+ "crafting": {
189
+ "I": [
190
+ "Craftsman's Command Materia I",
191
+ "Craftsman's Competence Materia I",
192
+ "Craftsman's Cunning Materia I"
193
+ ],
194
+ "II": [
195
+ "Craftsman's Command Materia II",
196
+ "Craftsman's Competence Materia II",
197
+ "Craftsman's Cunning Materia II"
198
+ ],
199
+ "III": [
200
+ "Craftsman's Command Materia III",
201
+ "Craftsman's Competence Materia III",
202
+ "Craftsman's Cunning Materia III"
203
+ ],
204
+ "IV": [
205
+ "Craftsman's Command Materia IV",
206
+ "Craftsman's Competence Materia IV",
207
+ "Craftsman's Cunning Materia IV"
208
+ ],
209
+ "V": [
210
+ "Craftsman's Command Materia V",
211
+ "Craftsman's Competence Materia V",
212
+ "Craftsman's Cunning Materia V"
213
+ ],
214
+ "VI": [
215
+ "Craftsman's Command Materia VI",
216
+ "Craftsman's Competence Materia VI",
217
+ "Craftsman's Cunning Materia VI"
218
+ ],
219
+ "VII": [
220
+ "Craftsman's Command Materia VII",
221
+ "Craftsman's Competence Materia VII",
222
+ "Craftsman's Cunning Materia VII"
223
+ ],
224
+ "VIII": [
225
+ "Craftsman's Command Materia VIII",
226
+ "Craftsman's Competence Materia VIII",
227
+ "Craftsman's Cunning Materia VIII"
228
+ ],
229
+ "IX": [
230
+ "Craftsman's Command Materia IX",
231
+ "Craftsman's Competence Materia IX",
232
+ "Craftsman's Cunning Materia IX"
233
+ ],
234
+ "X": [
235
+ "Craftsman's Command Materia X",
236
+ "Craftsman's Competence Materia X",
237
+ "Craftsman's Cunning Materia X"
238
+ ],
239
+ "XI": [
240
+ "Craftsman's Command Materia XI",
241
+ "Craftsman's Competence Materia XI",
242
+ "Craftsman's Cunning Materia XI"
243
+ ],
244
+ "XII": [
245
+ "Craftsman's Command Materia XII",
246
+ "Craftsman's Competence Materia XII",
247
+ "Craftsman's Cunning Materia XII"
248
+ ]
249
+ },
250
+ "gathering": {
251
+ "I": [
252
+ "Gatherer's Grasp Materia I",
253
+ "Gatherer's Guerdon Materia I",
254
+ "Gatherer's Guile Materia I"
255
+ ],
256
+ "II": [
257
+ "Gatherer's Grasp Materia II",
258
+ "Gatherer's Guerdon Materia II",
259
+ "Gatherer's Guile Materia II"
260
+ ],
261
+ "III": [
262
+ "Gatherer's Grasp Materia III",
263
+ "Gatherer's Guerdon Materia III",
264
+ "Gatherer's Guile Materia III"
265
+ ],
266
+ "IV": [
267
+ "Gatherer's Grasp Materia IV",
268
+ "Gatherer's Guerdon Materia IV",
269
+ "Gatherer's Guile Materia IV"
270
+ ],
271
+ "V": [
272
+ "Gatherer's Grasp Materia V",
273
+ "Gatherer's Guerdon Materia V",
274
+ "Gatherer's Guile Materia V"
275
+ ],
276
+ "VI": [
277
+ "Gatherer's Grasp Materia VI",
278
+ "Gatherer's Guerdon Materia VI",
279
+ "Gatherer's Guile Materia VI"
280
+ ],
281
+ "VII": [
282
+ "Gatherer's Grasp Materia VII",
283
+ "Gatherer's Guerdon Materia VII",
284
+ "Gatherer's Guile Materia VII"
285
+ ],
286
+ "VIII": [
287
+ "Gatherer's Grasp Materia VIII",
288
+ "Gatherer's Guerdon Materia VIII",
289
+ "Gatherer's Guile Materia VIII"
290
+ ],
291
+ "IX": [
292
+ "Gatherer's Grasp Materia IX",
293
+ "Gatherer's Guerdon Materia IX",
294
+ "Gatherer's Guile Materia IX"
295
+ ],
296
+ "X": [
297
+ "Gatherer's Grasp Materia X",
298
+ "Gatherer's Guerdon Materia X",
299
+ "Gatherer's Guile Materia X"
300
+ ],
301
+ "XI": [
302
+ "Gatherer's Grasp Materia XI",
303
+ "Gatherer's Guerdon Materia XI",
304
+ "Gatherer's Guile Materia XI"
305
+ ],
306
+ "XII": [
307
+ "Gatherer's Grasp Materia XII",
308
+ "Gatherer's Guerdon Materia XII",
309
+ "Gatherer's Guile Materia XII"
310
+ ]
311
+ }
312
+ },
313
+ "base_param_category": {
314
+ "Strength": "combat",
315
+ "Vitality": "combat",
316
+ "Dexterity": "combat",
317
+ "Intelligence": "combat",
318
+ "Mind": "combat",
319
+ "Piety": "combat",
320
+ "Fire Resistance": "combat",
321
+ "Ice Resistance": "combat",
322
+ "Wind Resistance": "combat",
323
+ "Earth Resistance": "combat",
324
+ "Lightning Resistance": "combat",
325
+ "Water Resistance": "combat",
326
+ "Direct Hit Rate": "combat",
327
+ "Critical Hit": "combat",
328
+ "Determination": "combat",
329
+ "Tenacity": "combat",
330
+ "Gathering": "gathering",
331
+ "Perception": "gathering",
332
+ "GP": "gathering",
333
+ "Craftsmanship": "crafting",
334
+ "CP": "crafting",
335
+ "Control": "crafting",
336
+ "Skill Speed": "combat",
337
+ "Spell Speed": "combat",
338
+ "Slow Resistance": "combat",
339
+ "Silence Resistance": "combat",
340
+ "Blind Resistance": "combat",
341
+ "Poison Resistance": "combat",
342
+ "Stun Resistance": "combat",
343
+ "Sleep Resistance": "combat",
344
+ "Bind Resistance": "combat",
345
+ "Heavy Resistance": "combat"
346
+ }
347
+ }
package/dist/constants.js CHANGED
@@ -1,8 +1,11 @@
1
1
  export const UNIVERSALIS_BASE_URL = process.env.UNIVERSALIS_BASE_URL ?? "https://universalis.app/api/v2";
2
2
  export const XIVAPI_BASE_URL = process.env.XIVAPI_BASE_URL ?? "https://v2.xivapi.com/api";
3
+ export const SADDLEBAG_BASE_URL = process.env.SADDLEBAG_BASE_URL ?? "https://docs.saddlebagexchange.com/api";
3
4
  export const DEFAULT_UNIVERSALIS_TIMEOUT_MS = 30000;
4
5
  export const DEFAULT_XIVAPI_TIMEOUT_MS = 30000;
6
+ export const DEFAULT_SADDLEBAG_TIMEOUT_MS = 30000;
5
7
  export const DEFAULT_TIMEOUT_MS = 30000;
8
+ export const DEFAULT_MATERIA_CACHE_TTL_MS = 1000 * 60 * 60 * 24;
6
9
  export const CHARACTER_LIMIT = 25000;
7
10
  export const DEFAULT_PAGE_LIMIT = 20;
8
11
  export const MAX_PAGE_LIMIT = 100;
package/dist/index.js CHANGED
@@ -2,11 +2,14 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import pkg from "../package.json" with { type: "json" };
5
+ import { SERVER_INSTRUCTIONS } from "./instructions.js";
5
6
  import { createClients } from "./services/clients.js";
6
7
  import { registerLookupTools } from "./tools/lookup.js";
7
8
  import { registerMarketTools } from "./tools/market.js";
8
9
  import { registerReferenceTools } from "./tools/reference.js";
10
+ import { registerSaddlebagTools } from "./tools/saddlebag.js";
9
11
  import { registerStatsTools } from "./tools/stats.js";
12
+ import { registerWorkflowTools } from "./tools/workflows.js";
10
13
  function toNumber(value) {
11
14
  if (!value)
12
15
  return undefined;
@@ -17,12 +20,15 @@ async function main() {
17
20
  const server = new McpServer({
18
21
  name: "universalis-mcp-server",
19
22
  version: pkg.version,
23
+ }, {
24
+ instructions: SERVER_INSTRUCTIONS,
20
25
  });
21
26
  const userAgent = process.env.UNIVERSALIS_MCP_USER_AGENT ?? `universalis-mcp-server/${pkg.version}`;
22
27
  const clients = createClients({
23
28
  userAgent,
24
29
  universalisTimeoutMs: toNumber(process.env.UNIVERSALIS_TIMEOUT_MS),
25
30
  xivapiTimeoutMs: toNumber(process.env.XIVAPI_TIMEOUT_MS),
31
+ saddlebagTimeoutMs: toNumber(process.env.SADDLEBAG_TIMEOUT_MS),
26
32
  xivapiLanguage: process.env.XIVAPI_LANGUAGE,
27
33
  xivapiVersion: process.env.XIVAPI_VERSION,
28
34
  });
@@ -30,6 +36,22 @@ async function main() {
30
36
  registerReferenceTools(server, clients);
31
37
  registerStatsTools(server, clients);
32
38
  registerLookupTools(server, clients);
39
+ registerSaddlebagTools(server, clients);
40
+ registerWorkflowTools(server, clients);
41
+ server.registerPrompt("universalis_usage_guide", {
42
+ title: "Universalis Usage Guide",
43
+ description: "Quick guidance on which tools to use and when.",
44
+ }, async () => ({
45
+ messages: [
46
+ {
47
+ role: "user",
48
+ content: {
49
+ type: "text",
50
+ text: SERVER_INSTRUCTIONS,
51
+ },
52
+ },
53
+ ],
54
+ }));
33
55
  const transport = new StdioServerTransport();
34
56
  await server.connect(transport);
35
57
  console.error("universalis-mcp-server running on stdio");
@@ -0,0 +1,56 @@
1
+ export const SERVER_INSTRUCTIONS = `Use this server to analyze FFXIV market data via Universalis and Saddlebag Exchange, plus item data via XIVAPI.
2
+
3
+ Tool guide:
4
+ - universalis_rank_items_by_profitability: best for "most profitable to farm" questions with cost inputs; ranks by demand and profit (defaults to best HQ/NQ price, can filter unmarketable items, and includes supply metrics).
5
+ - universalis_resolve_items_by_names: bulk name-to-ID resolution in one query; prefer over per-item search.
6
+ - universalis_resolve_items_by_name: single-item name search.
7
+ - universalis_get_item_by_id: fetch one item row by ID from XIVAPI.
8
+ - universalis_get_items_by_ids: fetch multiple item rows by ID in one request.
9
+
10
+ - universalis_get_aggregated_prices: cached summary stats (min listing, recent purchase, averages, velocity). Use for most analysis.
11
+ - universalis_get_current_listings: listings + recent history when the user needs live listings or example sales.
12
+ - universalis_get_sales_history: detailed sales history when trend analysis or filters are required.
13
+
14
+ - universalis_list_worlds: list and validate worlds.
15
+ - universalis_list_data_centers: list and validate data centers.
16
+ - universalis_get_tax_rates: current tax rates for a world.
17
+ - universalis_list_marketable_items: marketable item IDs (paginate).
18
+ - universalis_get_list: retrieve a Universalis list by ID.
19
+ - universalis_get_content: content metadata by ID (best-effort endpoint).
20
+
21
+ - universalis_get_most_recent_updates: most recently updated items for a world or DC.
22
+ - universalis_get_least_recent_updates: least recently updated items for a world or DC.
23
+ - universalis_get_recent_updates: legacy list of recently updated items (no world/DC info).
24
+ - universalis_get_upload_counts_by_source: upload counts by client app.
25
+ - universalis_get_upload_counts_by_world: upload counts by world.
26
+ - universalis_get_upload_history: daily upload totals for the last 30 days.
27
+
28
+ Saddlebag tools (FFXIV):
29
+ - saddlebag_get_listing_metrics: listing competition metrics and current listings.
30
+ - saddlebag_get_history_metrics: aggregated history metrics and price distributions.
31
+ - saddlebag_get_raw_stats: daily snapshot stats (median, average, sales volume).
32
+ - saddlebag_get_scrip_exchange: gil-per-scrip rankings.
33
+ - saddlebag_get_shopping_list: crafting shopping list (may return exception payloads).
34
+ - saddlebag_get_export_prices: cross-world price comparison for export trading.
35
+ - saddlebag_get_marketshare: marketshare leaderboard snapshot for a server.
36
+ - saddlebag_get_reselling_scan: reselling opportunities (region/DC/vendor filters).
37
+ - saddlebag_get_weekly_price_group_delta: weekly deltas for custom item groups.
38
+ - saddlebag_get_price_check: price alert checks (user-supplied auctions).
39
+ - saddlebag_get_quantity_check: quantity alert checks (user-supplied auctions).
40
+ - saddlebag_get_sale_alert: sale alerts for retainer listings.
41
+ - saddlebag_get_craftsim: crafting profitability scan (use max_results to limit payloads).
42
+ - saddlebag_get_blog_description: item description text lookup.
43
+
44
+ Notes:
45
+ - world_dc_region accepts a world name/ID, data center name, or region.
46
+ - response_format defaults to markdown; use json for structured processing.
47
+ - Materia categories like "Combat Materia VII", "Crafting Materia VII", and "Gathering Materia VII" are expanded to their specific item names; grade is required.
48
+ - Bulk resolve and profitability tools can fall back to partial matches for unresolved exact inputs; check match_type for "fallback_partial".
49
+ - Materia expansion uses cached XIVAPI data; refresh is controlled by MATERIA_CACHE_TTL_MS and MATERIA_REFRESH.
50
+ - Profitability tool options: marketable_only (default true), min_velocity threshold, include_supply (default true).
51
+ - price_variant defaults to "best".
52
+ - Prefer Universalis for raw listings/sales history; use Saddlebag for competition metrics, rankings, and aggregate distributions.
53
+ - Saddlebag best-deals is excluded (premium gated + inconsistent API validation).
54
+ - Some Saddlebag endpoints call Universalis directly; be mindful of rate limits.
55
+ - saddlebag_get_raw_stats supports item_ids = -1 for all items and can return very large payloads.
56
+ `;
@@ -1,5 +1,6 @@
1
1
  import Bottleneck from "bottleneck";
2
- import { DEFAULT_UNIVERSALIS_TIMEOUT_MS, DEFAULT_XIVAPI_TIMEOUT_MS } from "../constants.js";
2
+ import { DEFAULT_SADDLEBAG_TIMEOUT_MS, DEFAULT_UNIVERSALIS_TIMEOUT_MS, DEFAULT_XIVAPI_TIMEOUT_MS, } from "../constants.js";
3
+ import { SaddlebagClient } from "./saddlebag.js";
3
4
  import { UniversalisClient } from "./universalis.js";
4
5
  import { XivapiClient } from "./xivapi.js";
5
6
  export function createClients(options = {}) {
@@ -15,7 +16,18 @@ export function createClients(options = {}) {
15
16
  reservoirRefreshAmount: 10,
16
17
  reservoirRefreshInterval: 1000,
17
18
  });
19
+ const saddlebagLimiter = new Bottleneck({
20
+ maxConcurrent: 4,
21
+ reservoir: 20,
22
+ reservoirRefreshAmount: 10,
23
+ reservoirRefreshInterval: 1000,
24
+ });
18
25
  return {
26
+ saddlebag: new SaddlebagClient({
27
+ limiter: saddlebagLimiter,
28
+ timeoutMs: options.saddlebagTimeoutMs ?? DEFAULT_SADDLEBAG_TIMEOUT_MS,
29
+ userAgent: options.userAgent,
30
+ }),
19
31
  universalis: new UniversalisClient({
20
32
  limiter: universalisLimiter,
21
33
  timeoutMs: options.universalisTimeoutMs ?? DEFAULT_UNIVERSALIS_TIMEOUT_MS,