@expandai/mcp-server 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs ADDED
@@ -0,0 +1,814 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var ai = require('@effect/ai');
5
+ var platformNode = require('@effect/platform-node');
6
+ var effect = require('effect');
7
+ var platform = require('@effect/platform');
8
+ var HttpClientError = require('@effect/platform/HttpClientError');
9
+ var HttpClientRequest = require('@effect/platform/HttpClientRequest');
10
+ var HttpClientResponse = require('@effect/platform/HttpClientResponse');
11
+ var Data = require('effect/Data');
12
+ var Effect2 = require('effect/Effect');
13
+ var S = require('effect/Schema');
14
+
15
+ function _interopNamespace(e) {
16
+ if (e && e.__esModule) return e;
17
+ var n = Object.create(null);
18
+ if (e) {
19
+ Object.keys(e).forEach(function (k) {
20
+ if (k !== 'default') {
21
+ var d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: function () { return e[k]; }
25
+ });
26
+ }
27
+ });
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+
33
+ var HttpClientError__namespace = /*#__PURE__*/_interopNamespace(HttpClientError);
34
+ var HttpClientRequest__namespace = /*#__PURE__*/_interopNamespace(HttpClientRequest);
35
+ var HttpClientResponse__namespace = /*#__PURE__*/_interopNamespace(HttpClientResponse);
36
+ var Data__namespace = /*#__PURE__*/_interopNamespace(Data);
37
+ var Effect2__namespace = /*#__PURE__*/_interopNamespace(Effect2);
38
+ var S__namespace = /*#__PURE__*/_interopNamespace(S);
39
+
40
+ // package.json
41
+ var package_default = {
42
+ version: "0.1.1"};
43
+ var ExpandDocs = ai.McpServer.resource({
44
+ uri: "expand://about",
45
+ name: "About expand.ai",
46
+ description: "Key links for the expand.ai platform",
47
+ content: effect.Effect.succeed(`# expand.ai
48
+
49
+ - Website: https://expand.ai
50
+ - Quickstart: https://expand.ai/docs
51
+ - Dashboard: https://expand.ai/dashboard
52
+ `)
53
+ });
54
+ (class extends S__namespace.Struct({
55
+ url: S__namespace.String
56
+ }) {
57
+ });
58
+ var IssueTag = class extends S__namespace.Literal(
59
+ "Pointer",
60
+ "Unexpected",
61
+ "Missing",
62
+ "Composite",
63
+ "Refinement",
64
+ "Transformation",
65
+ "Type",
66
+ "Forbidden"
67
+ ) {
68
+ };
69
+ var PropertyKeyEnumTag = class extends S__namespace.Literal("symbol") {
70
+ };
71
+ var PropertyKey = class extends S__namespace.Union(
72
+ S__namespace.String,
73
+ S__namespace.Number,
74
+ /**
75
+ * an object to be decoded into a globally shared symbol
76
+ */
77
+ S__namespace.Struct({
78
+ _tag: PropertyKeyEnumTag,
79
+ key: S__namespace.String
80
+ })
81
+ ) {
82
+ };
83
+ var Issue = class extends S__namespace.Class("Issue")({
84
+ /**
85
+ * The tag identifying the type of parse issue
86
+ */
87
+ _tag: IssueTag,
88
+ /**
89
+ * The path to the property where the issue occurred
90
+ */
91
+ path: S__namespace.Array(PropertyKey),
92
+ /**
93
+ * A descriptive message explaining the issue
94
+ */
95
+ message: S__namespace.String
96
+ }) {
97
+ };
98
+ var HttpApiDecodeErrorTag = class extends S__namespace.Literal("HttpApiDecodeError") {
99
+ };
100
+ var HttpApiDecodeError = class extends S__namespace.Class("HttpApiDecodeError")({
101
+ issues: S__namespace.Array(Issue),
102
+ message: S__namespace.String,
103
+ _tag: HttpApiDecodeErrorTag
104
+ }) {
105
+ };
106
+ var UnauthorizedAccessTag = class extends S__namespace.Literal("UnauthorizedAccess") {
107
+ };
108
+ var UnauthorizedAccess = class extends S__namespace.Class("UnauthorizedAccess")({
109
+ _tag: UnauthorizedAccessTag
110
+ }) {
111
+ };
112
+ var AssetNotFoundTag = class extends S__namespace.Literal("AssetNotFound") {
113
+ };
114
+ var AssetNotFound = class extends S__namespace.Class("AssetNotFound")({
115
+ browserSessionId: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
116
+ filename: S__namespace.String,
117
+ _tag: AssetNotFoundTag
118
+ }) {
119
+ };
120
+ var AssetNotInWaczTag = class extends S__namespace.Literal("AssetNotInWacz") {
121
+ };
122
+ var AssetNotInWacz = class extends S__namespace.Class("AssetNotInWacz")({
123
+ url: S__namespace.String,
124
+ _tag: AssetNotInWaczTag
125
+ }) {
126
+ };
127
+ var AssetsGetByUrl404 = class extends S__namespace.Union(AssetNotFound, AssetNotInWacz) {
128
+ };
129
+ var AssetReadErrorTag = class extends S__namespace.Literal("AssetReadError") {
130
+ };
131
+ var AssetReadError = class extends S__namespace.Class("AssetReadError")({
132
+ browserSessionId: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
133
+ filename: S__namespace.String,
134
+ _tag: AssetReadErrorTag
135
+ }) {
136
+ };
137
+ var InvalidWaczFormatTag = class extends S__namespace.Literal("InvalidWaczFormat") {
138
+ };
139
+ var InvalidWaczFormat = class extends S__namespace.Class("InvalidWaczFormat")({
140
+ message: S__namespace.String,
141
+ _tag: InvalidWaczFormatTag
142
+ }) {
143
+ };
144
+ var AssetRetrievalErrorTag = class extends S__namespace.Literal("AssetRetrievalError") {
145
+ };
146
+ var AssetRetrievalError = class extends S__namespace.Class("AssetRetrievalError")({
147
+ browserSessionId: S__namespace.String,
148
+ url: S__namespace.String,
149
+ _tag: AssetRetrievalErrorTag
150
+ }) {
151
+ };
152
+ var AssetsGetByUrl500 = class extends S__namespace.Union(AssetReadError, InvalidWaczFormat, AssetRetrievalError) {
153
+ };
154
+ var CurlErrorInputMethod = class extends S__namespace.Literal(
155
+ "GET",
156
+ "POST",
157
+ "HEAD",
158
+ "PUT",
159
+ "DELETE",
160
+ "CONNECT",
161
+ "OPTIONS",
162
+ "TRACE",
163
+ "PATCH"
164
+ ) {
165
+ };
166
+ var CurlErrorTag = class extends S__namespace.Literal("CurlError") {
167
+ };
168
+ var CurlError = class extends S__namespace.Class("CurlError")({
169
+ status: S__namespace.Number,
170
+ input: S__namespace.Struct({
171
+ method: CurlErrorInputMethod,
172
+ url: S__namespace.String,
173
+ body: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
174
+ headers: S__namespace.optionalWith(S__namespace.Struct({}), { nullable: true }),
175
+ proxy: S__namespace.optionalWith(
176
+ S__namespace.Struct({
177
+ server: S__namespace.String,
178
+ username: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
179
+ password: S__namespace.optionalWith(S__namespace.String, { nullable: true })
180
+ }),
181
+ { nullable: true }
182
+ ),
183
+ timeout: S__namespace.optionalWith(S__namespace.Number, { nullable: true }),
184
+ connectTimeout: S__namespace.optionalWith(S__namespace.Number, { nullable: true })
185
+ }),
186
+ _tag: CurlErrorTag
187
+ }) {
188
+ };
189
+ var AssetListItem = class extends S__namespace.Class("AssetListItem")({
190
+ url: S__namespace.String,
191
+ mime: S__namespace.String,
192
+ status: S__namespace.Number
193
+ }) {
194
+ };
195
+ var AssetListResponse = class extends S__namespace.Class("AssetListResponse")({
196
+ browserSessionId: S__namespace.String,
197
+ assets: S__namespace.Array(AssetListItem)
198
+ }) {
199
+ };
200
+ var AssetsList500 = class extends S__namespace.Union(AssetReadError, InvalidWaczFormat) {
201
+ };
202
+ var URL = class extends S__namespace.String {
203
+ };
204
+ var SelectHtmlConfig = class extends S__namespace.Record({ key: S__namespace.String, value: S__namespace.Unknown }) {
205
+ };
206
+ var SelectMarkdownConfig = class extends S__namespace.Record({ key: S__namespace.String, value: S__namespace.Unknown }) {
207
+ };
208
+ var SelectScreenshotConfig = class extends S__namespace.Class("SelectScreenshotConfig")({
209
+ /**
210
+ * Whether to capture the full page including content below the fold
211
+ */
212
+ fullPage: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true })
213
+ }) {
214
+ };
215
+ var Trimmed = class extends S__namespace.String.pipe(S__namespace.pattern(/^\S[\s\S]*\S$|^\S$|^$/)) {
216
+ };
217
+ var Int2 = class extends S__namespace.Int {
218
+ };
219
+ (class extends S__namespace.Class("FetchRequest")({
220
+ url: URL,
221
+ /**
222
+ * Specifies which content formats to include in the response
223
+ */
224
+ select: S__namespace.optionalWith(
225
+ S__namespace.Struct({
226
+ html: S__namespace.optionalWith(
227
+ S__namespace.Union(
228
+ S__namespace.Boolean,
229
+ SelectHtmlConfig
230
+ ),
231
+ { nullable: true }
232
+ ),
233
+ /**
234
+ * Include markdown-formatted content in the response
235
+ */
236
+ markdown: S__namespace.optionalWith(
237
+ S__namespace.Union(
238
+ S__namespace.Boolean,
239
+ SelectMarkdownConfig
240
+ ),
241
+ { nullable: true }
242
+ ),
243
+ screenshot: S__namespace.optionalWith(
244
+ S__namespace.Union(
245
+ S__namespace.Boolean,
246
+ SelectScreenshotConfig
247
+ ),
248
+ { nullable: true }
249
+ ),
250
+ summary: S__namespace.optionalWith(
251
+ S__namespace.Union(
252
+ S__namespace.Boolean,
253
+ /**
254
+ * Options for AI-powered page summarization
255
+ */
256
+ S__namespace.Struct({
257
+ /**
258
+ * Custom prompt for AI summarization (max 5000 characters)
259
+ */
260
+ prompt: S__namespace.optionalWith(S__namespace.String.pipe(S__namespace.maxLength(5e3)), {
261
+ nullable: true,
262
+ default: () => "You are a helpful assistant that summarizes web page content.\nGiven the markdown content of a web page, provide a clear and concise summary.\nFocus on the main points and key information.\nKeep the summary informative but brief."
263
+ })
264
+ })
265
+ ),
266
+ { nullable: true }
267
+ ),
268
+ /**
269
+ * Options for extracting relevant snippets from page content using semantic search
270
+ */
271
+ snippets: S__namespace.optionalWith(
272
+ S__namespace.Struct({
273
+ /**
274
+ * Query to find relevant content snippets from the page (required, non-empty)
275
+ */
276
+ query: Trimmed,
277
+ /**
278
+ * Maximum number of snippets to return (1-50)
279
+ */
280
+ maxSnippets: S__namespace.optionalWith(Int2, { nullable: true, default: () => 5 }),
281
+ /**
282
+ * Minimum relevance score threshold (0-1). Snippets below this score are filtered out.
283
+ */
284
+ minScore: S__namespace.optionalWith(S__namespace.Number.pipe(S__namespace.greaterThanOrEqualTo(0), S__namespace.lessThanOrEqualTo(1)), {
285
+ nullable: true,
286
+ default: () => 0.5
287
+ }),
288
+ /**
289
+ * Target snippet size in characters (100-2000)
290
+ */
291
+ targetSnippetSize: S__namespace.optionalWith(Int2, { nullable: true, default: () => 384 })
292
+ }),
293
+ { nullable: true }
294
+ ),
295
+ /**
296
+ * Include page metadata in the response
297
+ */
298
+ meta: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => true }),
299
+ /**
300
+ * Configure response info options (headers inclusion)
301
+ */
302
+ response: S__namespace.optionalWith(
303
+ S__namespace.Struct({
304
+ /**
305
+ * Whether to include HTTP response headers
306
+ */
307
+ includeHeaders: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
308
+ }),
309
+ { nullable: true }
310
+ )
311
+ }),
312
+ { nullable: true }
313
+ ),
314
+ /**
315
+ * Configuration options for browser behavior during the fetch
316
+ */
317
+ browserConfig: S__namespace.optionalWith(
318
+ S__namespace.Struct({
319
+ /**
320
+ * Whether to scroll the entire page to capture lazy-loaded content
321
+ */
322
+ scrollFullPage: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
323
+ }),
324
+ { nullable: true }
325
+ )
326
+ }) {
327
+ });
328
+ var ResponseInfo = class extends S__namespace.Class("ResponseInfo")({
329
+ /**
330
+ * The URL that was fetched
331
+ */
332
+ url: S__namespace.String,
333
+ /**
334
+ * HTTP status code of the response
335
+ */
336
+ statusCode: S__namespace.Number,
337
+ /**
338
+ * Response headers from the fetch operation (keys are lower-cased HTTP header names)
339
+ */
340
+ headers: S__namespace.optionalWith(S__namespace.Struct({}), { nullable: true })
341
+ }) {
342
+ };
343
+ var IconMeta = class extends S__namespace.Class("IconMeta")({
344
+ /**
345
+ * Icon URL or path
346
+ */
347
+ href: S__namespace.String,
348
+ /**
349
+ * Link relationship type
350
+ */
351
+ rel: S__namespace.String,
352
+ /**
353
+ * MIME type of the icon
354
+ */
355
+ type: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
356
+ /**
357
+ * Icon dimensions
358
+ */
359
+ sizes: S__namespace.optionalWith(S__namespace.String, { nullable: true })
360
+ }) {
361
+ };
362
+ var OgImage = class extends S__namespace.Class("OgImage")({
363
+ /**
364
+ * Image URL
365
+ */
366
+ url: S__namespace.String,
367
+ /**
368
+ * Image width in pixels
369
+ */
370
+ width: S__namespace.optionalWith(S__namespace.Number, { nullable: true }),
371
+ /**
372
+ * Image height in pixels
373
+ */
374
+ height: S__namespace.optionalWith(S__namespace.Number, { nullable: true }),
375
+ /**
376
+ * Image alt text for accessibility
377
+ */
378
+ alt: S__namespace.optionalWith(S__namespace.String, { nullable: true })
379
+ }) {
380
+ };
381
+ var OpenGraphMeta = class extends S__namespace.Class("OpenGraphMeta")({
382
+ /**
383
+ * Open Graph title (og:title)
384
+ */
385
+ title: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
386
+ /**
387
+ * Open Graph description (og:description)
388
+ */
389
+ description: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
390
+ /**
391
+ * Open Graph type (og:type) - website, article, product, etc.
392
+ */
393
+ type: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
394
+ /**
395
+ * Canonical URL for the content (og:url)
396
+ */
397
+ url: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
398
+ /**
399
+ * Site name (og:site_name)
400
+ */
401
+ siteName: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
402
+ /**
403
+ * Locale in language_TERRITORY format (og:locale)
404
+ */
405
+ locale: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
406
+ /**
407
+ * Open Graph images (og:image and related properties)
408
+ */
409
+ images: S__namespace.optionalWith(S__namespace.Array(OgImage), { nullable: true })
410
+ }) {
411
+ };
412
+ var TwitterCardMeta = class extends S__namespace.Class("TwitterCardMeta")({
413
+ /**
414
+ * Twitter card type (twitter:card)
415
+ */
416
+ card: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
417
+ /**
418
+ * Twitter @username of the website (twitter:site)
419
+ */
420
+ site: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
421
+ /**
422
+ * Twitter @username of content creator (twitter:creator)
423
+ */
424
+ creator: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
425
+ /**
426
+ * Title for Twitter card (twitter:title)
427
+ */
428
+ title: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
429
+ /**
430
+ * Description for Twitter card (twitter:description)
431
+ */
432
+ description: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
433
+ /**
434
+ * Image URL for Twitter card (twitter:image)
435
+ */
436
+ image: S__namespace.optionalWith(S__namespace.String, { nullable: true })
437
+ }) {
438
+ };
439
+ var PageMeta = class extends S__namespace.Class("PageMeta")({
440
+ /**
441
+ * Page title from <title> tag
442
+ */
443
+ title: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
444
+ /**
445
+ * Meta description from <meta name="description">
446
+ */
447
+ description: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
448
+ /**
449
+ * Canonical URL from <link rel="canonical">
450
+ */
451
+ canonicalUrl: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
452
+ /**
453
+ * Page language from <html lang="...">
454
+ */
455
+ language: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
456
+ /**
457
+ * Character encoding from <meta charset="...">
458
+ */
459
+ charset: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
460
+ /**
461
+ * Primary favicon URL (first icon found)
462
+ */
463
+ favicon: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
464
+ /**
465
+ * All icon links (favicons, apple-touch-icons, etc.)
466
+ */
467
+ icons: S__namespace.optionalWith(S__namespace.Array(IconMeta), { nullable: true }),
468
+ /**
469
+ * Open Graph metadata from og:* meta tags
470
+ */
471
+ openGraph: S__namespace.optionalWith(OpenGraphMeta, { nullable: true }),
472
+ /**
473
+ * Twitter Card metadata from twitter:* meta tags
474
+ */
475
+ twitter: S__namespace.optionalWith(TwitterCardMeta, { nullable: true })
476
+ }) {
477
+ };
478
+ var FetchData = class extends S__namespace.Class("FetchData")({
479
+ response: ResponseInfo,
480
+ /**
481
+ * Page metadata extracted from HTML head (title, description, Open Graph, Twitter Card, icons)
482
+ */
483
+ meta: S__namespace.optionalWith(PageMeta, { nullable: true }),
484
+ /**
485
+ * The HTML content of the fetched page
486
+ */
487
+ html: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
488
+ /**
489
+ * The markdown-formatted content extracted from the page
490
+ */
491
+ markdown: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
492
+ /**
493
+ * Base64-encoded data URI of the screenshot image
494
+ */
495
+ screenshot: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
496
+ /**
497
+ * AI-generated summary of the page content
498
+ */
499
+ summary: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
500
+ /**
501
+ * Relevant snippets extracted from the page based on the search query
502
+ */
503
+ snippets: S__namespace.optionalWith(
504
+ S__namespace.Array(
505
+ S__namespace.Struct({
506
+ /**
507
+ * Type identifier for TextPart compatibility
508
+ */
509
+ type: S__namespace.optionalWith(S__namespace.Literal("text"), { nullable: true, default: () => "text" }),
510
+ /**
511
+ * The text content of the snippet
512
+ */
513
+ text: S__namespace.String,
514
+ /**
515
+ * Relevance score from the reranker (0-1)
516
+ */
517
+ score: S__namespace.Number,
518
+ /**
519
+ * Original chunk index
520
+ */
521
+ index: S__namespace.Number
522
+ })
523
+ ),
524
+ { nullable: true }
525
+ )
526
+ }) {
527
+ };
528
+ var FetchResult = class extends S__namespace.Class("FetchResult")({
529
+ data: FetchData
530
+ }) {
531
+ };
532
+ var FetchErrorTag = class extends S__namespace.Literal("FetchError") {
533
+ };
534
+ var FetchError = class extends S__namespace.Class("FetchError")({
535
+ _tag: FetchErrorTag
536
+ }) {
537
+ };
538
+ (class extends S__namespace.Class("MarkdownRequest")({
539
+ /**
540
+ * The URL to fetch markdown content from
541
+ */
542
+ url: S__namespace.String,
543
+ /**
544
+ * Configuration options for browser behavior during the fetch
545
+ */
546
+ browserConfig: S__namespace.optionalWith(
547
+ S__namespace.Struct({
548
+ /**
549
+ * Whether to scroll the entire page to capture lazy-loaded content
550
+ */
551
+ scrollFullPage: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
552
+ }),
553
+ { nullable: true }
554
+ )
555
+ }) {
556
+ });
557
+ var InvalidAssetHashTag = class extends S__namespace.Literal("InvalidAssetHash") {
558
+ };
559
+ var InvalidAssetHash = class extends S__namespace.Class("InvalidAssetHash")({
560
+ message: S__namespace.String,
561
+ _tag: InvalidAssetHashTag
562
+ }) {
563
+ };
564
+ var AssetNotFoundInHarTag = class extends S__namespace.Literal("AssetNotFoundInHar") {
565
+ };
566
+ var AssetNotFoundInHar = class extends S__namespace.Class("AssetNotFoundInHar")({
567
+ snapshotDir: S__namespace.String,
568
+ assetUrl: S__namespace.String,
569
+ _tag: AssetNotFoundInHarTag
570
+ }) {
571
+ };
572
+ var HarNotFoundTag = class extends S__namespace.Literal("HarNotFound") {
573
+ };
574
+ var HarNotFound = class extends S__namespace.Class("HarNotFound")({
575
+ snapshotDir: S__namespace.String,
576
+ _tag: HarNotFoundTag
577
+ }) {
578
+ };
579
+ var AssetFetchErrorTag = class extends S__namespace.Literal("AssetFetchError") {
580
+ };
581
+ var AssetFetchError = class extends S__namespace.Class("AssetFetchError")({
582
+ snapshotDir: S__namespace.String,
583
+ assetUrl: S__namespace.String,
584
+ _tag: AssetFetchErrorTag
585
+ }) {
586
+ };
587
+ var LocalAssetsGetAsset500 = class extends S__namespace.Union(
588
+ InvalidAssetHash,
589
+ AssetNotFoundInHar,
590
+ HarNotFound,
591
+ AssetFetchError
592
+ ) {
593
+ };
594
+ var make = (httpClient, options = {}) => {
595
+ const unexpectedStatus = (response) => Effect2__namespace.flatMap(
596
+ Effect2__namespace.orElseSucceed(response.json, () => "Unexpected status code"),
597
+ (description) => Effect2__namespace.fail(
598
+ new HttpClientError__namespace.ResponseError({
599
+ request: response.request,
600
+ response,
601
+ reason: "StatusCode",
602
+ description: typeof description === "string" ? description : JSON.stringify(description)
603
+ })
604
+ )
605
+ );
606
+ const withResponse = options.transformClient ? (f) => (request) => Effect2__namespace.flatMap(
607
+ Effect2__namespace.flatMap(options.transformClient(httpClient), (client) => client.execute(request)),
608
+ f
609
+ ) : (f) => (request) => Effect2__namespace.flatMap(httpClient.execute(request), f);
610
+ const decodeSuccess = (schema) => (response) => HttpClientResponse__namespace.schemaBodyJson(schema)(response);
611
+ const decodeError = (tag, schema) => (response) => Effect2__namespace.flatMap(
612
+ HttpClientResponse__namespace.schemaBodyJson(schema)(response),
613
+ (cause) => Effect2__namespace.fail(ClientError(tag, cause, response))
614
+ );
615
+ return {
616
+ httpClient,
617
+ assetsGetByUrl: (browserSessionId, options2) => HttpClientRequest__namespace.get(`/v1/assets/${browserSessionId}/asset`).pipe(
618
+ HttpClientRequest__namespace.setUrlParams({ url: options2?.["url"] }),
619
+ withResponse(
620
+ HttpClientResponse__namespace.matchStatus({
621
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
622
+ "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
623
+ "404": decodeError("AssetsGetByUrl404", AssetsGetByUrl404),
624
+ "500": decodeError("AssetsGetByUrl500", AssetsGetByUrl500),
625
+ "502": decodeError("CurlError", CurlError),
626
+ "429": () => Effect2__namespace.void,
627
+ orElse: unexpectedStatus
628
+ })
629
+ )
630
+ ),
631
+ assetsList: (browserSessionId) => HttpClientRequest__namespace.get(`/v1/assets/${browserSessionId}`).pipe(
632
+ withResponse(
633
+ HttpClientResponse__namespace.matchStatus({
634
+ "2xx": decodeSuccess(AssetListResponse),
635
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
636
+ "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
637
+ "404": decodeError("AssetNotFound", AssetNotFound),
638
+ "500": decodeError("AssetsList500", AssetsList500),
639
+ "429": () => Effect2__namespace.void,
640
+ orElse: unexpectedStatus
641
+ })
642
+ )
643
+ ),
644
+ fetch: (options2) => HttpClientRequest__namespace.post(`/v1/fetch`).pipe(
645
+ HttpClientRequest__namespace.bodyUnsafeJson(options2),
646
+ withResponse(
647
+ HttpClientResponse__namespace.matchStatus({
648
+ "2xx": decodeSuccess(FetchResult),
649
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
650
+ "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
651
+ "500": decodeError("FetchError", FetchError),
652
+ "429": () => Effect2__namespace.void,
653
+ orElse: unexpectedStatus
654
+ })
655
+ )
656
+ ),
657
+ markdown: (options2) => HttpClientRequest__namespace.post(`/v1/fetch/markdown`).pipe(
658
+ HttpClientRequest__namespace.bodyUnsafeJson(options2),
659
+ withResponse(
660
+ HttpClientResponse__namespace.matchStatus({
661
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
662
+ "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
663
+ "500": decodeError("FetchError", FetchError),
664
+ "429": () => Effect2__namespace.void,
665
+ orElse: unexpectedStatus
666
+ })
667
+ )
668
+ ),
669
+ localAssetsGetAsset: (assetHash) => HttpClientRequest__namespace.get(`/local-asset/${assetHash}`).pipe(
670
+ withResponse(
671
+ HttpClientResponse__namespace.matchStatus({
672
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
673
+ "500": decodeError("LocalAssetsGetAsset500", LocalAssetsGetAsset500),
674
+ "204": () => Effect2__namespace.void,
675
+ "429": () => Effect2__namespace.void,
676
+ orElse: unexpectedStatus
677
+ })
678
+ )
679
+ )
680
+ };
681
+ };
682
+ var ClientErrorImpl = class extends Data__namespace.Error {
683
+ };
684
+ var ClientError = (tag, cause, response) => new ClientErrorImpl({
685
+ _tag: tag,
686
+ cause,
687
+ response,
688
+ request: response.request
689
+ });
690
+
691
+ // src/ExpandClient.ts
692
+ var ExpandConfig = effect.Config.all({
693
+ apiKey: effect.Config.redacted("EXPAND_API_KEY"),
694
+ baseUrl: effect.Config.withDefault(effect.Config.string("EXPAND_BASE_URL"), "https://api.expand.ai")
695
+ });
696
+ var ExpandClient = class extends effect.Effect.Service()("ExpandClient", {
697
+ dependencies: [],
698
+ scoped: effect.Effect.gen(function* () {
699
+ const config = yield* ExpandConfig;
700
+ const httpClient = yield* platform.HttpClient.HttpClient;
701
+ return make(httpClient, {
702
+ transformClient: (client) => effect.Effect.succeed(
703
+ client.pipe(
704
+ platform.HttpClient.mapRequest(platform.HttpClientRequest.prependUrl(config.baseUrl)),
705
+ platform.HttpClient.mapRequest(platform.HttpClientRequest.setHeader("x-expand-api-key", effect.Redacted.value(config.apiKey)))
706
+ )
707
+ )
708
+ });
709
+ })
710
+ }) {
711
+ };
712
+ var SnippetsFormat = class extends effect.Schema.Class("SnippetsFormat")({
713
+ query: effect.Schema.String.annotations({
714
+ description: "Query to find relevant content snippets from the page"
715
+ }),
716
+ maxSnippets: effect.Schema.optional(
717
+ effect.Schema.Int.pipe(effect.Schema.greaterThanOrEqualTo(1), effect.Schema.lessThanOrEqualTo(50))
718
+ ).annotations({
719
+ description: "Maximum number of snippets to return (1-50, default: 5)"
720
+ }),
721
+ targetSnippetSize: effect.Schema.optional(
722
+ effect.Schema.Int.pipe(effect.Schema.greaterThanOrEqualTo(100), effect.Schema.lessThanOrEqualTo(2e3))
723
+ ).annotations({
724
+ description: "Target snippet size in characters (100-2000, default: 384)"
725
+ })
726
+ }) {
727
+ };
728
+ var Format = effect.Schema.Union(
729
+ effect.Schema.Literal("markdown").annotations({
730
+ description: "Return as cleaned markdown content"
731
+ }),
732
+ effect.Schema.Literal("html").annotations({
733
+ description: "Return as raw HTML content"
734
+ }),
735
+ effect.Schema.Literal("summary").annotations({
736
+ description: "Return AI-generated summary of the page content"
737
+ }),
738
+ SnippetsFormat
739
+ ).annotations({
740
+ description: "Output format for the fetched content"
741
+ });
742
+ var FetchParams = class extends effect.Schema.Class("FetchParams")({
743
+ url: effect.Schema.String.annotations({
744
+ description: "The URL to fetch content from"
745
+ }),
746
+ format: Format,
747
+ includeMeta: effect.Schema.Boolean.annotations({
748
+ description: "Whether to include page meta tags in the response"
749
+ })
750
+ }) {
751
+ };
752
+ var FetchResult2 = class extends effect.Schema.Class("FetchResult")({
753
+ content: effect.Schema.String,
754
+ url: effect.Schema.String,
755
+ meta: effect.Schema.optional(PageMeta)
756
+ }) {
757
+ };
758
+ var FetchTool = ai.Tool.make("fetch", {
759
+ description: "Fetch and extract content from any URL.",
760
+ parameters: FetchParams.fields,
761
+ success: FetchResult2
762
+ }).annotate(ai.Tool.Readonly, true).annotate(ai.Tool.Destructive, false);
763
+ var Fetch = class extends effect.Effect.Service()("Fetch", {
764
+ dependencies: [ExpandClient.Default],
765
+ scoped: effect.Effect.gen(function* () {
766
+ const client = yield* ExpandClient;
767
+ const fetch = effect.Effect.fn("Fetch.fetch")(function* ({ url, format, includeMeta }) {
768
+ const result = yield* client.fetch({
769
+ url,
770
+ select: {
771
+ markdown: format === "markdown",
772
+ html: format === "html",
773
+ summary: format === "summary",
774
+ snippets: format instanceof SnippetsFormat ? { ...format } : void 0,
775
+ meta: includeMeta
776
+ }
777
+ });
778
+ const content = result.data.markdown ?? result.data.html ?? result.data.summary ?? result.data.snippets?.map((snippet) => `${snippet.text} (Score: ${snippet.score})`).join("\n") ?? "";
779
+ return new FetchResult2({
780
+ content,
781
+ url: result.data.response.url,
782
+ meta: result.data.meta
783
+ });
784
+ }, effect.Effect.orDie);
785
+ return { fetch };
786
+ })
787
+ }) {
788
+ };
789
+
790
+ // src/tools/index.ts
791
+ var toolkit = ai.Toolkit.make(FetchTool);
792
+ var ToolkitLayer = toolkit.toLayer(
793
+ effect.Effect.gen(function* () {
794
+ const fetchService = yield* Fetch;
795
+ return toolkit.of({
796
+ fetch: fetchService.fetch
797
+ });
798
+ })
799
+ ).pipe(effect.Layer.provide(Fetch.Default), effect.Layer.provide(ExpandClient.Default), effect.Layer.provide(platformNode.NodeHttpClient.layerUndici));
800
+ var ExpandTools = ai.McpServer.toolkit(toolkit).pipe(effect.Layer.provide(ToolkitLayer));
801
+
802
+ // src/main.ts
803
+ var enableDocs = effect.Config.withDefault(effect.Config.boolean("EXPAND_ENABLE_DOCS"), () => false);
804
+ var program = effect.Effect.gen(function* () {
805
+ const docsEnabled = yield* enableDocs;
806
+ const layers = docsEnabled ? effect.Layer.mergeAll(ExpandTools, ExpandDocs) : ExpandTools;
807
+ yield* ai.McpServer.layerStdio({
808
+ name: "expandai-mcp-server",
809
+ version: package_default.version,
810
+ stdin: platformNode.NodeStream.stdin,
811
+ stdout: platformNode.NodeSink.stdout
812
+ }).pipe(effect.Layer.provide(layers), effect.Layer.provide(effect.Logger.minimumLogLevel(effect.LogLevel.None)), effect.Layer.launch);
813
+ });
814
+ program.pipe(platformNode.NodeRuntime.runMain);