appfigures-mcp 0.1.0 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +13 -0
  2. package/dist/index.js +532 -147
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,3 +28,16 @@ APPFIGURES_TOKEN=pat_... npx appfigures-mcp
28
28
  ```
29
29
 
30
30
  To use in an MCP client, configure the command to `npx` with args `appfigures-mcp`, and pass `APPFIGURES_TOKEN` in the environment.
31
+
32
+ ## API Coverage
33
+
34
+ All endpoints are available via the `appfigures_request` tool (any method/path/query/body).
35
+ Convenience tools (grouped) exist for:
36
+ - `appfigures_products`
37
+ - `appfigures_ratings`
38
+ - `appfigures_featured`
39
+ - `appfigures_sales`
40
+ - `appfigures_ads`
41
+ - `appfigures_reviews`
42
+ - `appfigures_users`
43
+ - `appfigures_data`
package/dist/index.js CHANGED
@@ -28309,7 +28309,7 @@ function buildQuery(params) {
28309
28309
  if (Array.isArray(value)) {
28310
28310
  if (value.length === 0)
28311
28311
  continue;
28312
- parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value.join(","))}`);
28312
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value.map((item) => String(item)).join(","))}`);
28313
28313
  continue;
28314
28314
  }
28315
28315
  parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
@@ -28334,21 +28334,79 @@ function getUserAgent() {
28334
28334
  const userAgent = process.env.APPFIGURES_USER_AGENT;
28335
28335
  return userAgent && userAgent.length > 0 ? userAgent : DEFAULT_USER_AGENT;
28336
28336
  }
28337
- async function appfiguresGet(path, query) {
28338
- const token = getAuthToken();
28339
- if (!token) {
28340
- return "Missing APPFIGURES_TOKEN in environment. Set a Personal Access Token (Bearer token).";
28337
+ function buildAuthHeader(auth) {
28338
+ if (!auth) {
28339
+ const token = getAuthToken();
28340
+ return token ? `Bearer ${token}` : null;
28341
+ }
28342
+ if (auth.type === "none")
28343
+ return null;
28344
+ if (auth.type === "bearer") {
28345
+ const token = auth.token ?? getAuthToken();
28346
+ return token ? `Bearer ${token}` : null;
28347
+ }
28348
+ const encoded = Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
28349
+ return `Basic ${encoded}`;
28350
+ }
28351
+ function buildFormBody(body) {
28352
+ const parts = [];
28353
+ for (const [key, value] of Object.entries(body)) {
28354
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
28355
+ }
28356
+ return parts.join("&");
28357
+ }
28358
+ function isRecordOfPrimitives(value) {
28359
+ if (!value || typeof value !== "object" || Array.isArray(value))
28360
+ return false;
28361
+ for (const entry of Object.entries(value)) {
28362
+ const entryValue = entry[1];
28363
+ if (typeof entryValue !== "string" && typeof entryValue !== "number" && typeof entryValue !== "boolean") {
28364
+ return false;
28365
+ }
28366
+ }
28367
+ return true;
28368
+ }
28369
+ async function appfiguresRequest(params) {
28370
+ const { method, path, query, body, contentType, headers, auth } = params;
28371
+ const authorization = buildAuthHeader(auth);
28372
+ if (!authorization && (!headers || !headers.Authorization)) {
28373
+ return "Missing authentication. Set APPFIGURES_TOKEN or pass auth/headers.Authorization.";
28374
+ }
28375
+ if (auth && headers && headers.Authorization) {
28376
+ return "Provide auth or headers.Authorization, not both.";
28341
28377
  }
28342
28378
  const url2 = `${APPFIGURES_BASE_URL}${path}${query ?? ""}`;
28343
- const response = await fetch(url2, {
28344
- method: "GET",
28345
- headers: {
28346
- Authorization: `Bearer ${token}`,
28347
- "User-Agent": getUserAgent()
28379
+ const outgoingHeaders = {
28380
+ "User-Agent": getUserAgent(),
28381
+ ...headers
28382
+ };
28383
+ if (authorization) {
28384
+ outgoingHeaders.Authorization = authorization;
28385
+ }
28386
+ let requestBody;
28387
+ if (method !== "GET" && method !== "DELETE" && body !== undefined) {
28388
+ if (contentType === "form") {
28389
+ if (isRecordOfPrimitives(body)) {
28390
+ requestBody = buildFormBody(body);
28391
+ outgoingHeaders["Content-Type"] = "application/x-www-form-urlencoded";
28392
+ } else {
28393
+ return "Form bodies must be an object of primitive values.";
28394
+ }
28395
+ } else if (contentType === "text") {
28396
+ requestBody = String(body);
28397
+ outgoingHeaders["Content-Type"] = "text/plain";
28398
+ } else {
28399
+ requestBody = JSON.stringify(body ?? {});
28400
+ outgoingHeaders["Content-Type"] = "application/json";
28348
28401
  }
28402
+ }
28403
+ const response = await fetch(url2, {
28404
+ method,
28405
+ headers: outgoingHeaders,
28406
+ body: requestBody
28349
28407
  });
28350
- const body = await response.text();
28351
- const formattedBody = prettyBody(body, response.headers.get("content-type"));
28408
+ const responseBody = await response.text();
28409
+ const formattedBody = prettyBody(responseBody, response.headers.get("content-type"));
28352
28410
  if (!response.ok) {
28353
28411
  return `HTTP ${response.status} ${response.statusText}
28354
28412
  ${formattedBody}`;
@@ -28362,198 +28420,525 @@ server.registerTool("appfigures_status", {
28362
28420
  content: [
28363
28421
  {
28364
28422
  type: "text",
28365
- text: await appfiguresGet("/")
28423
+ text: await appfiguresRequest({ method: "GET", path: "/" })
28366
28424
  }
28367
28425
  ]
28368
28426
  }));
28369
- server.registerTool("appfigures_get_product", {
28370
- description: "Get product metadata by Appfigures product id.",
28371
- inputSchema: {
28372
- id: exports_external.number().int().positive()
28427
+ var reportSchemaBase = exports_external.object({
28428
+ start_date: exports_external.string().min(1).optional(),
28429
+ end_date: exports_external.string().min(1).optional(),
28430
+ group_by: exports_external.array(exports_external.string().min(1)).optional(),
28431
+ granularity: exports_external.string().min(1).optional(),
28432
+ products: exports_external.array(exports_external.string().min(1)).optional(),
28433
+ countries: exports_external.array(exports_external.string().min(2)).optional(),
28434
+ format: exports_external.enum(["json", "csv", "JSON", "CSV"]).optional()
28435
+ });
28436
+ var reviewsQuerySchema = exports_external.object({
28437
+ q: exports_external.string().min(1).optional(),
28438
+ products: exports_external.array(exports_external.string().min(1)).optional(),
28439
+ countries: exports_external.array(exports_external.string().min(2)).optional(),
28440
+ page: exports_external.number().int().positive().optional(),
28441
+ count: exports_external.number().int().positive().optional(),
28442
+ lang: exports_external.string().min(1).optional(),
28443
+ author: exports_external.string().min(1).optional(),
28444
+ versions: exports_external.array(exports_external.string().min(1)).optional(),
28445
+ stars: exports_external.array(exports_external.number().int().min(1).max(5)).optional(),
28446
+ sort: exports_external.string().min(1).optional(),
28447
+ start: exports_external.string().min(1).optional(),
28448
+ end: exports_external.string().min(1).optional()
28449
+ });
28450
+ function buildReviewsQuery(input) {
28451
+ return buildQuery({
28452
+ q: input.q,
28453
+ products: input.products,
28454
+ countries: input.countries,
28455
+ page: input.page,
28456
+ count: input.count,
28457
+ lang: input.lang,
28458
+ author: input.author,
28459
+ versions: input.versions,
28460
+ stars: input.stars,
28461
+ sort: input.sort,
28462
+ start: input.start,
28463
+ end: input.end
28464
+ });
28465
+ }
28466
+ function reportQueryFrom(input) {
28467
+ return {
28468
+ start_date: input.start_date,
28469
+ end_date: input.end_date,
28470
+ group_by: input.group_by,
28471
+ granularity: input.granularity,
28472
+ products: input.products,
28473
+ countries: input.countries,
28474
+ format: input.format,
28475
+ networks: input.networks
28476
+ };
28477
+ }
28478
+ server.registerTool("appfigures_products", {
28479
+ description: "Product lookups: get/search/list.",
28480
+ inputSchema: exports_external.discriminatedUnion("action", [
28481
+ exports_external.object({
28482
+ action: exports_external.literal("get"),
28483
+ id: exports_external.number().int().positive()
28484
+ }),
28485
+ exports_external.object({
28486
+ action: exports_external.literal("get_by_store"),
28487
+ store: exports_external.string().min(1),
28488
+ id_in_store: exports_external.string().min(1)
28489
+ }),
28490
+ exports_external.object({
28491
+ action: exports_external.literal("search"),
28492
+ term: exports_external.string().min(1),
28493
+ storefronts: exports_external.array(exports_external.string().min(1)).optional(),
28494
+ page: exports_external.number().int().positive().optional(),
28495
+ count: exports_external.number().int().positive().optional()
28496
+ }),
28497
+ exports_external.object({
28498
+ action: exports_external.literal("list_mine"),
28499
+ store: exports_external.string().min(1).optional(),
28500
+ include_inactive: exports_external.boolean().optional()
28501
+ })
28502
+ ])
28503
+ }, async (input) => {
28504
+ if (input.action === "get") {
28505
+ return {
28506
+ content: [
28507
+ {
28508
+ type: "text",
28509
+ text: await appfiguresRequest({
28510
+ method: "GET",
28511
+ path: `/products/${input.id}`
28512
+ })
28513
+ }
28514
+ ]
28515
+ };
28373
28516
  }
28374
- }, async ({ id }) => ({
28375
- content: [
28376
- {
28377
- type: "text",
28378
- text: await appfiguresGet(`/products/${id}`)
28379
- }
28380
- ]
28381
- }));
28382
- server.registerTool("appfigures_get_product_by_store_id", {
28383
- description: "Get product metadata by store id (store + id in store).",
28384
- inputSchema: {
28385
- store: exports_external.string().min(1),
28386
- id_in_store: exports_external.string().min(1)
28517
+ if (input.action === "get_by_store") {
28518
+ return {
28519
+ content: [
28520
+ {
28521
+ type: "text",
28522
+ text: await appfiguresRequest({
28523
+ method: "GET",
28524
+ path: `/products/${encodeURIComponent(input.store)}/${encodeURIComponent(input.id_in_store)}`
28525
+ })
28526
+ }
28527
+ ]
28528
+ };
28529
+ }
28530
+ if (input.action === "search") {
28531
+ const query2 = buildQuery({
28532
+ storefronts: input.storefronts ? input.storefronts.join(";") : undefined,
28533
+ page: input.page,
28534
+ count: input.count
28535
+ });
28536
+ return {
28537
+ content: [
28538
+ {
28539
+ type: "text",
28540
+ text: await appfiguresRequest({
28541
+ method: "GET",
28542
+ path: `/products/search/${encodeURIComponent(input.term)}`,
28543
+ query: query2
28544
+ })
28545
+ }
28546
+ ]
28547
+ };
28387
28548
  }
28388
- }, async ({ store, id_in_store }) => ({
28389
- content: [
28390
- {
28391
- type: "text",
28392
- text: await appfiguresGet(`/products/${encodeURIComponent(store)}/${encodeURIComponent(id_in_store)}`)
28393
- }
28394
- ]
28395
- }));
28396
- server.registerTool("appfigures_search_products", {
28397
- description: "Search for products by term. Requires Public Data API access for non-owned products.",
28398
- inputSchema: {
28399
- term: exports_external.string().min(1),
28400
- storefronts: exports_external.array(exports_external.string().min(1)).optional(),
28401
- page: exports_external.number().int().positive().optional(),
28402
- count: exports_external.number().int().positive().optional()
28403
- }
28404
- }, async ({ term, storefronts, page, count }) => {
28405
28549
  const query = buildQuery({
28406
- storefronts: storefronts ? storefronts.join(";") : undefined,
28407
- page,
28408
- count
28550
+ store: input.store,
28551
+ include_inactive: input.include_inactive
28409
28552
  });
28410
28553
  return {
28411
28554
  content: [
28412
28555
  {
28413
28556
  type: "text",
28414
- text: await appfiguresGet(`/products/search/${encodeURIComponent(term)}`, query)
28557
+ text: await appfiguresRequest({
28558
+ method: "GET",
28559
+ path: "/products/mine",
28560
+ query
28561
+ })
28415
28562
  }
28416
28563
  ]
28417
28564
  };
28418
28565
  });
28419
- server.registerTool("appfigures_list_my_products", {
28420
- description: "List products owned or shared with the authenticated account.",
28421
- inputSchema: {
28422
- store: exports_external.string().min(1).optional(),
28423
- include_inactive: exports_external.boolean().optional()
28566
+ server.registerTool("appfigures_ratings", {
28567
+ description: "Ratings reports.",
28568
+ inputSchema: reportSchemaBase.extend({
28569
+ group_by: exports_external.array(exports_external.enum(["product", "country", "date"])).optional()
28570
+ })
28571
+ }, async (input) => {
28572
+ const query = buildQuery(reportQueryFrom(input));
28573
+ return {
28574
+ content: [
28575
+ {
28576
+ type: "text",
28577
+ text: await appfiguresRequest({
28578
+ method: "GET",
28579
+ path: "/reports/ratings",
28580
+ query
28581
+ })
28582
+ }
28583
+ ]
28584
+ };
28585
+ });
28586
+ server.registerTool("appfigures_featured", {
28587
+ description: "Featured reports.",
28588
+ inputSchema: exports_external.discriminatedUnion("action", [
28589
+ exports_external.object({
28590
+ action: exports_external.literal("summary"),
28591
+ start_date: exports_external.string().min(1),
28592
+ end_date: exports_external.string().min(1),
28593
+ products: exports_external.array(exports_external.string().min(1)).optional()
28594
+ }),
28595
+ exports_external.object({
28596
+ action: exports_external.literal("full"),
28597
+ product_id: exports_external.number().int().positive(),
28598
+ start_date: exports_external.string().min(1),
28599
+ end_date: exports_external.string().min(1),
28600
+ countries: exports_external.array(exports_external.string().min(2)).optional()
28601
+ }),
28602
+ exports_external.object({
28603
+ action: exports_external.literal("counts"),
28604
+ end: exports_external.string().min(1).optional(),
28605
+ products: exports_external.array(exports_external.string().min(1)).optional(),
28606
+ count: exports_external.number().int().positive().optional(),
28607
+ granularity: exports_external.string().min(1).optional(),
28608
+ show_empty: exports_external.boolean().optional()
28609
+ }),
28610
+ exports_external.object({
28611
+ action: exports_external.literal("history"),
28612
+ product_id: exports_external.number().int().positive(),
28613
+ featured_category_id: exports_external.number().int().positive()
28614
+ })
28615
+ ])
28616
+ }, async (input) => {
28617
+ if (input.action === "summary") {
28618
+ const query = buildQuery({ products: input.products });
28619
+ return {
28620
+ content: [
28621
+ {
28622
+ type: "text",
28623
+ text: await appfiguresRequest({
28624
+ method: "GET",
28625
+ path: `/featured/summary/${encodeURIComponent(input.start_date)}/${encodeURIComponent(input.end_date)}`,
28626
+ query
28627
+ })
28628
+ }
28629
+ ]
28630
+ };
28631
+ }
28632
+ if (input.action === "full") {
28633
+ const query = buildQuery({ countries: input.countries });
28634
+ return {
28635
+ content: [
28636
+ {
28637
+ type: "text",
28638
+ text: await appfiguresRequest({
28639
+ method: "GET",
28640
+ path: `/featured/full/${input.product_id}/${encodeURIComponent(input.start_date)}/${encodeURIComponent(input.end_date)}`,
28641
+ query
28642
+ })
28643
+ }
28644
+ ]
28645
+ };
28646
+ }
28647
+ if (input.action === "counts") {
28648
+ const query = buildQuery({
28649
+ end: input.end,
28650
+ products: input.products,
28651
+ count: input.count,
28652
+ granularity: input.granularity,
28653
+ show_empty: input.show_empty
28654
+ });
28655
+ return {
28656
+ content: [
28657
+ {
28658
+ type: "text",
28659
+ text: await appfiguresRequest({
28660
+ method: "GET",
28661
+ path: "/featured/counts",
28662
+ query
28663
+ })
28664
+ }
28665
+ ]
28666
+ };
28424
28667
  }
28425
- }, async ({ store, include_inactive }) => {
28426
- const query = buildQuery({
28427
- store,
28428
- include_inactive
28429
- });
28430
28668
  return {
28431
28669
  content: [
28432
28670
  {
28433
28671
  type: "text",
28434
- text: await appfiguresGet("/products/mine", query)
28672
+ text: await appfiguresRequest({
28673
+ method: "GET",
28674
+ path: `/featured/history/${input.product_id}/${input.featured_category_id}`
28675
+ })
28435
28676
  }
28436
28677
  ]
28437
28678
  };
28438
28679
  });
28439
- server.registerTool("appfigures_ratings_report", {
28440
- description: "Get ratings report (totals or grouped) for products and countries.",
28441
- inputSchema: {
28442
- start_date: exports_external.string().min(1).optional(),
28443
- end_date: exports_external.string().min(1).optional(),
28444
- group_by: exports_external.array(exports_external.enum(["product", "country", "date"])).optional(),
28445
- granularity: exports_external.string().min(1).optional(),
28446
- products: exports_external.array(exports_external.string().min(1)).optional(),
28447
- countries: exports_external.array(exports_external.string().min(2)).optional(),
28448
- format: exports_external.enum(["json", "csv", "JSON", "CSV"]).optional()
28449
- }
28450
- }, async ({
28451
- start_date,
28452
- end_date,
28453
- group_by,
28454
- granularity,
28455
- products,
28456
- countries,
28457
- format
28458
- }) => {
28459
- const query = buildQuery({
28460
- start_date,
28461
- end_date,
28462
- group_by,
28463
- granularity,
28464
- products,
28465
- countries,
28466
- format
28467
- });
28680
+ server.registerTool("appfigures_sales", {
28681
+ description: "Sales-related reports.",
28682
+ inputSchema: exports_external.discriminatedUnion("type", [
28683
+ reportSchemaBase.extend({ type: exports_external.literal("sales") }),
28684
+ reportSchemaBase.extend({ type: exports_external.literal("revenue") }),
28685
+ reportSchemaBase.extend({ type: exports_external.literal("subscriptions") }),
28686
+ reportSchemaBase.extend({ type: exports_external.literal("estimates") })
28687
+ ])
28688
+ }, async (input) => {
28689
+ const query = buildQuery(reportQueryFrom(input));
28690
+ const path = input.type === "sales" ? "/reports/sales" : input.type === "revenue" ? "/reports/revenue" : input.type === "subscriptions" ? "/reports/subscriptions" : "/reports/estimates";
28468
28691
  return {
28469
28692
  content: [
28470
28693
  {
28471
28694
  type: "text",
28472
- text: await appfiguresGet("/reports/ratings", query)
28695
+ text: await appfiguresRequest({
28696
+ method: "GET",
28697
+ path,
28698
+ query
28699
+ })
28473
28700
  }
28474
28701
  ]
28475
28702
  };
28476
28703
  });
28477
- server.registerTool("appfigures_featured_summary", {
28478
- description: "Get featured summary report for a date range.",
28479
- inputSchema: {
28480
- start_date: exports_external.string().min(1),
28481
- end_date: exports_external.string().min(1),
28482
- products: exports_external.array(exports_external.string().min(1)).optional()
28483
- }
28484
- }, async ({ start_date, end_date, products }) => {
28485
- const query = buildQuery({
28486
- products
28487
- });
28704
+ server.registerTool("appfigures_ads", {
28705
+ description: "Ad revenue and spend reports.",
28706
+ inputSchema: exports_external.discriminatedUnion("type", [
28707
+ reportSchemaBase.extend({
28708
+ type: exports_external.literal("ads"),
28709
+ networks: exports_external.array(exports_external.string().min(1)).optional()
28710
+ }),
28711
+ reportSchemaBase.extend({
28712
+ type: exports_external.literal("adspend"),
28713
+ networks: exports_external.array(exports_external.string().min(1)).optional()
28714
+ })
28715
+ ])
28716
+ }, async (input) => {
28717
+ const query = buildQuery(reportQueryFrom(input));
28718
+ const path = input.type === "ads" ? "/reports/ads" : "/reports/adspend";
28488
28719
  return {
28489
28720
  content: [
28490
28721
  {
28491
28722
  type: "text",
28492
- text: await appfiguresGet(`/featured/summary/${encodeURIComponent(start_date)}/${encodeURIComponent(end_date)}`, query)
28723
+ text: await appfiguresRequest({
28724
+ method: "GET",
28725
+ path,
28726
+ query
28727
+ })
28493
28728
  }
28494
28729
  ]
28495
28730
  };
28496
28731
  });
28497
- server.registerTool("appfigures_featured_full", {
28498
- description: "Get full featured report for a product and date range.",
28499
- inputSchema: {
28500
- product_id: exports_external.number().int().positive(),
28501
- start_date: exports_external.string().min(1),
28502
- end_date: exports_external.string().min(1),
28503
- countries: exports_external.array(exports_external.string().min(2)).optional()
28732
+ server.registerTool("appfigures_reviews", {
28733
+ description: "Reviews: list, counts, responses.",
28734
+ inputSchema: exports_external.discriminatedUnion("action", [
28735
+ reviewsQuerySchema.extend({ action: exports_external.literal("list") }),
28736
+ reviewsQuerySchema.extend({ action: exports_external.literal("count") }),
28737
+ exports_external.object({
28738
+ action: exports_external.literal("response_get"),
28739
+ review_id: exports_external.string().min(1)
28740
+ }),
28741
+ exports_external.object({
28742
+ action: exports_external.literal("response_post"),
28743
+ review_id: exports_external.string().min(1),
28744
+ content: exports_external.string().min(1)
28745
+ })
28746
+ ])
28747
+ }, async (input) => {
28748
+ if (input.action === "list" || input.action === "count") {
28749
+ const query = buildReviewsQuery(input);
28750
+ const path = input.action === "list" ? "/reviews" : "/reviews/count";
28751
+ return {
28752
+ content: [
28753
+ {
28754
+ type: "text",
28755
+ text: await appfiguresRequest({
28756
+ method: "GET",
28757
+ path,
28758
+ query
28759
+ })
28760
+ }
28761
+ ]
28762
+ };
28763
+ }
28764
+ if (input.action === "response_get") {
28765
+ return {
28766
+ content: [
28767
+ {
28768
+ type: "text",
28769
+ text: await appfiguresRequest({
28770
+ method: "GET",
28771
+ path: `/reviews/${encodeURIComponent(input.review_id)}/response`
28772
+ })
28773
+ }
28774
+ ]
28775
+ };
28504
28776
  }
28505
- }, async ({ product_id, start_date, end_date, countries }) => {
28506
- const query = buildQuery({
28507
- countries
28508
- });
28509
28777
  return {
28510
28778
  content: [
28511
28779
  {
28512
28780
  type: "text",
28513
- text: await appfiguresGet(`/featured/full/${product_id}/${encodeURIComponent(start_date)}/${encodeURIComponent(end_date)}`, query)
28781
+ text: await appfiguresRequest({
28782
+ method: "POST",
28783
+ path: `/reviews/${encodeURIComponent(input.review_id)}/response`,
28784
+ body: { content: input.content },
28785
+ contentType: "json"
28786
+ })
28514
28787
  }
28515
28788
  ]
28516
28789
  };
28517
28790
  });
28518
- server.registerTool("appfigures_featured_counts", {
28519
- description: "Get counts for featured appearances.",
28520
- inputSchema: {
28521
- end: exports_external.string().min(1).optional(),
28522
- products: exports_external.array(exports_external.string().min(1)).optional(),
28523
- count: exports_external.number().int().positive().optional(),
28524
- granularity: exports_external.string().min(1).optional(),
28525
- show_empty: exports_external.boolean().optional()
28791
+ server.registerTool("appfigures_users", {
28792
+ description: "User administration.",
28793
+ inputSchema: exports_external.discriminatedUnion("action", [
28794
+ exports_external.object({
28795
+ action: exports_external.literal("list"),
28796
+ count: exports_external.number().int().positive().optional(),
28797
+ page: exports_external.number().int().positive().optional()
28798
+ }),
28799
+ exports_external.object({
28800
+ action: exports_external.literal("get"),
28801
+ user: exports_external.string().min(1)
28802
+ }),
28803
+ exports_external.object({
28804
+ action: exports_external.literal("update"),
28805
+ user_id: exports_external.union([exports_external.string().min(1), exports_external.number().int().positive()]),
28806
+ body: exports_external.record(exports_external.string(), exports_external.unknown())
28807
+ }),
28808
+ exports_external.object({
28809
+ action: exports_external.literal("delete"),
28810
+ user_id: exports_external.union([exports_external.string().min(1), exports_external.number().int().positive()])
28811
+ })
28812
+ ])
28813
+ }, async (input) => {
28814
+ if (input.action === "list") {
28815
+ return {
28816
+ content: [
28817
+ {
28818
+ type: "text",
28819
+ text: await appfiguresRequest({
28820
+ method: "GET",
28821
+ path: "/users",
28822
+ query: buildQuery({ count: input.count, page: input.page })
28823
+ })
28824
+ }
28825
+ ]
28826
+ };
28827
+ }
28828
+ if (input.action === "get") {
28829
+ return {
28830
+ content: [
28831
+ {
28832
+ type: "text",
28833
+ text: await appfiguresRequest({
28834
+ method: "GET",
28835
+ path: `/users/${encodeURIComponent(input.user)}`
28836
+ })
28837
+ }
28838
+ ]
28839
+ };
28840
+ }
28841
+ if (input.action === "update") {
28842
+ return {
28843
+ content: [
28844
+ {
28845
+ type: "text",
28846
+ text: await appfiguresRequest({
28847
+ method: "PUT",
28848
+ path: `/users/${encodeURIComponent(String(input.user_id))}`,
28849
+ body: input.body,
28850
+ contentType: "json"
28851
+ })
28852
+ }
28853
+ ]
28854
+ };
28526
28855
  }
28527
- }, async ({ end, products, count, granularity, show_empty }) => {
28528
- const query = buildQuery({
28529
- end,
28530
- products,
28531
- count,
28532
- granularity,
28533
- show_empty
28534
- });
28535
28856
  return {
28536
28857
  content: [
28537
28858
  {
28538
28859
  type: "text",
28539
- text: await appfiguresGet("/featured/counts", query)
28860
+ text: await appfiguresRequest({
28861
+ method: "DELETE",
28862
+ path: `/users/${encodeURIComponent(String(input.user_id))}`
28863
+ })
28864
+ }
28865
+ ]
28866
+ };
28867
+ });
28868
+ server.registerTool("appfigures_data", {
28869
+ description: "Reference data (countries, languages, stores).",
28870
+ inputSchema: exports_external.object({
28871
+ kind: exports_external.enum(["countries", "languages", "stores"])
28872
+ })
28873
+ }, async ({ kind }) => {
28874
+ const path = kind === "countries" ? "/data/countries" : kind === "languages" ? "/data/languages" : "/data/stores";
28875
+ return {
28876
+ content: [
28877
+ {
28878
+ type: "text",
28879
+ text: await appfiguresRequest({ method: "GET", path })
28880
+ }
28881
+ ]
28882
+ };
28883
+ });
28884
+ var queryValueSchema = exports_external.union([
28885
+ exports_external.string(),
28886
+ exports_external.number(),
28887
+ exports_external.boolean(),
28888
+ exports_external.array(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()]))
28889
+ ]);
28890
+ var authSchema = exports_external.discriminatedUnion("type", [
28891
+ exports_external.object({
28892
+ type: exports_external.literal("bearer"),
28893
+ token: exports_external.string().min(1).optional()
28894
+ }),
28895
+ exports_external.object({
28896
+ type: exports_external.literal("basic"),
28897
+ username: exports_external.string().min(1),
28898
+ password: exports_external.string().min(1)
28899
+ }),
28900
+ exports_external.object({
28901
+ type: exports_external.literal("none")
28902
+ })
28903
+ ]);
28904
+ var baseRequestSchema = exports_external.object({
28905
+ path: exports_external.string().regex(new RegExp("^/"), "Path must start with '/'"),
28906
+ query: exports_external.record(exports_external.string(), queryValueSchema).optional(),
28907
+ headers: exports_external.record(exports_external.string(), exports_external.string().min(1)).optional(),
28908
+ auth: authSchema.optional(),
28909
+ content_type: exports_external.enum(["json", "form", "text"]).optional()
28910
+ });
28911
+ var requestSchema = exports_external.discriminatedUnion("method", [
28912
+ baseRequestSchema.extend({
28913
+ method: exports_external.enum(["GET", "DELETE"])
28914
+ }),
28915
+ baseRequestSchema.extend({
28916
+ method: exports_external.enum(["POST", "PUT", "PATCH"]),
28917
+ body: exports_external.unknown().optional()
28918
+ })
28919
+ ]);
28920
+ server.registerTool("appfigures_request", {
28921
+ description: "Call any Appfigures API endpoint. Supports bearer or basic auth and optional query/body.",
28922
+ inputSchema: requestSchema
28923
+ }, async (input) => {
28924
+ const query = input.query && Object.keys(input.query).length > 0 ? buildQuery(input.query) : "";
28925
+ const body = "body" in input && input.body !== undefined ? input.body : undefined;
28926
+ return {
28927
+ content: [
28928
+ {
28929
+ type: "text",
28930
+ text: await appfiguresRequest({
28931
+ method: input.method,
28932
+ path: input.path,
28933
+ query,
28934
+ body,
28935
+ contentType: input.content_type,
28936
+ headers: input.headers,
28937
+ auth: input.auth
28938
+ })
28540
28939
  }
28541
28940
  ]
28542
28941
  };
28543
28942
  });
28544
- server.registerTool("appfigures_featured_history", {
28545
- description: "Get full history for a category and product.",
28546
- inputSchema: {
28547
- product_id: exports_external.number().int().positive(),
28548
- featured_category_id: exports_external.number().int().positive()
28549
- }
28550
- }, async ({ product_id, featured_category_id }) => ({
28551
- content: [
28552
- {
28553
- type: "text",
28554
- text: await appfiguresGet(`/featured/history/${product_id}/${featured_category_id}`)
28555
- }
28556
- ]
28557
- }));
28558
28943
  var transport = new StdioServerTransport;
28559
28944
  await server.connect(transport);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "appfigures-mcp",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.1.0",
5
+ "version": "0.1.1",
6
6
  "private": false,
7
7
  "scripts": {
8
8
  "typecheck": "bun x tsc -p tsconfig.json --noEmit",