@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.
- package/README.md +74 -0
- package/bin/solidcommerce-mcp.js +8 -0
- package/dist/audit/auditClient.d.ts +51 -0
- package/dist/audit/auditClient.d.ts.map +1 -0
- package/dist/audit/auditClient.js +93 -0
- package/dist/audit/auditClient.js.map +1 -0
- package/dist/auth/apiKey.d.ts +44 -0
- package/dist/auth/apiKey.d.ts.map +1 -0
- package/dist/auth/apiKey.js +80 -0
- package/dist/auth/apiKey.js.map +1 -0
- package/dist/auth/oauth.d.ts +108 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +300 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/generator/fromOpenApi.d.ts +54 -0
- package/dist/generator/fromOpenApi.d.ts.map +1 -0
- package/dist/generator/fromOpenApi.js +411 -0
- package/dist/generator/fromOpenApi.js.map +1 -0
- package/dist/generator/schemaToZod.d.ts +81 -0
- package/dist/generator/schemaToZod.d.ts.map +1 -0
- package/dist/generator/schemaToZod.js +277 -0
- package/dist/generator/schemaToZod.js.map +1 -0
- package/dist/generator/scopeInference.d.ts +26 -0
- package/dist/generator/scopeInference.d.ts.map +1 -0
- package/dist/generator/scopeInference.js +91 -0
- package/dist/generator/scopeInference.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +106 -0
- package/dist/index.js.map +1 -0
- package/dist/server/buildServer.d.ts +35 -0
- package/dist/server/buildServer.d.ts.map +1 -0
- package/dist/server/buildServer.js +104 -0
- package/dist/server/buildServer.js.map +1 -0
- package/dist/server/dispatcher.d.ts +14 -0
- package/dist/server/dispatcher.d.ts.map +1 -0
- package/dist/server/dispatcher.js +190 -0
- package/dist/server/dispatcher.js.map +1 -0
- package/dist/session.d.ts +9 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +11 -0
- package/dist/session.js.map +1 -0
- package/dist/telemetry/hostName.d.ts +26 -0
- package/dist/telemetry/hostName.d.ts.map +1 -0
- package/dist/telemetry/hostName.js +80 -0
- package/dist/telemetry/hostName.js.map +1 -0
- package/dist/tools/contract.d.ts +125 -0
- package/dist/tools/contract.d.ts.map +1 -0
- package/dist/tools/contract.js +101 -0
- package/dist/tools/contract.js.map +1 -0
- package/dist/tools/foundation/catalog_amazon_items_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_amazon_items_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_amazon_items_list.js +47 -0
- package/dist/tools/foundation/catalog_amazon_items_list.js.map +1 -0
- package/dist/tools/foundation/catalog_attribute_filters_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_attribute_filters_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_attribute_filters_list.js +47 -0
- package/dist/tools/foundation/catalog_attribute_filters_list.js.map +1 -0
- package/dist/tools/foundation/catalog_attribute_tags_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_attribute_tags_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_attribute_tags_list.js +47 -0
- package/dist/tools/foundation/catalog_attribute_tags_list.js.map +1 -0
- package/dist/tools/foundation/catalog_attributes_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_attributes_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_attributes_list.js +57 -0
- package/dist/tools/foundation/catalog_attributes_list.js.map +1 -0
- package/dist/tools/foundation/catalog_column_views_default_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_column_views_default_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_column_views_default_list.js +47 -0
- package/dist/tools/foundation/catalog_column_views_default_list.js.map +1 -0
- package/dist/tools/foundation/catalog_column_views_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_column_views_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_column_views_list.js +47 -0
- package/dist/tools/foundation/catalog_column_views_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_categories_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_categories_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_categories_list.js +56 -0
- package/dist/tools/foundation/catalog_ebay_categories_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_category_specifics_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_category_specifics_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_category_specifics_list.js +56 -0
- package/dist/tools/foundation/catalog_ebay_category_specifics_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_listing_templates_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_listing_templates_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_listing_templates_list.js +47 -0
- package/dist/tools/foundation/catalog_ebay_listing_templates_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_product_search_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_product_search_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_product_search_list.js +56 -0
- package/dist/tools/foundation/catalog_ebay_product_search_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_template_fields_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_template_fields_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_template_fields_list.js +47 -0
- package/dist/tools/foundation/catalog_ebay_template_fields_list.js.map +1 -0
- package/dist/tools/foundation/catalog_ebay_variation_groups_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_ebay_variation_groups_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_ebay_variation_groups_list.js +56 -0
- package/dist/tools/foundation/catalog_ebay_variation_groups_list.js.map +1 -0
- package/dist/tools/foundation/catalog_inventory_sources_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_inventory_sources_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_inventory_sources_list.js +47 -0
- package/dist/tools/foundation/catalog_inventory_sources_list.js.map +1 -0
- package/dist/tools/foundation/catalog_listing_rules_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_listing_rules_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_listing_rules_list.js +47 -0
- package/dist/tools/foundation/catalog_listing_rules_list.js.map +1 -0
- package/dist/tools/foundation/catalog_listing_templates_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_listing_templates_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_listing_templates_list.js +47 -0
- package/dist/tools/foundation/catalog_listing_templates_list.js.map +1 -0
- package/dist/tools/foundation/catalog_manufacturers_all_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_manufacturers_all_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_manufacturers_all_list.js +47 -0
- package/dist/tools/foundation/catalog_manufacturers_all_list.js.map +1 -0
- package/dist/tools/foundation/catalog_manufacturers_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_manufacturers_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_manufacturers_list.js +47 -0
- package/dist/tools/foundation/catalog_manufacturers_list.js.map +1 -0
- package/dist/tools/foundation/catalog_market_lists_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_market_lists_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_market_lists_list.js +47 -0
- package/dist/tools/foundation/catalog_market_lists_list.js.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_filters_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_product_usage_filters_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_filters_list.js +47 -0
- package/dist/tools/foundation/catalog_product_usage_filters_list.js.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_product_usage_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_list.js +61 -0
- package/dist/tools/foundation/catalog_product_usage_list.js.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_totals_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_product_usage_totals_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_product_usage_totals_list.js +58 -0
- package/dist/tools/foundation/catalog_product_usage_totals_list.js.map +1 -0
- package/dist/tools/foundation/catalog_products_generate_sku_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_products_generate_sku_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_products_generate_sku_list.js +47 -0
- package/dist/tools/foundation/catalog_products_generate_sku_list.js.map +1 -0
- package/dist/tools/foundation/catalog_products_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_products_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_products_list.js +60 -0
- package/dist/tools/foundation/catalog_products_list.js.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_channels_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_taxonomy_channels_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_channels_list.js +47 -0
- package/dist/tools/foundation/catalog_taxonomy_channels_list.js.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_mappings_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_taxonomy_mappings_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_mappings_list.js +56 -0
- package/dist/tools/foundation/catalog_taxonomy_mappings_list.js.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_product_values_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_taxonomy_product_values_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_taxonomy_product_values_list.js +57 -0
- package/dist/tools/foundation/catalog_taxonomy_product_values_list.js.map +1 -0
- package/dist/tools/foundation/catalog_tree_list.d.ts +4 -0
- package/dist/tools/foundation/catalog_tree_list.d.ts.map +1 -0
- package/dist/tools/foundation/catalog_tree_list.js +47 -0
- package/dist/tools/foundation/catalog_tree_list.js.map +1 -0
- package/dist/tools/foundation/crm_customers_list.d.ts +4 -0
- package/dist/tools/foundation/crm_customers_list.d.ts.map +1 -0
- package/dist/tools/foundation/crm_customers_list.js +59 -0
- package/dist/tools/foundation/crm_customers_list.js.map +1 -0
- package/dist/tools/foundation/fulfillment_manifests_list.d.ts +4 -0
- package/dist/tools/foundation/fulfillment_manifests_list.d.ts.map +1 -0
- package/dist/tools/foundation/fulfillment_manifests_list.js +47 -0
- package/dist/tools/foundation/fulfillment_manifests_list.js.map +1 -0
- package/dist/tools/foundation/fulfillment_ship_now_addresses_list.d.ts +4 -0
- package/dist/tools/foundation/fulfillment_ship_now_addresses_list.d.ts.map +1 -0
- package/dist/tools/foundation/fulfillment_ship_now_addresses_list.js +47 -0
- package/dist/tools/foundation/fulfillment_ship_now_addresses_list.js.map +1 -0
- package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.d.ts +4 -0
- package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.d.ts.map +1 -0
- package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.js +56 -0
- package/dist/tools/foundation/fulfillment_ship_now_dictionaries_list.js.map +1 -0
- package/dist/tools/foundation/index.d.ts +8 -0
- package/dist/tools/foundation/index.d.ts.map +1 -0
- package/dist/tools/foundation/index.js +93 -0
- package/dist/tools/foundation/index.js.map +1 -0
- package/dist/tools/foundation/inventory_alert_rules_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_alert_rules_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_alert_rules_list.js +47 -0
- package/dist/tools/foundation/inventory_alert_rules_list.js.map +1 -0
- package/dist/tools/foundation/inventory_alert_settings_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_alert_settings_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_alert_settings_list.js +47 -0
- package/dist/tools/foundation/inventory_alert_settings_list.js.map +1 -0
- package/dist/tools/foundation/inventory_analytics_alert_count_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_analytics_alert_count_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_analytics_alert_count_list.js +47 -0
- package/dist/tools/foundation/inventory_analytics_alert_count_list.js.map +1 -0
- package/dist/tools/foundation/inventory_rules_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_rules_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_rules_list.js +47 -0
- package/dist/tools/foundation/inventory_rules_list.js.map +1 -0
- package/dist/tools/foundation/inventory_rules_periods_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_rules_periods_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_rules_periods_list.js +47 -0
- package/dist/tools/foundation/inventory_rules_periods_list.js.map +1 -0
- package/dist/tools/foundation/inventory_seasonal_factors_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_seasonal_factors_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_seasonal_factors_list.js +47 -0
- package/dist/tools/foundation/inventory_seasonal_factors_list.js.map +1 -0
- package/dist/tools/foundation/inventory_warehouses_list.d.ts +4 -0
- package/dist/tools/foundation/inventory_warehouses_list.d.ts.map +1 -0
- package/dist/tools/foundation/inventory_warehouses_list.js +47 -0
- package/dist/tools/foundation/inventory_warehouses_list.js.map +1 -0
- package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.d.ts +4 -0
- package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.d.ts.map +1 -0
- package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.js +56 -0
- package/dist/tools/foundation/listings_dictionary_marketplace_locales_list.js.map +1 -0
- package/dist/tools/foundation/listings_dictionary_marketplaces_list.d.ts +4 -0
- package/dist/tools/foundation/listings_dictionary_marketplaces_list.d.ts.map +1 -0
- package/dist/tools/foundation/listings_dictionary_marketplaces_list.js +47 -0
- package/dist/tools/foundation/listings_dictionary_marketplaces_list.js.map +1 -0
- package/dist/tools/tasks/bulk_update_prices.d.ts +4 -0
- package/dist/tools/tasks/bulk_update_prices.d.ts.map +1 -0
- package/dist/tools/tasks/bulk_update_prices.js +96 -0
- package/dist/tools/tasks/bulk_update_prices.js.map +1 -0
- package/dist/tools/tasks/cancel_order_with_reason.d.ts +4 -0
- package/dist/tools/tasks/cancel_order_with_reason.d.ts.map +1 -0
- package/dist/tools/tasks/cancel_order_with_reason.js +117 -0
- package/dist/tools/tasks/cancel_order_with_reason.js.map +1 -0
- package/dist/tools/tasks/check_listing_health.d.ts +4 -0
- package/dist/tools/tasks/check_listing_health.d.ts.map +1 -0
- package/dist/tools/tasks/check_listing_health.js +123 -0
- package/dist/tools/tasks/check_listing_health.js.map +1 -0
- package/dist/tools/tasks/create_and_submit_purchase_order.d.ts +4 -0
- package/dist/tools/tasks/create_and_submit_purchase_order.d.ts.map +1 -0
- package/dist/tools/tasks/create_and_submit_purchase_order.js +142 -0
- package/dist/tools/tasks/create_and_submit_purchase_order.js.map +1 -0
- package/dist/tools/tasks/find_product_by_sku.d.ts +4 -0
- package/dist/tools/tasks/find_product_by_sku.d.ts.map +1 -0
- package/dist/tools/tasks/find_product_by_sku.js +68 -0
- package/dist/tools/tasks/find_product_by_sku.js.map +1 -0
- package/dist/tools/tasks/fulfill_order.d.ts +4 -0
- package/dist/tools/tasks/fulfill_order.d.ts.map +1 -0
- package/dist/tools/tasks/fulfill_order.js +121 -0
- package/dist/tools/tasks/fulfill_order.js.map +1 -0
- package/dist/tools/tasks/get_inventory_across_warehouses.d.ts +4 -0
- package/dist/tools/tasks/get_inventory_across_warehouses.d.ts.map +1 -0
- package/dist/tools/tasks/get_inventory_across_warehouses.js +118 -0
- package/dist/tools/tasks/get_inventory_across_warehouses.js.map +1 -0
- package/dist/tools/tasks/index.d.ts +14 -0
- package/dist/tools/tasks/index.d.ts.map +1 -0
- package/dist/tools/tasks/index.js +32 -0
- package/dist/tools/tasks/index.js.map +1 -0
- package/dist/tools/tasks/publish_product_to_channels.d.ts +4 -0
- package/dist/tools/tasks/publish_product_to_channels.d.ts.map +1 -0
- package/dist/tools/tasks/publish_product_to_channels.js +109 -0
- package/dist/tools/tasks/publish_product_to_channels.js.map +1 -0
- package/dist/tools/tasks/reply_to_buyer_message.d.ts +4 -0
- package/dist/tools/tasks/reply_to_buyer_message.d.ts.map +1 -0
- package/dist/tools/tasks/reply_to_buyer_message.js +72 -0
- package/dist/tools/tasks/reply_to_buyer_message.js.map +1 -0
- package/dist/tools/tasks/reprice_listing.d.ts +4 -0
- package/dist/tools/tasks/reprice_listing.d.ts.map +1 -0
- package/dist/tools/tasks/reprice_listing.js +74 -0
- package/dist/tools/tasks/reprice_listing.js.map +1 -0
- package/dist/transports/stdio.d.ts +12 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +30 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/transports/streamableHttp.d.ts +33 -0
- package/dist/transports/streamableHttp.d.ts.map +1 -0
- package/dist/transports/streamableHttp.js +237 -0
- package/dist/transports/streamableHttp.js.map +1 -0
- package/package.json +47 -0
- package/vendor/openapi.snapshot.json +19887 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// src/server/buildServer.ts
|
|
3
|
+
// Wave: W6 — Stream C
|
|
4
|
+
//
|
|
5
|
+
// Constructs an `@modelcontextprotocol/sdk` `Server` configured with the
|
|
6
|
+
// dispatcher + provided tool list. The server returned here is *unconnected* —
|
|
7
|
+
// callers (transports/stdio.ts, transports/streamableHttp.ts) call
|
|
8
|
+
// `server.connect(t)` to bind a transport. For Streamable HTTP this is called
|
|
9
|
+
// once per session via the index.ts `makeServer` factory.
|
|
10
|
+
//
|
|
11
|
+
// Why this is split from index.ts: tests need to stand up a server with a
|
|
12
|
+
// fake `client` and assert dispatcher behavior in isolation, without booting
|
|
13
|
+
// stdio/SSE.
|
|
14
|
+
// =============================================================================
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
import { dirname, join } from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
19
|
+
import { registerTools } from "./dispatcher.js";
|
|
20
|
+
/**
|
|
21
|
+
* Project the full session auth context down to the subset tools may read.
|
|
22
|
+
* Deliberately DROPS the raw bearer token — tool handlers never need it (the
|
|
23
|
+
* SDK client already carries it) and must not be able to exfiltrate it.
|
|
24
|
+
*/
|
|
25
|
+
function toToolAuthInfo(auth) {
|
|
26
|
+
if (!auth)
|
|
27
|
+
return { mode: "apiKey", scopes: [] };
|
|
28
|
+
return {
|
|
29
|
+
mode: auth.mode,
|
|
30
|
+
...(auth.companyId !== undefined ? { companyId: auth.companyId } : {}),
|
|
31
|
+
...(auth.installId !== undefined ? { installId: auth.installId } : {}),
|
|
32
|
+
scopes: auth.scopes,
|
|
33
|
+
...(auth.introspectionDegraded ? { introspectionDegraded: true } : {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export const SERVER_NAME = "@solidcommerce/mcp-server";
|
|
37
|
+
/**
|
|
38
|
+
* Read the package.json sibling to dist/index.js (or src/index.js under tsx).
|
|
39
|
+
* We resolve relative to this module rather than `process.cwd()` so the
|
|
40
|
+
* version stays correct when the binary is launched from any directory.
|
|
41
|
+
*
|
|
42
|
+
* Defensive fallback: if package.json is unreadable (extremely unusual —
|
|
43
|
+
* would mean the install is broken), we ship a clearly-labelled
|
|
44
|
+
* `0.0.0-unknown` so the server still boots.
|
|
45
|
+
*/
|
|
46
|
+
function readPackageVersion() {
|
|
47
|
+
try {
|
|
48
|
+
// src/server/buildServer.ts → ../../package.json
|
|
49
|
+
// dist/server/buildServer.js → ../../package.json (same relative depth)
|
|
50
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
51
|
+
const pkgPath = join(here, "..", "..", "package.json");
|
|
52
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
55
|
+
return parsed.version;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// fall through
|
|
60
|
+
}
|
|
61
|
+
return "0.0.0-unknown";
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Wire a fully-configured MCP `Server`. Caller is responsible for `connect()`.
|
|
65
|
+
*
|
|
66
|
+
* The dispatcher's `ctxFactory` is closed over `client` + `setCurrentToolName`
|
|
67
|
+
* so each tool invocation:
|
|
68
|
+
*
|
|
69
|
+
* 1. Sets the audit ref to the tool name.
|
|
70
|
+
* 2. Receives a ToolContext { client, toolName }.
|
|
71
|
+
* 3. The SDK fires onRequest hooks → audit headers go on the wire.
|
|
72
|
+
* 4. After tool.handle resolves (or throws), the ref is cleared.
|
|
73
|
+
*/
|
|
74
|
+
export function buildMcpServer(opts) {
|
|
75
|
+
const version = opts.version ?? readPackageVersion();
|
|
76
|
+
const server = new Server({ name: SERVER_NAME, version }, {
|
|
77
|
+
// We advertise tools support; resources/prompts/sampling come in later
|
|
78
|
+
// waves (W8+). Empty `tools: {}` is the canonical "we have tools" flag
|
|
79
|
+
// per the MCP spec; the actual list is served by tools/list.
|
|
80
|
+
capabilities: { tools: {} },
|
|
81
|
+
});
|
|
82
|
+
const auth = toToolAuthInfo(opts.auth);
|
|
83
|
+
const ctxFactory = (toolName) => {
|
|
84
|
+
// Set the ref BEFORE returning the context — the very next thing the
|
|
85
|
+
// dispatcher does is call `tool.handle(args, ctx)`, and that handler
|
|
86
|
+
// is what triggers SDK requests + onRequest hooks.
|
|
87
|
+
opts.setCurrentToolName(toolName);
|
|
88
|
+
return { client: opts.client, toolName, auth };
|
|
89
|
+
};
|
|
90
|
+
registerTools(server, opts.tools, ctxFactory);
|
|
91
|
+
// Best-effort: clear the ref whenever the transport closes. With per-session
|
|
92
|
+
// Server instances (E-A1) each Streamable HTTP session has its own ref, but
|
|
93
|
+
// stdio reuses one Server for the process lifetime, so clearing on close
|
|
94
|
+
// still prevents a stale tool name leaking across a reconnect.
|
|
95
|
+
const originalOnClose = server.onclose;
|
|
96
|
+
server.onclose = () => {
|
|
97
|
+
opts.setCurrentToolName(null);
|
|
98
|
+
if (typeof originalOnClose === "function") {
|
|
99
|
+
originalOnClose();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return server;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=buildServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildServer.js","sourceRoot":"","sources":["../../src/server/buildServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { ToolContext, ToolModule } from "../tools/contract.js";
|
|
3
|
+
export interface ContextFactory {
|
|
4
|
+
(toolName: string): ToolContext;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Register `tools/list` and `tools/call` handlers on the MCP server.
|
|
8
|
+
*
|
|
9
|
+
* The dispatcher does NOT attach audit hooks; that's the job of the caller
|
|
10
|
+
* (index.ts) wiring `attachAuditHook(client)` and threading the resulting
|
|
11
|
+
* `setCurrentToolName` into `ctxFactory`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerTools(server: Server, tools: ReadonlyArray<ToolModule>, ctxFactory: ContextFactory): void;
|
|
14
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/server/dispatcher.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAOxE,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EAGX,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC7B,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC;CACjC;AA0FD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,EAChC,UAAU,EAAE,cAAc,GACzB,IAAI,CAyFN"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// src/server/dispatcher.ts
|
|
3
|
+
// Wave: W6 — Stream C
|
|
4
|
+
//
|
|
5
|
+
// Wires `ToolModule` instances onto an MCP `Server` via `setRequestHandler`
|
|
6
|
+
// for `tools/list` and `tools/call`.
|
|
7
|
+
//
|
|
8
|
+
// Why direct setRequestHandler over the higher-level MCP `tool()` ergonomics:
|
|
9
|
+
//
|
|
10
|
+
// 1. SDK 1.0.4's `Server` class is the documented low-level API (the
|
|
11
|
+
// newer `McpServer` helper landed in 1.4+ and we're pinned to 1.0.4 to
|
|
12
|
+
// match Claude Desktop's bundled SDK).
|
|
13
|
+
// 2. We need full control over the response envelope so we can surface
|
|
14
|
+
// `isError: true` + structured `required_scope` for the LLM scope-denied
|
|
15
|
+
// path. The high-level helper auto-serializes thrown errors into a flat
|
|
16
|
+
// text block which would lose structure.
|
|
17
|
+
//
|
|
18
|
+
// Flow per tools/call:
|
|
19
|
+
// 1. Resolve the tool by name. Unknown name → `{ isError: true }` with a
|
|
20
|
+
// hint (do NOT throw — the SDK turns thrown errors into JSON-RPC errors,
|
|
21
|
+
// and we want the LLM to *see* the failure as a regular tool result).
|
|
22
|
+
// 2. Parse args via the tool's Zod schema. Validation failure → structured
|
|
23
|
+
// `invalid_request` ToolResult.
|
|
24
|
+
// 3. Call ctxFactory(toolName) → ToolContext, then tool.handle(args, ctx).
|
|
25
|
+
// 4. Serialize ToolResult.content into MCP TextContent blocks. JSON entries
|
|
26
|
+
// are pretty-printed with 2-space indent so logs (and human eyes during
|
|
27
|
+
// debugging) stay readable.
|
|
28
|
+
// 5. Propagate isError through the wire response.
|
|
29
|
+
// =============================================================================
|
|
30
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
31
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
32
|
+
/**
|
|
33
|
+
* Convert a `ToolResultContent[]` into MCP wire `TextContent` blocks. JSON
|
|
34
|
+
* entries are stringified with 2-space indent. Text entries are passed through.
|
|
35
|
+
*
|
|
36
|
+
* The MCP wire content shape for tools is `{ type: "text", text: string }`
|
|
37
|
+
* (plus newer `image`/`resource` variants we don't use here).
|
|
38
|
+
*/
|
|
39
|
+
function serializeContent(content) {
|
|
40
|
+
return content.map((c) => {
|
|
41
|
+
if (c.type === "text") {
|
|
42
|
+
return { type: "text", text: c.text };
|
|
43
|
+
}
|
|
44
|
+
return { type: "text", text: JSON.stringify(c.json, null, 2) };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build an MCP-shape error result without invoking the tool. Used for
|
|
49
|
+
* unknown-tool and arg-validation paths.
|
|
50
|
+
*/
|
|
51
|
+
function buildClientErrorResult(errorType, message, extra = {}) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "json",
|
|
56
|
+
json: { error: { type: errorType, message, ...extra } },
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
isError: true,
|
|
60
|
+
structuredError: { type: errorType, message },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a Zod schema to JSON Schema for the MCP `tools/list` response.
|
|
65
|
+
*
|
|
66
|
+
* MCP requires `inputSchema` to be a JSON Schema object with `type: "object"`
|
|
67
|
+
* at the root. `zod-to-json-schema` emits `$schema` + `definitions` keys we
|
|
68
|
+
* don't want on the wire — strip them. If a tool's schema isn't an object
|
|
69
|
+
* (e.g., `z.array(...)`), we wrap it under a single `value` property; this
|
|
70
|
+
* shouldn't happen in practice (every ToolModule takes a named-arg object),
|
|
71
|
+
* but we'd rather degrade gracefully than crash tools/list.
|
|
72
|
+
*/
|
|
73
|
+
function zodToMcpInputSchema(schema) {
|
|
74
|
+
// We intentionally accept ZodTypeAny but treat it loosely so we don't pull in
|
|
75
|
+
// the full zod-to-json-schema generic surface; the upstream types are
|
|
76
|
+
// permissive enough that ts-strict compilation here would require @ts-expect.
|
|
77
|
+
const raw = zodToJsonSchema(schema, {
|
|
78
|
+
target: "jsonSchema7",
|
|
79
|
+
$refStrategy: "none",
|
|
80
|
+
});
|
|
81
|
+
// Strip MCP-irrelevant top-level keys.
|
|
82
|
+
delete raw["$schema"];
|
|
83
|
+
delete raw["definitions"];
|
|
84
|
+
if (raw["type"] === "object") {
|
|
85
|
+
const out = {
|
|
86
|
+
type: "object",
|
|
87
|
+
};
|
|
88
|
+
if (raw["properties"] && typeof raw["properties"] === "object") {
|
|
89
|
+
out.properties = raw["properties"];
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(raw["required"])) {
|
|
92
|
+
out.required = raw["required"];
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
// Fallback: wrap non-object schemas. See doc comment above.
|
|
97
|
+
return {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: { value: raw },
|
|
100
|
+
required: ["value"],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Register `tools/list` and `tools/call` handlers on the MCP server.
|
|
105
|
+
*
|
|
106
|
+
* The dispatcher does NOT attach audit hooks; that's the job of the caller
|
|
107
|
+
* (index.ts) wiring `attachAuditHook(client)` and threading the resulting
|
|
108
|
+
* `setCurrentToolName` into `ctxFactory`.
|
|
109
|
+
*/
|
|
110
|
+
export function registerTools(server, tools, ctxFactory) {
|
|
111
|
+
// Index for O(1) lookup; rejecting duplicates upfront is friendlier than
|
|
112
|
+
// letting the second registration silently shadow the first.
|
|
113
|
+
const byName = new Map();
|
|
114
|
+
for (const tool of tools) {
|
|
115
|
+
if (byName.has(tool.name)) {
|
|
116
|
+
throw new Error(`duplicate tool name: ${tool.name}`);
|
|
117
|
+
}
|
|
118
|
+
byName.set(tool.name, tool);
|
|
119
|
+
}
|
|
120
|
+
// tools/list — emit each tool's name, description, JSON-schema'd args, and
|
|
121
|
+
// the Claude UI annotations object. The `required_scope` field is documented
|
|
122
|
+
// in the description so the LLM can see it inline (the MCP spec doesn't
|
|
123
|
+
// define a top-level scope field).
|
|
124
|
+
//
|
|
125
|
+
// `annotations.readOnlyHint` / `.destructiveHint` is the March 2025 MCP-spec
|
|
126
|
+
// addition Claude UI requires for Connectors Directory listing. We surface
|
|
127
|
+
// exactly one per tool (mutually exclusive — enforced by
|
|
128
|
+
// test/tools/annotations.test.ts). Hosts that ignore the field degrade
|
|
129
|
+
// safely; hosts that require it (Claude UI) get a green lint pass.
|
|
130
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
131
|
+
const list = tools.map((tool) => {
|
|
132
|
+
const annotations = {};
|
|
133
|
+
if (tool.readOnlyHint === true)
|
|
134
|
+
annotations.readOnlyHint = true;
|
|
135
|
+
if (tool.destructiveHint === true)
|
|
136
|
+
annotations.destructiveHint = true;
|
|
137
|
+
return {
|
|
138
|
+
name: tool.name,
|
|
139
|
+
description: `${tool.description}\n\nRequired scope: \`${tool.required_scope}\``,
|
|
140
|
+
inputSchema: zodToMcpInputSchema(tool.inputSchema),
|
|
141
|
+
annotations,
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
return { tools: list };
|
|
145
|
+
});
|
|
146
|
+
// tools/call — dispatch to the resolved ToolModule.
|
|
147
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
148
|
+
const { name, arguments: rawArgs } = req.params;
|
|
149
|
+
const tool = byName.get(name);
|
|
150
|
+
if (!tool) {
|
|
151
|
+
const err = buildClientErrorResult("not_found", `Unknown tool: ${name}`, { tool_name: name });
|
|
152
|
+
return {
|
|
153
|
+
content: serializeContent(err.content),
|
|
154
|
+
isError: true,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// Validate args. Zod's `safeParse` lets us return a structured error
|
|
158
|
+
// instead of letting a thrown ZodError bubble into the SDK's generic
|
|
159
|
+
// error path.
|
|
160
|
+
const parsed = tool.inputSchema.safeParse(rawArgs ?? {});
|
|
161
|
+
if (!parsed.success) {
|
|
162
|
+
const err = buildClientErrorResult("invalid_request", `Invalid arguments for tool ${name}`, { issues: parsed.error.issues });
|
|
163
|
+
return {
|
|
164
|
+
content: serializeContent(err.content),
|
|
165
|
+
isError: true,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
let result;
|
|
169
|
+
try {
|
|
170
|
+
const ctx = ctxFactory(name);
|
|
171
|
+
result = await tool.handle(parsed.data, ctx);
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
// Defense in depth: every well-behaved ToolModule.handle returns a
|
|
175
|
+
// ToolResult, even for errors (see contract.ts → mapSdkErrorToToolResult).
|
|
176
|
+
// But if a tool *does* throw, we still want a structured response.
|
|
177
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
178
|
+
const fallback = buildClientErrorResult("server_error", message);
|
|
179
|
+
return {
|
|
180
|
+
content: serializeContent(fallback.content),
|
|
181
|
+
isError: true,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
content: serializeContent(result.content),
|
|
186
|
+
...(result.isError ? { isError: true } : {}),
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/server/dispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SessionAuthContext } from "./auth/oauth.js";
|
|
2
|
+
import type { McpHostName } from "./telemetry/hostName.js";
|
|
3
|
+
export interface SessionContext {
|
|
4
|
+
/** Resolved per-user OAuth / apiKey identity (E-A3). */
|
|
5
|
+
readonly auth: SessionAuthContext;
|
|
6
|
+
/** Canonical calling surface for per-surface telemetry (E-A4). */
|
|
7
|
+
readonly hostName: McpHostName;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;CAChC"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// src/session.ts
|
|
3
|
+
// Phase 0 / E-A3 + E-A4 — the per-session identity bundle.
|
|
4
|
+
//
|
|
5
|
+
// One SessionContext is resolved at `initialize` and bound to the session's
|
|
6
|
+
// dedicated MCP Server: the auth identity (E-A3) and the calling host surface
|
|
7
|
+
// (E-A4). Future per-session concerns (E-A5 rate-limit budget, etc.) attach
|
|
8
|
+
// here rather than widening every factory signature.
|
|
9
|
+
// =============================================================================
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,iBAAiB;AACjB,2DAA2D;AAC3D,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC5E,qDAAqD;AACrD,gFAAgF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Canonical surface ids (mirror docs/use_cases.md §7 telemetry NFR). */
|
|
2
|
+
export declare const MCP_HOST_NAMES: readonly ["claude_code", "claude_ui", "codex_cli", "chatgpt_ui", "gemini_ui", "gemini_cli", "m365_copilot", "grok_cli"];
|
|
3
|
+
export type McpHostName = (typeof MCP_HOST_NAMES)[number] | "unknown";
|
|
4
|
+
export declare const MCP_HOST_UNKNOWN = "unknown";
|
|
5
|
+
/** Force a fixed host id (single-host deployments / tests). Wins over detection. */
|
|
6
|
+
export declare const ENV_HOST_NAME_OVERRIDE = "SC_MCP_HOST_NAME";
|
|
7
|
+
export interface HostNameSignals {
|
|
8
|
+
/** MCP `initialize` params.clientInfo.name. */
|
|
9
|
+
readonly clientInfoName?: string | undefined;
|
|
10
|
+
/** HTTP `User-Agent` header. */
|
|
11
|
+
readonly userAgent?: string | undefined;
|
|
12
|
+
/** Env override (SC_MCP_HOST_NAME). Wins when set. */
|
|
13
|
+
readonly override?: string | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Map host signals to a canonical surface id. Override wins; otherwise the
|
|
17
|
+
* first matching pattern across (clientInfoName + userAgent); else `unknown`.
|
|
18
|
+
* Never throws.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveHostName(signals: HostNameSignals): McpHostName;
|
|
21
|
+
/**
|
|
22
|
+
* Defensively pull `params.clientInfo.name` out of a parsed MCP `initialize`
|
|
23
|
+
* request body. Returns undefined for any shape mismatch — never throws.
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractClientInfoName(body: unknown): string | undefined;
|
|
26
|
+
//# sourceMappingURL=hostName.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hostName.d.ts","sourceRoot":"","sources":["../../src/telemetry/hostName.ts"],"names":[],"mappings":"AAeA,yEAAyE;AACzE,eAAO,MAAM,cAAc,yHASjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;AAEtE,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAezD,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,gCAAgC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,CAkBrE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQvE"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// src/telemetry/hostName.ts
|
|
3
|
+
// Phase 0 / Item E-A4 — per-surface telemetry: resolve the calling AI host.
|
|
4
|
+
//
|
|
5
|
+
// Every one of the 8 distribution surfaces hits the SAME hosted MCP URL, so we
|
|
6
|
+
// attribute traffic by the MCP `clientInfo.name` sent in the `initialize`
|
|
7
|
+
// request (the canonical, host-controlled identity), with the HTTP User-Agent
|
|
8
|
+
// as a secondary signal and an env override as an escape hatch.
|
|
9
|
+
//
|
|
10
|
+
// This is BEST-EFFORT telemetry, NOT a security control: a client can spoof its
|
|
11
|
+
// name. Reliable attribution comes from pairing this with the server-minted
|
|
12
|
+
// `install_id` (E-A3). The audit hook stamps both; the KQL dashboard pivots on
|
|
13
|
+
// `mcp_host_name`.
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/** Canonical surface ids (mirror docs/use_cases.md §7 telemetry NFR). */
|
|
16
|
+
export const MCP_HOST_NAMES = [
|
|
17
|
+
"claude_code",
|
|
18
|
+
"claude_ui",
|
|
19
|
+
"codex_cli",
|
|
20
|
+
"chatgpt_ui",
|
|
21
|
+
"gemini_ui",
|
|
22
|
+
"gemini_cli",
|
|
23
|
+
"m365_copilot",
|
|
24
|
+
"grok_cli",
|
|
25
|
+
];
|
|
26
|
+
export const MCP_HOST_UNKNOWN = "unknown";
|
|
27
|
+
/** Force a fixed host id (single-host deployments / tests). Wins over detection. */
|
|
28
|
+
export const ENV_HOST_NAME_OVERRIDE = "SC_MCP_HOST_NAME";
|
|
29
|
+
// Order matters — most specific first. `claude-code` must precede the `claude`
|
|
30
|
+
// catch-all; `gemini-cli` must precede `gemini`.
|
|
31
|
+
const HOST_PATTERNS = [
|
|
32
|
+
[/claude[-_ ]?code/i, "claude_code"],
|
|
33
|
+
[/codex/i, "codex_cli"],
|
|
34
|
+
[/chatgpt|openai/i, "chatgpt_ui"],
|
|
35
|
+
[/gemini[-_ ]?cli/i, "gemini_cli"],
|
|
36
|
+
[/gemini|vertex/i, "gemini_ui"],
|
|
37
|
+
[/copilot|m365|microsoft[-_ ]?365|teams/i, "m365_copilot"],
|
|
38
|
+
[/grok|xai/i, "grok_cli"],
|
|
39
|
+
[/claude|anthropic/i, "claude_ui"], // catch-all AFTER claude-code
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Map host signals to a canonical surface id. Override wins; otherwise the
|
|
43
|
+
* first matching pattern across (clientInfoName + userAgent); else `unknown`.
|
|
44
|
+
* Never throws.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveHostName(signals) {
|
|
47
|
+
const override = signals.override?.trim();
|
|
48
|
+
if (override && override.length > 0) {
|
|
49
|
+
// Accept a known canonical id verbatim; otherwise still honor the operator's
|
|
50
|
+
// explicit string by returning it (cast) — telemetry, not a closed enum gate.
|
|
51
|
+
return override;
|
|
52
|
+
}
|
|
53
|
+
const haystack = [signals.clientInfoName, signals.userAgent]
|
|
54
|
+
.filter((s) => typeof s === "string" && s.length > 0)
|
|
55
|
+
.join(" ");
|
|
56
|
+
if (haystack.length === 0)
|
|
57
|
+
return MCP_HOST_UNKNOWN;
|
|
58
|
+
for (const [pattern, name] of HOST_PATTERNS) {
|
|
59
|
+
if (pattern.test(haystack))
|
|
60
|
+
return name;
|
|
61
|
+
}
|
|
62
|
+
return MCP_HOST_UNKNOWN;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Defensively pull `params.clientInfo.name` out of a parsed MCP `initialize`
|
|
66
|
+
* request body. Returns undefined for any shape mismatch — never throws.
|
|
67
|
+
*/
|
|
68
|
+
export function extractClientInfoName(body) {
|
|
69
|
+
if (body === null || typeof body !== "object")
|
|
70
|
+
return undefined;
|
|
71
|
+
const params = body.params;
|
|
72
|
+
if (params === null || typeof params !== "object")
|
|
73
|
+
return undefined;
|
|
74
|
+
const clientInfo = params.clientInfo;
|
|
75
|
+
if (clientInfo === null || typeof clientInfo !== "object")
|
|
76
|
+
return undefined;
|
|
77
|
+
const name = clientInfo.name;
|
|
78
|
+
return typeof name === "string" && name.length > 0 ? name : undefined;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=hostName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hostName.js","sourceRoot":"","sources":["../../src/telemetry/hostName.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4BAA4B;AAC5B,4EAA4E;AAC5E,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,gEAAgE;AAChE,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,+EAA+E;AAC/E,mBAAmB;AACnB,gFAAgF;AAEhF,yEAAyE;AACzE,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa;IACb,WAAW;IACX,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,cAAc;IACd,UAAU;CACF,CAAC;AAIX,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAE1C,oFAAoF;AACpF,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAEzD,+EAA+E;AAC/E,iDAAiD;AACjD,MAAM,aAAa,GAAkD;IACnE,CAAC,mBAAmB,EAAE,aAAa,CAAC;IACpC,CAAC,QAAQ,EAAE,WAAW,CAAC;IACvB,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACjC,CAAC,kBAAkB,EAAE,YAAY,CAAC;IAClC,CAAC,gBAAgB,EAAE,WAAW,CAAC;IAC/B,CAAC,wCAAwC,EAAE,cAAc,CAAC;IAC1D,CAAC,WAAW,EAAE,UAAU,CAAC;IACzB,CAAC,mBAAmB,EAAE,WAAW,CAAC,EAAE,8BAA8B;CACnE,CAAC;AAWF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,6EAA6E;QAC7E,8EAA8E;QAC9E,OAAO,QAAuB,CAAC;IACjC,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC;SACzD,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SACjE,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAEnD,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,aAAa,EAAE,CAAC;QAC5C,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IAC1C,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,MAAM,GAAI,IAA6B,CAAC,MAAM,CAAC;IACrD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpE,MAAM,UAAU,GAAI,MAAmC,CAAC,UAAU,CAAC;IACnE,IAAI,UAAU,KAAK,IAAI,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC5E,MAAM,IAAI,GAAI,UAAiC,CAAC,IAAI,CAAC;IACrD,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { SolidCommerceClient } from "@solidcommerce/sdk";
|
|
2
|
+
import type { ZodTypeAny } from "zod";
|
|
3
|
+
/** Foundation = OpenAPI-derived; Task = hand-authored composition. */
|
|
4
|
+
export type ToolKind = "foundation" | "task";
|
|
5
|
+
/**
|
|
6
|
+
* Resolved auth identity for the current MCP session (Phase 0 / E-A3).
|
|
7
|
+
* Populated by the per-session server factory from either a per-user OAuth
|
|
8
|
+
* bearer token (remote hosts) or the env API key (stdio / Scotty / internal).
|
|
9
|
+
*/
|
|
10
|
+
export interface ToolAuthInfo {
|
|
11
|
+
/** `oauth` = per-user bearer; `apiKey` = service-to-service env key. */
|
|
12
|
+
readonly mode: "oauth" | "apiKey";
|
|
13
|
+
/** Company the token is scoped to, when introspection surfaced it. */
|
|
14
|
+
readonly companyId?: string;
|
|
15
|
+
/** Per-(host, company) install id minted at OAuth consent. */
|
|
16
|
+
readonly installId?: string;
|
|
17
|
+
/** Granted scopes (empty for apiKey / when not surfaced). */
|
|
18
|
+
readonly scopes: ReadonlyArray<string>;
|
|
19
|
+
/**
|
|
20
|
+
* True when introspection could not verify the token (Auth outage / circuit
|
|
21
|
+
* open) and we forwarded it unverified — Platform remains the authority.
|
|
22
|
+
*/
|
|
23
|
+
readonly introspectionDegraded?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Provided to every tool handler. The client is already auth-injected. */
|
|
26
|
+
export interface ToolContext {
|
|
27
|
+
/** Fully configured SDK client with audit hooks pre-installed. */
|
|
28
|
+
readonly client: SolidCommerceClient;
|
|
29
|
+
/** The MCP tool name being dispatched (for logging / audit headers). */
|
|
30
|
+
readonly toolName: string;
|
|
31
|
+
/**
|
|
32
|
+
* Resolved session auth identity. Optional so existing unit tests that build
|
|
33
|
+
* a bare context still compile; the dispatcher always populates it in
|
|
34
|
+
* production (see server/buildServer.ts).
|
|
35
|
+
*/
|
|
36
|
+
readonly auth?: ToolAuthInfo;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* MCP wire content. We deliberately accept both text + json — the
|
|
40
|
+
* MCP TypeScript SDK serializes both into its `TextContent` shape,
|
|
41
|
+
* with JSON values pretty-printed.
|
|
42
|
+
*/
|
|
43
|
+
export type ToolResultContent = {
|
|
44
|
+
readonly type: "text";
|
|
45
|
+
readonly text: string;
|
|
46
|
+
} | {
|
|
47
|
+
readonly type: "json";
|
|
48
|
+
readonly json: unknown;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Structured error payload exposed to the LLM when an SDK call fails.
|
|
52
|
+
* Carrying `required_scope` distinct from the human message lets the LLM
|
|
53
|
+
* surface "you need scope X" cleanly without parsing English.
|
|
54
|
+
*/
|
|
55
|
+
export interface StructuredError {
|
|
56
|
+
readonly type: string;
|
|
57
|
+
readonly code?: string;
|
|
58
|
+
readonly required_scope?: string;
|
|
59
|
+
readonly retry_after?: number;
|
|
60
|
+
readonly request_id?: string;
|
|
61
|
+
readonly message?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface ToolResult {
|
|
64
|
+
readonly content: ReadonlyArray<ToolResultContent>;
|
|
65
|
+
readonly isError?: boolean;
|
|
66
|
+
readonly structuredError?: StructuredError;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One MCP tool. Foundation tools are auto-emitted by the generator;
|
|
70
|
+
* task tools are hand-authored.
|
|
71
|
+
*
|
|
72
|
+
* `inputSchema` is a Zod schema — Stream C converts it to JSON Schema for
|
|
73
|
+
* the MCP `tools/list` response (the MCP SDK accepts JSON Schema, and Zod
|
|
74
|
+
* provides `z.toJSONSchema(...)` ergonomics in v3+).
|
|
75
|
+
*/
|
|
76
|
+
export interface ToolModule {
|
|
77
|
+
readonly name: string;
|
|
78
|
+
readonly kind: ToolKind;
|
|
79
|
+
readonly description: string;
|
|
80
|
+
readonly required_scope: string;
|
|
81
|
+
readonly inputSchema: ZodTypeAny;
|
|
82
|
+
readonly handle: (args: unknown, ctx: ToolContext) => Promise<ToolResult>;
|
|
83
|
+
/**
|
|
84
|
+
* Claude UI Connectors Directory submission requirement (March 2025 MCP spec):
|
|
85
|
+
* every tool MUST advertise exactly one of `readOnlyHint` or `destructiveHint`.
|
|
86
|
+
* Foundation tools derive this from HTTP method (GET → readOnly, write verbs →
|
|
87
|
+
* destructive). Task tools must set it manually — natural language can mislead
|
|
88
|
+
* (e.g. `publish_product_to_channels` is destructive even though "publish"
|
|
89
|
+
* reads neutrally). Enforced by `test/tools/annotations.test.ts`.
|
|
90
|
+
*
|
|
91
|
+
* Mutually exclusive: setting both is a build-time error.
|
|
92
|
+
*/
|
|
93
|
+
readonly readOnlyHint?: boolean;
|
|
94
|
+
readonly destructiveHint?: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Map a thrown SDK error into a structured ToolResult. Used by the
|
|
98
|
+
* dispatcher (Stream C) AND by task tools (Stream B) when they catch
|
|
99
|
+
* partial failures and want to fold them into the result.
|
|
100
|
+
*
|
|
101
|
+
* Accepts three input shapes:
|
|
102
|
+
*
|
|
103
|
+
* 1. A typed `ApiError` (or duck-typed equivalent) with camelCase fields
|
|
104
|
+
* (`requiredScope`, `requestId`, `retryAfter`). This is what the SDK's
|
|
105
|
+
* `unwrap()` / `mapErrorEnvelope()` produces.
|
|
106
|
+
*
|
|
107
|
+
* 2. The raw openapi-fetch `result.error` — the *parsed JSON body* of a
|
|
108
|
+
* 4xx/5xx response. Foundation tools call `client.raw.<METHOD>(...)`
|
|
109
|
+
* directly and forward `result.error` here without going through
|
|
110
|
+
* `unwrap()`. The body is shaped `{ error: { type, code, message,
|
|
111
|
+
* required_scope, retry_after, request_id, ... } }` (snake_case wire
|
|
112
|
+
* fields). We unwrap one layer if present.
|
|
113
|
+
*
|
|
114
|
+
* 3. Anything else (network-level errors, plain `Error`, etc.) — wrapped
|
|
115
|
+
* as `type: "transport"` so the LLM doesn't try to interpret a
|
|
116
|
+
* missing `required_scope`.
|
|
117
|
+
*
|
|
118
|
+
* Why the unwrap matters for W6 acceptance: §4 requires that scope-denied
|
|
119
|
+
* tool calls surface the `required_scope` field on the wire. Without the
|
|
120
|
+
* unwrap, foundation tools (which forward `result.error` from openapi-fetch)
|
|
121
|
+
* would emit `type: "transport"` and lose `required_scope` entirely. See
|
|
122
|
+
* test/e2e/inspector.test.ts and scripts/w6_smoke.sh probe A6.
|
|
123
|
+
*/
|
|
124
|
+
export declare function mapSdkErrorToToolResult(err: unknown): ToolResult;
|
|
125
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/tools/contract.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAY,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,sEAAsE;AACtE,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC1C;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1E;;;;;;;;;OASG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CA+DhE"}
|