@youdotcom-oss/mcp 1.5.1 → 1.6.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/bin/stdio.js +394 -415
- package/package.json +12 -23
- package/src/contents/contents.schemas.ts +3 -48
- package/src/contents/contents.utils.ts +33 -133
- package/src/contents/register-contents-tool.ts +24 -24
- package/src/contents/tests/contents.utils.spec.ts +58 -134
- package/src/express/express.schema.ts +23 -0
- package/src/express/express.utils.ts +10 -121
- package/src/express/register-express-tool.ts +19 -19
- package/src/express/tests/express.utils.spec.ts +80 -159
- package/src/get-mcp-server.ts +3 -3
- package/src/http.ts +38 -38
- package/src/search/register-search-tool.ts +23 -23
- package/src/search/search.schema.ts +38 -0
- package/src/search/search.utils.ts +18 -96
- package/src/search/tests/search.utils.spec.ts +61 -194
- package/src/shared/format-search-results-text.ts +16 -16
- package/src/shared/get-logger.ts +4 -4
- package/src/shared/tests/shared.utils.spec.ts +56 -56
- package/src/shared/use-client-version.ts +8 -8
- package/src/stdio.ts +16 -16
- package/src/tests/http.spec.ts +105 -105
- package/src/tests/tool.spec.ts +212 -212
- package/dist/contents/contents.schemas.d.ts +0 -55
- package/dist/contents/contents.utils.d.ts +0 -28
- package/dist/contents/register-contents-tool.d.ts +0 -10
- package/dist/express/express.schemas.d.ts +0 -56
- package/dist/express/express.utils.d.ts +0 -45
- package/dist/express/register-express-tool.d.ts +0 -6
- package/dist/get-mcp-server.d.ts +0 -2
- package/dist/http.d.ts +0 -3
- package/dist/main.d.ts +0 -9
- package/dist/search/register-search-tool.d.ts +0 -6
- package/dist/search/search.schemas.d.ts +0 -133
- package/dist/search/search.utils.d.ts +0 -98
- package/dist/shared/api-constants.d.ts +0 -9
- package/dist/shared/check-response-for-errors.d.ts +0 -6
- package/dist/shared/format-search-results-text.d.ts +0 -19
- package/dist/shared/generate-error-report-link.d.ts +0 -9
- package/dist/shared/get-logger.d.ts +0 -7
- package/dist/shared/use-client-version.d.ts +0 -6
- package/dist/stdio.d.ts +0 -2
- package/src/express/express.schemas.ts +0 -99
- package/src/main.ts +0 -9
- package/src/search/search.schemas.ts +0 -147
- package/src/shared/api-constants.ts +0 -10
- package/src/shared/check-response-for-errors.ts +0 -13
- package/src/shared/generate-error-report-link.ts +0 -37
- package/src/tests/exports.spec.ts +0 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youdotcom-oss/mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "You.com API Model Context Protocol Server",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "You.com API Model Context Protocol Server - For programmatic API access, use @youdotcom-oss/api",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=18",
|
|
@@ -24,14 +24,8 @@
|
|
|
24
24
|
],
|
|
25
25
|
"bin": "bin/stdio.js",
|
|
26
26
|
"type": "module",
|
|
27
|
-
"main": "./src/main.ts",
|
|
28
27
|
"exports": {
|
|
29
|
-
"
|
|
30
|
-
"types": "./dist/main.d.ts",
|
|
31
|
-
"default": "./src/main.ts"
|
|
32
|
-
},
|
|
33
|
-
"./http": "./src/http.ts",
|
|
34
|
-
"./stdio": "./src/stdio.ts"
|
|
28
|
+
"./http": "./src/http.ts"
|
|
35
29
|
},
|
|
36
30
|
"files": [
|
|
37
31
|
"bin/stdio.js",
|
|
@@ -44,36 +38,31 @@
|
|
|
44
38
|
"access": "public"
|
|
45
39
|
},
|
|
46
40
|
"scripts": {
|
|
47
|
-
"build": "bun
|
|
48
|
-
"build:stdio": "bun build ./src/stdio.ts --outfile ./bin/stdio.js --target=node",
|
|
49
|
-
"build:types": "tsc --project tsconfig.json --declaration --emitDeclarationOnly --noEmit false",
|
|
41
|
+
"build": "bun build ./src/stdio.ts --outfile ./bin/stdio.js --target=node",
|
|
50
42
|
"check": "bun run check:biome && bun run check:types && bun run check:package",
|
|
51
43
|
"check:biome": "biome check",
|
|
52
44
|
"check:package": "format-package --check",
|
|
53
45
|
"check:types": "tsc --noEmit",
|
|
54
|
-
"check:write": "
|
|
46
|
+
"check:write": "biome check --write && bun run format:package",
|
|
55
47
|
"dev": "bun src/stdio.ts",
|
|
56
|
-
"format": "biome format --write",
|
|
57
|
-
"format:check": "biome format",
|
|
58
48
|
"format:package": "format-package --write",
|
|
59
49
|
"inspect": "bash -c 'source .env 2>/dev/null || true; bunx @modelcontextprotocol/inspector -e YDC_API_KEY=$YDC_API_KEY bun dev'",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"start": "bun run bin/http",
|
|
50
|
+
"prepublishOnly": "bun run build",
|
|
51
|
+
"start": "bun run src/http.ts",
|
|
63
52
|
"test": "bun test",
|
|
64
53
|
"test:coverage": "bun test --coverage",
|
|
65
54
|
"test:coverage:watch": "bun test --coverage --watch",
|
|
66
55
|
"test:watch": "bun test --watch"
|
|
67
56
|
},
|
|
68
57
|
"mcpName": "io.github.youdotcom-oss/mcp",
|
|
69
|
-
"types": "./dist/main.d.ts",
|
|
70
58
|
"dependencies": {
|
|
71
|
-
"
|
|
59
|
+
"@youdotcom-oss/api": "0.1.1",
|
|
60
|
+
"zod": "^4.3.6",
|
|
72
61
|
"@hono/mcp": "^0.2.3",
|
|
73
|
-
"@modelcontextprotocol/sdk": "^1.25.
|
|
74
|
-
"hono": "^4.11.
|
|
62
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
63
|
+
"hono": "^4.11.7"
|
|
75
64
|
},
|
|
76
65
|
"devDependencies": {
|
|
77
|
-
"@modelcontextprotocol/inspector": "0.
|
|
66
|
+
"@modelcontextprotocol/inspector": "0.19.0"
|
|
78
67
|
}
|
|
79
68
|
}
|
|
@@ -1,49 +1,4 @@
|
|
|
1
|
-
import * as z from 'zod'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Input schema for the you-contents tool
|
|
5
|
-
* Accepts an array of URLs, optional formats array (or legacy format string), and optional crawl timeout
|
|
6
|
-
*/
|
|
7
|
-
export const ContentsQuerySchema = z.object({
|
|
8
|
-
urls: z
|
|
9
|
-
.array(z.string().url())
|
|
10
|
-
.min(1)
|
|
11
|
-
.describe('Array of webpage URLs to extract content from (e.g., ["https://example.com"])'),
|
|
12
|
-
formats: z
|
|
13
|
-
.array(z.enum(['markdown', 'html', 'metadata']))
|
|
14
|
-
.optional()
|
|
15
|
-
.describe('Output formats: array of "markdown" (text), "html" (layout), or "metadata" (structured data)'),
|
|
16
|
-
format: z.enum(['markdown', 'html']).optional().describe('(Deprecated) Output format - use formats array instead'),
|
|
17
|
-
crawl_timeout: z.number().min(1).max(60).optional().describe('Optional timeout in seconds (1-60) for page crawling'),
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export type ContentsQuery = z.infer<typeof ContentsQuerySchema>;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Schema for a single content item in the API response
|
|
24
|
-
*/
|
|
25
|
-
const ContentsItemSchema = z.object({
|
|
26
|
-
url: z.string().describe('URL'),
|
|
27
|
-
title: z.string().optional().describe('Title'),
|
|
28
|
-
html: z.string().optional().describe('HTML content'),
|
|
29
|
-
markdown: z.string().optional().describe('Markdown content'),
|
|
30
|
-
metadata: z
|
|
31
|
-
.object({
|
|
32
|
-
jsonld: z.array(z.record(z.string(), z.unknown())).optional().describe('JSON-LD structured data (Schema.org)'),
|
|
33
|
-
opengraph: z.record(z.string(), z.string()).optional().describe('OpenGraph meta tags'),
|
|
34
|
-
twitter: z.record(z.string(), z.string()).optional().describe('Twitter Card metadata'),
|
|
35
|
-
})
|
|
36
|
-
.optional()
|
|
37
|
-
.describe('Structured metadata when available'),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* API response schema from You.com Contents API
|
|
42
|
-
* Validates the full response array
|
|
43
|
-
*/
|
|
44
|
-
export const ContentsApiResponseSchema = z.array(ContentsItemSchema);
|
|
45
|
-
|
|
46
|
-
export type ContentsApiResponse = z.infer<typeof ContentsApiResponseSchema>;
|
|
1
|
+
import * as z from 'zod'
|
|
47
2
|
|
|
48
3
|
/**
|
|
49
4
|
* Structured content schema for MCP response
|
|
@@ -70,6 +25,6 @@ export const ContentsStructuredContentSchema = z.object({
|
|
|
70
25
|
}),
|
|
71
26
|
)
|
|
72
27
|
.describe('Extracted items'),
|
|
73
|
-
})
|
|
28
|
+
})
|
|
74
29
|
|
|
75
|
-
export type ContentsStructuredContent = z.infer<typeof ContentsStructuredContentSchema
|
|
30
|
+
export type ContentsStructuredContent = z.infer<typeof ContentsStructuredContentSchema>
|
|
@@ -1,105 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
type ContentsApiResponse,
|
|
5
|
-
ContentsApiResponseSchema,
|
|
6
|
-
type ContentsQuery,
|
|
7
|
-
type ContentsStructuredContent,
|
|
8
|
-
} from './contents.schemas.ts';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Fetch content from You.com Contents API
|
|
12
|
-
* The API accepts multiple URLs in a single request and returns all results
|
|
13
|
-
* @param contentsQuery - Query parameters including URLs and format
|
|
14
|
-
* @param YDC_API_KEY - You.com API key
|
|
15
|
-
* @param getUserAgent - Function to get User-Agent string
|
|
16
|
-
* @returns Parsed and validated API response
|
|
17
|
-
*/
|
|
18
|
-
export const fetchContents = async ({
|
|
19
|
-
contentsQuery: { urls, formats, format, crawl_timeout },
|
|
20
|
-
YDC_API_KEY = process.env.YDC_API_KEY,
|
|
21
|
-
getUserAgent,
|
|
22
|
-
}: {
|
|
23
|
-
contentsQuery: ContentsQuery;
|
|
24
|
-
YDC_API_KEY?: string;
|
|
25
|
-
getUserAgent: () => string;
|
|
26
|
-
}): Promise<ContentsApiResponse> => {
|
|
27
|
-
if (!YDC_API_KEY) {
|
|
28
|
-
throw new Error('YDC_API_KEY is required for Contents API');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Handle backward compatibility: prefer formats array, fallback to format string, default to ['markdown']
|
|
32
|
-
const requestFormats = formats || (format ? [format] : ['markdown']);
|
|
33
|
-
|
|
34
|
-
// Build request body
|
|
35
|
-
const requestBody: {
|
|
36
|
-
urls: string[];
|
|
37
|
-
formats: string[];
|
|
38
|
-
crawl_timeout?: number;
|
|
39
|
-
} = {
|
|
40
|
-
urls,
|
|
41
|
-
formats: requestFormats,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
if (crawl_timeout !== undefined) {
|
|
45
|
-
requestBody.crawl_timeout = crawl_timeout;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Make single API call with all URLs
|
|
49
|
-
const options = {
|
|
50
|
-
method: 'POST',
|
|
51
|
-
headers: new Headers({
|
|
52
|
-
'X-API-Key': YDC_API_KEY,
|
|
53
|
-
'Content-Type': 'application/json',
|
|
54
|
-
'User-Agent': getUserAgent(),
|
|
55
|
-
}),
|
|
56
|
-
body: JSON.stringify(requestBody),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const response = await fetch(CONTENTS_API_URL, options);
|
|
60
|
-
|
|
61
|
-
// Handle HTTP errors
|
|
62
|
-
if (!response.ok) {
|
|
63
|
-
const errorCode = response.status;
|
|
64
|
-
|
|
65
|
-
// Try to parse error response body
|
|
66
|
-
let errorDetail = `Failed to fetch contents. HTTP ${errorCode}`;
|
|
67
|
-
try {
|
|
68
|
-
const errorBody = await response.json();
|
|
69
|
-
if (errorBody && typeof errorBody === 'object' && 'detail' in errorBody) {
|
|
70
|
-
errorDetail = String(errorBody.detail);
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
// If parsing fails, use default error message
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Handle specific error codes
|
|
77
|
-
if (errorCode === 401) {
|
|
78
|
-
throw new Error(`Authentication failed: ${errorDetail}. Please check your You.com API key.`);
|
|
79
|
-
}
|
|
80
|
-
if (errorCode === 403) {
|
|
81
|
-
throw new Error(`Forbidden: ${errorDetail}. Your API key may not have access to the Contents API.`);
|
|
82
|
-
}
|
|
83
|
-
if (errorCode === 429) {
|
|
84
|
-
throw new Error('Rate limited by You.com API. Please try again later.');
|
|
85
|
-
}
|
|
86
|
-
if (errorCode >= 500) {
|
|
87
|
-
throw new Error(`You.com API server error: ${errorDetail}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
throw new Error(errorDetail);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const results = await response.json();
|
|
94
|
-
|
|
95
|
-
// Check for error field in 200 responses
|
|
96
|
-
checkResponseForErrors(results);
|
|
97
|
-
|
|
98
|
-
// Validate schema
|
|
99
|
-
const parsedResults = ContentsApiResponseSchema.parse(results);
|
|
100
|
-
|
|
101
|
-
return parsedResults;
|
|
102
|
-
};
|
|
1
|
+
import type { ContentsApiResponse } from '@youdotcom-oss/api'
|
|
2
|
+
import type { ContentsStructuredContent } from './contents.schemas.ts'
|
|
103
3
|
|
|
104
4
|
/**
|
|
105
5
|
* Format contents API response for MCP output
|
|
@@ -112,69 +12,69 @@ export const formatContentsResponse = (
|
|
|
112
12
|
response: ContentsApiResponse,
|
|
113
13
|
formats: string[],
|
|
114
14
|
): {
|
|
115
|
-
content: Array<{ type: 'text'; text: string }
|
|
116
|
-
structuredContent: ContentsStructuredContent
|
|
15
|
+
content: Array<{ type: 'text'; text: string }>
|
|
16
|
+
structuredContent: ContentsStructuredContent
|
|
117
17
|
} => {
|
|
118
18
|
// Build text content with full extracted content
|
|
119
|
-
const textParts: string[] = [`Successfully extracted content from ${response.length} URL(s):\n`]
|
|
120
|
-
textParts.push(`Formats: ${formats.join(', ')}\n`)
|
|
19
|
+
const textParts: string[] = [`Successfully extracted content from ${response.length} URL(s):\n`]
|
|
20
|
+
textParts.push(`Formats: ${formats.join(', ')}\n`)
|
|
121
21
|
|
|
122
|
-
const items: ContentsStructuredContent['items'] = []
|
|
22
|
+
const items: ContentsStructuredContent['items'] = []
|
|
123
23
|
|
|
124
24
|
for (const item of response) {
|
|
125
25
|
// Add header for this item
|
|
126
|
-
textParts.push(`\n## ${item.title || 'Untitled'}`)
|
|
127
|
-
textParts.push(`URL: ${item.url}\n`)
|
|
128
|
-
textParts.push('---\n')
|
|
26
|
+
textParts.push(`\n## ${item.title || 'Untitled'}`)
|
|
27
|
+
textParts.push(`URL: ${item.url}\n`)
|
|
28
|
+
textParts.push('---\n')
|
|
129
29
|
|
|
130
30
|
// Add content based on requested formats
|
|
131
31
|
if (formats.includes('markdown') && item.markdown) {
|
|
132
|
-
textParts.push('\n### Markdown Content\n')
|
|
133
|
-
textParts.push(item.markdown)
|
|
134
|
-
textParts.push('\n')
|
|
32
|
+
textParts.push('\n### Markdown Content\n')
|
|
33
|
+
textParts.push(item.markdown)
|
|
34
|
+
textParts.push('\n')
|
|
135
35
|
}
|
|
136
36
|
|
|
137
37
|
if (formats.includes('html') && item.html) {
|
|
138
|
-
textParts.push('\n### HTML Content\n')
|
|
139
|
-
textParts.push(`Length: ${item.html.length} characters\n`)
|
|
140
|
-
textParts.push(item.html.substring(0, 500))
|
|
38
|
+
textParts.push('\n### HTML Content\n')
|
|
39
|
+
textParts.push(`Length: ${item.html.length} characters\n`)
|
|
40
|
+
textParts.push(item.html.substring(0, 500))
|
|
141
41
|
if (item.html.length > 500) {
|
|
142
|
-
textParts.push('...\n(truncated for display)')
|
|
42
|
+
textParts.push('...\n(truncated for display)')
|
|
143
43
|
}
|
|
144
|
-
textParts.push('\n')
|
|
44
|
+
textParts.push('\n')
|
|
145
45
|
}
|
|
146
46
|
|
|
147
47
|
if (formats.includes('metadata') && item.metadata) {
|
|
148
|
-
textParts.push('\n### Metadata\n')
|
|
48
|
+
textParts.push('\n### Metadata\n')
|
|
149
49
|
|
|
150
50
|
if (item.metadata.jsonld && item.metadata.jsonld.length > 0) {
|
|
151
|
-
textParts.push('\n**JSON-LD:**\n')
|
|
152
|
-
const jsonldStr = JSON.stringify(item.metadata.jsonld, null, 2)
|
|
51
|
+
textParts.push('\n**JSON-LD:**\n')
|
|
52
|
+
const jsonldStr = JSON.stringify(item.metadata.jsonld, null, 2)
|
|
153
53
|
if (jsonldStr.length > 2000) {
|
|
154
|
-
textParts.push(jsonldStr.substring(0, 2000))
|
|
155
|
-
textParts.push('\n...(truncated for display, see structuredContent for full data)')
|
|
54
|
+
textParts.push(jsonldStr.substring(0, 2000))
|
|
55
|
+
textParts.push('\n...(truncated for display, see structuredContent for full data)')
|
|
156
56
|
} else {
|
|
157
|
-
textParts.push(jsonldStr)
|
|
57
|
+
textParts.push(jsonldStr)
|
|
158
58
|
}
|
|
159
|
-
textParts.push('\n')
|
|
59
|
+
textParts.push('\n')
|
|
160
60
|
}
|
|
161
61
|
|
|
162
62
|
if (item.metadata.opengraph) {
|
|
163
|
-
textParts.push('\n**OpenGraph:**\n')
|
|
63
|
+
textParts.push('\n**OpenGraph:**\n')
|
|
164
64
|
for (const [key, value] of Object.entries(item.metadata.opengraph)) {
|
|
165
|
-
textParts.push(`- ${key}: ${value}\n`)
|
|
65
|
+
textParts.push(`- ${key}: ${value}\n`)
|
|
166
66
|
}
|
|
167
67
|
}
|
|
168
68
|
|
|
169
69
|
if (item.metadata.twitter) {
|
|
170
|
-
textParts.push('\n**Twitter:**\n')
|
|
70
|
+
textParts.push('\n**Twitter:**\n')
|
|
171
71
|
for (const [key, value] of Object.entries(item.metadata.twitter)) {
|
|
172
|
-
textParts.push(`- ${key}: ${value}\n`)
|
|
72
|
+
textParts.push(`- ${key}: ${value}\n`)
|
|
173
73
|
}
|
|
174
74
|
}
|
|
175
75
|
}
|
|
176
76
|
|
|
177
|
-
textParts.push('\n---\n')
|
|
77
|
+
textParts.push('\n---\n')
|
|
178
78
|
|
|
179
79
|
// Add to structured content
|
|
180
80
|
items.push({
|
|
@@ -183,7 +83,7 @@ export const formatContentsResponse = (
|
|
|
183
83
|
markdown: item.markdown,
|
|
184
84
|
html: item.html,
|
|
185
85
|
metadata: item.metadata,
|
|
186
|
-
})
|
|
86
|
+
})
|
|
187
87
|
}
|
|
188
88
|
|
|
189
89
|
return {
|
|
@@ -198,5 +98,5 @@ export const formatContentsResponse = (
|
|
|
198
98
|
formats,
|
|
199
99
|
items,
|
|
200
100
|
},
|
|
201
|
-
}
|
|
202
|
-
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
2
|
-
import { generateErrorReportLink } from '
|
|
3
|
-
import { getLogger } from '../shared/get-logger.ts'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
2
|
+
import { ContentsQuerySchema, fetchContents, generateErrorReportLink } from '@youdotcom-oss/api'
|
|
3
|
+
import { getLogger } from '../shared/get-logger.ts'
|
|
4
|
+
import { ContentsStructuredContentSchema } from './contents.schemas.ts'
|
|
5
|
+
import { formatContentsResponse } from './contents.utils.ts'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Register the you-contents tool with the MCP server
|
|
@@ -13,9 +13,9 @@ export const registerContentsTool = ({
|
|
|
13
13
|
YDC_API_KEY,
|
|
14
14
|
getUserAgent,
|
|
15
15
|
}: {
|
|
16
|
-
mcp: McpServer
|
|
17
|
-
YDC_API_KEY?: string
|
|
18
|
-
getUserAgent: () => string
|
|
16
|
+
mcp: McpServer
|
|
17
|
+
YDC_API_KEY?: string
|
|
18
|
+
getUserAgent: () => string
|
|
19
19
|
}) => {
|
|
20
20
|
// Register the tool
|
|
21
21
|
mcp.registerTool(
|
|
@@ -27,56 +27,56 @@ export const registerContentsTool = ({
|
|
|
27
27
|
outputSchema: ContentsStructuredContentSchema.shape,
|
|
28
28
|
},
|
|
29
29
|
async (toolInput) => {
|
|
30
|
-
const logger = getLogger(mcp)
|
|
30
|
+
const logger = getLogger(mcp)
|
|
31
31
|
|
|
32
32
|
try {
|
|
33
33
|
// Validate and parse input
|
|
34
|
-
const contentsQuery = ContentsQuerySchema.parse(toolInput)
|
|
35
|
-
const { urls, formats, format, crawl_timeout } = contentsQuery
|
|
34
|
+
const contentsQuery = ContentsQuerySchema.parse(toolInput)
|
|
35
|
+
const { urls, formats, format, crawl_timeout } = contentsQuery
|
|
36
36
|
|
|
37
37
|
// Handle backward compatibility: prefer formats array, fallback to format string, default to ['markdown']
|
|
38
|
-
const requestFormats = formats || (format ? [format] : ['markdown'])
|
|
38
|
+
const requestFormats = formats || (format ? [format] : ['markdown'])
|
|
39
39
|
|
|
40
40
|
// Log the request
|
|
41
|
-
const timeoutInfo = crawl_timeout ? ` with timeout: ${crawl_timeout}s` : ''
|
|
41
|
+
const timeoutInfo = crawl_timeout ? ` with timeout: ${crawl_timeout}s` : ''
|
|
42
42
|
await logger({
|
|
43
43
|
level: 'info',
|
|
44
44
|
data: `Contents API call initiated for ${urls.length} URL(s) with formats: ${requestFormats.join(', ')}${timeoutInfo}`,
|
|
45
|
-
})
|
|
45
|
+
})
|
|
46
46
|
|
|
47
47
|
// Fetch contents from API
|
|
48
48
|
const response = await fetchContents({
|
|
49
49
|
contentsQuery,
|
|
50
50
|
YDC_API_KEY,
|
|
51
51
|
getUserAgent,
|
|
52
|
-
})
|
|
52
|
+
})
|
|
53
53
|
|
|
54
54
|
// Format response with full content
|
|
55
|
-
const { content, structuredContent } = formatContentsResponse(response, requestFormats)
|
|
55
|
+
const { content, structuredContent } = formatContentsResponse(response, requestFormats)
|
|
56
56
|
|
|
57
57
|
// Log success
|
|
58
58
|
await logger({
|
|
59
59
|
level: 'info',
|
|
60
60
|
data: `Contents API call successful: extracted ${response.length} page(s)`,
|
|
61
|
-
})
|
|
61
|
+
})
|
|
62
62
|
|
|
63
63
|
return {
|
|
64
64
|
content,
|
|
65
65
|
structuredContent,
|
|
66
|
-
}
|
|
66
|
+
}
|
|
67
67
|
} catch (err: unknown) {
|
|
68
68
|
// Handle and log errors
|
|
69
|
-
const errorMessage = err instanceof Error ? err.message : String(err)
|
|
69
|
+
const errorMessage = err instanceof Error ? err.message : String(err)
|
|
70
70
|
const reportLink = generateErrorReportLink({
|
|
71
71
|
errorMessage,
|
|
72
72
|
tool: 'you-contents',
|
|
73
73
|
clientInfo: getUserAgent(),
|
|
74
|
-
})
|
|
74
|
+
})
|
|
75
75
|
|
|
76
76
|
await logger({
|
|
77
77
|
level: 'error',
|
|
78
78
|
data: `Contents API call failed: ${errorMessage}\n\nReport this issue: ${reportLink}`,
|
|
79
|
-
})
|
|
79
|
+
})
|
|
80
80
|
|
|
81
81
|
return {
|
|
82
82
|
content: [
|
|
@@ -87,8 +87,8 @@ export const registerContentsTool = ({
|
|
|
87
87
|
],
|
|
88
88
|
structuredContent: undefined,
|
|
89
89
|
isError: true,
|
|
90
|
-
}
|
|
90
|
+
}
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
|
-
)
|
|
94
|
-
}
|
|
93
|
+
)
|
|
94
|
+
}
|