@sealmetrics/mcp 0.1.0 → 1.3.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 (103) hide show
  1. package/README.md +173 -0
  2. package/dist/client.d.ts +68 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +225 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/embedded.d.ts +29 -0
  7. package/dist/embedded.d.ts.map +1 -0
  8. package/dist/embedded.js +37 -0
  9. package/dist/embedded.js.map +1 -0
  10. package/dist/errors.d.ts +10 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +55 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/index.d.ts +1 -6
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +3809 -780
  17. package/dist/index.js.map +1 -0
  18. package/dist/resources/tracking-guide.d.ts +13 -0
  19. package/dist/resources/tracking-guide.d.ts.map +1 -0
  20. package/dist/resources/tracking-guide.js +479 -0
  21. package/dist/resources/tracking-guide.js.map +1 -0
  22. package/dist/sealmetrics.mcpb +0 -0
  23. package/dist/server.d.ts +38 -0
  24. package/dist/server.d.ts.map +1 -0
  25. package/dist/server.js +132 -0
  26. package/dist/server.js.map +1 -0
  27. package/dist/tools/alerts.d.ts +5 -0
  28. package/dist/tools/alerts.d.ts.map +1 -0
  29. package/dist/tools/alerts.js +80 -0
  30. package/dist/tools/alerts.js.map +1 -0
  31. package/dist/tools/audience.d.ts +7 -0
  32. package/dist/tools/audience.d.ts.map +1 -0
  33. package/dist/tools/audience.js +146 -0
  34. package/dist/tools/audience.js.map +1 -0
  35. package/dist/tools/bots.d.ts +4 -0
  36. package/dist/tools/bots.d.ts.map +1 -0
  37. package/dist/tools/bots.js +52 -0
  38. package/dist/tools/bots.js.map +1 -0
  39. package/dist/tools/channels.d.ts +5 -0
  40. package/dist/tools/channels.d.ts.map +1 -0
  41. package/dist/tools/channels.js +88 -0
  42. package/dist/tools/channels.js.map +1 -0
  43. package/dist/tools/content.d.ts +3 -0
  44. package/dist/tools/content.d.ts.map +1 -0
  45. package/dist/tools/content.js +47 -0
  46. package/dist/tools/content.js.map +1 -0
  47. package/dist/tools/conversions.d.ts +9 -0
  48. package/dist/tools/conversions.d.ts.map +1 -0
  49. package/dist/tools/conversions.js +427 -0
  50. package/dist/tools/conversions.js.map +1 -0
  51. package/dist/tools/funnel.d.ts +3 -0
  52. package/dist/tools/funnel.d.ts.map +1 -0
  53. package/dist/tools/funnel.js +27 -0
  54. package/dist/tools/funnel.js.map +1 -0
  55. package/dist/tools/index.d.ts +16 -0
  56. package/dist/tools/index.d.ts.map +1 -0
  57. package/dist/tools/index.js +83 -0
  58. package/dist/tools/index.js.map +1 -0
  59. package/dist/tools/overview.d.ts +3 -0
  60. package/dist/tools/overview.d.ts.map +1 -0
  61. package/dist/tools/overview.js +26 -0
  62. package/dist/tools/overview.js.map +1 -0
  63. package/dist/tools/pages.d.ts +7 -0
  64. package/dist/tools/pages.d.ts.map +1 -0
  65. package/dist/tools/pages.js +307 -0
  66. package/dist/tools/pages.js.map +1 -0
  67. package/dist/tools/properties.d.ts +5 -0
  68. package/dist/tools/properties.d.ts.map +1 -0
  69. package/dist/tools/properties.js +107 -0
  70. package/dist/tools/properties.js.map +1 -0
  71. package/dist/tools/segments.d.ts +4 -0
  72. package/dist/tools/segments.d.ts.map +1 -0
  73. package/dist/tools/segments.js +49 -0
  74. package/dist/tools/segments.js.map +1 -0
  75. package/dist/tools/setup.d.ts +49 -0
  76. package/dist/tools/setup.d.ts.map +1 -0
  77. package/dist/tools/setup.js +347 -0
  78. package/dist/tools/setup.js.map +1 -0
  79. package/dist/tools/shared.d.ts +33 -0
  80. package/dist/tools/shared.d.ts.map +1 -0
  81. package/dist/tools/shared.js +40 -0
  82. package/dist/tools/shared.js.map +1 -0
  83. package/dist/tools/sites.d.ts +4 -0
  84. package/dist/tools/sites.d.ts.map +1 -0
  85. package/dist/tools/sites.js +36 -0
  86. package/dist/tools/sites.js.map +1 -0
  87. package/dist/tools/tracking.d.ts +3 -0
  88. package/dist/tools/tracking.d.ts.map +1 -0
  89. package/dist/tools/tracking.js +220 -0
  90. package/dist/tools/tracking.js.map +1 -0
  91. package/dist/tools/traffic.d.ts +10 -0
  92. package/dist/tools/traffic.d.ts.map +1 -0
  93. package/dist/tools/traffic.js +273 -0
  94. package/dist/tools/traffic.js.map +1 -0
  95. package/dist/tools/webhooks.d.ts +5 -0
  96. package/dist/tools/webhooks.d.ts.map +1 -0
  97. package/dist/tools/webhooks.js +101 -0
  98. package/dist/tools/webhooks.js.map +1 -0
  99. package/dist/types.d.ts +118 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +22 -0
  102. package/dist/types.js.map +1 -0
  103. package/package.json +44 -27
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # @sealmetrics/mcp
2
+
3
+ MCP server for querying [SealMetrics](https://sealmetrics.com) analytics from Claude Code, Claude Desktop, or any MCP-compatible client.
4
+
5
+ ## Setup
6
+
7
+ ### 1. Get an API key
8
+
9
+ Go to **Settings > API Tokens** in your SealMetrics dashboard and generate a new API key.
10
+
11
+ ### 2. Configure your MCP client
12
+
13
+ Add to your project's `.mcp.json` or `~/.claude/settings.json`:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "sealmetrics": {
19
+ "command": "npx",
20
+ "args": ["-y", "@sealmetrics/mcp"],
21
+ "env": {
22
+ "SEALMETRICS_API_KEY": "sm_xxxx...",
23
+ "SEALMETRICS_SITE_ID": "my-site"
24
+ }
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ ### Environment variables
31
+
32
+ | Variable | Required | Description |
33
+ |----------|----------|-------------|
34
+ | `SEALMETRICS_API_KEY` | Yes | Your API key (starts with `sm_`) |
35
+ | `SEALMETRICS_SITE_ID` | No | Default site ID (skips needing to pass `site_id` to every tool) |
36
+ | `SEALMETRICS_BASE_URL` | No | API base URL (default: `https://my.sealmetrics.com/api/v1`) |
37
+
38
+ ## Available tools
39
+
40
+ ### list_sites
41
+
42
+ List all sites accessible with your API key.
43
+
44
+ ### get_overview
45
+
46
+ Dashboard KPIs: pageviews, entrances, bounce rate, conversions, revenue. Includes time series data and optional period comparison.
47
+
48
+ **Parameters:** `site_id`, `period`, `compare`
49
+
50
+ ### get_traffic_sources
51
+
52
+ Traffic broken down by source (utm_source): google, facebook, direct, etc.
53
+
54
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`
55
+
56
+ ### get_traffic_mediums
57
+
58
+ Traffic broken down by medium (utm_medium): organic, cpc, email, referral, etc.
59
+
60
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`
61
+
62
+ ### get_campaigns
63
+
64
+ Campaign performance (utm_campaign) with entrances, conversions, and revenue.
65
+
66
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`, `utm_source`, `utm_medium`
67
+
68
+ ### get_pages
69
+
70
+ Metrics per page URL path: pageviews, entrances, conversions.
71
+
72
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`, `path_filter`, multi-value filters `country`, `device_type`, `browser`, `os`, `channel_group`, `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, and `include` (`device|browser|os|channel_group`).
73
+
74
+ > **Breaking change in 1.2.0**: `country` is now `array of string` (was `string`). Pass `country: ["ES"]` instead of `country: "ES"`.
75
+
76
+ ### get_landing_pages
77
+
78
+ Landing page performance: entrances, bounce rate, conversions.
79
+
80
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`, `path_filter`, plus the same multi-value filter set and `include` parameter as `get_pages` (same breaking change on `country`).
81
+
82
+ ### get_conversions
83
+
84
+ Aggregated conversions by type (purchase, signup) with count, revenue, and average order value.
85
+
86
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`, `utm_source`, `utm_medium`, `country`
87
+
88
+ For per-event detail use `get_conversions_raw`. For per-product analysis use `get_conversion_items_raw`.
89
+
90
+ ### get_microconversions
91
+
92
+ Aggregated microconversions (add_to_cart, newsletter_signup, etc.) by type with counts.
93
+
94
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`, `conversion_type`
95
+
96
+ For per-event detail use `get_microconversions_raw`.
97
+
98
+ ### get_conversions_raw
99
+
100
+ Raw conversion rows (one per event) with `timestamp_utc`, `timestamp_local`, full attribution. Date range capped at 31 days; `limit` capped at 100 (default 10) to control LLM token usage.
101
+
102
+ **Parameters:** `site_id`, `period` or (`start_date` + `end_date`), `page`, `limit` (1–100), `include_properties` (default `false`), and multi-value filters `conversion_type`, `country`, `device_type`, `browser`, `os`, `channel_group`, `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`.
103
+
104
+ When `include_properties=false` the custom `properties` map is stripped from each row to keep responses compact.
105
+
106
+ ### get_microconversions_raw
107
+
108
+ Same shape as `get_conversions_raw` but for `/stats/microconversions/raw` (no `amount`/`clid`).
109
+
110
+ ### get_conversion_items_raw
111
+
112
+ One row per item inside a conversion (e.g. one row per product in a purchase). `properties` is **always** included — that's where `product_id`, `sku`, `price`, `quantity` live.
113
+
114
+ **Parameters:** `site_id`, `period` or (`start_date` + `end_date`), `page`, `limit` (1–100), and the same multi-value filter set as the other raw tools. Note: this tool does **not** accept `include_properties`.
115
+
116
+ ### get_countries
117
+
118
+ Traffic by country with entrances, conversions, and revenue.
119
+
120
+ **Parameters:** `site_id`, `period`, `compare`, `limit`, `sort_by`, `sort_order`
121
+
122
+ ### get_devices
123
+
124
+ Device type (desktop/mobile/tablet), browser, and OS breakdown in a single call.
125
+
126
+ **Parameters:** `site_id`, `period`, `compare`
127
+
128
+ ### get_funnel
129
+
130
+ Funnel analysis with step-by-step conversion rates and dropoff.
131
+
132
+ **Parameters:** `site_id`, `period`, `country`
133
+
134
+ ### get_tracking_code
135
+
136
+ Get the tracking pixel code for a site and the full JavaScript API reference for implementing pageviews, conversions, microconversions, and content grouping. Use this when you need to install tracking on a website.
137
+
138
+ **Parameters:** `site_id`
139
+
140
+ ## Common parameters
141
+
142
+ | Parameter | Values | Default | Description |
143
+ |-----------|--------|---------|-------------|
144
+ | `site_id` | string | `$SEALMETRICS_SITE_ID` | Site to query |
145
+ | `period` | `today`, `yesterday`, `7d`, `30d`, `90d`, `this_month`, `last_month`, `this_year`, etc. | `30d` | Time period |
146
+ | `compare` | `previous`, `yoy` | none | Comparison mode |
147
+ | `limit` | 1-100 | 20 | Max rows returned |
148
+ | `page` | number | 1 | Page number for paginated results |
149
+ | `sort_by` | varies per tool | varies | Sort field |
150
+ | `sort_order` | `asc`, `desc` | `desc` | Sort direction |
151
+
152
+ ## Example usage
153
+
154
+ Once configured, you can ask Claude:
155
+
156
+ - "Show me an overview of my site for the last 7 days"
157
+ - "What are the top traffic sources this month?"
158
+ - "Compare this month's conversions with last month"
159
+ - "Which landing pages have the highest bounce rate?"
160
+ - "Show me revenue by country for Q1"
161
+
162
+ ## Development
163
+
164
+ ```bash
165
+ npm install
166
+ npm run build # Compile TypeScript
167
+ npm test # Run tests
168
+ npm run dev # Run with tsx (dev mode)
169
+ ```
170
+
171
+ ## License
172
+
173
+ MIT
@@ -0,0 +1,68 @@
1
+ /** Raw JSON response from the API before envelope unwrapping. */
2
+ export interface RawAPIResponse {
3
+ success: boolean;
4
+ data: unknown;
5
+ total?: number;
6
+ page?: number;
7
+ page_size?: number;
8
+ has_next?: boolean;
9
+ has_prev?: boolean;
10
+ comparison?: unknown;
11
+ totals?: unknown;
12
+ [key: string]: unknown;
13
+ }
14
+ export declare class SealMetricsClient {
15
+ /**
16
+ * Read-only api_key (X-API-Key). Optional + mutable so the server can start in
17
+ * setup-only mode without a key (RF-3202) and adopt the key returned by
18
+ * provision_site at runtime to enable the read-only tools (RF-3202b). Held in
19
+ * memory only — never echoed to the model or logs (VAL-3201).
20
+ */
21
+ private apiKey;
22
+ private readonly baseUrl;
23
+ constructor(apiKey: string | undefined, baseUrl: string);
24
+ /** True once a read-only api_key is available (env at boot or post-provision). */
25
+ hasApiKey(): boolean;
26
+ /** Return the in-memory api_key (for setup-core verify). Never logged by callers. */
27
+ getApiKey(): string | undefined;
28
+ /** Adopt the api_key returned by provision_site so read-only tools work (RF-3202b). */
29
+ setApiKey(apiKey: string): void;
30
+ /**
31
+ * Authenticated POST (RF-3201). The client was GET-only in v1.2.0; the
32
+ * write-path needs it. NOT auto-retried — POST is not idempotent (a blind retry
33
+ * of /provision could create duplicate accounts). Authenticates with the
34
+ * publishable provision key (`provisionKey`) for provisioning, or X-API-Key
35
+ * otherwise. On 2xx returns the parsed JSON; on non-2xx / network throws
36
+ * SealMetricsAPIError carrying the status code for the caller to map.
37
+ */
38
+ post<T>(path: string, body: unknown, opts?: {
39
+ provisionKey?: string;
40
+ }): Promise<T>;
41
+ /**
42
+ * Send an authenticated GET request. Unwraps the API envelope
43
+ * and returns just the `data` field.
44
+ */
45
+ request<T>(path: string, params?: Record<string, string | string[] | undefined>): Promise<T>;
46
+ /**
47
+ * Send an authenticated GET request and return the full JSON body
48
+ * without unwrapping. Use this for endpoints that don't use the
49
+ * standard APIResponse envelope (e.g. alerts, webhooks).
50
+ */
51
+ requestDirect<T>(path: string, params?: Record<string, string | string[] | undefined>): Promise<T>;
52
+ /**
53
+ * Send an authenticated GET request and return the full response
54
+ * including pagination fields (total, page, has_next, etc.).
55
+ * Use this for paginated endpoints.
56
+ */
57
+ requestPaginated<T>(path: string, params?: Record<string, string | string[] | undefined>): Promise<{
58
+ data: T[];
59
+ total: number;
60
+ page: number;
61
+ page_size: number;
62
+ has_next: boolean;
63
+ comparison?: unknown;
64
+ totals?: unknown;
65
+ }>;
66
+ private requestRaw;
67
+ }
68
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAMA,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IAEd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,iBAAiB;IAC5B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM;IAKvD,kFAAkF;IAClF,SAAS,IAAI,OAAO;IAIpB,qFAAqF;IACrF,SAAS,IAAI,MAAM,GAAG,SAAS;IAI/B,uFAAuF;IACvF,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B;;;;;;;OAOG;IACG,IAAI,CAAC,CAAC,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,CAAC,CAAC;IA0Cb;;;OAGG;IACG,OAAO,CAAC,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,OAAO,CAAC,CAAC,CAAC;IAKb;;;;OAIG;IACG,aAAa,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,OAAO,CAAC,CAAC,CAAC;IAKb;;;;OAIG;IACG,gBAAgB,CAAC,CAAC,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,OAAO,CAAC;QACT,IAAI,EAAE,CAAC,EAAE,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;YAsBY,UAAU;CAwHzB"}
package/dist/client.js ADDED
@@ -0,0 +1,225 @@
1
+ import { mapHttpError, SealMetricsAPIError } from "./errors.js";
2
+ const DEFAULT_TIMEOUT_MS = 30_000;
3
+ const MAX_RETRIES = 2;
4
+ const RETRY_BASE_MS = 1_000;
5
+ export class SealMetricsClient {
6
+ /**
7
+ * Read-only api_key (X-API-Key). Optional + mutable so the server can start in
8
+ * setup-only mode without a key (RF-3202) and adopt the key returned by
9
+ * provision_site at runtime to enable the read-only tools (RF-3202b). Held in
10
+ * memory only — never echoed to the model or logs (VAL-3201).
11
+ */
12
+ apiKey;
13
+ baseUrl;
14
+ constructor(apiKey, baseUrl) {
15
+ this.apiKey = apiKey;
16
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
17
+ }
18
+ /** True once a read-only api_key is available (env at boot or post-provision). */
19
+ hasApiKey() {
20
+ return typeof this.apiKey === "string" && this.apiKey.length > 0;
21
+ }
22
+ /** Return the in-memory api_key (for setup-core verify). Never logged by callers. */
23
+ getApiKey() {
24
+ return this.apiKey;
25
+ }
26
+ /** Adopt the api_key returned by provision_site so read-only tools work (RF-3202b). */
27
+ setApiKey(apiKey) {
28
+ this.apiKey = apiKey;
29
+ }
30
+ /**
31
+ * Authenticated POST (RF-3201). The client was GET-only in v1.2.0; the
32
+ * write-path needs it. NOT auto-retried — POST is not idempotent (a blind retry
33
+ * of /provision could create duplicate accounts). Authenticates with the
34
+ * publishable provision key (`provisionKey`) for provisioning, or X-API-Key
35
+ * otherwise. On 2xx returns the parsed JSON; on non-2xx / network throws
36
+ * SealMetricsAPIError carrying the status code for the caller to map.
37
+ */
38
+ async post(path, body, opts) {
39
+ const url = `${this.baseUrl}${path}`;
40
+ const headers = {
41
+ "Content-Type": "application/json",
42
+ Accept: "application/json",
43
+ };
44
+ if (opts?.provisionKey) {
45
+ headers["X-Provision-Key"] = opts.provisionKey;
46
+ }
47
+ else if (this.apiKey) {
48
+ headers["X-API-Key"] = this.apiKey;
49
+ }
50
+ const controller = new AbortController();
51
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
52
+ let response;
53
+ try {
54
+ response = await fetch(url, {
55
+ method: "POST",
56
+ headers,
57
+ body: JSON.stringify(body),
58
+ signal: controller.signal,
59
+ });
60
+ }
61
+ catch (error) {
62
+ if (error instanceof Error && error.name === "AbortError") {
63
+ throw new SealMetricsAPIError(0, "Request timed out after 30 seconds.");
64
+ }
65
+ throw new SealMetricsAPIError(0, error instanceof Error ? error.message : "Network error");
66
+ }
67
+ finally {
68
+ clearTimeout(timeout);
69
+ }
70
+ const text = await response.text();
71
+ if (!response.ok) {
72
+ throw mapHttpError(response.status, text);
73
+ }
74
+ try {
75
+ return JSON.parse(text);
76
+ }
77
+ catch {
78
+ throw new SealMetricsAPIError(response.status, "API returned invalid JSON.", text.slice(0, 500));
79
+ }
80
+ }
81
+ /**
82
+ * Send an authenticated GET request. Unwraps the API envelope
83
+ * and returns just the `data` field.
84
+ */
85
+ async request(path, params) {
86
+ const raw = await this.requestRaw(path, params);
87
+ return raw.data;
88
+ }
89
+ /**
90
+ * Send an authenticated GET request and return the full JSON body
91
+ * without unwrapping. Use this for endpoints that don't use the
92
+ * standard APIResponse envelope (e.g. alerts, webhooks).
93
+ */
94
+ async requestDirect(path, params) {
95
+ const raw = await this.requestRaw(path, params);
96
+ return raw;
97
+ }
98
+ /**
99
+ * Send an authenticated GET request and return the full response
100
+ * including pagination fields (total, page, has_next, etc.).
101
+ * Use this for paginated endpoints.
102
+ */
103
+ async requestPaginated(path, params) {
104
+ const raw = await this.requestRaw(path, params);
105
+ const result = {
106
+ data: raw.data,
107
+ total: raw.total ?? 0,
108
+ page: raw.page ?? 1,
109
+ page_size: raw.page_size ?? 0,
110
+ has_next: raw.has_next ?? false,
111
+ };
112
+ if (raw.comparison != null)
113
+ result.comparison = raw.comparison;
114
+ if (raw.totals != null)
115
+ result.totals = raw.totals;
116
+ return result;
117
+ }
118
+ async requestRaw(path, params) {
119
+ // Defense in depth (RF-3202/RF-3602): without an api_key the read-only tools
120
+ // are never registered, but if one is somehow invoked, fail with a clear
121
+ // AUTH_REQUIRED instead of sending an unauthenticated request.
122
+ if (!this.apiKey) {
123
+ throw new SealMetricsAPIError(401, "AUTH_REQUIRED: a SealMetrics api_key is required for data tools. " +
124
+ "Provision a site first (provision_site) or set SEALMETRICS_API_KEY.");
125
+ }
126
+ const apiKey = this.apiKey;
127
+ const url = new URL(`${this.baseUrl}${path}`);
128
+ if (params) {
129
+ for (const [key, value] of Object.entries(params)) {
130
+ if (value === undefined)
131
+ continue;
132
+ if (Array.isArray(value)) {
133
+ // Multi-value: append each entry as a repeated query param
134
+ // (FastAPI deserializes `?k=a&k=b` into a list[str]).
135
+ for (const item of value) {
136
+ if (item !== undefined && item !== "") {
137
+ url.searchParams.append(key, item);
138
+ }
139
+ }
140
+ }
141
+ else if (value !== "") {
142
+ url.searchParams.set(key, value);
143
+ }
144
+ }
145
+ }
146
+ let lastError;
147
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
148
+ if (attempt > 0) {
149
+ const delay = RETRY_BASE_MS * Math.pow(2, attempt - 1);
150
+ await sleep(delay);
151
+ }
152
+ const controller = new AbortController();
153
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
154
+ try {
155
+ const response = await fetch(url.toString(), {
156
+ method: "GET",
157
+ headers: {
158
+ "X-API-Key": apiKey,
159
+ Accept: "application/json",
160
+ },
161
+ signal: controller.signal,
162
+ });
163
+ if (response.ok) {
164
+ const text = await response.text();
165
+ try {
166
+ return JSON.parse(text);
167
+ }
168
+ catch {
169
+ throw new SealMetricsAPIError(response.status, "API returned invalid JSON.", text.slice(0, 500));
170
+ }
171
+ }
172
+ const body = await response.text();
173
+ // Retry on 429 (respect Retry-After) or 5xx
174
+ if (response.status === 429 || response.status >= 500) {
175
+ if (response.status === 429) {
176
+ const retryAfter = parseRetryAfter(response.headers.get("Retry-After"));
177
+ if (retryAfter > 0) {
178
+ await sleep(retryAfter);
179
+ }
180
+ }
181
+ lastError = mapHttpError(response.status, body);
182
+ continue;
183
+ }
184
+ // Non-retryable error
185
+ const siteIdRaw = params?.["site_id"] ?? params?.["account_id"] ?? undefined;
186
+ const siteId = typeof siteIdRaw === "string" ? siteIdRaw : undefined;
187
+ throw mapHttpError(response.status, body, siteId);
188
+ }
189
+ catch (error) {
190
+ if (error instanceof SealMetricsAPIError) {
191
+ throw error;
192
+ }
193
+ if (error instanceof Error &&
194
+ error.name === "AbortError") {
195
+ lastError = new SealMetricsAPIError(0, "Request timed out after 30 seconds.");
196
+ continue;
197
+ }
198
+ lastError =
199
+ error instanceof Error
200
+ ? error
201
+ : new Error("Unknown error occurred");
202
+ // Network errors are retryable
203
+ continue;
204
+ }
205
+ finally {
206
+ clearTimeout(timeout);
207
+ }
208
+ }
209
+ throw (lastError ??
210
+ new SealMetricsAPIError(0, "Request failed after retries."));
211
+ }
212
+ }
213
+ function sleep(ms) {
214
+ return new Promise((resolve) => setTimeout(resolve, ms));
215
+ }
216
+ function parseRetryAfter(header) {
217
+ if (!header)
218
+ return 0;
219
+ const seconds = parseInt(header, 10);
220
+ if (!isNaN(seconds) && seconds > 0 && seconds <= 120) {
221
+ return seconds * 1000;
222
+ }
223
+ return 0;
224
+ }
225
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Compile-time constants for the MCP write-path.
3
+ *
4
+ * The provision key is **publishable** (Fase 1, RF-202 / RF-1001 / VAL-3301): it
5
+ * only grants attribution + rate-limited access to POST /provision and is
6
+ * revocable per channel without republishing. It is NEVER a TOKEN_SECRET/
7
+ * API_KEY_SECRET.
8
+ *
9
+ * This is the **dedicated `mcp`-channel key** (RF-3205 / PRE-2), distinct from the
10
+ * CLI's `npx` key and the `pk_provision_fallback`. A separate key lets us revoke
11
+ * the chat-provisioning channel on its own:
12
+ * UPDATE provision_keys SET is_active=FALSE WHERE channel='mcp'; (VAL-3601)
13
+ * without touching the CLI. Override with SEALMETRICS_PROVISION_KEY when targeting
14
+ * local/PRE (the PROD key doesn't exist there — use `pk_provision_fallback`).
15
+ */
16
+ export declare const EMBEDDED_PROVISION_KEY = "pk_mcp_69bb5a1ec96f2cc4d5dd77be";
17
+ /** Publishable fallback key seeded in non-prod DBs (local/PRE) but NOT in PROD. */
18
+ export declare const FALLBACK_PROVISION_KEY = "pk_provision_fallback";
19
+ /** Attribution channel sent as `install_source` on /provision (RF-3205 / RF-3604). */
20
+ export declare const INSTALL_SOURCE = "mcp";
21
+ /** True for local/PRE base URLs, where the fallback provision key is auto-used. */
22
+ export declare function isNonProdTarget(baseUrl: string): boolean;
23
+ /**
24
+ * Resolve the provision key to embed in /provision requests. Precedence:
25
+ * explicit env (SEALMETRICS_PROVISION_KEY) > local/PRE auto-fallback > embedded
26
+ * PROD mcp-channel key (mirrors the CLI's resolveProvisionKey).
27
+ */
28
+ export declare function resolveProvisionKey(baseUrl: string): string;
29
+ //# sourceMappingURL=embedded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedded.d.ts","sourceRoot":"","sources":["../src/embedded.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,oCAAoC,CAAC;AAExE,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D,sFAAsF;AACtF,eAAO,MAAM,cAAc,QAAQ,CAAC;AAEpC,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Compile-time constants for the MCP write-path.
3
+ *
4
+ * The provision key is **publishable** (Fase 1, RF-202 / RF-1001 / VAL-3301): it
5
+ * only grants attribution + rate-limited access to POST /provision and is
6
+ * revocable per channel without republishing. It is NEVER a TOKEN_SECRET/
7
+ * API_KEY_SECRET.
8
+ *
9
+ * This is the **dedicated `mcp`-channel key** (RF-3205 / PRE-2), distinct from the
10
+ * CLI's `npx` key and the `pk_provision_fallback`. A separate key lets us revoke
11
+ * the chat-provisioning channel on its own:
12
+ * UPDATE provision_keys SET is_active=FALSE WHERE channel='mcp'; (VAL-3601)
13
+ * without touching the CLI. Override with SEALMETRICS_PROVISION_KEY when targeting
14
+ * local/PRE (the PROD key doesn't exist there — use `pk_provision_fallback`).
15
+ */
16
+ export const EMBEDDED_PROVISION_KEY = "pk_mcp_69bb5a1ec96f2cc4d5dd77be";
17
+ /** Publishable fallback key seeded in non-prod DBs (local/PRE) but NOT in PROD. */
18
+ export const FALLBACK_PROVISION_KEY = "pk_provision_fallback";
19
+ /** Attribution channel sent as `install_source` on /provision (RF-3205 / RF-3604). */
20
+ export const INSTALL_SOURCE = "mcp";
21
+ /** True for local/PRE base URLs, where the fallback provision key is auto-used. */
22
+ export function isNonProdTarget(baseUrl) {
23
+ return /localhost|127\.0\.0\.1|pre\.sealmetrics\.com/.test(baseUrl);
24
+ }
25
+ /**
26
+ * Resolve the provision key to embed in /provision requests. Precedence:
27
+ * explicit env (SEALMETRICS_PROVISION_KEY) > local/PRE auto-fallback > embedded
28
+ * PROD mcp-channel key (mirrors the CLI's resolveProvisionKey).
29
+ */
30
+ export function resolveProvisionKey(baseUrl) {
31
+ if (process.env.SEALMETRICS_PROVISION_KEY)
32
+ return process.env.SEALMETRICS_PROVISION_KEY;
33
+ if (isNonProdTarget(baseUrl))
34
+ return FALLBACK_PROVISION_KEY;
35
+ return EMBEDDED_PROVISION_KEY;
36
+ }
37
+ //# sourceMappingURL=embedded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedded.js","sourceRoot":"","sources":["../src/embedded.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iCAAiC,CAAC;AAExE,mFAAmF;AACnF,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAE9D,sFAAsF;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AAEpC,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,8CAA8C,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACxF,IAAI,eAAe,CAAC,OAAO,CAAC;QAAE,OAAO,sBAAsB,CAAC;IAC5D,OAAO,sBAAsB,CAAC;AAChC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** SealMetrics API error with user-friendly message. */
2
+ export declare class SealMetricsAPIError extends Error {
3
+ readonly statusCode: number;
4
+ readonly userMessage: string;
5
+ readonly detail?: string | undefined;
6
+ constructor(statusCode: number, userMessage: string, detail?: string | undefined);
7
+ }
8
+ /** Map HTTP status codes to user-friendly error messages. */
9
+ export declare function mapHttpError(status: number, body: string, siteId?: string): SealMetricsAPIError;
10
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,UAAU,EAAE,MAAM;aAClB,WAAW,EAAE,MAAM;aACnB,MAAM,CAAC,EAAE,MAAM;gBAFf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,YAAA;CAKlC;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GACd,mBAAmB,CAkDrB"}
package/dist/errors.js ADDED
@@ -0,0 +1,55 @@
1
+ /** SealMetrics API error with user-friendly message. */
2
+ export class SealMetricsAPIError extends Error {
3
+ statusCode;
4
+ userMessage;
5
+ detail;
6
+ constructor(statusCode, userMessage, detail) {
7
+ super(userMessage);
8
+ this.statusCode = statusCode;
9
+ this.userMessage = userMessage;
10
+ this.detail = detail;
11
+ this.name = "SealMetricsAPIError";
12
+ }
13
+ }
14
+ /** Map HTTP status codes to user-friendly error messages. */
15
+ export function mapHttpError(status, body, siteId) {
16
+ switch (status) {
17
+ case 401:
18
+ return new SealMetricsAPIError(401, "Invalid API key. Generate one at Settings > API Tokens in your SealMetrics dashboard.", body);
19
+ case 403:
20
+ return new SealMetricsAPIError(403, siteId
21
+ ? `Access denied to site "${siteId}". Your API key may not have access to this site.`
22
+ : "Access denied. Your API key does not have the required permissions.", body);
23
+ case 404:
24
+ return new SealMetricsAPIError(404, siteId
25
+ ? `Site "${siteId}" not found. Use list_sites to see available sites.`
26
+ : "Resource not found.", body);
27
+ case 422:
28
+ return new SealMetricsAPIError(422, `Invalid request parameters: ${extractValidationMessage(body)}`, body);
29
+ case 429:
30
+ return new SealMetricsAPIError(429, "Rate limit exceeded. Please wait a moment before retrying.", body);
31
+ default:
32
+ if (status >= 500) {
33
+ return new SealMetricsAPIError(status, "SealMetrics API is temporarily unavailable. Please try again later.", body);
34
+ }
35
+ return new SealMetricsAPIError(status, `API request failed with status ${status}.`, body);
36
+ }
37
+ }
38
+ function extractValidationMessage(body) {
39
+ try {
40
+ const parsed = JSON.parse(body);
41
+ if (parsed.detail) {
42
+ if (Array.isArray(parsed.detail)) {
43
+ return parsed.detail
44
+ .map((d) => `${d.loc?.join(".") ?? "field"}: ${d.msg ?? "invalid"}`)
45
+ .join("; ");
46
+ }
47
+ return String(parsed.detail);
48
+ }
49
+ return body;
50
+ }
51
+ catch {
52
+ return body;
53
+ }
54
+ }
55
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAE1B;IACA;IACA;IAHlB,YACkB,UAAkB,EAClB,WAAmB,EACnB,MAAe;QAE/B,KAAK,CAAC,WAAW,CAAC,CAAC;QAJH,eAAU,GAAV,UAAU,CAAQ;QAClB,gBAAW,GAAX,WAAW,CAAQ;QACnB,WAAM,GAAN,MAAM,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,6DAA6D;AAC7D,MAAM,UAAU,YAAY,CAC1B,MAAc,EACd,IAAY,EACZ,MAAe;IAEf,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAC5B,GAAG,EACH,uFAAuF,EACvF,IAAI,CACL,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAC5B,GAAG,EACH,MAAM;gBACJ,CAAC,CAAC,0BAA0B,MAAM,mDAAmD;gBACrF,CAAC,CAAC,qEAAqE,EACzE,IAAI,CACL,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAC5B,GAAG,EACH,MAAM;gBACJ,CAAC,CAAC,SAAS,MAAM,qDAAqD;gBACtE,CAAC,CAAC,qBAAqB,EACzB,IAAI,CACL,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAC5B,GAAG,EACH,+BAA+B,wBAAwB,CAAC,IAAI,CAAC,EAAE,EAC/D,IAAI,CACL,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,IAAI,mBAAmB,CAC5B,GAAG,EACH,4DAA4D,EAC5D,IAAI,CACL,CAAC;QACJ;YACE,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;gBAClB,OAAO,IAAI,mBAAmB,CAC5B,MAAM,EACN,qEAAqE,EACrE,IAAI,CACL,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,mBAAmB,CAC5B,MAAM,EACN,kCAAkC,MAAM,GAAG,EAC3C,IAAI,CACL,CAAC;IACN,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAY;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACjC,OAAO,MAAM,CAAC,MAAM;qBACjB,GAAG,CACF,CAAC,CAAmC,EAAE,EAAE,CACtC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,GAAG,IAAI,SAAS,EAAE,CAC1D;qBACA,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;YACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,3 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * SealMetrics MCP Server
4
- *
5
- * A Model Context Protocol server that provides access to SealMetrics analytics data.
6
- * Allows AI assistants to query traffic, conversions, sales, and generate tracking pixels.
7
- */
8
2
  export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}