@solidcommerce/mcp-server 2.0.0-alpha.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 (268) hide show
  1. package/README.md +74 -0
  2. package/bin/solidcommerce-mcp.js +8 -0
  3. package/dist/audit/auditClient.d.ts +51 -0
  4. package/dist/audit/auditClient.d.ts.map +1 -0
  5. package/dist/audit/auditClient.js +93 -0
  6. package/dist/audit/auditClient.js.map +1 -0
  7. package/dist/auth/apiKey.d.ts +44 -0
  8. package/dist/auth/apiKey.d.ts.map +1 -0
  9. package/dist/auth/apiKey.js +80 -0
  10. package/dist/auth/apiKey.js.map +1 -0
  11. package/dist/auth/oauth.d.ts +108 -0
  12. package/dist/auth/oauth.d.ts.map +1 -0
  13. package/dist/auth/oauth.js +300 -0
  14. package/dist/auth/oauth.js.map +1 -0
  15. package/dist/generator/fromOpenApi.d.ts +54 -0
  16. package/dist/generator/fromOpenApi.d.ts.map +1 -0
  17. package/dist/generator/fromOpenApi.js +411 -0
  18. package/dist/generator/fromOpenApi.js.map +1 -0
  19. package/dist/generator/schemaToZod.d.ts +81 -0
  20. package/dist/generator/schemaToZod.d.ts.map +1 -0
  21. package/dist/generator/schemaToZod.js +277 -0
  22. package/dist/generator/schemaToZod.js.map +1 -0
  23. package/dist/generator/scopeInference.d.ts +26 -0
  24. package/dist/generator/scopeInference.d.ts.map +1 -0
  25. package/dist/generator/scopeInference.js +91 -0
  26. package/dist/generator/scopeInference.js.map +1 -0
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +106 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/server/buildServer.d.ts +35 -0
  32. package/dist/server/buildServer.d.ts.map +1 -0
  33. package/dist/server/buildServer.js +104 -0
  34. package/dist/server/buildServer.js.map +1 -0
  35. package/dist/server/dispatcher.d.ts +14 -0
  36. package/dist/server/dispatcher.d.ts.map +1 -0
  37. package/dist/server/dispatcher.js +190 -0
  38. package/dist/server/dispatcher.js.map +1 -0
  39. package/dist/session.d.ts +9 -0
  40. package/dist/session.d.ts.map +1 -0
  41. package/dist/session.js +11 -0
  42. package/dist/session.js.map +1 -0
  43. package/dist/telemetry/hostName.d.ts +26 -0
  44. package/dist/telemetry/hostName.d.ts.map +1 -0
  45. package/dist/telemetry/hostName.js +80 -0
  46. package/dist/telemetry/hostName.js.map +1 -0
  47. package/dist/tools/contract.d.ts +125 -0
  48. package/dist/tools/contract.d.ts.map +1 -0
  49. package/dist/tools/contract.js +101 -0
  50. package/dist/tools/contract.js.map +1 -0
  51. package/dist/tools/foundation/catalog_amazon_items_list.d.ts +4 -0
  52. package/dist/tools/foundation/catalog_amazon_items_list.d.ts.map +1 -0
  53. package/dist/tools/foundation/catalog_amazon_items_list.js +47 -0
  54. package/dist/tools/foundation/catalog_amazon_items_list.js.map +1 -0
  55. package/dist/tools/foundation/catalog_attribute_filters_list.d.ts +4 -0
  56. package/dist/tools/foundation/catalog_attribute_filters_list.d.ts.map +1 -0
  57. package/dist/tools/foundation/catalog_attribute_filters_list.js +47 -0
  58. package/dist/tools/foundation/catalog_attribute_filters_list.js.map +1 -0
  59. package/dist/tools/foundation/catalog_attribute_tags_list.d.ts +4 -0
  60. package/dist/tools/foundation/catalog_attribute_tags_list.d.ts.map +1 -0
  61. package/dist/tools/foundation/catalog_attribute_tags_list.js +47 -0
  62. package/dist/tools/foundation/catalog_attribute_tags_list.js.map +1 -0
  63. package/dist/tools/foundation/catalog_attributes_list.d.ts +4 -0
  64. package/dist/tools/foundation/catalog_attributes_list.d.ts.map +1 -0
  65. package/dist/tools/foundation/catalog_attributes_list.js +57 -0
  66. package/dist/tools/foundation/catalog_attributes_list.js.map +1 -0
  67. package/dist/tools/foundation/catalog_column_views_default_list.d.ts +4 -0
  68. package/dist/tools/foundation/catalog_column_views_default_list.d.ts.map +1 -0
  69. package/dist/tools/foundation/catalog_column_views_default_list.js +47 -0
  70. package/dist/tools/foundation/catalog_column_views_default_list.js.map +1 -0
  71. package/dist/tools/foundation/catalog_column_views_list.d.ts +4 -0
  72. package/dist/tools/foundation/catalog_column_views_list.d.ts.map +1 -0
  73. package/dist/tools/foundation/catalog_column_views_list.js +47 -0
  74. package/dist/tools/foundation/catalog_column_views_list.js.map +1 -0
  75. package/dist/tools/foundation/catalog_ebay_categories_list.d.ts +4 -0
  76. package/dist/tools/foundation/catalog_ebay_categories_list.d.ts.map +1 -0
  77. package/dist/tools/foundation/catalog_ebay_categories_list.js +56 -0
  78. package/dist/tools/foundation/catalog_ebay_categories_list.js.map +1 -0
  79. package/dist/tools/foundation/catalog_ebay_category_specifics_list.d.ts +4 -0
  80. package/dist/tools/foundation/catalog_ebay_category_specifics_list.d.ts.map +1 -0
  81. package/dist/tools/foundation/catalog_ebay_category_specifics_list.js +56 -0
  82. package/dist/tools/foundation/catalog_ebay_category_specifics_list.js.map +1 -0
  83. package/dist/tools/foundation/catalog_ebay_listing_templates_list.d.ts +4 -0
  84. package/dist/tools/foundation/catalog_ebay_listing_templates_list.d.ts.map +1 -0
  85. package/dist/tools/foundation/catalog_ebay_listing_templates_list.js +47 -0
  86. package/dist/tools/foundation/catalog_ebay_listing_templates_list.js.map +1 -0
  87. package/dist/tools/foundation/catalog_ebay_product_search_list.d.ts +4 -0
  88. package/dist/tools/foundation/catalog_ebay_product_search_list.d.ts.map +1 -0
  89. package/dist/tools/foundation/catalog_ebay_product_search_list.js +56 -0
  90. package/dist/tools/foundation/catalog_ebay_product_search_list.js.map +1 -0
  91. package/dist/tools/foundation/catalog_ebay_template_fields_list.d.ts +4 -0
  92. package/dist/tools/foundation/catalog_ebay_template_fields_list.d.ts.map +1 -0
  93. package/dist/tools/foundation/catalog_ebay_template_fields_list.js +47 -0
  94. package/dist/tools/foundation/catalog_ebay_template_fields_list.js.map +1 -0
  95. package/dist/tools/foundation/catalog_ebay_variation_groups_list.d.ts +4 -0
  96. package/dist/tools/foundation/catalog_ebay_variation_groups_list.d.ts.map +1 -0
  97. package/dist/tools/foundation/catalog_ebay_variation_groups_list.js +56 -0
  98. package/dist/tools/foundation/catalog_ebay_variation_groups_list.js.map +1 -0
  99. package/dist/tools/foundation/catalog_inventory_sources_list.d.ts +4 -0
  100. package/dist/tools/foundation/catalog_inventory_sources_list.d.ts.map +1 -0
  101. package/dist/tools/foundation/catalog_inventory_sources_list.js +47 -0
  102. package/dist/tools/foundation/catalog_inventory_sources_list.js.map +1 -0
  103. package/dist/tools/foundation/catalog_listing_rules_list.d.ts +4 -0
  104. package/dist/tools/foundation/catalog_listing_rules_list.d.ts.map +1 -0
  105. package/dist/tools/foundation/catalog_listing_rules_list.js +47 -0
  106. package/dist/tools/foundation/catalog_listing_rules_list.js.map +1 -0
  107. package/dist/tools/foundation/catalog_listing_templates_list.d.ts +4 -0
  108. package/dist/tools/foundation/catalog_listing_templates_list.d.ts.map +1 -0
  109. package/dist/tools/foundation/catalog_listing_templates_list.js +47 -0
  110. package/dist/tools/foundation/catalog_listing_templates_list.js.map +1 -0
  111. package/dist/tools/foundation/catalog_manufacturers_all_list.d.ts +4 -0
  112. package/dist/tools/foundation/catalog_manufacturers_all_list.d.ts.map +1 -0
  113. package/dist/tools/foundation/catalog_manufacturers_all_list.js +47 -0
  114. package/dist/tools/foundation/catalog_manufacturers_all_list.js.map +1 -0
  115. package/dist/tools/foundation/catalog_manufacturers_list.d.ts +4 -0
  116. package/dist/tools/foundation/catalog_manufacturers_list.d.ts.map +1 -0
  117. package/dist/tools/foundation/catalog_manufacturers_list.js +47 -0
  118. package/dist/tools/foundation/catalog_manufacturers_list.js.map +1 -0
  119. package/dist/tools/foundation/catalog_market_lists_list.d.ts +4 -0
  120. package/dist/tools/foundation/catalog_market_lists_list.d.ts.map +1 -0
  121. package/dist/tools/foundation/catalog_market_lists_list.js +47 -0
  122. package/dist/tools/foundation/catalog_market_lists_list.js.map +1 -0
  123. package/dist/tools/foundation/catalog_product_usage_filters_list.d.ts +4 -0
  124. package/dist/tools/foundation/catalog_product_usage_filters_list.d.ts.map +1 -0
  125. package/dist/tools/foundation/catalog_product_usage_filters_list.js +47 -0
  126. package/dist/tools/foundation/catalog_product_usage_filters_list.js.map +1 -0
  127. package/dist/tools/foundation/catalog_product_usage_list.d.ts +4 -0
  128. package/dist/tools/foundation/catalog_product_usage_list.d.ts.map +1 -0
  129. package/dist/tools/foundation/catalog_product_usage_list.js +61 -0
  130. package/dist/tools/foundation/catalog_product_usage_list.js.map +1 -0
  131. package/dist/tools/foundation/catalog_product_usage_totals_list.d.ts +4 -0
  132. package/dist/tools/foundation/catalog_product_usage_totals_list.d.ts.map +1 -0
  133. package/dist/tools/foundation/catalog_product_usage_totals_list.js +58 -0
  134. package/dist/tools/foundation/catalog_product_usage_totals_list.js.map +1 -0
  135. package/dist/tools/foundation/catalog_products_generate_sku_list.d.ts +4 -0
  136. package/dist/tools/foundation/catalog_products_generate_sku_list.d.ts.map +1 -0
  137. package/dist/tools/foundation/catalog_products_generate_sku_list.js +47 -0
  138. package/dist/tools/foundation/catalog_products_generate_sku_list.js.map +1 -0
  139. package/dist/tools/foundation/catalog_products_list.d.ts +4 -0
  140. package/dist/tools/foundation/catalog_products_list.d.ts.map +1 -0
  141. package/dist/tools/foundation/catalog_products_list.js +60 -0
  142. package/dist/tools/foundation/catalog_products_list.js.map +1 -0
  143. package/dist/tools/foundation/catalog_taxonomy_channels_list.d.ts +4 -0
  144. package/dist/tools/foundation/catalog_taxonomy_channels_list.d.ts.map +1 -0
  145. package/dist/tools/foundation/catalog_taxonomy_channels_list.js +47 -0
  146. package/dist/tools/foundation/catalog_taxonomy_channels_list.js.map +1 -0
  147. package/dist/tools/foundation/catalog_taxonomy_mappings_list.d.ts +4 -0
  148. package/dist/tools/foundation/catalog_taxonomy_mappings_list.d.ts.map +1 -0
  149. package/dist/tools/foundation/catalog_taxonomy_mappings_list.js +56 -0
  150. package/dist/tools/foundation/catalog_taxonomy_mappings_list.js.map +1 -0
  151. package/dist/tools/foundation/catalog_taxonomy_product_values_list.d.ts +4 -0
  152. package/dist/tools/foundation/catalog_taxonomy_product_values_list.d.ts.map +1 -0
  153. package/dist/tools/foundation/catalog_taxonomy_product_values_list.js +57 -0
  154. package/dist/tools/foundation/catalog_taxonomy_product_values_list.js.map +1 -0
  155. package/dist/tools/foundation/catalog_tree_list.d.ts +4 -0
  156. package/dist/tools/foundation/catalog_tree_list.d.ts.map +1 -0
  157. package/dist/tools/foundation/catalog_tree_list.js +47 -0
  158. package/dist/tools/foundation/catalog_tree_list.js.map +1 -0
  159. package/dist/tools/foundation/crm_customers_list.d.ts +4 -0
  160. package/dist/tools/foundation/crm_customers_list.d.ts.map +1 -0
  161. package/dist/tools/foundation/crm_customers_list.js +59 -0
  162. package/dist/tools/foundation/crm_customers_list.js.map +1 -0
  163. package/dist/tools/foundation/fulfillment_manifests_list.d.ts +4 -0
  164. package/dist/tools/foundation/fulfillment_manifests_list.d.ts.map +1 -0
  165. package/dist/tools/foundation/fulfillment_manifests_list.js +47 -0
  166. package/dist/tools/foundation/fulfillment_manifests_list.js.map +1 -0
  167. package/dist/tools/foundation/fulfillment_ship_now_addresses_list.d.ts +4 -0
  168. package/dist/tools/foundation/fulfillment_ship_now_addresses_list.d.ts.map +1 -0
  169. package/dist/tools/foundation/fulfillment_ship_now_addresses_list.js +47 -0
  170. package/dist/tools/foundation/fulfillment_ship_now_addresses_list.js.map +1 -0
  171. package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.d.ts +4 -0
  172. package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.d.ts.map +1 -0
  173. package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.js +56 -0
  174. package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.js.map +1 -0
  175. package/dist/tools/foundation/index.d.ts +8 -0
  176. package/dist/tools/foundation/index.d.ts.map +1 -0
  177. package/dist/tools/foundation/index.js +93 -0
  178. package/dist/tools/foundation/index.js.map +1 -0
  179. package/dist/tools/foundation/inventory_alert_rules_list.d.ts +4 -0
  180. package/dist/tools/foundation/inventory_alert_rules_list.d.ts.map +1 -0
  181. package/dist/tools/foundation/inventory_alert_rules_list.js +47 -0
  182. package/dist/tools/foundation/inventory_alert_rules_list.js.map +1 -0
  183. package/dist/tools/foundation/inventory_alert_settings_list.d.ts +4 -0
  184. package/dist/tools/foundation/inventory_alert_settings_list.d.ts.map +1 -0
  185. package/dist/tools/foundation/inventory_alert_settings_list.js +47 -0
  186. package/dist/tools/foundation/inventory_alert_settings_list.js.map +1 -0
  187. package/dist/tools/foundation/inventory_analytics_alert_count_list.d.ts +4 -0
  188. package/dist/tools/foundation/inventory_analytics_alert_count_list.d.ts.map +1 -0
  189. package/dist/tools/foundation/inventory_analytics_alert_count_list.js +47 -0
  190. package/dist/tools/foundation/inventory_analytics_alert_count_list.js.map +1 -0
  191. package/dist/tools/foundation/inventory_rules_list.d.ts +4 -0
  192. package/dist/tools/foundation/inventory_rules_list.d.ts.map +1 -0
  193. package/dist/tools/foundation/inventory_rules_list.js +47 -0
  194. package/dist/tools/foundation/inventory_rules_list.js.map +1 -0
  195. package/dist/tools/foundation/inventory_rules_periods_list.d.ts +4 -0
  196. package/dist/tools/foundation/inventory_rules_periods_list.d.ts.map +1 -0
  197. package/dist/tools/foundation/inventory_rules_periods_list.js +47 -0
  198. package/dist/tools/foundation/inventory_rules_periods_list.js.map +1 -0
  199. package/dist/tools/foundation/inventory_seasonal_factors_list.d.ts +4 -0
  200. package/dist/tools/foundation/inventory_seasonal_factors_list.d.ts.map +1 -0
  201. package/dist/tools/foundation/inventory_seasonal_factors_list.js +47 -0
  202. package/dist/tools/foundation/inventory_seasonal_factors_list.js.map +1 -0
  203. package/dist/tools/foundation/inventory_warehouses_list.d.ts +4 -0
  204. package/dist/tools/foundation/inventory_warehouses_list.d.ts.map +1 -0
  205. package/dist/tools/foundation/inventory_warehouses_list.js +47 -0
  206. package/dist/tools/foundation/inventory_warehouses_list.js.map +1 -0
  207. package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.d.ts +4 -0
  208. package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.d.ts.map +1 -0
  209. package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.js +56 -0
  210. package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.js.map +1 -0
  211. package/dist/tools/foundation/listings_dictionary_marketplaces_list.d.ts +4 -0
  212. package/dist/tools/foundation/listings_dictionary_marketplaces_list.d.ts.map +1 -0
  213. package/dist/tools/foundation/listings_dictionary_marketplaces_list.js +47 -0
  214. package/dist/tools/foundation/listings_dictionary_marketplaces_list.js.map +1 -0
  215. package/dist/tools/tasks/bulk_update_prices.d.ts +4 -0
  216. package/dist/tools/tasks/bulk_update_prices.d.ts.map +1 -0
  217. package/dist/tools/tasks/bulk_update_prices.js +96 -0
  218. package/dist/tools/tasks/bulk_update_prices.js.map +1 -0
  219. package/dist/tools/tasks/cancel_order_with_reason.d.ts +4 -0
  220. package/dist/tools/tasks/cancel_order_with_reason.d.ts.map +1 -0
  221. package/dist/tools/tasks/cancel_order_with_reason.js +117 -0
  222. package/dist/tools/tasks/cancel_order_with_reason.js.map +1 -0
  223. package/dist/tools/tasks/check_listing_health.d.ts +4 -0
  224. package/dist/tools/tasks/check_listing_health.d.ts.map +1 -0
  225. package/dist/tools/tasks/check_listing_health.js +123 -0
  226. package/dist/tools/tasks/check_listing_health.js.map +1 -0
  227. package/dist/tools/tasks/create_and_submit_purchase_order.d.ts +4 -0
  228. package/dist/tools/tasks/create_and_submit_purchase_order.d.ts.map +1 -0
  229. package/dist/tools/tasks/create_and_submit_purchase_order.js +142 -0
  230. package/dist/tools/tasks/create_and_submit_purchase_order.js.map +1 -0
  231. package/dist/tools/tasks/find_product_by_sku.d.ts +4 -0
  232. package/dist/tools/tasks/find_product_by_sku.d.ts.map +1 -0
  233. package/dist/tools/tasks/find_product_by_sku.js +68 -0
  234. package/dist/tools/tasks/find_product_by_sku.js.map +1 -0
  235. package/dist/tools/tasks/fulfill_order.d.ts +4 -0
  236. package/dist/tools/tasks/fulfill_order.d.ts.map +1 -0
  237. package/dist/tools/tasks/fulfill_order.js +121 -0
  238. package/dist/tools/tasks/fulfill_order.js.map +1 -0
  239. package/dist/tools/tasks/get_inventory_across_warehouses.d.ts +4 -0
  240. package/dist/tools/tasks/get_inventory_across_warehouses.d.ts.map +1 -0
  241. package/dist/tools/tasks/get_inventory_across_warehouses.js +118 -0
  242. package/dist/tools/tasks/get_inventory_across_warehouses.js.map +1 -0
  243. package/dist/tools/tasks/index.d.ts +14 -0
  244. package/dist/tools/tasks/index.d.ts.map +1 -0
  245. package/dist/tools/tasks/index.js +32 -0
  246. package/dist/tools/tasks/index.js.map +1 -0
  247. package/dist/tools/tasks/publish_product_to_channels.d.ts +4 -0
  248. package/dist/tools/tasks/publish_product_to_channels.d.ts.map +1 -0
  249. package/dist/tools/tasks/publish_product_to_channels.js +109 -0
  250. package/dist/tools/tasks/publish_product_to_channels.js.map +1 -0
  251. package/dist/tools/tasks/reply_to_buyer_message.d.ts +4 -0
  252. package/dist/tools/tasks/reply_to_buyer_message.d.ts.map +1 -0
  253. package/dist/tools/tasks/reply_to_buyer_message.js +72 -0
  254. package/dist/tools/tasks/reply_to_buyer_message.js.map +1 -0
  255. package/dist/tools/tasks/reprice_listing.d.ts +4 -0
  256. package/dist/tools/tasks/reprice_listing.d.ts.map +1 -0
  257. package/dist/tools/tasks/reprice_listing.js +74 -0
  258. package/dist/tools/tasks/reprice_listing.js.map +1 -0
  259. package/dist/transports/stdio.d.ts +12 -0
  260. package/dist/transports/stdio.d.ts.map +1 -0
  261. package/dist/transports/stdio.js +30 -0
  262. package/dist/transports/stdio.js.map +1 -0
  263. package/dist/transports/streamableHttp.d.ts +33 -0
  264. package/dist/transports/streamableHttp.d.ts.map +1 -0
  265. package/dist/transports/streamableHttp.js +237 -0
  266. package/dist/transports/streamableHttp.js.map +1 -0
  267. package/package.json +47 -0
  268. package/vendor/openapi.snapshot.json +19887 -0
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # @solidcommerce/mcp-server
2
+
3
+ > **The Solid Commerce Platform — for AI agents.** Drop a single line into Claude Desktop (or any MCP-aware client) and an LLM can query catalog, orders, listings, inventory, vendors, CRM, and webhooks against your live tenant — read endpoints, repricing, fulfillment, bulk operations, the works — using your existing Solid Commerce API key. Foundation tools auto-track every endpoint in our OpenAPI spec; curated task tools collapse 5-10-call workflows into a single agent action so the LLM doesn't have to plan them itself.
4
+ >
5
+ > **Pick this when:** you want Claude (Desktop or hosted), the OpenAI Responses API, or any MCP client to operate on Solid Commerce data without writing custom integration code, OR you're a Solid Commerce customer building an internal copilot and need the platform's full API surface exposed safely (scoped per-tool, audited per-call, no token gymnastics).
6
+
7
+ The official Model Context Protocol (MCP) server for the Solid Commerce Platform API. Exposes a hybrid tool set — foundation tools auto-generated from the OpenAPI spec plus curated task-shaped tools — over both stdio (for local clients like Claude Desktop / Claude Code) and **Streamable HTTP over HTTPS** (for hosted `mcp.solidcommerce.com`, the transport required by the Claude UI Connectors Directory). SSE was removed in Phase 0 / E-A1.
8
+
9
+ See `phase3_solution_plan.md` and `requirements_api_cli_mcp.md` for the wider initiative context.
10
+
11
+ ## Quickstart
12
+
13
+ ```bash
14
+ # Local (stdio, for Claude Desktop)
15
+ npx @solidcommerce/cli mcp install # idempotent Claude Desktop config snippet
16
+ npx @solidcommerce/cli mcp serve # boot stdio server
17
+
18
+ # Or invoke this package directly
19
+ SOLIDCOMMERCE_API_KEY=sk_... npx @solidcommerce/mcp-server
20
+ ```
21
+
22
+ ## Auth
23
+
24
+ Two modes coexist on the same server (Phase 0 / E-A3):
25
+
26
+ **API key (stdio / service-to-service / Scotty / internal).** Pass your Solid
27
+ Commerce API key via env var:
28
+
29
+ ```
30
+ SOLIDCOMMERCE_API_KEY=sk_live_...
31
+ ```
32
+
33
+ **Per-user OAuth (remote hosts — Claude UI, ChatGPT, Gemini, M365, Grok).** A
34
+ host sends a per-user `Authorization: Bearer <token>` issued by SC.Base.Auth on
35
+ the Streamable HTTP transport. The server introspects the token against
36
+ `/oauth/introspect` (using the `sc-mcp-server` confidential client) to fast-fail
37
+ invalid tokens and extract claims for audit + telemetry, then forwards the token
38
+ to Platform, which independently re-validates it. Configure with:
39
+
40
+ ```
41
+ SC_MCP_OAUTH_ENABLED=true # auto-on when the two below are set
42
+ SC_AUTH_INTROSPECT_URL=https://auth.solidcommerce.com/oauth/introspect
43
+ SC_MCP_CLIENT_ID=sc-mcp-server
44
+ SC_MCP_CLIENT_SECRET=... # from Key Vault
45
+ ```
46
+
47
+ Resilience: introspection results are cached (bounded TTL under token `exp`) and
48
+ guarded by a circuit breaker. Because Platform is the authority, an Auth outage
49
+ **fails open** — a present bearer is still forwarded (marked degraded in audit) —
50
+ while an explicitly *inactive* token is hard-rejected with `401`. A request with
51
+ no `Authorization` header falls back to the API-key path.
52
+
53
+ ## Tool surface
54
+
55
+ - **Foundation tools** — auto-generated from `vendor/openapi.snapshot.json`. ~40 selected via heuristic (read-heavy lists + composition-target POSTs). Naming: `<segment>_<resource>_<verb>` (matching the CLI's resource driver).
56
+ - **Task tools** — 10 hand-authored workflow tools (publish_product_to_channels, reprice_listing, fulfill_order, …). Each composes 2-10 SDK calls and reports a clean structured result.
57
+
58
+ ## Audit trail
59
+
60
+ Every tool invocation tags the underlying SDK call with `X-Audit-Source: mcp` and `X-Audit-Tool-Name: <tool>` headers; Platform's `AuditLogMiddleware` (W3) writes one `audit_log` row per call.
61
+
62
+ ## Development
63
+
64
+ ```bash
65
+ npm install
66
+ npm run typecheck
67
+ npm run lint
68
+ npm run test
69
+ npm run build
70
+ ```
71
+
72
+ ## License
73
+
74
+ UNLICENSED — internal Solid Commerce code. Distribution via private Azure Artifacts npm feed (gated until 2026-05-10).
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ // =============================================================================
3
+ // bin/solidcommerce-mcp.js
4
+ // Wave: W6 — MCP Server entrypoint shim.
5
+ //
6
+ // Forwards to dist/index.js. The TS source lives at src/index.ts.
7
+ // =============================================================================
8
+ import "../dist/index.js";
@@ -0,0 +1,51 @@
1
+ import type { SolidCommerceClient } from "@solidcommerce/sdk";
2
+ import type { SessionAuthContext } from "../auth/oauth.js";
3
+ export declare const AUDIT_HEADER_SOURCE = "X-Audit-Source";
4
+ export declare const AUDIT_HEADER_TOOL_NAME = "X-Audit-Tool-Name";
5
+ export declare const AUDIT_HEADER_AUTH_MODE = "X-Audit-Auth-Mode";
6
+ export declare const AUDIT_HEADER_INSTALL_ID = "X-Audit-Install-Id";
7
+ /** Set when the bearer was forwarded WITHOUT a successful introspection
8
+ * (Auth outage / circuit open). Lets Platform audit flag unverified calls. */
9
+ export declare const AUDIT_HEADER_AUTH_DEGRADED = "X-Audit-Auth-Degraded";
10
+ /** Canonical calling surface (E-A4) — powers the per-surface KQL dashboard. */
11
+ export declare const AUDIT_HEADER_HOST_NAME = "X-Audit-Host-Name";
12
+ export declare const AUDIT_SOURCE_VALUE = "mcp";
13
+ export interface CurrentToolNameRef {
14
+ current: string | null;
15
+ }
16
+ export interface AttachAuditHookOptions {
17
+ /**
18
+ * Resolved session auth identity (Phase 0 / E-A3). When present, the hook
19
+ * tags every outbound call with the auth mode and (if known) the install id
20
+ * so Platform's audit log can attribute the call to a user/install/surface.
21
+ * Static for the session, so captured once here rather than threaded per-call.
22
+ */
23
+ readonly auth?: SessionAuthContext;
24
+ /**
25
+ * Canonical calling surface (Phase 0 / E-A4). Emitted as X-Audit-Host-Name so
26
+ * Platform telemetry can pivot per-surface. Best-effort (see telemetry/hostName).
27
+ */
28
+ readonly hostName?: string;
29
+ }
30
+ export interface AttachAuditHookResult {
31
+ /** Dispose the hook (mainly for tests). */
32
+ readonly dispose: () => void;
33
+ /**
34
+ * Set the tool name to be attached to the NEXT outbound request(s). The
35
+ * dispatcher pairs every set with a clear (set name → invoke handler →
36
+ * clear name) so leakage between calls is impossible even when the SDK
37
+ * issues parallel sub-requests.
38
+ */
39
+ readonly setCurrentToolName: (name: string | null) => void;
40
+ /** Inspect the current ref — useful in tests; do not mutate externally. */
41
+ readonly ref: CurrentToolNameRef;
42
+ }
43
+ /**
44
+ * Register an `onRequest` hook on `client` that injects audit headers.
45
+ *
46
+ * Returns helpers the dispatcher (or tests) use to control the per-call tool
47
+ * name. Returning the ref itself lets unit tests assert isolation without
48
+ * resorting to Sinon spies.
49
+ */
50
+ export declare function attachAuditHook(client: SolidCommerceClient, opts?: AttachAuditHookOptions): AttachAuditHookResult;
51
+ //# sourceMappingURL=auditClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditClient.d.ts","sourceRoot":"","sources":["../../src/audit/auditClient.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AACpD,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAC5D;8EAC8E;AAC9E,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,mBAAmB,EAC3B,IAAI,GAAE,sBAA2B,GAChC,qBAAqB,CAyCvB"}
@@ -0,0 +1,93 @@
1
+ // =============================================================================
2
+ // src/audit/auditClient.ts
3
+ // Wave: W6 — Stream C
4
+ //
5
+ // Wraps the @solidcommerce/sdk transport so every SDK call carries
6
+ // X-Audit-Source: mcp
7
+ // X-Audit-Tool-Name: <tool-name>
8
+ //
9
+ // Platform's AuditLogMiddleware (SC.Base.API.Common, extended in W6 Step 6)
10
+ // reads these and persists them to dbo.audit_log.
11
+ //
12
+ // Design notes:
13
+ //
14
+ // - The audit hook is a `client.use({ onRequest })` registration. We deliberately
15
+ // do NOT modify the SDK package; the SDK exposes a public hook system for
16
+ // this exact use case (see options.d.ts → ClientHooks).
17
+ //
18
+ // - The current tool name is threaded via a closed-over ref-cell (a plain
19
+ // `{ current: string | null }` object). We rejected AsyncLocalStorage to
20
+ // keep this portable across server transports (stdio + Streamable HTTP) and to avoid
21
+ // the extra complexity. The dispatcher (server/dispatcher.ts) sets the ref
22
+ // *just before* invoking the tool's handler and clears it after — see
23
+ // `setCurrentToolName` returned from `attachAuditHook`.
24
+ //
25
+ // - `X-Audit-Source: mcp` is ALWAYS injected. The CLI resource driver (W5)
26
+ // must not see this header — it ships a different audit hook. Keeping the
27
+ // hook scoped to *this* client (constructed in src/auth/apiKey.ts) ensures
28
+ // isolation by construction.
29
+ //
30
+ // - The hook is non-throwing per the SDK contract (options.d.ts:60). If the
31
+ // headers are read-only somehow we silently no-op rather than blow up the
32
+ // request — audit data loss is preferable to losing the user's call.
33
+ // =============================================================================
34
+ export const AUDIT_HEADER_SOURCE = "X-Audit-Source";
35
+ export const AUDIT_HEADER_TOOL_NAME = "X-Audit-Tool-Name";
36
+ // Phase 0 / E-A3 + E-A4: identity + surface attribution on every audited call.
37
+ export const AUDIT_HEADER_AUTH_MODE = "X-Audit-Auth-Mode";
38
+ export const AUDIT_HEADER_INSTALL_ID = "X-Audit-Install-Id";
39
+ /** Set when the bearer was forwarded WITHOUT a successful introspection
40
+ * (Auth outage / circuit open). Lets Platform audit flag unverified calls. */
41
+ export const AUDIT_HEADER_AUTH_DEGRADED = "X-Audit-Auth-Degraded";
42
+ /** Canonical calling surface (E-A4) — powers the per-surface KQL dashboard. */
43
+ export const AUDIT_HEADER_HOST_NAME = "X-Audit-Host-Name";
44
+ export const AUDIT_SOURCE_VALUE = "mcp";
45
+ /**
46
+ * Register an `onRequest` hook on `client` that injects audit headers.
47
+ *
48
+ * Returns helpers the dispatcher (or tests) use to control the per-call tool
49
+ * name. Returning the ref itself lets unit tests assert isolation without
50
+ * resorting to Sinon spies.
51
+ */
52
+ export function attachAuditHook(client, opts = {}) {
53
+ const ref = { current: null };
54
+ const auth = opts.auth;
55
+ const hostName = opts.hostName;
56
+ const dispose = client.use({
57
+ onRequest: ({ request }) => {
58
+ // The SDK's hook contract documents that request.headers is mutable;
59
+ // wrap defensively so a frozen header bag doesn't kill the call.
60
+ try {
61
+ request.headers.set(AUDIT_HEADER_SOURCE, AUDIT_SOURCE_VALUE);
62
+ const toolName = ref.current;
63
+ if (toolName !== null && toolName.length > 0) {
64
+ request.headers.set(AUDIT_HEADER_TOOL_NAME, toolName);
65
+ }
66
+ if (hostName !== undefined && hostName.length > 0) {
67
+ request.headers.set(AUDIT_HEADER_HOST_NAME, hostName);
68
+ }
69
+ if (auth) {
70
+ request.headers.set(AUDIT_HEADER_AUTH_MODE, auth.mode);
71
+ if (auth.installId !== undefined && auth.installId.length > 0) {
72
+ request.headers.set(AUDIT_HEADER_INSTALL_ID, auth.installId);
73
+ }
74
+ if (auth.introspectionDegraded) {
75
+ request.headers.set(AUDIT_HEADER_AUTH_DEGRADED, "true");
76
+ }
77
+ }
78
+ }
79
+ catch {
80
+ // Audit data loss > losing the user's call. SDK swallows hook
81
+ // throws but we don't want to depend on that behavior.
82
+ }
83
+ },
84
+ });
85
+ return {
86
+ dispose,
87
+ setCurrentToolName: (name) => {
88
+ ref.current = name;
89
+ },
90
+ ref,
91
+ };
92
+ }
93
+ //# sourceMappingURL=auditClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditClient.js","sourceRoot":"","sources":["../../src/audit/auditClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { SolidCommerceClient } from "@solidcommerce/sdk";
2
+ export declare const DEFAULT_BASE_URL = "https://api.solidcommerce.com";
3
+ export declare const ENV_API_KEY = "SOLIDCOMMERCE_API_KEY";
4
+ export declare const ENV_BASE_URL = "SOLIDCOMMERCE_API_BASE_URL";
5
+ export interface ApiKeySource {
6
+ readonly apiKey: string;
7
+ }
8
+ /**
9
+ * Read the API key from env. Throws an actionable error if missing — fail
10
+ * fast at boot, do NOT defer to the first tool call.
11
+ */
12
+ export declare function loadApiKeyFromEnv(): ApiKeySource;
13
+ /**
14
+ * Resolve the API base URL. Caller-provided override beats env beats default.
15
+ * We trim trailing slashes so that `${baseUrl}/v1/...` paths don't double-slash.
16
+ */
17
+ export declare function resolveBaseUrl(override?: string): string;
18
+ export interface BuildClientOptions {
19
+ readonly apiKey?: string;
20
+ readonly baseUrl?: string;
21
+ /** Inject for tests. */
22
+ readonly fetchImpl?: typeof fetch;
23
+ }
24
+ /**
25
+ * Build a configured SolidCommerceClient with apiKey auth + base URL.
26
+ *
27
+ * Note: audit hooks are NOT attached here. The caller (index.ts) attaches
28
+ * them via `attachAuditHook(client)` so the ref-cell ownership stays at
29
+ * the dispatcher level.
30
+ */
31
+ export declare function buildClient(opts?: BuildClientOptions): SolidCommerceClient;
32
+ export interface BuildBearerClientOptions {
33
+ readonly baseUrl?: string;
34
+ /** Inject for tests. */
35
+ readonly fetchImpl?: typeof fetch;
36
+ }
37
+ /**
38
+ * Build a SolidCommerceClient that forwards a per-user OAuth bearer token
39
+ * (Phase 0 / E-A3). Platform re-validates the token via its JWKS config on
40
+ * every call, so this client does not itself verify the token. Audit hooks are
41
+ * NOT attached here — the caller attaches them via `attachAuditHook(client)`.
42
+ */
43
+ export declare function buildBearerClient(token: string, opts?: BuildBearerClientOptions): SolidCommerceClient;
44
+ //# sourceMappingURL=apiKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiKey.d.ts","sourceRoot":"","sources":["../../src/auth/apiKey.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,eAAO,MAAM,gBAAgB,kCAAkC,CAAC;AAChE,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,YAAY,+BAA+B,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,YAAY,CAUhD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,mBAAmB,CAW9E;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,wBAA6B,GAClC,mBAAmB,CAcrB"}
@@ -0,0 +1,80 @@
1
+ // =============================================================================
2
+ // src/auth/apiKey.ts
3
+ // Wave: W6 — Stream C
4
+ // Phase 0 / E-A3 — added buildBearerClient for per-user OAuth sessions.
5
+ //
6
+ // Resolves SOLIDCOMMERCE_API_KEY from env and builds a SolidCommerceClient.
7
+ // Two auth modes now coexist on the same server:
8
+ // * apiKey — service-to-service (stdio / Scotty / internal), env key.
9
+ // * bearer — per-user OAuth token forwarded from a remote host (E-A3).
10
+ //
11
+ // Mirrors the W5 CLI sdk.ts factory pattern (auth resolution + base URL +
12
+ // retry config) but simplified — no token refresh / keychain here; bearer
13
+ // tokens are captured per session and Platform re-validates every call.
14
+ // =============================================================================
15
+ import { SolidCommerceClient } from "@solidcommerce/sdk";
16
+ export const DEFAULT_BASE_URL = "https://api.solidcommerce.com";
17
+ export const ENV_API_KEY = "SOLIDCOMMERCE_API_KEY";
18
+ export const ENV_BASE_URL = "SOLIDCOMMERCE_API_BASE_URL";
19
+ /**
20
+ * Read the API key from env. Throws an actionable error if missing — fail
21
+ * fast at boot, do NOT defer to the first tool call.
22
+ */
23
+ export function loadApiKeyFromEnv() {
24
+ const key = process.env[ENV_API_KEY]?.trim();
25
+ if (!key || key.length === 0) {
26
+ throw new Error(`${ENV_API_KEY} env var is required. Get one at ` +
27
+ "https://app.solidcommerce.com/settings/api-keys, then set it before " +
28
+ "starting the MCP server (e.g., in your Claude Desktop mcpServers config).");
29
+ }
30
+ return { apiKey: key };
31
+ }
32
+ /**
33
+ * Resolve the API base URL. Caller-provided override beats env beats default.
34
+ * We trim trailing slashes so that `${baseUrl}/v1/...` paths don't double-slash.
35
+ */
36
+ export function resolveBaseUrl(override) {
37
+ const raw = (override ?? process.env[ENV_BASE_URL] ?? DEFAULT_BASE_URL).trim();
38
+ return raw.replace(/\/+$/, "");
39
+ }
40
+ /**
41
+ * Build a configured SolidCommerceClient with apiKey auth + base URL.
42
+ *
43
+ * Note: audit hooks are NOT attached here. The caller (index.ts) attaches
44
+ * them via `attachAuditHook(client)` so the ref-cell ownership stays at
45
+ * the dispatcher level.
46
+ */
47
+ export function buildClient(opts = {}) {
48
+ const apiKey = opts.apiKey ?? loadApiKeyFromEnv().apiKey;
49
+ const baseUrl = resolveBaseUrl(opts.baseUrl);
50
+ const clientOptions = {
51
+ baseUrl,
52
+ auth: { kind: "apiKey", apiKey },
53
+ };
54
+ if (opts.fetchImpl) {
55
+ clientOptions.fetch = opts.fetchImpl;
56
+ }
57
+ return new SolidCommerceClient(clientOptions);
58
+ }
59
+ /**
60
+ * Build a SolidCommerceClient that forwards a per-user OAuth bearer token
61
+ * (Phase 0 / E-A3). Platform re-validates the token via its JWKS config on
62
+ * every call, so this client does not itself verify the token. Audit hooks are
63
+ * NOT attached here — the caller attaches them via `attachAuditHook(client)`.
64
+ */
65
+ export function buildBearerClient(token, opts = {}) {
66
+ const trimmed = token.trim();
67
+ if (trimmed.length === 0) {
68
+ throw new Error("buildBearerClient: token must be a non-empty string.");
69
+ }
70
+ const baseUrl = resolveBaseUrl(opts.baseUrl);
71
+ const clientOptions = {
72
+ baseUrl,
73
+ auth: { kind: "bearer", token: trimmed },
74
+ };
75
+ if (opts.fetchImpl) {
76
+ clientOptions.fetch = opts.fetchImpl;
77
+ }
78
+ return new SolidCommerceClient(clientOptions);
79
+ }
80
+ //# sourceMappingURL=apiKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiKey.js","sourceRoot":"","sources":["../../src/auth/apiKey.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,qBAAqB;AACrB,sBAAsB;AACtB,wEAAwE;AACxE,EAAE;AACF,4EAA4E;AAC5E,iDAAiD;AACjD,yEAAyE;AACzE,0EAA0E;AAC1E,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,wEAAwE;AACxE,gFAAgF;AAEhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,+BAA+B,CAAC;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AACnD,MAAM,CAAC,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAMzD;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,GAAG,WAAW,mCAAmC;YAC/C,sEAAsE;YACtE,2EAA2E,CAC9E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAiB;IAC9C,MAAM,GAAG,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,gBAAgB,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/E,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AASD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B,EAAE;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,iBAAiB,EAAE,CAAC,MAAM,CAAC;IACzD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAyD;QAC1E,OAAO;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE;KACjC,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,aAAa,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC;AAChD,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,OAAiC,EAAE;IAEnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAyD;QAC1E,OAAO;QACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE;KACzC,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,aAAa,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,mBAAmB,CAAC,aAAa,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,108 @@
1
+ export declare const ENV_OAUTH_ENABLED = "SC_MCP_OAUTH_ENABLED";
2
+ export declare const ENV_INTROSPECT_URL = "SC_AUTH_INTROSPECT_URL";
3
+ export declare const ENV_MCP_CLIENT_ID = "SC_MCP_CLIENT_ID";
4
+ export declare const ENV_MCP_CLIENT_SECRET = "SC_MCP_CLIENT_SECRET";
5
+ export interface OAuthConfig {
6
+ /** When false, the server is apiKey-only and ignores bearer headers. */
7
+ readonly enabled: boolean;
8
+ readonly introspectUrl: string;
9
+ readonly clientId: string;
10
+ readonly clientSecret: string;
11
+ /** Per-introspection-call network timeout. */
12
+ readonly timeoutMs: number;
13
+ /** Max lifetime for a cached ACTIVE result (capped under token `exp`). */
14
+ readonly positiveTtlMs: number;
15
+ /** Lifetime for a cached INACTIVE result (short — revocation re-issue). */
16
+ readonly negativeTtlMs: number;
17
+ /** Clock skew subtracted from token `exp` when computing positive TTL. */
18
+ readonly skewMs: number;
19
+ /** Consecutive failures before the circuit opens. */
20
+ readonly circuitThreshold: number;
21
+ /** How long the circuit stays open before a probe is allowed. */
22
+ readonly circuitCooldownMs: number;
23
+ /** Hard ceiling on cache entries (bounded memory). */
24
+ readonly maxCacheEntries: number;
25
+ }
26
+ /** Default MCP confidential client id — matches OpenIddictSeeder.McpServerClientId. */
27
+ export declare const DEFAULT_MCP_CLIENT_ID = "sc-mcp-server";
28
+ /**
29
+ * Load OAuth config from env. `enabled` defaults to ON when both an introspect
30
+ * URL and a client secret are present, so a correctly-provisioned deployment
31
+ * "just works"; an operator can force it on/off with SC_MCP_OAUTH_ENABLED.
32
+ */
33
+ export declare function loadOAuthConfigFromEnv(env?: NodeJS.ProcessEnv): OAuthConfig;
34
+ export type AuthMode = "oauth" | "apiKey";
35
+ export interface SessionAuthContext {
36
+ readonly mode: AuthMode;
37
+ /** Bearer token to forward to Platform (oauth mode only). */
38
+ readonly token?: string;
39
+ readonly companyId?: string;
40
+ readonly installId?: string;
41
+ readonly subject?: string;
42
+ readonly scopes: ReadonlyArray<string>;
43
+ /** Token `exp` (epoch seconds), when known. */
44
+ readonly expiresAtEpoch?: number;
45
+ /** True when forwarded unverified (Auth outage). Platform is authority. */
46
+ readonly introspectionDegraded: boolean;
47
+ }
48
+ /** Resolution outcome: either an accepted session context, or a rejection that
49
+ * the transport turns into a 401 (we never silently downgrade a bad bearer). */
50
+ export type AuthResolution = {
51
+ readonly ok: true;
52
+ readonly context: SessionAuthContext;
53
+ } | {
54
+ readonly ok: false;
55
+ readonly status: number;
56
+ readonly error: string;
57
+ };
58
+ type IntrospectOutcome = {
59
+ readonly kind: "active";
60
+ readonly claims: IntrospectionClaims;
61
+ } | {
62
+ readonly kind: "inactive";
63
+ } | {
64
+ readonly kind: "degraded";
65
+ readonly reason: string;
66
+ };
67
+ export interface IntrospectionClaims {
68
+ readonly companyId?: string;
69
+ readonly installId?: string;
70
+ readonly subject?: string;
71
+ readonly scopes: ReadonlyArray<string>;
72
+ readonly expiresAtEpoch?: number;
73
+ }
74
+ export interface Introspector {
75
+ introspect(token: string): Promise<IntrospectOutcome>;
76
+ /** Test/diagnostics: current circuit state. */
77
+ readonly isCircuitOpen: () => boolean;
78
+ }
79
+ export interface IntrospectorDeps {
80
+ /** Injectable for tests. Defaults to global fetch. */
81
+ readonly fetchImpl?: typeof fetch;
82
+ /** Injectable clock (ms epoch). Defaults to Date.now. */
83
+ readonly now?: () => number;
84
+ }
85
+ /**
86
+ * Build an introspector. Holds the cache + circuit state for the process; one
87
+ * instance is shared across all sessions (cache hits make repeated initialize
88
+ * calls for the same token cheap).
89
+ */
90
+ export declare function createIntrospector(config: OAuthConfig, deps?: IntrospectorDeps): Introspector;
91
+ /** Extract a bearer token, or undefined if the header is absent / not Bearer. */
92
+ export declare function parseBearer(authorizationHeader: string | undefined): string | undefined;
93
+ export interface AuthResolverDeps {
94
+ readonly config: OAuthConfig;
95
+ readonly introspector: Introspector;
96
+ /** Whether an env API key is available for the no-bearer fallback. */
97
+ readonly apiKeyAvailable: boolean;
98
+ }
99
+ export interface SessionAuthResolver {
100
+ resolve(authorizationHeader: string | undefined): Promise<AuthResolution>;
101
+ }
102
+ /**
103
+ * Build the resolver used by the Streamable HTTP transport at `initialize`.
104
+ * See the resilience matrix in this file's header for the full decision table.
105
+ */
106
+ export declare function createSessionAuthResolver(deps: AuthResolverDeps): SessionAuthResolver;
107
+ export {};
108
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}