@expandai/mcp-server 0.1.3 → 0.2.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/dist/Server.cjs CHANGED
@@ -40,7 +40,7 @@ var S__namespace = /*#__PURE__*/_interopNamespace(S);
40
40
 
41
41
  // package.json
42
42
  var package_default = {
43
- version: "0.1.3"};
43
+ version: "0.2.0"};
44
44
  var ExpandDocs = ai.McpServer.resource({
45
45
  uri: "expand://about",
46
46
  name: "About expand.ai",
@@ -104,10 +104,14 @@ var HttpApiDecodeError = class extends S__namespace.Class("HttpApiDecodeError")(
104
104
  _tag: HttpApiDecodeErrorTag
105
105
  }) {
106
106
  };
107
- var UnauthorizedAccessTag = class extends S__namespace.Literal("UnauthorizedAccess") {
107
+ var AuthFailedReason = class extends S__namespace.Literal("InvalidApiKey", "InvalidToken", "InvalidSession", "InvalidTenant") {
108
108
  };
109
- var UnauthorizedAccess = class extends S__namespace.Class("UnauthorizedAccess")({
110
- _tag: UnauthorizedAccessTag
109
+ var AuthFailedTag = class extends S__namespace.Literal("AuthFailed") {
110
+ };
111
+ var AuthFailed = class extends S__namespace.Class("AuthFailed")({
112
+ reason: AuthFailedReason,
113
+ description: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
114
+ _tag: AuthFailedTag
111
115
  }) {
112
116
  };
113
117
  var AssetNotFoundTag = class extends S__namespace.Literal("AssetNotFound") {
@@ -150,7 +154,13 @@ var AssetRetrievalError = class extends S__namespace.Class("AssetRetrievalError"
150
154
  _tag: AssetRetrievalErrorTag
151
155
  }) {
152
156
  };
153
- var AssetsGetByUrl500 = class extends S__namespace.Union(AssetReadError, InvalidWaczFormat, AssetRetrievalError) {
157
+ var InternalErrorTag = class extends S__namespace.Literal("InternalError") {
158
+ };
159
+ var InternalError = class extends S__namespace.Class("InternalError")({
160
+ _tag: InternalErrorTag
161
+ }) {
162
+ };
163
+ var AssetsGetByUrl500 = class extends S__namespace.Union(InternalError, AssetReadError, InvalidWaczFormat, AssetRetrievalError) {
154
164
  };
155
165
  var CurlErrorInputMethod = class extends S__namespace.Literal(
156
166
  "GET",
@@ -164,6 +174,8 @@ var CurlErrorInputMethod = class extends S__namespace.Literal(
164
174
  "PATCH"
165
175
  ) {
166
176
  };
177
+ var URL = class extends S__namespace.String {
178
+ };
167
179
  var CurlErrorTag = class extends S__namespace.Literal("CurlError") {
168
180
  };
169
181
  var CurlError = class extends S__namespace.Class("CurlError")({
@@ -174,11 +186,14 @@ var CurlError = class extends S__namespace.Class("CurlError")({
174
186
  body: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
175
187
  headers: S__namespace.optionalWith(S__namespace.Struct({}), { nullable: true }),
176
188
  proxy: S__namespace.optionalWith(
177
- S__namespace.Struct({
178
- server: S__namespace.String,
179
- username: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
180
- password: S__namespace.optionalWith(S__namespace.String, { nullable: true })
181
- }),
189
+ S__namespace.Union(
190
+ S__namespace.Struct({
191
+ server: S__namespace.String,
192
+ username: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
193
+ password: S__namespace.optionalWith(S__namespace.String, { nullable: true })
194
+ }),
195
+ URL
196
+ ),
182
197
  { nullable: true }
183
198
  ),
184
199
  timeout: S__namespace.optionalWith(S__namespace.Number, { nullable: true }),
@@ -198,9 +213,20 @@ var AssetListResponse = class extends S__namespace.Class("AssetListResponse")({
198
213
  assets: S__namespace.Array(AssetListItem)
199
214
  }) {
200
215
  };
201
- var AssetsList500 = class extends S__namespace.Union(AssetReadError, InvalidWaczFormat) {
216
+ var AssetsList500 = class extends S__namespace.Union(InternalError, AssetReadError, InvalidWaczFormat) {
202
217
  };
203
- var URL = class extends S__namespace.String {
218
+ var AssetsGetWacz500 = class extends S__namespace.Union(InternalError, AssetReadError) {
219
+ };
220
+ var DatasetNotFoundTag = class extends S__namespace.Literal("DatasetNotFound") {
221
+ };
222
+ var DatasetNotFound = class extends S__namespace.Class("DatasetNotFound")({
223
+ path: S__namespace.String,
224
+ _tag: DatasetNotFoundTag
225
+ }) {
226
+ };
227
+ var DatasetsGetDataset500 = class extends S__namespace.Union(InternalError, DatasetNotFound) {
228
+ };
229
+ var DatasetsGetFinetuneDataset500 = class extends S__namespace.Union(InternalError, DatasetNotFound) {
204
230
  };
205
231
  var SelectHtmlConfig = class extends S__namespace.Record({ key: S__namespace.String, value: S__namespace.Unknown }) {
206
232
  };
@@ -293,6 +319,29 @@ var Int2 = class extends S__namespace.Int {
293
319
  }),
294
320
  { nullable: true }
295
321
  ),
322
+ links: S__namespace.optionalWith(
323
+ S__namespace.Union(
324
+ S__namespace.Boolean,
325
+ /**
326
+ * Options for customizing link extraction from the page
327
+ */
328
+ S__namespace.Struct({
329
+ /**
330
+ * Only include links from the same domain as the fetched URL
331
+ */
332
+ sameDomainOnly: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => true }),
333
+ /**
334
+ * Regex patterns - only include links matching at least one pattern
335
+ */
336
+ includePatterns: S__namespace.optionalWith(S__namespace.Array(S__namespace.String), { nullable: true }),
337
+ /**
338
+ * Regex patterns - exclude links matching any pattern
339
+ */
340
+ excludePatterns: S__namespace.optionalWith(S__namespace.Array(S__namespace.String), { nullable: true })
341
+ })
342
+ ),
343
+ { nullable: true }
344
+ ),
296
345
  /**
297
346
  * Include page metadata in the response
298
347
  */
@@ -308,7 +357,15 @@ var Int2 = class extends S__namespace.Int {
308
357
  includeHeaders: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
309
358
  }),
310
359
  { nullable: true }
311
- )
360
+ ),
361
+ /**
362
+ * Include pruned JSON in the response (opt-in)
363
+ */
364
+ json: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false }),
365
+ /**
366
+ * Set to true to include extracted links and sidebar content
367
+ */
368
+ appendix: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true })
312
369
  }),
313
370
  { nullable: true }
314
371
  ),
@@ -476,58 +533,75 @@ var PageMeta = class extends S__namespace.Class("PageMeta")({
476
533
  twitter: S__namespace.optionalWith(TwitterCardMeta, { nullable: true })
477
534
  }) {
478
535
  };
479
- var FetchData = class extends S__namespace.Class("FetchData")({
480
- response: ResponseInfo,
536
+ var FetchLink = class extends S__namespace.Class("FetchLink")({
481
537
  /**
482
- * Page metadata extracted from HTML head (title, description, Open Graph, Twitter Card, icons)
538
+ * The URL of the link
483
539
  */
484
- meta: S__namespace.optionalWith(PageMeta, { nullable: true }),
485
- /**
486
- * The HTML content of the fetched page
487
- */
488
- html: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
489
- /**
490
- * The markdown-formatted content extracted from the page
491
- */
492
- markdown: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
493
- /**
494
- * Base64-encoded data URI of the screenshot image
495
- */
496
- screenshot: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
497
- /**
498
- * AI-generated summary of the page content
499
- */
500
- summary: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
540
+ url: S__namespace.String,
501
541
  /**
502
- * Relevant snippets extracted from the page based on the search query
542
+ * The anchor text of the link
503
543
  */
504
- snippets: S__namespace.optionalWith(
505
- S__namespace.Array(
506
- S__namespace.Struct({
507
- /**
508
- * Type identifier for TextPart compatibility
509
- */
510
- type: S__namespace.optionalWith(S__namespace.Literal("text"), { nullable: true, default: () => "text" }),
511
- /**
512
- * The text content of the snippet
513
- */
514
- text: S__namespace.String,
515
- /**
516
- * Relevance score from the reranker (0-1)
517
- */
518
- score: S__namespace.Number,
519
- /**
520
- * Original chunk index
521
- */
522
- index: S__namespace.Number
523
- })
524
- ),
525
- { nullable: true }
526
- )
544
+ text: S__namespace.optionalWith(S__namespace.String, { nullable: true })
527
545
  }) {
528
546
  };
529
547
  var FetchResult = class extends S__namespace.Class("FetchResult")({
530
- data: FetchData
548
+ /**
549
+ * Contains the extracted content in the formats specified by the select configuration
550
+ */
551
+ data: S__namespace.Struct({
552
+ response: ResponseInfo,
553
+ meta: S__namespace.optionalWith(PageMeta, { nullable: true }),
554
+ /**
555
+ * The HTML content of the fetched page
556
+ */
557
+ html: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
558
+ /**
559
+ * The markdown-formatted content extracted from the page
560
+ */
561
+ markdown: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
562
+ /**
563
+ * Base64-encoded data URI of the screenshot image
564
+ */
565
+ screenshot: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
566
+ /**
567
+ * AI-generated summary of the page content
568
+ */
569
+ summary: S__namespace.optionalWith(S__namespace.String, { nullable: true }),
570
+ /**
571
+ * Relevant snippets extracted from the page based on the search query
572
+ */
573
+ snippets: S__namespace.optionalWith(
574
+ S__namespace.Array(
575
+ S__namespace.Struct({
576
+ /**
577
+ * Type identifier for TextPart compatibility
578
+ */
579
+ type: S__namespace.optionalWith(S__namespace.Literal("text"), { nullable: true, default: () => "text" }),
580
+ /**
581
+ * The text content of the snippet
582
+ */
583
+ text: S__namespace.String,
584
+ /**
585
+ * Relevance score from the reranker (0-1)
586
+ */
587
+ score: S__namespace.Number,
588
+ /**
589
+ * Original chunk index
590
+ */
591
+ index: S__namespace.Number
592
+ })
593
+ ),
594
+ { nullable: true }
595
+ ),
596
+ /**
597
+ * Links extracted from the page
598
+ */
599
+ links: S__namespace.optionalWith(S__namespace.Array(FetchLink), { nullable: true }),
600
+ /**
601
+ * Extracted links and sidebar content
602
+ */
603
+ appendix: S__namespace.optionalWith(S__namespace.String, { nullable: true })
604
+ })
531
605
  }) {
532
606
  };
533
607
  var FetchErrorTag = class extends S__namespace.Literal("FetchError") {
@@ -536,25 +610,8 @@ var FetchError = class extends S__namespace.Class("FetchError")({
536
610
  _tag: FetchErrorTag
537
611
  }) {
538
612
  };
539
- (class extends S__namespace.Class("MarkdownRequest")({
540
- /**
541
- * The URL to fetch markdown content from
542
- */
543
- url: S__namespace.String,
544
- /**
545
- * Configuration options for browser behavior during the fetch
546
- */
547
- browserConfig: S__namespace.optionalWith(
548
- S__namespace.Struct({
549
- /**
550
- * Whether to scroll the entire page to capture lazy-loaded content
551
- */
552
- scrollFullPage: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
553
- }),
554
- { nullable: true }
555
- )
556
- }) {
557
- });
613
+ var Fetch500 = class extends S__namespace.Union(InternalError, FetchError) {
614
+ };
558
615
  var InvalidAssetHashTag = class extends S__namespace.Literal("InvalidAssetHash") {
559
616
  };
560
617
  var InvalidAssetHash = class extends S__namespace.Class("InvalidAssetHash")({
@@ -586,12 +643,223 @@ var AssetFetchError = class extends S__namespace.Class("AssetFetchError")({
586
643
  }) {
587
644
  };
588
645
  var LocalAssetsGetAsset500 = class extends S__namespace.Union(
646
+ InternalError,
589
647
  InvalidAssetHash,
590
648
  AssetNotFoundInHar,
591
649
  HarNotFound,
592
650
  AssetFetchError
593
651
  ) {
594
652
  };
653
+ (class extends S__namespace.Class("PlaygroundFetchRequest")({
654
+ url: URL,
655
+ /**
656
+ * Specifies which content formats to include in the response
657
+ */
658
+ select: S__namespace.optionalWith(
659
+ S__namespace.Struct({
660
+ html: S__namespace.optionalWith(
661
+ S__namespace.Union(
662
+ S__namespace.Boolean,
663
+ SelectHtmlConfig
664
+ ),
665
+ { nullable: true }
666
+ ),
667
+ /**
668
+ * Include markdown-formatted content in the response
669
+ */
670
+ markdown: S__namespace.optionalWith(
671
+ S__namespace.Union(
672
+ S__namespace.Boolean,
673
+ SelectMarkdownConfig
674
+ ),
675
+ { nullable: true }
676
+ ),
677
+ screenshot: S__namespace.optionalWith(
678
+ S__namespace.Union(
679
+ S__namespace.Boolean,
680
+ SelectScreenshotConfig
681
+ ),
682
+ { nullable: true }
683
+ ),
684
+ summary: S__namespace.optionalWith(
685
+ S__namespace.Union(
686
+ S__namespace.Boolean,
687
+ /**
688
+ * Options for AI-powered page summarization
689
+ */
690
+ S__namespace.Struct({
691
+ /**
692
+ * Custom prompt for AI summarization (max 5000 characters)
693
+ */
694
+ prompt: S__namespace.optionalWith(S__namespace.String.pipe(S__namespace.maxLength(5e3)), {
695
+ nullable: true,
696
+ 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."
697
+ })
698
+ })
699
+ ),
700
+ { nullable: true }
701
+ ),
702
+ /**
703
+ * Options for extracting relevant snippets from page content using semantic search
704
+ */
705
+ snippets: S__namespace.optionalWith(
706
+ S__namespace.Struct({
707
+ /**
708
+ * Query to find relevant content snippets from the page (required, non-empty)
709
+ */
710
+ query: Trimmed,
711
+ /**
712
+ * Maximum number of snippets to return (1-50)
713
+ */
714
+ maxSnippets: S__namespace.optionalWith(Int2, { nullable: true, default: () => 5 }),
715
+ /**
716
+ * Minimum relevance score threshold (0-1). Snippets below this score are filtered out.
717
+ */
718
+ minScore: S__namespace.optionalWith(S__namespace.Number.pipe(S__namespace.greaterThanOrEqualTo(0), S__namespace.lessThanOrEqualTo(1)), {
719
+ nullable: true,
720
+ default: () => 0.5
721
+ }),
722
+ /**
723
+ * Target snippet size in characters (100-2000)
724
+ */
725
+ targetSnippetSize: S__namespace.optionalWith(Int2, { nullable: true, default: () => 384 })
726
+ }),
727
+ { nullable: true }
728
+ ),
729
+ links: S__namespace.optionalWith(
730
+ S__namespace.Union(
731
+ S__namespace.Boolean,
732
+ /**
733
+ * Options for customizing link extraction from the page
734
+ */
735
+ S__namespace.Struct({
736
+ /**
737
+ * Only include links from the same domain as the fetched URL
738
+ */
739
+ sameDomainOnly: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => true }),
740
+ /**
741
+ * Regex patterns - only include links matching at least one pattern
742
+ */
743
+ includePatterns: S__namespace.optionalWith(S__namespace.Array(S__namespace.String), { nullable: true }),
744
+ /**
745
+ * Regex patterns - exclude links matching any pattern
746
+ */
747
+ excludePatterns: S__namespace.optionalWith(S__namespace.Array(S__namespace.String), { nullable: true })
748
+ })
749
+ ),
750
+ { nullable: true }
751
+ ),
752
+ /**
753
+ * Include page metadata in the response
754
+ */
755
+ meta: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => true }),
756
+ /**
757
+ * Configure response info options (headers inclusion)
758
+ */
759
+ response: S__namespace.optionalWith(
760
+ S__namespace.Struct({
761
+ /**
762
+ * Whether to include HTTP response headers
763
+ */
764
+ includeHeaders: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
765
+ }),
766
+ { nullable: true }
767
+ ),
768
+ /**
769
+ * Include pruned JSON in the response (opt-in)
770
+ */
771
+ json: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false }),
772
+ /**
773
+ * Set to true to include extracted links and sidebar content
774
+ */
775
+ appendix: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true })
776
+ }),
777
+ { nullable: true }
778
+ ),
779
+ /**
780
+ * Configuration options for browser behavior during the fetch
781
+ */
782
+ browserConfig: S__namespace.optionalWith(
783
+ S__namespace.Struct({
784
+ /**
785
+ * Whether to scroll the entire page to capture lazy-loaded content
786
+ */
787
+ scrollFullPage: S__namespace.optionalWith(S__namespace.Boolean, { nullable: true, default: () => false })
788
+ }),
789
+ { nullable: true }
790
+ )
791
+ }) {
792
+ });
793
+ var PlaygroundData = class extends S__namespace.Class("PlaygroundData")({
794
+ response: ResponseInfo,
795
+ /**
796
+ * HTML with expand-id attributes on elements
797
+ */
798
+ html: S__namespace.String,
799
+ browserSessionId: S__namespace.String
800
+ }) {
801
+ };
802
+ var PlaygroundResult = class extends S__namespace.Class("PlaygroundResult")({
803
+ data: PlaygroundData
804
+ }) {
805
+ };
806
+ var PlaygroundFetch500 = class extends S__namespace.Union(InternalError, FetchError) {
807
+ };
808
+ var PlaygroundGet500 = class extends S__namespace.Union(InternalError, FetchError) {
809
+ };
810
+ var PlaygroundGetBySession500 = class extends S__namespace.Union(InternalError, FetchError) {
811
+ };
812
+ (class extends S__namespace.Class("PlaygroundSearchRequest")({
813
+ /**
814
+ * Search query to find relevant content chunks
815
+ */
816
+ query: Trimmed,
817
+ /**
818
+ * Browser session ID from the playground fetch result
819
+ */
820
+ browserSessionId: S__namespace.String,
821
+ /**
822
+ * Maximum number of results to return
823
+ */
824
+ maxResults: S__namespace.optionalWith(S__namespace.Number, { nullable: true }),
825
+ /**
826
+ * Minimum relevance score threshold (0-1). A value of 0 disables filtering.
827
+ */
828
+ minScore: S__namespace.optionalWith(S__namespace.Number, { nullable: true })
829
+ }) {
830
+ });
831
+ var PlaygroundSearchChunk = class extends S__namespace.Class("PlaygroundSearchChunk")({
832
+ /**
833
+ * The chunk text content
834
+ */
835
+ text: S__namespace.String,
836
+ /**
837
+ * Relevance score from 0-1
838
+ */
839
+ score: S__namespace.Number,
840
+ /**
841
+ * Original chunk index
842
+ */
843
+ index: S__namespace.Number,
844
+ /**
845
+ * MDAST originalNodeIds for highlighting in HTML/markdown views
846
+ */
847
+ nodeIds: S__namespace.Array(S__namespace.Number)
848
+ }) {
849
+ };
850
+ var PlaygroundSearch200 = class extends S__namespace.Struct({
851
+ /**
852
+ * Scored and ranked content chunks
853
+ */
854
+ chunks: S__namespace.Array(PlaygroundSearchChunk),
855
+ /**
856
+ * Duration of the search operation in milliseconds
857
+ */
858
+ durationMs: S__namespace.optionalWith(S__namespace.Number, { nullable: true })
859
+ }) {
860
+ };
861
+ var PlaygroundSearch500 = class extends S__namespace.Union(InternalError, FetchError) {
862
+ };
595
863
  var make = (httpClient, options = {}) => {
596
864
  const unexpectedStatus = (response) => Effect2__namespace.flatMap(
597
865
  Effect2__namespace.orElseSucceed(response.json, () => "Unexpected status code"),
@@ -620,49 +888,79 @@ var make = (httpClient, options = {}) => {
620
888
  withResponse(
621
889
  HttpClientResponse__namespace.matchStatus({
622
890
  "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
623
- "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
891
+ "401": decodeError("AuthFailed", AuthFailed),
624
892
  "404": decodeError("AssetsGetByUrl404", AssetsGetByUrl404),
625
893
  "500": decodeError("AssetsGetByUrl500", AssetsGetByUrl500),
626
894
  "502": decodeError("CurlError", CurlError),
627
895
  "429": () => Effect2__namespace.void,
896
+ "503": () => Effect2__namespace.void,
628
897
  orElse: unexpectedStatus
629
898
  })
630
899
  )
631
900
  ),
632
- assetsList: (browserSessionId) => HttpClientRequest__namespace.get(`/v1/assets/${browserSessionId}`).pipe(
901
+ assetsList: (browserSessionId) => HttpClientRequest__namespace.get(`/v1/assets/${browserSessionId}/list`).pipe(
633
902
  withResponse(
634
903
  HttpClientResponse__namespace.matchStatus({
635
904
  "2xx": decodeSuccess(AssetListResponse),
636
905
  "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
637
- "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
906
+ "401": decodeError("AuthFailed", AuthFailed),
638
907
  "404": decodeError("AssetNotFound", AssetNotFound),
639
908
  "500": decodeError("AssetsList500", AssetsList500),
640
909
  "429": () => Effect2__namespace.void,
910
+ "503": () => Effect2__namespace.void,
641
911
  orElse: unexpectedStatus
642
912
  })
643
913
  )
644
914
  ),
645
- fetch: (options2) => HttpClientRequest__namespace.post(`/v1/fetch`).pipe(
646
- HttpClientRequest__namespace.bodyUnsafeJson(options2),
915
+ assetsGetWacz: (browserSessionId) => HttpClientRequest__namespace.get(`/v1/assets/${browserSessionId}`).pipe(
916
+ withResponse(
917
+ HttpClientResponse__namespace.matchStatus({
918
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
919
+ "401": decodeError("AuthFailed", AuthFailed),
920
+ "404": decodeError("AssetNotFound", AssetNotFound),
921
+ "500": decodeError("AssetsGetWacz500", AssetsGetWacz500),
922
+ "429": () => Effect2__namespace.void,
923
+ "503": () => Effect2__namespace.void,
924
+ orElse: unexpectedStatus
925
+ })
926
+ )
927
+ ),
928
+ datasetsGetDataset: () => HttpClientRequest__namespace.get(`/datasets/page-analysis`).pipe(
929
+ withResponse(
930
+ HttpClientResponse__namespace.matchStatus({
931
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
932
+ "401": decodeError("AuthFailed", AuthFailed),
933
+ "500": decodeError("DatasetsGetDataset500", DatasetsGetDataset500),
934
+ "204": () => Effect2__namespace.void,
935
+ "429": () => Effect2__namespace.void,
936
+ "503": () => Effect2__namespace.void,
937
+ orElse: unexpectedStatus
938
+ })
939
+ )
940
+ ),
941
+ datasetsGetFinetuneDataset: () => HttpClientRequest__namespace.get(`/datasets/finetune`).pipe(
647
942
  withResponse(
648
943
  HttpClientResponse__namespace.matchStatus({
649
- "2xx": decodeSuccess(FetchResult),
650
944
  "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
651
- "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
652
- "500": decodeError("FetchError", FetchError),
945
+ "401": decodeError("AuthFailed", AuthFailed),
946
+ "500": decodeError("DatasetsGetFinetuneDataset500", DatasetsGetFinetuneDataset500),
947
+ "204": () => Effect2__namespace.void,
653
948
  "429": () => Effect2__namespace.void,
949
+ "503": () => Effect2__namespace.void,
654
950
  orElse: unexpectedStatus
655
951
  })
656
952
  )
657
953
  ),
658
- markdown: (options2) => HttpClientRequest__namespace.post(`/v1/fetch/markdown`).pipe(
954
+ fetch: (options2) => HttpClientRequest__namespace.post(`/v1/fetch`).pipe(
659
955
  HttpClientRequest__namespace.bodyUnsafeJson(options2),
660
956
  withResponse(
661
957
  HttpClientResponse__namespace.matchStatus({
958
+ "2xx": decodeSuccess(FetchResult),
662
959
  "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
663
- "401": decodeError("UnauthorizedAccess", UnauthorizedAccess),
664
- "500": decodeError("FetchError", FetchError),
960
+ "401": decodeError("AuthFailed", AuthFailed),
961
+ "500": decodeError("Fetch500", Fetch500),
665
962
  "429": () => Effect2__namespace.void,
963
+ "503": () => Effect2__namespace.void,
666
964
  orElse: unexpectedStatus
667
965
  })
668
966
  )
@@ -671,9 +969,65 @@ var make = (httpClient, options = {}) => {
671
969
  withResponse(
672
970
  HttpClientResponse__namespace.matchStatus({
673
971
  "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
972
+ "401": decodeError("AuthFailed", AuthFailed),
674
973
  "500": decodeError("LocalAssetsGetAsset500", LocalAssetsGetAsset500),
675
974
  "204": () => Effect2__namespace.void,
676
975
  "429": () => Effect2__namespace.void,
976
+ "503": () => Effect2__namespace.void,
977
+ orElse: unexpectedStatus
978
+ })
979
+ )
980
+ ),
981
+ playgroundFetch: (options2) => HttpClientRequest__namespace.post(`/v1/playground/fetch`).pipe(
982
+ HttpClientRequest__namespace.bodyUnsafeJson(options2),
983
+ withResponse(
984
+ HttpClientResponse__namespace.matchStatus({
985
+ "2xx": decodeSuccess(PlaygroundResult),
986
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
987
+ "401": decodeError("AuthFailed", AuthFailed),
988
+ "500": decodeError("PlaygroundFetch500", PlaygroundFetch500),
989
+ "429": () => Effect2__namespace.void,
990
+ "503": () => Effect2__namespace.void,
991
+ orElse: unexpectedStatus
992
+ })
993
+ )
994
+ ),
995
+ playgroundGet: (fetchRequestId) => HttpClientRequest__namespace.get(`/v1/playground/get/${fetchRequestId}`).pipe(
996
+ withResponse(
997
+ HttpClientResponse__namespace.matchStatus({
998
+ "2xx": decodeSuccess(PlaygroundResult),
999
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
1000
+ "401": decodeError("AuthFailed", AuthFailed),
1001
+ "500": decodeError("PlaygroundGet500", PlaygroundGet500),
1002
+ "429": () => Effect2__namespace.void,
1003
+ "503": () => Effect2__namespace.void,
1004
+ orElse: unexpectedStatus
1005
+ })
1006
+ )
1007
+ ),
1008
+ playgroundGetBySession: (browserSessionId) => HttpClientRequest__namespace.get(`/v1/playground/session/${browserSessionId}`).pipe(
1009
+ withResponse(
1010
+ HttpClientResponse__namespace.matchStatus({
1011
+ "2xx": decodeSuccess(PlaygroundResult),
1012
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
1013
+ "401": decodeError("AuthFailed", AuthFailed),
1014
+ "500": decodeError("PlaygroundGetBySession500", PlaygroundGetBySession500),
1015
+ "429": () => Effect2__namespace.void,
1016
+ "503": () => Effect2__namespace.void,
1017
+ orElse: unexpectedStatus
1018
+ })
1019
+ )
1020
+ ),
1021
+ playgroundSearch: (options2) => HttpClientRequest__namespace.post(`/v1/playground/search`).pipe(
1022
+ HttpClientRequest__namespace.bodyUnsafeJson(options2),
1023
+ withResponse(
1024
+ HttpClientResponse__namespace.matchStatus({
1025
+ "2xx": decodeSuccess(PlaygroundSearch200),
1026
+ "400": decodeError("HttpApiDecodeError", HttpApiDecodeError),
1027
+ "401": decodeError("AuthFailed", AuthFailed),
1028
+ "500": decodeError("PlaygroundSearch500", PlaygroundSearch500),
1029
+ "429": () => Effect2__namespace.void,
1030
+ "503": () => Effect2__namespace.void,
677
1031
  orElse: unexpectedStatus
678
1032
  })
679
1033
  )
@@ -691,7 +1045,7 @@ var ClientError = (tag, cause, response) => new ClientErrorImpl({
691
1045
 
692
1046
  // src/ExpandClient.ts
693
1047
  var ExpandConfig = effect.Config.all({
694
- apiKey: effect.Config.redacted("EXPAND_API_KEY"),
1048
+ apiKey: effect.Config.option(effect.Config.redacted("EXPAND_API_KEY")),
695
1049
  baseUrl: effect.Config.withDefault(effect.Config.string("EXPAND_BASE_URL"), "https://api.expand.ai")
696
1050
  });
697
1051
  var ExpandClient = class extends effect.Effect.Service()("ExpandClient", {
@@ -699,93 +1053,106 @@ var ExpandClient = class extends effect.Effect.Service()("ExpandClient", {
699
1053
  scoped: effect.Effect.gen(function* () {
700
1054
  const config = yield* ExpandConfig;
701
1055
  const httpClient = yield* platform.HttpClient.HttpClient;
1056
+ const requestHeaders = yield* effect.Effect.serviceOption(CurrentRequestHeaders);
702
1057
  yield* effect.Effect.logInfo(`ExpandClient connected to ${config.baseUrl}`);
703
1058
  return make(httpClient, {
704
1059
  transformClient: (client) => effect.Effect.succeed(
705
1060
  client.pipe(
706
1061
  platform.HttpClient.mapRequest(platform.HttpClientRequest.prependUrl(config.baseUrl)),
707
- platform.HttpClient.mapRequest(platform.HttpClientRequest.setHeader("x-expand-api-key", effect.Redacted.value(config.apiKey)))
1062
+ platform.HttpClient.mapRequest((req) => {
1063
+ if (effect.Option.isSome(requestHeaders)) {
1064
+ const auth = requestHeaders.value["authorization"];
1065
+ if (auth) {
1066
+ return platform.HttpClientRequest.setHeader("authorization", auth)(req);
1067
+ }
1068
+ }
1069
+ if (effect.Option.isSome(config.apiKey)) {
1070
+ return platform.HttpClientRequest.setHeader("x-expand-api-key", effect.Redacted.value(config.apiKey.value))(req);
1071
+ }
1072
+ return req;
1073
+ })
708
1074
  )
709
1075
  )
710
1076
  });
711
1077
  })
712
1078
  }) {
713
1079
  };
714
- var SnippetsFormat = class extends effect.Schema.Class("SnippetsFormat")({
1080
+ var SearchParams = class extends effect.Schema.Class("SearchParams")({
715
1081
  query: effect.Schema.String.annotations({
716
- description: "Query to find relevant content snippets from the page"
1082
+ description: "Query to find relevant content snippets"
717
1083
  }),
718
- maxSnippets: effect.Schema.optional(
719
- effect.Schema.Int.pipe(effect.Schema.greaterThanOrEqualTo(1), effect.Schema.lessThanOrEqualTo(50))
720
- ).annotations({
721
- description: "Maximum number of snippets to return (1-50, default: 5)"
1084
+ minScore: effect.Schema.optionalWith(effect.Schema.Number.pipe(effect.Schema.greaterThanOrEqualTo(0), effect.Schema.lessThanOrEqualTo(1)), {
1085
+ default: () => 0.6
1086
+ }).annotations({
1087
+ description: "Minimum relevance score (0-1)",
1088
+ default: 0.6
722
1089
  }),
723
- targetSnippetSize: effect.Schema.optional(
724
- effect.Schema.Int.pipe(effect.Schema.greaterThanOrEqualTo(100), effect.Schema.lessThanOrEqualTo(2e3))
725
- ).annotations({
726
- description: "Target snippet size in characters (100-2000, default: 384)"
1090
+ maxResults: effect.Schema.optionalWith(effect.Schema.Int.pipe(effect.Schema.greaterThanOrEqualTo(1), effect.Schema.lessThanOrEqualTo(50)), {
1091
+ default: () => 5
1092
+ }).annotations({
1093
+ description: "Maximum snippets to return",
1094
+ default: 5
727
1095
  })
728
1096
  }) {
729
1097
  };
730
- var Format = effect.Schema.Union(
731
- effect.Schema.Literal("markdown").annotations({
732
- description: "Return as cleaned markdown content"
733
- }),
734
- effect.Schema.Literal("html").annotations({
735
- description: "Return as raw HTML content"
736
- }),
737
- effect.Schema.Literal("summary").annotations({
738
- description: "Return AI-generated summary of the page content"
739
- }),
740
- SnippetsFormat
741
- ).annotations({
742
- description: "Output format for the fetched content"
743
- });
744
1098
  var FetchParams = class extends effect.Schema.Class("FetchParams")({
745
1099
  url: effect.Schema.String.annotations({
746
1100
  description: "The URL to fetch content from"
747
1101
  }),
748
- format: Format,
749
- includeMeta: effect.Schema.Boolean.annotations({
750
- description: "Whether to include page meta tags in the response"
1102
+ includeMeta: effect.Schema.optionalWith(effect.Schema.Boolean, { default: () => false }).annotations({
1103
+ description: "Include page meta tags (title, description, Open Graph)",
1104
+ default: false
1105
+ }),
1106
+ includeAppendix: effect.Schema.optionalWith(effect.Schema.Boolean, { default: () => false }).annotations({
1107
+ description: "Include extracted links and sidebar content",
1108
+ default: false
1109
+ }),
1110
+ includeJson: effect.Schema.optionalWith(effect.Schema.Boolean, { default: () => false }).annotations({
1111
+ description: "Include JSON extracted from network responses and DOM",
1112
+ default: false
1113
+ }),
1114
+ search: effect.Schema.optional(SearchParams).annotations({
1115
+ description: "Semantic search. When provided, returns snippets instead of markdown."
751
1116
  })
752
1117
  }) {
753
1118
  };
754
- var FetchResult2 = class extends effect.Schema.Class("FetchResult")({
755
- content: effect.Schema.String,
756
- url: effect.Schema.String,
757
- meta: effect.Schema.optional(PageMeta)
758
- }) {
759
- };
760
1119
  var FetchTool = ai.Tool.make("fetch", {
761
- description: "Fetch and extract content from any URL.",
762
- parameters: FetchParams.fields,
763
- success: FetchResult2
1120
+ description: `Fetch and extract content from any URL.
1121
+
1122
+ Returns markdown by default. When \`search\` is provided, returns semantically relevant snippets instead.`,
1123
+ parameters: FetchParams.fields
764
1124
  }).annotate(ai.Tool.Readonly, true).annotate(ai.Tool.Destructive, false);
765
1125
  var Fetch = class extends effect.Effect.Service()("Fetch", {
766
1126
  dependencies: [ExpandClient.Default],
767
1127
  scoped: effect.Effect.gen(function* () {
768
1128
  const client = yield* ExpandClient;
769
- const fetch = effect.Effect.fn("Fetch.fetch")(function* ({ url, format, includeMeta }) {
770
- const formatLabel = format instanceof SnippetsFormat ? "snippets" : format;
771
- yield* effect.Effect.logDebug(`Fetching: ${url}`).pipe(effect.Effect.annotateLogs({ format: formatLabel, includeMeta }));
1129
+ const fetch = effect.Effect.fn("Fetch.fetch")(function* ({
1130
+ url,
1131
+ includeMeta,
1132
+ includeAppendix,
1133
+ includeJson,
1134
+ search
1135
+ }) {
1136
+ const hasSearch = search !== void 0;
1137
+ yield* effect.Effect.logDebug(`Fetching: ${url}`).pipe(
1138
+ effect.Effect.annotateLogs({ hasSearch, includeMeta, includeAppendix, includeJson })
1139
+ );
772
1140
  const result = yield* client.fetch({
773
1141
  url,
774
1142
  select: {
775
- markdown: format === "markdown",
776
- html: format === "html",
777
- summary: format === "summary",
778
- snippets: format instanceof SnippetsFormat ? { ...format } : void 0,
779
- meta: includeMeta
1143
+ markdown: !hasSearch,
1144
+ snippets: hasSearch ? {
1145
+ query: search.query,
1146
+ maxSnippets: search.maxResults,
1147
+ minScore: search.minScore
1148
+ } : void 0,
1149
+ meta: includeMeta,
1150
+ json: includeJson,
1151
+ appendix: includeAppendix
780
1152
  }
781
1153
  });
782
- const content = result.data.markdown ?? result.data.html ?? result.data.summary ?? result.data.snippets?.map((snippet) => `${snippet.text} (Score: ${snippet.score})`).join("\n") ?? "";
783
- yield* effect.Effect.logDebug(`\u{1F4E4} Fetched successfully: ${result.data.response.url}`);
784
- return new FetchResult2({
785
- content,
786
- url: result.data.response.url,
787
- meta: result.data.meta
788
- });
1154
+ yield* effect.Effect.logDebug(`Fetched successfully: ${result.data.response.url}`);
1155
+ return result.data;
789
1156
  }, effect.Effect.orDie);
790
1157
  return { fetch };
791
1158
  })
@@ -810,7 +1177,10 @@ var ServerInfo = {
810
1177
  name: "expandai-mcp-server",
811
1178
  version: package_default.version
812
1179
  };
1180
+ var CurrentRequestHeaders = class extends effect.Context.Tag("CurrentRequestHeaders")() {
1181
+ };
813
1182
  var makeServerLayer = (options = {}) => options.includeDocs ? effect.Layer.mergeAll(ExpandToolKit, ExpandDocs) : ExpandToolKit;
814
1183
 
1184
+ exports.CurrentRequestHeaders = CurrentRequestHeaders;
815
1185
  exports.ServerInfo = ServerInfo;
816
1186
  exports.makeServerLayer = makeServerLayer;