@youdotcom-oss/mcp 1.4.0 → 1.4.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/bin/stdio.js CHANGED
@@ -6489,7 +6489,7 @@ var require_dist = __commonJS((exports, module) => {
6489
6489
  exports.default = formatsPlugin;
6490
6490
  });
6491
6491
 
6492
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
6492
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
6493
6493
  import process3 from "node:process";
6494
6494
 
6495
6495
  // ../../node_modules/.bun/zod@4.3.5/node_modules/zod/v4/core/core.js
@@ -11524,7 +11524,7 @@ function preprocess(fn, schema) {
11524
11524
  // ../../node_modules/.bun/zod@4.3.5/node_modules/zod/v4/classic/external.js
11525
11525
  config(en_default());
11526
11526
 
11527
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
11527
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
11528
11528
  var LATEST_PROTOCOL_VERSION = "2025-11-25";
11529
11529
  var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
11530
11530
  var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
@@ -12366,7 +12366,7 @@ class UrlElicitationRequiredError extends McpError {
12366
12366
  }
12367
12367
  }
12368
12368
 
12369
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
12369
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
12370
12370
  class ReadBuffer {
12371
12371
  append(chunk) {
12372
12372
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
@@ -12396,7 +12396,7 @@ function serializeMessage(message) {
12396
12396
  `;
12397
12397
  }
12398
12398
 
12399
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
12399
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
12400
12400
  class StdioServerTransport {
12401
12401
  constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
12402
12402
  this._stdin = _stdin;
@@ -12456,7 +12456,7 @@ class StdioServerTransport {
12456
12456
  // package.json
12457
12457
  var package_default = {
12458
12458
  name: "@youdotcom-oss/mcp",
12459
- version: "1.4.0",
12459
+ version: "1.4.1",
12460
12460
  description: "You.com API Model Context Protocol Server",
12461
12461
  license: "MIT",
12462
12462
  engines: {
@@ -12818,6 +12818,10 @@ var ExpressStructuredContentSchema = object({
12818
12818
  var formatSearchResultsText = (results) => {
12819
12819
  return results.map((result) => {
12820
12820
  const parts = [`Title: ${result.title}`];
12821
+ parts.push(`URL: ${result.url}`);
12822
+ if (result.page_age) {
12823
+ parts.push(`Published: ${result.page_age}`);
12824
+ }
12821
12825
  if (result.description) {
12822
12826
  parts.push(`Description: ${result.description}`);
12823
12827
  }
@@ -16843,7 +16847,7 @@ function object2(shape, params) {
16843
16847
  };
16844
16848
  return new ZodMiniObject(def);
16845
16849
  }
16846
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
16850
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
16847
16851
  function isZ4Schema(s) {
16848
16852
  const schema = s;
16849
16853
  return !!schema._zod;
@@ -16987,7 +16991,7 @@ function getLiteralValue(schema) {
16987
16991
  return;
16988
16992
  }
16989
16993
 
16990
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
16994
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
16991
16995
  function isTerminal(status) {
16992
16996
  return status === "completed" || status === "failed" || status === "cancelled";
16993
16997
  }
@@ -18228,7 +18232,7 @@ var zodToJsonSchema = (schema, options) => {
18228
18232
  }
18229
18233
  return combined;
18230
18234
  };
18231
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
18235
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
18232
18236
  function mapMiniTarget(t) {
18233
18237
  if (!t)
18234
18238
  return "draft-7";
@@ -18270,7 +18274,7 @@ function parseWithCompat(schema, data) {
18270
18274
  return result.data;
18271
18275
  }
18272
18276
 
18273
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
18277
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
18274
18278
  var DEFAULT_REQUEST_TIMEOUT_MSEC = 60000;
18275
18279
 
18276
18280
  class Protocol {
@@ -19093,7 +19097,7 @@ function mergeCapabilities(base, additional) {
19093
19097
  return result;
19094
19098
  }
19095
19099
 
19096
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
19100
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
19097
19101
  var import_ajv = __toESM(require_ajv(), 1);
19098
19102
  var import_ajv_formats = __toESM(require_dist(), 1);
19099
19103
  function createDefaultAjvInstance() {
@@ -19133,7 +19137,7 @@ class AjvJsonSchemaValidator {
19133
19137
  }
19134
19138
  }
19135
19139
 
19136
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
19140
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
19137
19141
  class ExperimentalServerTasks {
19138
19142
  constructor(_server) {
19139
19143
  this._server = _server;
@@ -19155,7 +19159,7 @@ class ExperimentalServerTasks {
19155
19159
  }
19156
19160
  }
19157
19161
 
19158
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
19162
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
19159
19163
  function assertToolsCallTaskCapability(requests, method, entityName) {
19160
19164
  if (!requests) {
19161
19165
  throw new Error(`${entityName} does not support task creation (required for ${method})`);
@@ -19190,7 +19194,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
19190
19194
  }
19191
19195
  }
19192
19196
 
19193
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
19197
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
19194
19198
  class Server extends Protocol {
19195
19199
  constructor(_serverInfo, options) {
19196
19200
  super(options);
@@ -19523,7 +19527,7 @@ class Server extends Protocol {
19523
19527
  }
19524
19528
  }
19525
19529
 
19526
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
19530
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
19527
19531
  var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
19528
19532
  function isCompletable(schema) {
19529
19533
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -19537,7 +19541,7 @@ var McpZodTypeKind;
19537
19541
  McpZodTypeKind2["Completable"] = "McpCompletable";
19538
19542
  })(McpZodTypeKind || (McpZodTypeKind = {}));
19539
19543
 
19540
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
19544
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
19541
19545
  var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
19542
19546
  function validateToolName(name) {
19543
19547
  const warnings = [];
@@ -19595,7 +19599,7 @@ function validateAndWarnToolName(name) {
19595
19599
  return result.isValid;
19596
19600
  }
19597
19601
 
19598
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
19602
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
19599
19603
  class ExperimentalMcpServerTasks {
19600
19604
  constructor(_mcpServer) {
19601
19605
  this._mcpServer = _mcpServer;
@@ -19610,7 +19614,7 @@ class ExperimentalMcpServerTasks {
19610
19614
  }
19611
19615
  }
19612
19616
 
19613
- // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fde825ba4efdc684/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
19617
+ // ../../node_modules/.bun/@modelcontextprotocol+sdk@1.25.2+fd698e00a3b2abce/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
19614
19618
  class McpServer {
19615
19619
  constructor(serverInfo, options) {
19616
19620
  this._registeredResources = {};
@@ -20441,11 +20445,13 @@ var SearchStructuredContentSchema = object({
20441
20445
  results: object({
20442
20446
  web: array(object({
20443
20447
  url: string2().describe("URL"),
20444
- title: string2().describe("Title")
20448
+ title: string2().describe("Title"),
20449
+ page_age: string2().optional().describe("Publication timestamp")
20445
20450
  })).optional().describe("Web results"),
20446
20451
  news: array(object({
20447
20452
  url: string2().describe("URL"),
20448
- title: string2().describe("Title")
20453
+ title: string2().describe("Title"),
20454
+ page_age: string2().describe("Publication timestamp")
20449
20455
  })).optional().describe("News results")
20450
20456
  }).optional().describe("Search results")
20451
20457
  });
@@ -20505,6 +20511,7 @@ ${webResults}`;
20505
20511
  }
20506
20512
  if (response.results.news?.length) {
20507
20513
  const newsResults = response.results.news.map((article) => `Title: ${article.title}
20514
+ URL: ${article.url}
20508
20515
  Description: ${article.description}
20509
20516
  Published: ${article.page_age}`).join(`
20510
20517
 
@@ -20524,15 +20531,21 @@ ${newsResults}`;
20524
20531
  }
20525
20532
  const structuredResults = {};
20526
20533
  if (response.results.web?.length) {
20527
- structuredResults.web = response.results.web.map((result) => ({
20528
- url: result.url,
20529
- title: result.title
20530
- }));
20534
+ structuredResults.web = response.results.web.map((result) => {
20535
+ const item = {
20536
+ url: result.url,
20537
+ title: result.title
20538
+ };
20539
+ if (result.page_age)
20540
+ item.page_age = result.page_age;
20541
+ return item;
20542
+ });
20531
20543
  }
20532
20544
  if (response.results.news?.length) {
20533
20545
  structuredResults.news = response.results.news.map((article) => ({
20534
20546
  url: article.url,
20535
- title: article.title
20547
+ title: article.title,
20548
+ page_age: article.page_age
20536
20549
  }));
20537
20550
  }
20538
20551
  return {
@@ -120,10 +120,12 @@ export declare const SearchStructuredContentSchema: z.ZodObject<{
120
120
  web: z.ZodOptional<z.ZodArray<z.ZodObject<{
121
121
  url: z.ZodString;
122
122
  title: z.ZodString;
123
+ page_age: z.ZodOptional<z.ZodString>;
123
124
  }, z.core.$strip>>>;
124
125
  news: z.ZodOptional<z.ZodArray<z.ZodObject<{
125
126
  url: z.ZodString;
126
127
  title: z.ZodString;
128
+ page_age: z.ZodString;
127
129
  }, z.core.$strip>>>;
128
130
  }, z.core.$strip>>;
129
131
  }, z.core.$strip>;
@@ -52,10 +52,12 @@ export declare const formatSearchResults: (response: SearchResponse) => {
52
52
  web?: Array<{
53
53
  url: string;
54
54
  title: string;
55
+ page_age?: string;
55
56
  }>;
56
57
  news?: Array<{
57
58
  url: string;
58
59
  title: string;
60
+ page_age: string;
59
61
  }>;
60
62
  } | undefined;
61
63
  };
@@ -8,12 +8,12 @@ type GenericSearchResult = {
8
8
  description?: string;
9
9
  snippet?: string;
10
10
  snippets?: string[];
11
+ page_age?: string;
11
12
  };
12
13
  /**
13
14
  * Format array of search results into display text
14
15
  * Used by both search and express agent formatting
15
16
  * @param results - Array of search results to format
16
- * @param includeUrls - Whether to include URLs in the text (default: true)
17
17
  */
18
18
  export declare const formatSearchResultsText: (results: GenericSearchResult[]) => string;
19
19
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdotcom-oss/mcp",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "You.com API Model Context Protocol Server",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -148,14 +148,14 @@ describe('formatExpressAgentResponse', () => {
148
148
  expect(result.content[0]?.text).toContain('Express Agent Answer');
149
149
  expect(result.content[0]?.text).toContain('Quantum computing is advancing rapidly');
150
150
 
151
- // Verify search results come SECOND (without URLs in text)
151
+ // Verify search results come SECOND
152
152
  expect(result.content[1]?.type).toBe('text');
153
153
  expect(result.content[1]?.text).toContain('Search Results');
154
154
  expect(result.content[1]?.text).toContain('Quantum Computing Breakthrough');
155
155
  expect(result.content[1]?.text).toContain('Latest in Quantum Research');
156
- // URLs should NOT be in text content
157
- expect(result.content[1]?.text).not.toContain('https://example.com/quantum1');
158
- expect(result.content[1]?.text).not.toContain('https://example.com/quantum2');
156
+ // URLs should be in text content
157
+ expect(result.content[1]?.text).toContain('https://example.com/quantum1');
158
+ expect(result.content[1]?.text).toContain('https://example.com/quantum2');
159
159
 
160
160
  // Verify structuredContent is minimal with counts
161
161
  expect(result.structuredContent).toHaveProperty('answer');
@@ -124,6 +124,7 @@ export const SearchStructuredContentSchema = z.object({
124
124
  z.object({
125
125
  url: z.string().describe('URL'),
126
126
  title: z.string().describe('Title'),
127
+ page_age: z.string().optional().describe('Publication timestamp'),
127
128
  }),
128
129
  )
129
130
  .optional()
@@ -133,6 +134,7 @@ export const SearchStructuredContentSchema = z.object({
133
134
  z.object({
134
135
  url: z.string().describe('URL'),
135
136
  title: z.string().describe('Title'),
137
+ page_age: z.string().describe('Publication timestamp'),
136
138
  }),
137
139
  )
138
140
  .optional()
@@ -82,18 +82,18 @@ export const fetchSearchResults = async ({
82
82
  export const formatSearchResults = (response: SearchResponse) => {
83
83
  let formattedResults = '';
84
84
 
85
- // Format web results using shared utility (without URLs in text)
85
+ // Format web results using shared utility
86
86
  if (response.results.web?.length) {
87
87
  const webResults = formatSearchResultsText(response.results.web);
88
88
  formattedResults += `WEB RESULTS:\n\n${webResults}`;
89
89
  }
90
90
 
91
- // Format news results (without URLs in text)
91
+ // Format news results
92
92
  if (response.results.news?.length) {
93
93
  const newsResults = response.results.news
94
94
  .map(
95
95
  (article: NewsResult) =>
96
- `Title: ${article.title}\nDescription: ${article.description}\nPublished: ${article.page_age}`,
96
+ `Title: ${article.title}\nURL: ${article.url}\nDescription: ${article.description}\nPublished: ${article.page_age}`,
97
97
  )
98
98
  .join('\n\n---\n\n');
99
99
 
@@ -103,23 +103,28 @@ export const formatSearchResults = (response: SearchResponse) => {
103
103
  formattedResults += `NEWS RESULTS:\n\n${newsResults}`;
104
104
  }
105
105
 
106
- // Extract URLs and titles for structuredContent
106
+ // Extract fields for structuredContent
107
107
  const structuredResults: {
108
- web?: Array<{ url: string; title: string }>;
109
- news?: Array<{ url: string; title: string }>;
108
+ web?: Array<{ url: string; title: string; page_age?: string }>;
109
+ news?: Array<{ url: string; title: string; page_age: string }>;
110
110
  } = {};
111
111
 
112
112
  if (response.results.web?.length) {
113
- structuredResults.web = response.results.web.map((result) => ({
114
- url: result.url,
115
- title: result.title,
116
- }));
113
+ structuredResults.web = response.results.web.map((result) => {
114
+ const item: { url: string; title: string; page_age?: string } = {
115
+ url: result.url,
116
+ title: result.title,
117
+ };
118
+ if (result.page_age) item.page_age = result.page_age;
119
+ return item;
120
+ });
117
121
  }
118
122
 
119
123
  if (response.results.news?.length) {
120
124
  structuredResults.news = response.results.news.map((article) => ({
121
125
  url: article.url,
122
126
  title: article.title,
127
+ page_age: article.page_age,
123
128
  }));
124
129
  }
125
130
 
@@ -169,19 +169,21 @@ describe('formatSearchResults', () => {
169
169
  expect(result.content[0]).toHaveProperty('text');
170
170
  expect(result.content[0]?.text).toContain('WEB RESULTS:');
171
171
  expect(result.content[0]?.text).toContain('Test Title');
172
- // URLs should NOT be in text content
173
- expect(result.content[0]?.text).not.toContain('https://example.com');
172
+ // URL and page_age should be in text content
173
+ expect(result.content[0]?.text).toContain('URL: https://example.com');
174
+ expect(result.content[0]?.text).toContain('Published: 2023-01-01T00:00:00');
174
175
  expect(result.structuredContent).toHaveProperty('resultCounts');
175
176
  expect(result.structuredContent.resultCounts).toHaveProperty('web', 1);
176
177
  expect(result.structuredContent.resultCounts).toHaveProperty('news', 0);
177
178
  expect(result.structuredContent.resultCounts).toHaveProperty('total', 1);
178
- // URLs should be in structuredContent.results
179
+ // All fields should be in structuredContent.results
179
180
  expect(result.structuredContent).toHaveProperty('results');
180
181
  expect(result.structuredContent.results?.web).toBeDefined();
181
182
  expect(result.structuredContent.results?.web?.length).toBe(1);
182
- expect(result.structuredContent.results?.web?.[0]).toEqual({
183
+ expect(result.structuredContent.results?.web?.[0]).toMatchObject({
183
184
  url: 'https://example.com',
184
185
  title: 'Test Title',
186
+ page_age: '2023-01-01T00:00:00',
185
187
  });
186
188
  expect(result.fullResponse).toBe(mockResponse);
187
189
  });
@@ -211,19 +213,20 @@ describe('formatSearchResults', () => {
211
213
  expect(result.content[0]?.text).toContain('NEWS RESULTS:');
212
214
  expect(result.content[0]?.text).toContain('News Title');
213
215
  expect(result.content[0]?.text).toContain('Published: 2023-01-01T00:00:00');
214
- // URLs should NOT be in text content
215
- expect(result.content[0]?.text).not.toContain('https://news.com/article');
216
+ // URL should be in text content
217
+ expect(result.content[0]?.text).toContain('URL: https://news.com/article');
216
218
  expect(result.structuredContent).toHaveProperty('resultCounts');
217
219
  expect(result.structuredContent.resultCounts).toHaveProperty('web', 0);
218
220
  expect(result.structuredContent.resultCounts).toHaveProperty('news', 1);
219
221
  expect(result.structuredContent.resultCounts).toHaveProperty('total', 1);
220
- // URLs should be in structuredContent.results
222
+ // All fields should be in structuredContent.results
221
223
  expect(result.structuredContent).toHaveProperty('results');
222
224
  expect(result.structuredContent.results?.news).toBeDefined();
223
225
  expect(result.structuredContent.results?.news?.length).toBe(1);
224
- expect(result.structuredContent.results?.news?.[0]).toEqual({
226
+ expect(result.structuredContent.results?.news?.[0]).toMatchObject({
225
227
  url: 'https://news.com/article',
226
228
  title: 'News Title',
229
+ page_age: '2023-01-01T00:00:00',
227
230
  });
228
231
  });
229
232
 
@@ -261,25 +264,27 @@ describe('formatSearchResults', () => {
261
264
  expect(result.content[0]?.text).toContain('WEB RESULTS:');
262
265
  expect(result.content[0]?.text).toContain('NEWS RESULTS:');
263
266
  expect(result.content[0]?.text).toContain(`=${'='.repeat(49)}`);
264
- // URLs should NOT be in text content
265
- expect(result.content[0]?.text).not.toContain('https://web.com');
266
- expect(result.content[0]?.text).not.toContain('https://news.com/article');
267
+ // URLs should be in text content
268
+ expect(result.content[0]?.text).toContain('URL: https://web.com');
269
+ expect(result.content[0]?.text).toContain('URL: https://news.com/article');
267
270
  expect(result.structuredContent.resultCounts).toHaveProperty('web', 1);
268
271
  expect(result.structuredContent.resultCounts).toHaveProperty('news', 1);
269
272
  expect(result.structuredContent.resultCounts).toHaveProperty('total', 2);
270
- // URLs should be in structuredContent.results
273
+ // All fields should be in structuredContent.results
271
274
  expect(result.structuredContent).toHaveProperty('results');
272
275
  expect(result.structuredContent.results?.web).toBeDefined();
273
276
  expect(result.structuredContent.results?.news).toBeDefined();
274
277
  expect(result.structuredContent.results?.web?.length).toBe(1);
275
278
  expect(result.structuredContent.results?.news?.length).toBe(1);
276
- expect(result.structuredContent.results?.web?.[0]).toEqual({
279
+ expect(result.structuredContent.results?.web?.[0]).toMatchObject({
277
280
  url: 'https://web.com',
278
281
  title: 'Web Title',
282
+ page_age: '2023-01-01T00:00:00',
279
283
  });
280
- expect(result.structuredContent.results?.news?.[0]).toEqual({
284
+ expect(result.structuredContent.results?.news?.[0]).toMatchObject({
281
285
  url: 'https://news.com/article',
282
286
  title: 'News Title',
287
+ page_age: '2023-01-01T00:00:00',
283
288
  });
284
289
  });
285
290
  });
@@ -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}`);
@@ -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 NOT be in text content anymore
89
- expect(text).not.toContain('URL:');
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