@markstiles/sitecore-search-mcp 1.0.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 (88) hide show
  1. package/AUTHENTICATION.md +337 -0
  2. package/LICENSE +21 -0
  3. package/README.md +606 -0
  4. package/dist/client/base-client.d.ts +34 -0
  5. package/dist/client/base-client.d.ts.map +1 -0
  6. package/dist/client/base-client.js +117 -0
  7. package/dist/client/base-client.js.map +1 -0
  8. package/dist/client/events-client.d.ts +77 -0
  9. package/dist/client/events-client.d.ts.map +1 -0
  10. package/dist/client/events-client.js +32 -0
  11. package/dist/client/events-client.js.map +1 -0
  12. package/dist/client/ingestion-client.d.ts +76 -0
  13. package/dist/client/ingestion-client.d.ts.map +1 -0
  14. package/dist/client/ingestion-client.js +73 -0
  15. package/dist/client/ingestion-client.js.map +1 -0
  16. package/dist/client/search-client.d.ts +97 -0
  17. package/dist/client/search-client.d.ts.map +1 -0
  18. package/dist/client/search-client.js +18 -0
  19. package/dist/client/search-client.js.map +1 -0
  20. package/dist/config.d.ts +99 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +75 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +312 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/tools/events/track-event.d.ts +394 -0
  29. package/dist/tools/events/track-event.d.ts.map +1 -0
  30. package/dist/tools/events/track-event.js +80 -0
  31. package/dist/tools/events/track-event.js.map +1 -0
  32. package/dist/tools/events/validate-event.d.ts +94 -0
  33. package/dist/tools/events/validate-event.d.ts.map +1 -0
  34. package/dist/tools/events/validate-event.js +51 -0
  35. package/dist/tools/events/validate-event.js.map +1 -0
  36. package/dist/tools/ingestion/check-status.d.ts +50 -0
  37. package/dist/tools/ingestion/check-status.d.ts.map +1 -0
  38. package/dist/tools/ingestion/check-status.js +27 -0
  39. package/dist/tools/ingestion/check-status.js.map +1 -0
  40. package/dist/tools/ingestion/create-document.d.ts +50 -0
  41. package/dist/tools/ingestion/create-document.d.ts.map +1 -0
  42. package/dist/tools/ingestion/create-document.js +27 -0
  43. package/dist/tools/ingestion/create-document.js.map +1 -0
  44. package/dist/tools/ingestion/delete-document.d.ts +50 -0
  45. package/dist/tools/ingestion/delete-document.d.ts.map +1 -0
  46. package/dist/tools/ingestion/delete-document.js +27 -0
  47. package/dist/tools/ingestion/delete-document.js.map +1 -0
  48. package/dist/tools/ingestion/ingest-from-source.d.ts +234 -0
  49. package/dist/tools/ingestion/ingest-from-source.d.ts.map +1 -0
  50. package/dist/tools/ingestion/ingest-from-source.js +48 -0
  51. package/dist/tools/ingestion/ingest-from-source.js.map +1 -0
  52. package/dist/tools/ingestion/update-document.d.ts +62 -0
  53. package/dist/tools/ingestion/update-document.d.ts.map +1 -0
  54. package/dist/tools/ingestion/update-document.js +34 -0
  55. package/dist/tools/ingestion/update-document.js.map +1 -0
  56. package/dist/tools/search/ai-search.d.ts +132 -0
  57. package/dist/tools/search/ai-search.d.ts.map +1 -0
  58. package/dist/tools/search/ai-search.js +65 -0
  59. package/dist/tools/search/ai-search.js.map +1 -0
  60. package/dist/tools/search/basic-search.d.ts +98 -0
  61. package/dist/tools/search/basic-search.d.ts.map +1 -0
  62. package/dist/tools/search/basic-search.js +51 -0
  63. package/dist/tools/search/basic-search.js.map +1 -0
  64. package/dist/tools/search/faceted-search.d.ts +114 -0
  65. package/dist/tools/search/faceted-search.d.ts.map +1 -0
  66. package/dist/tools/search/faceted-search.js +52 -0
  67. package/dist/tools/search/faceted-search.js.map +1 -0
  68. package/dist/tools/search/recommendations.d.ts +62 -0
  69. package/dist/tools/search/recommendations.d.ts.map +1 -0
  70. package/dist/tools/search/recommendations.js +50 -0
  71. package/dist/tools/search/recommendations.js.map +1 -0
  72. package/dist/utils/auth-manager.d.ts +60 -0
  73. package/dist/utils/auth-manager.d.ts.map +1 -0
  74. package/dist/utils/auth-manager.js +184 -0
  75. package/dist/utils/auth-manager.js.map +1 -0
  76. package/dist/utils/errors.d.ts +18 -0
  77. package/dist/utils/errors.d.ts.map +1 -0
  78. package/dist/utils/errors.js +58 -0
  79. package/dist/utils/errors.js.map +1 -0
  80. package/dist/utils/logger.d.ts +12 -0
  81. package/dist/utils/logger.d.ts.map +1 -0
  82. package/dist/utils/logger.js +50 -0
  83. package/dist/utils/logger.js.map +1 -0
  84. package/dist/utils/schema.d.ts +6 -0
  85. package/dist/utils/schema.d.ts.map +1 -0
  86. package/dist/utils/schema.js +14 -0
  87. package/dist/utils/schema.js.map +1 -0
  88. package/package.json +58 -0
@@ -0,0 +1,337 @@
1
+ # Authentication Implementation Guide
2
+
3
+ This document provides a detailed explanation of how authentication works in the Sitecore Search MCP Server.
4
+
5
+ ## Overview
6
+
7
+ The MCP server supports two authentication methods as per Sitecore Search API documentation:
8
+
9
+ 1. **Subdomain Authentication** (Recommended) - No explicit authentication needed
10
+ 2. **API Key Authentication** - Using API keys and automatically managed access tokens
11
+
12
+ ## Authentication Flow
13
+
14
+ ```
15
+ ┌─────────────┐
16
+ │ API Key │ (52-character secret from Sitecore)
17
+ └──────┬──────┘
18
+
19
+
20
+ ┌─────────────────┐
21
+ │ AuthManager │ Manages tokens and authentication
22
+ └────────┬────────┘
23
+
24
+ ├──► Generate Access Token (POST to auth endpoint)
25
+ │ └──► Valid for 1 day (configurable)
26
+
27
+ ├──► Refresh Access Token (PUT to auth endpoint)
28
+ │ └──► Using refresh token when access token expires
29
+
30
+ └──► Clear & Re-authenticate when refresh token expires
31
+ └──► Valid for 7 days (configurable)
32
+ ```
33
+
34
+ ## Key Components
35
+
36
+ ### 1. AuthManager (`src/utils/auth-manager.ts`)
37
+
38
+ The `AuthManager` class handles all authentication logic:
39
+
40
+ **Responsibilities:**
41
+ - Stores API key and authentication scopes
42
+ - Generates access tokens from API key
43
+ - Refreshes access tokens using refresh tokens
44
+ - Tracks token expiry and auto-refreshes before expiration
45
+ - Provides authentication headers for API requests
46
+
47
+ **Key Methods:**
48
+ - `getAuthHeader()`: Returns authentication header (API key or Bearer token)
49
+ - `generateTokensFromApiKey()`: POST request to get access & refresh tokens
50
+ - `refreshAccessToken()`: PUT request to refresh expired access token
51
+ - `clearTokens()`: Manually clear stored tokens
52
+
53
+ **Token Expiry:**
54
+ - Access token: 1 day default (86400000 ms)
55
+ - Refresh token: 7 days default (604800000 ms)
56
+ - 1-minute buffer before access token expiry to prevent race conditions
57
+
58
+ ### 2. BaseClient (`src/client/base-client.ts`)
59
+
60
+ Updated to support authentication via `AuthManager`:
61
+
62
+ **Changes:**
63
+ - Constructor now accepts optional `AuthManager` instance
64
+ - Request interceptor calls `authManager.getAuthHeader()` before each request
65
+ - Headers are automatically injected into all API requests
66
+
67
+ ### 3. Client Classes
68
+
69
+ All client classes now accept and pass `AuthManager`:
70
+
71
+ - `SearchClient` - For Search & Recommendation API
72
+ - `IngestionClient` - For Ingestion API
73
+ - `EventsClient` - For Events API
74
+
75
+ ### 4. Configuration (`src/config.ts`)
76
+
77
+ Extended to support authentication settings:
78
+
79
+ **New Configuration Fields:**
80
+ - `apiKey`: The 52-character API key from Sitecore
81
+ - `authScopes`: Array of scopes (`discover`, `event`, `ingestion`)
82
+ - `accessTokenExpiry`: Access token validity in milliseconds
83
+ - `refreshTokenExpiry`: Refresh token validity in milliseconds
84
+
85
+ ## API Key and Token Usage
86
+
87
+ ### Getting Your API Key
88
+
89
+ 1. Log in to Sitecore Search Customer Engagement Console (CEC)
90
+ 2. Navigate to **Developer Resources > API Access**
91
+ 3. Copy your 52-character API key
92
+ - Format: `01-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
93
+
94
+ ### Authentication Scopes
95
+
96
+ Each API key has assigned scopes that determine which APIs you can access:
97
+
98
+ - **`discover`** - Search and Recommendation API
99
+ - **`event`** - Events API
100
+ - **`ingestion`** - Ingestion API
101
+
102
+ If you call an API without the proper scope, you'll receive an HTTP 4XX error.
103
+
104
+ ### How Tokens Are Used
105
+
106
+ #### Search & Recommendation API
107
+ ```
108
+ Authorization: Bearer <access-token>
109
+ ```
110
+
111
+ #### Events API
112
+ ```
113
+ Authorization: Bearer <access-token>
114
+ ```
115
+
116
+ #### Ingestion API (Special Case)
117
+ ```
118
+ Authorization: <api-key>
119
+ ```
120
+ **Note:** The Ingestion API always uses the API key directly (no Bearer prefix), per Sitecore documentation.
121
+
122
+ ## Token Lifecycle
123
+
124
+ ### 1. Initial Request
125
+ ```typescript
126
+ // User makes first API call
127
+ searchClient.search(domainId, request)
128
+
129
+ // AuthManager checks for valid access token (none exists)
130
+ authManager.getAuthHeader()
131
+
132
+ // Generates new tokens from API key
133
+ POST https://api.rfksrv.com/account/1/access-token
134
+ Headers: { 'x-api-key': '01-...' }
135
+ Body: {
136
+ "scope": ["discover", "event", "ingestion"],
137
+ "accessExpiry": 86400000,
138
+ "refreshExpiry": 604800000
139
+ }
140
+
141
+ // Response contains tokens
142
+ {
143
+ "accessToken": "167dgw2vyy733",
144
+ "refreshToken": "1n555d88sss448",
145
+ "accessTokenExpiry": 86400000,
146
+ "refreshTokenExpiry": 604800000
147
+ }
148
+
149
+ // Tokens stored in memory with expiry timestamps
150
+ // Access token used in Authorization header
151
+ Authorization: Bearer 167dgw2vyy733
152
+ ```
153
+
154
+ ### 2. Subsequent Requests (Token Valid)
155
+ ```typescript
156
+ // User makes another API call
157
+ searchClient.search(domainId, request)
158
+
159
+ // AuthManager checks for valid access token (exists and not expired)
160
+ authManager.getAuthHeader()
161
+
162
+ // Returns existing access token
163
+ Authorization: Bearer 167dgw2vyy733
164
+ ```
165
+
166
+ ### 3. Access Token Expiration
167
+ ```typescript
168
+ // User makes API call after ~1 day
169
+ searchClient.search(domainId, request)
170
+
171
+ // AuthManager detects expired access token
172
+ authManager.getAuthHeader()
173
+
174
+ // Refreshes access token using refresh token
175
+ PUT https://api.rfksrv.com/account/1/access-token
176
+ Headers: { 'Authorization': 'Bearer 1n555d88sss448' }
177
+
178
+ // Response contains new access token
179
+ {
180
+ "accessToken": "187dgb6vmy733"
181
+ }
182
+
183
+ // New access token stored and used
184
+ Authorization: Bearer 187dgb6vmy733
185
+ ```
186
+
187
+ ### 4. Refresh Token Expiration
188
+ ```typescript
189
+ // User makes API call after ~7 days
190
+ searchClient.search(domainId, request)
191
+
192
+ // AuthManager detects expired refresh token
193
+ authManager.getAuthHeader()
194
+
195
+ // Clears token storage and generates new tokens from API key
196
+ // (Returns to step 1)
197
+ ```
198
+
199
+ ## Configuration Examples
200
+
201
+ ### Basic Configuration (Subdomain)
202
+ ```env
203
+ SITECORE_DOMAIN_ID=my-domain
204
+ # No API key needed - subdomain handles authentication
205
+ ```
206
+
207
+ ### API Key Authentication
208
+ ```env
209
+ SITECORE_DOMAIN_ID=my-domain
210
+ SITECORE_API_KEY=01-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
211
+ ```
212
+
213
+ ### Custom Token Expiry
214
+ ```env
215
+ SITECORE_DOMAIN_ID=my-domain
216
+ SITECORE_API_KEY=01-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
217
+ SITECORE_ACCESS_TOKEN_EXPIRY=43200000 # 12 hours
218
+ SITECORE_REFRESH_TOKEN_EXPIRY=259200000 # 3 days
219
+ ```
220
+
221
+ ### Limited Scopes
222
+ ```env
223
+ SITECORE_DOMAIN_ID=my-domain
224
+ SITECORE_API_KEY=01-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
225
+ SITECORE_AUTH_SCOPES=discover,event # Only Search and Events APIs
226
+ ```
227
+
228
+ ### Multiple Domains
229
+ ```env
230
+ SITECORE_DOMAINS_JSON={
231
+ "production": {
232
+ "apiKey": "01-prod-key...",
233
+ "authScopes": ["discover", "event", "ingestion"]
234
+ },
235
+ "staging": {
236
+ "apiKey": "01-stage-key...",
237
+ "authScopes": ["discover"],
238
+ "accessTokenExpiry": 3600000
239
+ }
240
+ }
241
+ SITECORE_DEFAULT_DOMAIN=production
242
+ ```
243
+
244
+ ## Request Flow in Code
245
+
246
+ ### Location: `src/index.ts`
247
+
248
+ ```typescript
249
+ // 1. Server creates AuthManager for each domain
250
+ getAuthManager(domainId) {
251
+ return new AuthManager(
252
+ apiKey,
253
+ authScopes,
254
+ accessTokenExpiry,
255
+ refreshTokenExpiry
256
+ );
257
+ }
258
+
259
+ // 2. AuthManager passed to clients
260
+ getSearchClient(domainId) {
261
+ const authManager = this.getAuthManager(domainId);
262
+ return new SearchClient(baseUrl, authManager);
263
+ }
264
+
265
+ // 3. Client uses AuthManager in interceptor
266
+ // src/client/base-client.ts
267
+ axios.interceptors.request.use(async (config) => {
268
+ const authHeaders = await authManager.getAuthHeader();
269
+ // Headers injected into request
270
+ });
271
+ ```
272
+
273
+ ## Debugging Authentication
274
+
275
+ ### Check Token Status
276
+ ```typescript
277
+ const authManager = new AuthManager(apiKey, scopes);
278
+ const status = authManager.getTokenStatus();
279
+ console.log(status);
280
+ // {
281
+ // hasTokens: true,
282
+ // accessTokenValid: true,
283
+ // refreshTokenValid: true
284
+ // }
285
+ ```
286
+
287
+ ### Clear Tokens Manually
288
+ ```typescript
289
+ authManager.clearTokens();
290
+ // Forces re-authentication on next request
291
+ ```
292
+
293
+ ### Enable Debug Logging
294
+ ```env
295
+ DEBUG=true
296
+ ```
297
+
298
+ This will log:
299
+ - Token generation requests
300
+ - Token refresh requests
301
+ - Token expiry warnings
302
+ - Authentication header injection
303
+
304
+ ## Security Considerations
305
+
306
+ 1. **API Key Storage**: Never commit API keys to version control
307
+ 2. **Environment Variables**: Use `.env` file (gitignored) for local development
308
+ 3. **Production**: Use secure environment variable management (e.g., Azure Key Vault, AWS Secrets Manager)
309
+ 4. **Token Storage**: Tokens are stored in memory only (not persisted to disk)
310
+ 5. **Token Lifetime**: Use shorter expiry times for sensitive environments
311
+ 6. **Scope Limitation**: Only assign necessary scopes to each API key
312
+
313
+ ## Troubleshooting
314
+
315
+ ### 401 Unauthorized
316
+ - Verify API key is correct (52 characters)
317
+ - Check that API key has required scopes
318
+ - Ensure tokens haven't expired (check logs)
319
+
320
+ ### 403 Forbidden
321
+ - API key doesn't have permission for requested operation
322
+ - Contact Sitecore support to adjust API key scopes
323
+
324
+ ### Token Refresh Failures
325
+ - Refresh token may have expired (>7 days)
326
+ - Server will automatically re-authenticate with API key
327
+ - Check network connectivity to auth endpoint
328
+
329
+ ### Ingestion API Not Working
330
+ - Ingestion API requires `ingestion` scope
331
+ - Ensure API key is being used (not access token)
332
+
333
+ ## References
334
+
335
+ - [Sitecore Search API Authentication](https://doc.sitecore.com/search/en/developers/search-developer-guide/api-authentication-and-authorization.html)
336
+ - [Get Access & Refresh Tokens](https://doc.sitecore.com/search/en/developers/search-developer-guide/get-an-access-token-and-a-refresh-token.html)
337
+ - [Add API Key or Token to Request](https://doc.sitecore.com/search/en/developers/search-developer-guide/add-an-api-key-or-access-token-to-a-request-header.html)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mark Stiles
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.