@youdotcom-oss/mcp 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/bin/stdio.js +206 -116
- package/dist/contents/contents.schemas.d.ts +21 -5
- package/dist/contents/contents.utils.d.ts +3 -3
- package/dist/search/search.schemas.d.ts +2 -0
- package/dist/search/search.utils.d.ts +2 -0
- package/dist/shared/format-search-results-text.d.ts +1 -1
- package/package.json +2 -2
- package/src/contents/contents.schemas.ts +25 -8
- package/src/contents/contents.utils.ts +78 -20
- package/src/contents/register-contents-tool.ts +7 -3
- package/src/contents/tests/contents.utils.spec.ts +15 -16
- package/src/express/tests/express.utils.spec.ts +4 -4
- package/src/search/search.schemas.ts +2 -0
- package/src/search/search.utils.ts +15 -10
- package/src/search/tests/search.utils.spec.ts +19 -15
- package/src/shared/format-search-results-text.ts +9 -1
- package/src/tests/tool.spec.ts +11 -11
|
@@ -68,7 +68,6 @@ describe('fetchSearchResults', () => {
|
|
|
68
68
|
expect(Array.isArray(webResult?.snippets)).toBe(true);
|
|
69
69
|
|
|
70
70
|
// Test that news results have required properties
|
|
71
|
-
// biome-ignore lint/style/noNonNullAssertion: Test
|
|
72
71
|
// const newsResult = result.results.news![0];
|
|
73
72
|
// expect(newsResult).toHaveProperty('url');
|
|
74
73
|
// expect(newsResult).toHaveProperty('title');
|
|
@@ -169,19 +168,21 @@ describe('formatSearchResults', () => {
|
|
|
169
168
|
expect(result.content[0]).toHaveProperty('text');
|
|
170
169
|
expect(result.content[0]?.text).toContain('WEB RESULTS:');
|
|
171
170
|
expect(result.content[0]?.text).toContain('Test Title');
|
|
172
|
-
//
|
|
173
|
-
expect(result.content[0]?.text).
|
|
171
|
+
// URL and page_age should be in text content
|
|
172
|
+
expect(result.content[0]?.text).toContain('URL: https://example.com');
|
|
173
|
+
expect(result.content[0]?.text).toContain('Published: 2023-01-01T00:00:00');
|
|
174
174
|
expect(result.structuredContent).toHaveProperty('resultCounts');
|
|
175
175
|
expect(result.structuredContent.resultCounts).toHaveProperty('web', 1);
|
|
176
176
|
expect(result.structuredContent.resultCounts).toHaveProperty('news', 0);
|
|
177
177
|
expect(result.structuredContent.resultCounts).toHaveProperty('total', 1);
|
|
178
|
-
//
|
|
178
|
+
// All fields should be in structuredContent.results
|
|
179
179
|
expect(result.structuredContent).toHaveProperty('results');
|
|
180
180
|
expect(result.structuredContent.results?.web).toBeDefined();
|
|
181
181
|
expect(result.structuredContent.results?.web?.length).toBe(1);
|
|
182
|
-
expect(result.structuredContent.results?.web?.[0]).
|
|
182
|
+
expect(result.structuredContent.results?.web?.[0]).toMatchObject({
|
|
183
183
|
url: 'https://example.com',
|
|
184
184
|
title: 'Test Title',
|
|
185
|
+
page_age: '2023-01-01T00:00:00',
|
|
185
186
|
});
|
|
186
187
|
expect(result.fullResponse).toBe(mockResponse);
|
|
187
188
|
});
|
|
@@ -211,19 +212,20 @@ describe('formatSearchResults', () => {
|
|
|
211
212
|
expect(result.content[0]?.text).toContain('NEWS RESULTS:');
|
|
212
213
|
expect(result.content[0]?.text).toContain('News Title');
|
|
213
214
|
expect(result.content[0]?.text).toContain('Published: 2023-01-01T00:00:00');
|
|
214
|
-
//
|
|
215
|
-
expect(result.content[0]?.text).
|
|
215
|
+
// URL should be in text content
|
|
216
|
+
expect(result.content[0]?.text).toContain('URL: https://news.com/article');
|
|
216
217
|
expect(result.structuredContent).toHaveProperty('resultCounts');
|
|
217
218
|
expect(result.structuredContent.resultCounts).toHaveProperty('web', 0);
|
|
218
219
|
expect(result.structuredContent.resultCounts).toHaveProperty('news', 1);
|
|
219
220
|
expect(result.structuredContent.resultCounts).toHaveProperty('total', 1);
|
|
220
|
-
//
|
|
221
|
+
// All fields should be in structuredContent.results
|
|
221
222
|
expect(result.structuredContent).toHaveProperty('results');
|
|
222
223
|
expect(result.structuredContent.results?.news).toBeDefined();
|
|
223
224
|
expect(result.structuredContent.results?.news?.length).toBe(1);
|
|
224
|
-
expect(result.structuredContent.results?.news?.[0]).
|
|
225
|
+
expect(result.structuredContent.results?.news?.[0]).toMatchObject({
|
|
225
226
|
url: 'https://news.com/article',
|
|
226
227
|
title: 'News Title',
|
|
228
|
+
page_age: '2023-01-01T00:00:00',
|
|
227
229
|
});
|
|
228
230
|
});
|
|
229
231
|
|
|
@@ -261,25 +263,27 @@ describe('formatSearchResults', () => {
|
|
|
261
263
|
expect(result.content[0]?.text).toContain('WEB RESULTS:');
|
|
262
264
|
expect(result.content[0]?.text).toContain('NEWS RESULTS:');
|
|
263
265
|
expect(result.content[0]?.text).toContain(`=${'='.repeat(49)}`);
|
|
264
|
-
// URLs should
|
|
265
|
-
expect(result.content[0]?.text).
|
|
266
|
-
expect(result.content[0]?.text).
|
|
266
|
+
// URLs should be in text content
|
|
267
|
+
expect(result.content[0]?.text).toContain('URL: https://web.com');
|
|
268
|
+
expect(result.content[0]?.text).toContain('URL: https://news.com/article');
|
|
267
269
|
expect(result.structuredContent.resultCounts).toHaveProperty('web', 1);
|
|
268
270
|
expect(result.structuredContent.resultCounts).toHaveProperty('news', 1);
|
|
269
271
|
expect(result.structuredContent.resultCounts).toHaveProperty('total', 2);
|
|
270
|
-
//
|
|
272
|
+
// All fields should be in structuredContent.results
|
|
271
273
|
expect(result.structuredContent).toHaveProperty('results');
|
|
272
274
|
expect(result.structuredContent.results?.web).toBeDefined();
|
|
273
275
|
expect(result.structuredContent.results?.news).toBeDefined();
|
|
274
276
|
expect(result.structuredContent.results?.web?.length).toBe(1);
|
|
275
277
|
expect(result.structuredContent.results?.news?.length).toBe(1);
|
|
276
|
-
expect(result.structuredContent.results?.web?.[0]).
|
|
278
|
+
expect(result.structuredContent.results?.web?.[0]).toMatchObject({
|
|
277
279
|
url: 'https://web.com',
|
|
278
280
|
title: 'Web Title',
|
|
281
|
+
page_age: '2023-01-01T00:00:00',
|
|
279
282
|
});
|
|
280
|
-
expect(result.structuredContent.results?.news?.[0]).
|
|
283
|
+
expect(result.structuredContent.results?.news?.[0]).toMatchObject({
|
|
281
284
|
url: 'https://news.com/article',
|
|
282
285
|
title: 'News Title',
|
|
286
|
+
page_age: '2023-01-01T00:00:00',
|
|
283
287
|
});
|
|
284
288
|
});
|
|
285
289
|
});
|
|
@@ -8,19 +8,27 @@ type GenericSearchResult = {
|
|
|
8
8
|
description?: string;
|
|
9
9
|
snippet?: string;
|
|
10
10
|
snippets?: string[];
|
|
11
|
+
page_age?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Format array of search results into display text
|
|
15
16
|
* Used by both search and express agent formatting
|
|
16
17
|
* @param results - Array of search results to format
|
|
17
|
-
* @param includeUrls - Whether to include URLs in the text (default: true)
|
|
18
18
|
*/
|
|
19
19
|
export const formatSearchResultsText = (results: GenericSearchResult[]): string => {
|
|
20
20
|
return results
|
|
21
21
|
.map((result) => {
|
|
22
22
|
const parts: string[] = [`Title: ${result.title}`];
|
|
23
23
|
|
|
24
|
+
// Add URL
|
|
25
|
+
parts.push(`URL: ${result.url}`);
|
|
26
|
+
|
|
27
|
+
// Add page age if present
|
|
28
|
+
if (result.page_age) {
|
|
29
|
+
parts.push(`Published: ${result.page_age}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
// Add description if present (from Search API)
|
|
25
33
|
if (result.description) {
|
|
26
34
|
parts.push(`Description: ${result.description}`);
|
package/src/tests/tool.spec.ts
CHANGED
|
@@ -85,8 +85,8 @@ describe('registerSearchTool', () => {
|
|
|
85
85
|
const text = content[0]?.text;
|
|
86
86
|
expect(text).toContain('WEB RESULTS:');
|
|
87
87
|
expect(text).toContain('Title:');
|
|
88
|
-
// URL should
|
|
89
|
-
expect(text).
|
|
88
|
+
// URL should be in text content
|
|
89
|
+
expect(text).toContain('URL:');
|
|
90
90
|
expect(text).toContain('Description:');
|
|
91
91
|
expect(text).toContain('Snippets:');
|
|
92
92
|
|
|
@@ -500,11 +500,12 @@ describe('registerContentsTool', () => {
|
|
|
500
500
|
const text = content[0]?.text;
|
|
501
501
|
expect(text).toContain('Successfully extracted content');
|
|
502
502
|
expect(text).toContain('https://documentation.you.com/developer-resources/mcp-server');
|
|
503
|
-
expect(text).toContain('
|
|
503
|
+
expect(text).toContain('Formats: markdown');
|
|
504
504
|
|
|
505
505
|
const structuredContent = result.structuredContent as ContentsStructuredContent;
|
|
506
506
|
expect(structuredContent).toHaveProperty('count', 1);
|
|
507
|
-
expect(structuredContent).toHaveProperty('
|
|
507
|
+
expect(structuredContent).toHaveProperty('formats');
|
|
508
|
+
expect(structuredContent.formats).toEqual(['markdown']);
|
|
508
509
|
expect(structuredContent).toHaveProperty('items');
|
|
509
510
|
expect(structuredContent.items).toHaveLength(1);
|
|
510
511
|
|
|
@@ -512,10 +513,9 @@ describe('registerContentsTool', () => {
|
|
|
512
513
|
expect(item).toBeDefined();
|
|
513
514
|
|
|
514
515
|
expect(item).toHaveProperty('url', 'https://documentation.you.com/developer-resources/mcp-server');
|
|
515
|
-
expect(item).toHaveProperty('
|
|
516
|
-
expect(item).
|
|
517
|
-
expect(
|
|
518
|
-
expect(item?.content.length).toBeGreaterThan(0);
|
|
516
|
+
expect(item).toHaveProperty('markdown');
|
|
517
|
+
expect(typeof item?.markdown).toBe('string');
|
|
518
|
+
expect(item?.markdown?.length).toBeGreaterThan(0);
|
|
519
519
|
},
|
|
520
520
|
{ retry: 2 },
|
|
521
521
|
);
|
|
@@ -557,11 +557,11 @@ describe('registerContentsTool', () => {
|
|
|
557
557
|
});
|
|
558
558
|
|
|
559
559
|
const structuredContent = result.structuredContent as ContentsStructuredContent;
|
|
560
|
-
expect(structuredContent.
|
|
560
|
+
expect(structuredContent.formats).toEqual(['html']);
|
|
561
561
|
|
|
562
562
|
const content = result.content as { type: string; text: string }[];
|
|
563
563
|
const text = content[0]?.text;
|
|
564
|
-
expect(text).toContain('
|
|
564
|
+
expect(text).toContain('Formats: html');
|
|
565
565
|
},
|
|
566
566
|
{ retry: 2 },
|
|
567
567
|
);
|
|
@@ -577,7 +577,7 @@ describe('registerContentsTool', () => {
|
|
|
577
577
|
});
|
|
578
578
|
|
|
579
579
|
const structuredContent = result.structuredContent as ContentsStructuredContent;
|
|
580
|
-
expect(structuredContent.
|
|
580
|
+
expect(structuredContent.formats).toEqual(['markdown']);
|
|
581
581
|
},
|
|
582
582
|
{ retry: 2 },
|
|
583
583
|
);
|