@youdotcom-oss/mcp 1.3.5-next.5 → 1.3.6

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 CHANGED
@@ -288,7 +288,7 @@ Interested in contributing to the You.com MCP Server? We'd love your help!
288
288
  Need technical details? Check [AGENTS.md](./AGENTS.md) for complete development setup, architecture overview, code patterns, and testing guidelines.
289
289
 
290
290
  1. Fork the repository
291
- 2. Create a feature branch following naming conventions in [CONTRIBUTING.md](./CONTRIBUTING.md)
291
+ 2. Create a feature branch following naming conventions in [CONTRIBUTING.md](../../CONTRIBUTING.md)
292
292
  3. Follow the code style guidelines and use conventional commits
293
293
  4. Write tests for your changes (maintain >80% coverage)
294
294
  5. Run quality checks: `bun run check && bun test`
package/bin/stdio.js CHANGED
@@ -12155,7 +12155,7 @@ class StdioServerTransport {
12155
12155
  // package.json
12156
12156
  var package_default = {
12157
12157
  name: "@youdotcom-oss/mcp",
12158
- version: "1.3.5-next.5",
12158
+ version: "1.3.6",
12159
12159
  description: "You.com API Model Context Protocol Server",
12160
12160
  license: "MIT",
12161
12161
  engines: {
@@ -12164,12 +12164,13 @@ var package_default = {
12164
12164
  },
12165
12165
  repository: {
12166
12166
  type: "git",
12167
- url: "git+https://github.com/youdotcom-oss/mcp-server.git"
12167
+ url: "git+https://github.com/youdotcom-oss/dx-toolkit.git",
12168
+ directory: "packages/mcp"
12168
12169
  },
12169
12170
  bugs: {
12170
- url: "https://github.com/youdotcom-oss/mcp-server/issues"
12171
+ url: "https://github.com/youdotcom-oss/dx-toolkit/issues"
12171
12172
  },
12172
- homepage: "https://github.com/youdotcom-oss/mcp-server/tree/main#readme",
12173
+ homepage: "https://github.com/youdotcom-oss/dx-toolkit/tree/main/packages/mcp#readme",
12173
12174
  author: "You.com (https://you.com)",
12174
12175
  keywords: [
12175
12176
  "mcp",
@@ -12178,19 +12179,17 @@ var package_default = {
12178
12179
  ],
12179
12180
  bin: "bin/stdio.js",
12180
12181
  type: "module",
12181
- main: "./src/main.ts",
12182
+ main: "./src/utils.ts",
12182
12183
  exports: {
12183
- ".": "./src/main.ts"
12184
+ ".": "./src/utils.ts",
12185
+ "./http": "./src/http.ts",
12186
+ "./stdio": "./src/stdio.ts"
12184
12187
  },
12185
12188
  files: [
12186
12189
  "bin/stdio.js",
12187
- "src/**/*.schemas.ts",
12188
- "src/**/*.utils.ts",
12189
- "src/shared/check-response-for-errors.ts",
12190
- "src/shared/format-search-results-text.ts",
12191
- "AGENTS.md",
12192
- "CONTRIBUTING.md",
12193
- "docs/API.md"
12190
+ "./src/**",
12191
+ "!./src/**/tests/*",
12192
+ "!./src/**/*.spec.@(tsx|ts)"
12194
12193
  ],
12195
12194
  publishConfig: {
12196
12195
  access: "public"
@@ -12209,41 +12208,20 @@ var package_default = {
12209
12208
  inspect: "bash -c 'source .env 2>/dev/null || true; bunx @modelcontextprotocol/inspector -e YDC_API_KEY=$YDC_API_KEY bun dev'",
12210
12209
  lint: "biome lint",
12211
12210
  "lint:fix": "biome lint --write",
12212
- prepare: "git config core.hooksPath .hooks",
12213
12211
  start: "bun run bin/http",
12214
12212
  test: "bun test",
12215
12213
  "test:coverage": "bun test --coverage",
12216
12214
  "test:coverage:watch": "bun test --coverage --watch",
12217
12215
  "test:watch": "bun test --watch"
12218
12216
  },
12219
- "lint-staged": {
12220
- "*.{ts,tsx}": [
12221
- "biome check --write --no-errors-on-unmatched"
12222
- ],
12223
- "*.{json,md}": [
12224
- "biome format --write --no-errors-on-unmatched"
12225
- ],
12226
- "package.json": [
12227
- "format-package --write"
12228
- ]
12229
- },
12230
12217
  dependencies: {
12231
- zod: "^4.1.13"
12218
+ zod: "^4.1.13",
12219
+ "@hono/mcp": "^0.2.0",
12220
+ "@modelcontextprotocol/sdk": "^1.24.3",
12221
+ hono: "^4.10.7"
12232
12222
  },
12233
12223
  devDependencies: {
12234
- "@biomejs/biome": "2.3.8",
12235
- "@commitlint/cli": "20.1.0",
12236
- "@commitlint/config-conventional": "20.0.0",
12237
- "@eslint/js": "9.39.1",
12238
- "@modelcontextprotocol/inspector": "0.17.5",
12239
- "@types/bun": "latest",
12240
- typescript: "5.9.3",
12241
- "lint-staged": "16.2.7",
12242
- "format-package": "7.0.0",
12243
- "@hono/bun-compress": "0.1.0",
12244
- "@hono/mcp": "0.2.0",
12245
- "@modelcontextprotocol/sdk": "1.24.3",
12246
- hono: "4.10.7"
12224
+ "@modelcontextprotocol/inspector": "0.17.5"
12247
12225
  }
12248
12226
  };
12249
12227
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdotcom-oss/mcp",
3
- "version": "1.3.5-next.5",
3
+ "version": "1.3.6",
4
4
  "description": "You.com API Model Context Protocol Server",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -9,12 +9,13 @@
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/youdotcom-oss/mcp-server.git"
12
+ "url": "git+https://github.com/youdotcom-oss/dx-toolkit.git",
13
+ "directory": "packages/mcp"
13
14
  },
14
15
  "bugs": {
15
- "url": "https://github.com/youdotcom-oss/mcp-server/issues"
16
+ "url": "https://github.com/youdotcom-oss/dx-toolkit/issues"
16
17
  },
17
- "homepage": "https://github.com/youdotcom-oss/mcp-server/tree/main#readme",
18
+ "homepage": "https://github.com/youdotcom-oss/dx-toolkit/tree/main/packages/mcp#readme",
18
19
  "author": "You.com (https://you.com)",
19
20
  "keywords": [
20
21
  "mcp",
@@ -23,19 +24,17 @@
23
24
  ],
24
25
  "bin": "bin/stdio.js",
25
26
  "type": "module",
26
- "main": "./src/main.ts",
27
+ "main": "./src/utils.ts",
27
28
  "exports": {
28
- ".": "./src/main.ts"
29
+ ".": "./src/utils.ts",
30
+ "./http": "./src/http.ts",
31
+ "./stdio": "./src/stdio.ts"
29
32
  },
30
33
  "files": [
31
34
  "bin/stdio.js",
32
- "src/**/*.schemas.ts",
33
- "src/**/*.utils.ts",
34
- "src/shared/check-response-for-errors.ts",
35
- "src/shared/format-search-results-text.ts",
36
- "AGENTS.md",
37
- "CONTRIBUTING.md",
38
- "docs/API.md"
35
+ "./src/**",
36
+ "!./src/**/tests/*",
37
+ "!./src/**/*.spec.@(tsx|ts)"
39
38
  ],
40
39
  "publishConfig": {
41
40
  "access": "public"
@@ -54,40 +53,19 @@
54
53
  "inspect": "bash -c 'source .env 2>/dev/null || true; bunx @modelcontextprotocol/inspector -e YDC_API_KEY=$YDC_API_KEY bun dev'",
55
54
  "lint": "biome lint",
56
55
  "lint:fix": "biome lint --write",
57
- "prepare": "git config core.hooksPath .hooks",
58
56
  "start": "bun run bin/http",
59
57
  "test": "bun test",
60
58
  "test:coverage": "bun test --coverage",
61
59
  "test:coverage:watch": "bun test --coverage --watch",
62
60
  "test:watch": "bun test --watch"
63
61
  },
64
- "lint-staged": {
65
- "*.{ts,tsx}": [
66
- "biome check --write --no-errors-on-unmatched"
67
- ],
68
- "*.{json,md}": [
69
- "biome format --write --no-errors-on-unmatched"
70
- ],
71
- "package.json": [
72
- "format-package --write"
73
- ]
74
- },
75
62
  "dependencies": {
76
- "zod": "^4.1.13"
63
+ "zod": "^4.1.13",
64
+ "@hono/mcp": "^0.2.0",
65
+ "@modelcontextprotocol/sdk": "^1.24.3",
66
+ "hono": "^4.10.7"
77
67
  },
78
68
  "devDependencies": {
79
- "@biomejs/biome": "2.3.8",
80
- "@commitlint/cli": "20.1.0",
81
- "@commitlint/config-conventional": "20.0.0",
82
- "@eslint/js": "9.39.1",
83
- "@modelcontextprotocol/inspector": "0.17.5",
84
- "@types/bun": "latest",
85
- "typescript": "5.9.3",
86
- "lint-staged": "16.2.7",
87
- "format-package": "7.0.0",
88
- "@hono/bun-compress": "0.1.0",
89
- "@hono/mcp": "0.2.0",
90
- "@modelcontextprotocol/sdk": "1.24.3",
91
- "hono": "4.10.7"
69
+ "@modelcontextprotocol/inspector": "0.17.5"
92
70
  }
93
71
  }
@@ -0,0 +1,90 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { generateErrorReportLink } from '../shared/generate-error-report-link.ts';
3
+ import { getLogger } from '../shared/get-logger.ts';
4
+ import { ContentsQuerySchema, ContentsStructuredContentSchema } from './contents.schemas.ts';
5
+ import { fetchContents, formatContentsResponse } from './contents.utils.ts';
6
+
7
+ /**
8
+ * Register the you-contents tool with the MCP server
9
+ * Extracts and returns full content from multiple URLs in markdown or HTML format
10
+ */
11
+ export const registerContentsTool = ({
12
+ mcp,
13
+ YDC_API_KEY,
14
+ getUserAgent,
15
+ }: {
16
+ mcp: McpServer;
17
+ YDC_API_KEY?: string;
18
+ getUserAgent: () => string;
19
+ }) => {
20
+ // Register the tool
21
+ mcp.registerTool(
22
+ 'you-contents',
23
+ {
24
+ title: 'Extract Web Page Contents',
25
+ description: 'Extract page content in markdown or HTML',
26
+ inputSchema: ContentsQuerySchema.shape,
27
+ outputSchema: ContentsStructuredContentSchema.shape,
28
+ },
29
+ async (toolInput) => {
30
+ const logger = getLogger(mcp);
31
+
32
+ try {
33
+ // Validate and parse input
34
+ const contentsQuery = ContentsQuerySchema.parse(toolInput);
35
+ const { urls, format = 'markdown' } = contentsQuery;
36
+
37
+ // Log the request
38
+ await logger({
39
+ level: 'info',
40
+ data: `Contents API call initiated for ${urls.length} URL(s) with format: ${format}`,
41
+ });
42
+
43
+ // Fetch contents from API
44
+ const response = await fetchContents({
45
+ contentsQuery,
46
+ YDC_API_KEY,
47
+ getUserAgent,
48
+ });
49
+
50
+ // Format response with full content
51
+ const { content, structuredContent } = formatContentsResponse(response, format);
52
+
53
+ // Log success
54
+ await logger({
55
+ level: 'info',
56
+ data: `Contents API call successful: extracted ${response.length} page(s)`,
57
+ });
58
+
59
+ return {
60
+ content,
61
+ structuredContent,
62
+ };
63
+ } catch (err: unknown) {
64
+ // Handle and log errors
65
+ const errorMessage = err instanceof Error ? err.message : String(err);
66
+ const reportLink = generateErrorReportLink({
67
+ errorMessage,
68
+ tool: 'you-contents',
69
+ clientInfo: getUserAgent(),
70
+ });
71
+
72
+ await logger({
73
+ level: 'error',
74
+ data: `Contents API call failed: ${errorMessage}\n\nReport this issue: ${reportLink}`,
75
+ });
76
+
77
+ return {
78
+ content: [
79
+ {
80
+ type: 'text' as const,
81
+ text: `Error extracting contents: ${errorMessage}`,
82
+ },
83
+ ],
84
+ structuredContent: undefined,
85
+ isError: true,
86
+ };
87
+ }
88
+ },
89
+ );
90
+ };
@@ -0,0 +1,188 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import type { ContentsApiResponse } from '../contents.schemas.ts';
3
+ import { fetchContents, formatContentsResponse } from '../contents.utils.ts';
4
+
5
+ const getUserAgent = () => 'MCP/test (You.com; test-client)';
6
+
7
+ // NOTE: The following tests require a You.com API key with access to the Contents API
8
+ // Using example.com/example.org as test URLs since You.com blocks self-scraping
9
+ describe('fetchContents', () => {
10
+ test('returns valid response structure for single URL', async () => {
11
+ const result = await fetchContents({
12
+ contentsQuery: {
13
+ urls: ['https://documentation.you.com/developer-resources/mcp-server'],
14
+ format: 'markdown',
15
+ },
16
+ getUserAgent,
17
+ });
18
+
19
+ expect(Array.isArray(result)).toBe(true);
20
+ expect(result.length).toBeGreaterThan(0);
21
+
22
+ const firstItem = result[0];
23
+ expect(firstItem).toBeDefined();
24
+
25
+ // Should have markdown content
26
+ expect(firstItem?.markdown).toBeDefined();
27
+ expect(typeof firstItem?.markdown).toBe('string');
28
+ });
29
+
30
+ test('handles multiple URLs', async () => {
31
+ const result = await fetchContents({
32
+ contentsQuery: {
33
+ urls: [
34
+ 'https://documentation.you.com/developer-resources/mcp-server',
35
+ 'https://documentation.you.com/developer-resources/python-sdk',
36
+ ],
37
+ format: 'markdown',
38
+ },
39
+ getUserAgent,
40
+ });
41
+
42
+ expect(Array.isArray(result)).toBe(true);
43
+ expect(result.length).toBe(2);
44
+
45
+ for (const item of result) {
46
+ expect(item).toHaveProperty('url');
47
+ expect(item.markdown).toBeDefined();
48
+ }
49
+ });
50
+
51
+ test('handles html format', async () => {
52
+ const result = await fetchContents({
53
+ contentsQuery: {
54
+ urls: ['https://documentation.you.com/developer-resources/mcp-server'],
55
+ format: 'html',
56
+ },
57
+ getUserAgent,
58
+ });
59
+
60
+ expect(Array.isArray(result)).toBe(true);
61
+ const firstItem = result[0];
62
+ expect(firstItem).toBeDefined();
63
+
64
+ expect(firstItem?.html).toBeDefined();
65
+ expect(typeof firstItem?.html).toBe('string');
66
+ });
67
+ });
68
+
69
+ describe('formatContentsResponse', () => {
70
+ test('formats single markdown content correctly', () => {
71
+ const mockResponse: ContentsApiResponse = [
72
+ {
73
+ url: 'https://example.com',
74
+ title: 'Example Page',
75
+ markdown: '# Hello\n\nThis is a test page with some content.',
76
+ },
77
+ ];
78
+
79
+ const result = formatContentsResponse(mockResponse, 'markdown');
80
+
81
+ expect(result).toHaveProperty('content');
82
+ expect(result).toHaveProperty('structuredContent');
83
+ expect(Array.isArray(result.content)).toBe(true);
84
+ expect(result.content[0]).toHaveProperty('type', 'text');
85
+ expect(result.content[0]).toHaveProperty('text');
86
+
87
+ const text = result.content[0]?.text;
88
+ expect(text).toContain('Example Page');
89
+ expect(text).toContain('https://example.com');
90
+ expect(text).toContain('Format: markdown');
91
+ expect(text).toContain('# Hello');
92
+ expect(text).toContain('This is a test page with some content.');
93
+
94
+ expect(result.structuredContent).toHaveProperty('count', 1);
95
+ expect(result.structuredContent).toHaveProperty('format', 'markdown');
96
+ expect(result.structuredContent.items).toHaveLength(1);
97
+
98
+ const item = result.structuredContent.items[0];
99
+ expect(item).toBeDefined();
100
+
101
+ expect(item).toHaveProperty('url', 'https://example.com');
102
+ expect(item).toHaveProperty('title', 'Example Page');
103
+ expect(item).toHaveProperty('content', '# Hello\n\nThis is a test page with some content.');
104
+ expect(item?.contentLength).toBe('# Hello\n\nThis is a test page with some content.'.length);
105
+ });
106
+
107
+ test('formats multiple items correctly', () => {
108
+ const mockResponse: ContentsApiResponse = [
109
+ {
110
+ url: 'https://example1.com',
111
+ title: 'Page 1',
112
+ markdown: 'Content 1',
113
+ },
114
+ {
115
+ url: 'https://example2.com',
116
+ title: 'Page 2',
117
+ markdown: 'Content 2',
118
+ },
119
+ ];
120
+
121
+ const result = formatContentsResponse(mockResponse, 'markdown');
122
+
123
+ expect(result.structuredContent.count).toBe(2);
124
+ expect(result.structuredContent.items).toHaveLength(2);
125
+
126
+ const text = result.content[0]?.text;
127
+ expect(text).toContain('Page 1');
128
+ expect(text).toContain('Page 2');
129
+ expect(text).toContain('https://example1.com');
130
+ expect(text).toContain('https://example2.com');
131
+ });
132
+
133
+ test('handles html format', () => {
134
+ const mockResponse: ContentsApiResponse = [
135
+ {
136
+ url: 'https://example.com',
137
+ title: 'HTML Page',
138
+ html: '<html><body><h1>Hello</h1></body></html>',
139
+ },
140
+ ];
141
+
142
+ const result = formatContentsResponse(mockResponse, 'html');
143
+
144
+ expect(result.structuredContent.format).toBe('html');
145
+ const text = result.content[0]?.text;
146
+ expect(text).toContain('Format: html');
147
+ expect(text).toContain('<html>');
148
+ });
149
+
150
+ test('includes full content for long text', () => {
151
+ const longContent = 'a'.repeat(1000);
152
+ const mockResponse: ContentsApiResponse = [
153
+ {
154
+ url: 'https://example.com',
155
+ title: 'Long Page',
156
+ markdown: longContent,
157
+ },
158
+ ];
159
+
160
+ const result = formatContentsResponse(mockResponse, 'markdown');
161
+
162
+ const text = result.content[0]?.text;
163
+ // Full content should be included (not truncated)
164
+ expect(text).toContain(longContent);
165
+
166
+ // Structured content should have full content and correct length
167
+ const item = result.structuredContent.items[0];
168
+ expect(item?.content).toBe(longContent);
169
+ expect(item?.contentLength).toBe(1000);
170
+ });
171
+
172
+ test('handles empty content gracefully', () => {
173
+ const mockResponse: ContentsApiResponse = [
174
+ {
175
+ url: 'https://example.com',
176
+ title: 'Empty Page',
177
+ markdown: '',
178
+ },
179
+ ];
180
+
181
+ const result = formatContentsResponse(mockResponse, 'markdown');
182
+
183
+ expect(result.structuredContent.items[0]?.contentLength).toBe(0);
184
+ const text = result.content[0]?.text;
185
+ expect(text).toContain('Empty Page');
186
+ expect(text).toContain('Content Length: 0 characters');
187
+ });
188
+ });
@@ -0,0 +1,67 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { generateErrorReportLink } from '../shared/generate-error-report-link.ts';
3
+ import { getLogger } from '../shared/get-logger.ts';
4
+ import { ExpressAgentInputSchema, ExpressStructuredContentSchema } from './express.schemas.ts';
5
+ import { callExpressAgent, formatExpressAgentResponse } from './express.utils.ts';
6
+
7
+ export const registerExpressTool = ({
8
+ mcp,
9
+ YDC_API_KEY,
10
+ getUserAgent,
11
+ }: {
12
+ mcp: McpServer;
13
+ YDC_API_KEY?: string;
14
+ getUserAgent: () => string;
15
+ }) => {
16
+ mcp.registerTool(
17
+ 'you-express',
18
+ {
19
+ title: 'Express Agent',
20
+ description: 'Fast AI answers with web search',
21
+ inputSchema: ExpressAgentInputSchema.shape,
22
+ outputSchema: ExpressStructuredContentSchema.shape,
23
+ },
24
+ async (agentInput) => {
25
+ const logger = getLogger(mcp);
26
+
27
+ try {
28
+ const response = await callExpressAgent({
29
+ agentInput,
30
+ YDC_API_KEY,
31
+ getUserAgent,
32
+ });
33
+
34
+ await logger({
35
+ level: 'info',
36
+ data: `Express agent call successful for input: "${agentInput.input}"`,
37
+ });
38
+
39
+ const { content, structuredContent } = formatExpressAgentResponse(response);
40
+ return { content, structuredContent };
41
+ } catch (err: unknown) {
42
+ const errorMessage = err instanceof Error ? err.message : String(err);
43
+ const reportLink = generateErrorReportLink({
44
+ errorMessage,
45
+ tool: 'you-express',
46
+ clientInfo: getUserAgent(),
47
+ });
48
+
49
+ await logger({
50
+ level: 'error',
51
+ data: `Express agent call failed: ${errorMessage}\n\nReport this issue: ${reportLink}`,
52
+ });
53
+
54
+ return {
55
+ content: [
56
+ {
57
+ type: 'text' as const,
58
+ text: `Error: ${errorMessage}`,
59
+ },
60
+ ],
61
+ structuredContent: undefined,
62
+ isError: true,
63
+ };
64
+ }
65
+ },
66
+ );
67
+ };