@bedolla/enriweb 0.1.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.
Files changed (35) hide show
  1. package/LICENSE +619 -0
  2. package/README.md +182 -0
  3. package/dist/client/EnriProxyClient.d.ts +271 -0
  4. package/dist/client/EnriProxyClient.d.ts.map +1 -0
  5. package/dist/client/EnriProxyClient.js +221 -0
  6. package/dist/client/EnriProxyClient.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +148 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/package-info.d.ts +8 -0
  12. package/dist/package-info.d.ts.map +1 -0
  13. package/dist/package-info.js +28 -0
  14. package/dist/package-info.js.map +1 -0
  15. package/dist/server/EnriWebServer.d.ts +70 -0
  16. package/dist/server/EnriWebServer.d.ts.map +1 -0
  17. package/dist/server/EnriWebServer.js +218 -0
  18. package/dist/server/EnriWebServer.js.map +1 -0
  19. package/dist/shared/validation.d.ts +54 -0
  20. package/dist/shared/validation.d.ts.map +1 -0
  21. package/dist/shared/validation.js +112 -0
  22. package/dist/shared/validation.js.map +1 -0
  23. package/dist/tools/WebFetchTool.d.ts +232 -0
  24. package/dist/tools/WebFetchTool.d.ts.map +1 -0
  25. package/dist/tools/WebFetchTool.js +429 -0
  26. package/dist/tools/WebFetchTool.js.map +1 -0
  27. package/dist/tools/WebSearchRegistryVerifier.d.ts +323 -0
  28. package/dist/tools/WebSearchRegistryVerifier.d.ts.map +1 -0
  29. package/dist/tools/WebSearchRegistryVerifier.js +890 -0
  30. package/dist/tools/WebSearchRegistryVerifier.js.map +1 -0
  31. package/dist/tools/WebSearchTool.d.ts +132 -0
  32. package/dist/tools/WebSearchTool.d.ts.map +1 -0
  33. package/dist/tools/WebSearchTool.js +101 -0
  34. package/dist/tools/WebSearchTool.js.map +1 -0
  35. package/package.json +54 -0
package/dist/index.js ADDED
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ENRIWEB - MCP ENTRYPOINT
4
+ *
5
+ * Starts the EnriWeb MCP server on stdio.
6
+ *
7
+ * @module index
8
+ */
9
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10
+ import { EnriProxyClient } from "./client/EnriProxyClient.js";
11
+ import { WebSearchTool } from "./tools/WebSearchTool.js";
12
+ import { WebFetchTool } from "./tools/WebFetchTool.js";
13
+ import { WebSearchRegistryVerifier } from "./tools/WebSearchRegistryVerifier.js";
14
+ import { EnriWebServer } from "./server/EnriWebServer.js";
15
+ import { packageInfoService } from "./package-info.js";
16
+ /**
17
+ * Environment variable for EnriProxy base URL.
18
+ */
19
+ const ENRIPROXY_URL_ENV = "ENRIPROXY_URL";
20
+ /**
21
+ * Environment variable for EnriProxy API key.
22
+ */
23
+ const ENRIPROXY_API_KEY_ENV = "ENRIPROXY_API_KEY";
24
+ /**
25
+ * Environment variable for default request timeout in milliseconds.
26
+ */
27
+ const ENRIWEB_TIMEOUT_MS_ENV = "ENRIWEB_TIMEOUT_MS";
28
+ /**
29
+ * Environment variable for the default `web_fetch` max_chars limit.
30
+ */
31
+ const ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS_ENV = "ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS";
32
+ /**
33
+ * Environment variable for an optional GitHub token used by `web_search`
34
+ * enrichment to improve GitHub API rate limits.
35
+ */
36
+ const ENRIWEB_GITHUB_TOKEN_ENV = "ENRIWEB_GITHUB_TOKEN";
37
+ /**
38
+ * Default EnriProxy URL used when env is not set.
39
+ */
40
+ const DEFAULT_ENRIPROXY_URL = "http://127.0.0.1:8787";
41
+ /**
42
+ * Default request timeout in milliseconds.
43
+ */
44
+ const DEFAULT_TIMEOUT_MS = 60 * 1000;
45
+ /**
46
+ * Default maximum `web_fetch` content length.
47
+ *
48
+ * @remarks
49
+ * This aligns with EnriProxy's tool-preview defaults to reduce the risk of MCP
50
+ * tool-result truncation in clients that enforce output token limits.
51
+ *
52
+ * Note: Some MCP clients enforce tool-result token limits (for example Claude
53
+ * Code CLI limits like MAX_MCP_OUTPUT_TOKENS=32000). Large outputs may be
54
+ * truncated by the client or written to a tool-results file for paging.
55
+ */
56
+ const DEFAULT_WEB_FETCH_MAX_CHARS = 200_000;
57
+ /**
58
+ * Default timeout (ms) for registry enrichment requests.
59
+ */
60
+ const DEFAULT_REGISTRY_TIMEOUT_MS = 15_000;
61
+ /**
62
+ * Default cache TTL (ms) for registry enrichment.
63
+ */
64
+ const DEFAULT_REGISTRY_CACHE_TTL_MS = 5 * 60 * 1000;
65
+ /**
66
+ * Default maximum entities verified per `web_search` call.
67
+ */
68
+ const DEFAULT_REGISTRY_MAX_ENTITIES_PER_CALL = 6;
69
+ /**
70
+ * Entry point for the MCP server.
71
+ */
72
+ async function main() {
73
+ const args = process.argv.slice(2);
74
+ if (args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
75
+ console.log("EnriWeb");
76
+ console.log("");
77
+ console.log("This is an MCP server over stdio that provides web search and URL fetching via EnriProxy.");
78
+ console.log("");
79
+ console.log("Usage:");
80
+ console.log(" enriweb (start MCP server over stdio)");
81
+ console.log(" enriweb --version");
82
+ console.log(" enriweb --help");
83
+ console.log("");
84
+ console.log("Environment variables:");
85
+ console.log(" ENRIPROXY_URL (optional, default: http://127.0.0.1:8787)");
86
+ console.log(" ENRIPROXY_API_KEY (required)");
87
+ console.log(" ENRIWEB_TIMEOUT_MS (optional, default: 60000)");
88
+ console.log(" ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS (optional, default: 200000)");
89
+ console.log(" ENRIWEB_GITHUB_TOKEN (optional, improves GitHub API rate limits)");
90
+ process.exit(0);
91
+ }
92
+ if (args[0] === "--version" || args[0] === "-v" || args[0] === "version") {
93
+ console.log(packageInfoService.getVersion());
94
+ process.exit(0);
95
+ }
96
+ const serverUrl = (process.env[ENRIPROXY_URL_ENV] ?? DEFAULT_ENRIPROXY_URL).trim();
97
+ const apiKey = (process.env[ENRIPROXY_API_KEY_ENV] ?? "").trim();
98
+ const timeoutMsRaw = (process.env[ENRIWEB_TIMEOUT_MS_ENV] ?? "").trim();
99
+ const defaultWebFetchMaxCharsRaw = (process.env[ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS_ENV] ?? "").trim();
100
+ const timeoutMs = timeoutMsRaw ? Number.parseInt(timeoutMsRaw, 10) : DEFAULT_TIMEOUT_MS;
101
+ const defaultWebFetchMaxChars = defaultWebFetchMaxCharsRaw
102
+ ? Number.parseInt(defaultWebFetchMaxCharsRaw, 10)
103
+ : DEFAULT_WEB_FETCH_MAX_CHARS;
104
+ const githubToken = (process.env[ENRIWEB_GITHUB_TOKEN_ENV] ?? "").trim();
105
+ const createClient = (baseUrl, key, timeout) => new EnriProxyClient({
106
+ baseUrl,
107
+ apiKey: key,
108
+ timeoutMs: timeout
109
+ });
110
+ const resolvedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS;
111
+ const resolvedDefaultWebFetchMaxChars = Number.isFinite(defaultWebFetchMaxChars) && defaultWebFetchMaxChars > 0
112
+ ? defaultWebFetchMaxChars
113
+ : DEFAULT_WEB_FETCH_MAX_CHARS;
114
+ const webSearchTool = new WebSearchTool({
115
+ createClient,
116
+ defaultServerUrl: serverUrl,
117
+ defaultApiKey: apiKey,
118
+ defaultTimeoutMs: resolvedTimeoutMs,
119
+ registryVerifier: new WebSearchRegistryVerifier({
120
+ fetchImpl: fetch,
121
+ timeoutMs: DEFAULT_REGISTRY_TIMEOUT_MS,
122
+ cacheTtlMs: DEFAULT_REGISTRY_CACHE_TTL_MS,
123
+ maxEntitiesPerCall: DEFAULT_REGISTRY_MAX_ENTITIES_PER_CALL,
124
+ githubToken: githubToken.length > 0 ? githubToken : undefined
125
+ })
126
+ });
127
+ const webFetchTool = new WebFetchTool({
128
+ createClient,
129
+ defaultServerUrl: serverUrl,
130
+ defaultApiKey: apiKey,
131
+ defaultTimeoutMs: resolvedTimeoutMs,
132
+ defaultMaxChars: resolvedDefaultWebFetchMaxChars
133
+ });
134
+ const server = new EnriWebServer({
135
+ name: "EnriWeb",
136
+ version: packageInfoService.getVersion(),
137
+ webSearchTool,
138
+ webFetchTool
139
+ });
140
+ const transport = new StdioServerTransport();
141
+ await server.connect(transport);
142
+ console.error("[EnriWeb] MCP server running on stdio");
143
+ }
144
+ void main().catch((error) => {
145
+ console.error("[EnriWeb] FATAL:", error instanceof Error ? error.message : String(error));
146
+ process.exit(1);
147
+ });
148
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare class PackageInfoService {
2
+ private readonly require;
3
+ private cachedVersion;
4
+ constructor();
5
+ getVersion(): string;
6
+ }
7
+ export declare const packageInfoService: PackageInfoService;
8
+ //# sourceMappingURL=package-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-info.d.ts","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAIA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,aAAa,CAAuB;;IAMrC,UAAU,IAAI,MAAM;CAkB5B;AAED,eAAO,MAAM,kBAAkB,EAAE,kBAA6C,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { createRequire } from "node:module";
2
+ export class PackageInfoService {
3
+ require;
4
+ cachedVersion = null;
5
+ constructor() {
6
+ this.require = createRequire(import.meta.url);
7
+ }
8
+ getVersion() {
9
+ if (this.cachedVersion !== null)
10
+ return this.cachedVersion;
11
+ const fallback = "0.0.0";
12
+ try {
13
+ const pkg = this.require("../package.json");
14
+ const version = pkg.version;
15
+ if (typeof version === "string" && version.trim().length > 0) {
16
+ this.cachedVersion = version;
17
+ return version;
18
+ }
19
+ }
20
+ catch {
21
+ // ignore
22
+ }
23
+ this.cachedVersion = fallback;
24
+ return fallback;
25
+ }
26
+ }
27
+ export const packageInfoService = new PackageInfoService();
28
+ //# sourceMappingURL=package-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-info.js","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,MAAM,OAAO,kBAAkB;IACZ,OAAO,CAAc;IAC9B,aAAa,GAAkB,IAAI,CAAC;IAE5C;QACE,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,CAAC;IAEM,UAAU;QACf,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,aAAa,CAAC;QAE3D,MAAM,QAAQ,GAAG,OAAO,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAqB,CAAC;YAChE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YAC5B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7D,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;gBAC7B,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAuB,IAAI,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,70 @@
1
+ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
2
+ import type { WebSearchTool } from "../tools/WebSearchTool.js";
3
+ import type { WebFetchTool } from "../tools/WebFetchTool.js";
4
+ /**
5
+ * Configuration for {@link EnriWebServer}.
6
+ */
7
+ export interface EnriWebServerConfig {
8
+ /**
9
+ * Server name reported via MCP.
10
+ */
11
+ readonly name: string;
12
+ /**
13
+ * Server version reported via MCP.
14
+ */
15
+ readonly version: string;
16
+ /**
17
+ * Web search tool implementation.
18
+ */
19
+ readonly webSearchTool: WebSearchTool;
20
+ /**
21
+ * Web fetch tool implementation.
22
+ */
23
+ readonly webFetchTool: WebFetchTool;
24
+ }
25
+ /**
26
+ * MCP server exposing EnriWeb tools.
27
+ */
28
+ export declare class EnriWebServer {
29
+ /**
30
+ * Underlying MCP server implementation.
31
+ */
32
+ private readonly server;
33
+ /**
34
+ * Web search tool implementation.
35
+ */
36
+ private readonly webSearchTool;
37
+ /**
38
+ * Web fetch tool implementation.
39
+ */
40
+ private readonly webFetchTool;
41
+ /**
42
+ * Creates a new {@link EnriWebServer}.
43
+ *
44
+ * @param config - Server configuration
45
+ */
46
+ constructor(config: EnriWebServerConfig);
47
+ /**
48
+ * Connects the server to a transport and starts listening.
49
+ *
50
+ * @param transport - MCP transport (stdio)
51
+ */
52
+ connect(transport: Transport): Promise<void>;
53
+ /**
54
+ * Registers tool list and tool call handlers.
55
+ */
56
+ private registerToolHandlers;
57
+ /**
58
+ * Returns the JSON schema tool definition for `web_search`.
59
+ *
60
+ * @returns Tool definition
61
+ */
62
+ private getWebSearchToolDefinition;
63
+ /**
64
+ * Returns the JSON schema tool definition for `web_fetch`.
65
+ *
66
+ * @returns Tool definition
67
+ */
68
+ private getWebFetchToolDefinition;
69
+ }
70
+ //# sourceMappingURL=EnriWebServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnriWebServer.d.ts","sourceRoot":"","sources":["../../src/server/EnriWebServer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAQ/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IAEtC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C;;;;OAIG;gBACgB,MAAM,EAAE,mBAAmB;IAkB9C;;;;OAIG;IACU,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAiD5B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAyDlC;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;CAwDlC"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * ENRIWEB MCP SERVER
3
+ *
4
+ * Implements a minimal MCP server (stdio transport) exposing:
5
+ * - `web_search`
6
+ * - `web_fetch`
7
+ *
8
+ * @module server/EnriWebServer
9
+ */
10
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
11
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
12
+ /**
13
+ * MCP server exposing EnriWeb tools.
14
+ */
15
+ export class EnriWebServer {
16
+ /**
17
+ * Underlying MCP server implementation.
18
+ */
19
+ server;
20
+ /**
21
+ * Web search tool implementation.
22
+ */
23
+ webSearchTool;
24
+ /**
25
+ * Web fetch tool implementation.
26
+ */
27
+ webFetchTool;
28
+ /**
29
+ * Creates a new {@link EnriWebServer}.
30
+ *
31
+ * @param config - Server configuration
32
+ */
33
+ constructor(config) {
34
+ this.webSearchTool = config.webSearchTool;
35
+ this.webFetchTool = config.webFetchTool;
36
+ this.server = new Server({ name: config.name, version: config.version }, {
37
+ capabilities: {
38
+ tools: {
39
+ listChanged: false
40
+ }
41
+ }
42
+ });
43
+ this.registerToolHandlers();
44
+ }
45
+ /**
46
+ * Connects the server to a transport and starts listening.
47
+ *
48
+ * @param transport - MCP transport (stdio)
49
+ */
50
+ async connect(transport) {
51
+ await this.server.connect(transport);
52
+ }
53
+ /**
54
+ * Registers tool list and tool call handlers.
55
+ */
56
+ registerToolHandlers() {
57
+ const tools = [
58
+ this.getWebSearchToolDefinition(),
59
+ this.getWebFetchToolDefinition()
60
+ ];
61
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
62
+ return { tools };
63
+ });
64
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
65
+ const toolName = request.params.name;
66
+ const args = request.params.arguments ?? {};
67
+ try {
68
+ if (toolName === "web_search") {
69
+ const params = this.webSearchTool.parseParams(args);
70
+ const result = await this.webSearchTool.execute(params);
71
+ return {
72
+ isError: false,
73
+ content: [{ type: "text", text: this.webSearchTool.formatOutput(result) }],
74
+ structuredContent: result
75
+ };
76
+ }
77
+ if (toolName === "web_fetch") {
78
+ const params = this.webFetchTool.parseParams(args);
79
+ const result = await this.webFetchTool.execute(params);
80
+ return {
81
+ isError: false,
82
+ content: [{ type: "text", text: this.webFetchTool.formatOutput(result) }],
83
+ structuredContent: result
84
+ };
85
+ }
86
+ return {
87
+ isError: true,
88
+ content: [{ type: "text", text: `Unknown tool: ${toolName}` }]
89
+ };
90
+ }
91
+ catch (error) {
92
+ const message = error instanceof Error ? error.message : String(error);
93
+ return {
94
+ isError: true,
95
+ content: [{ type: "text", text: message }]
96
+ };
97
+ }
98
+ });
99
+ }
100
+ /**
101
+ * Returns the JSON schema tool definition for `web_search`.
102
+ *
103
+ * @returns Tool definition
104
+ */
105
+ getWebSearchToolDefinition() {
106
+ return {
107
+ name: "web_search",
108
+ description: "Search the web via EnriProxy's multi-tier search service.\n" +
109
+ "\n" +
110
+ "When to use:\n" +
111
+ "- When you need to find current information, news, or documentation.\n" +
112
+ "- When searching for technical solutions, APIs, or code examples.\n" +
113
+ "- When you need to verify facts or find up-to-date sources.\n" +
114
+ "\n" +
115
+ "Features:\n" +
116
+ "- Automatic fallback across multiple search backends (details intentionally not exposed)\n" +
117
+ "- Automatic registry verification: enriches results with latest stable + prerelease versions when registry URLs are detected (npm, PyPI, crates.io, NuGet, GitHub)\n" +
118
+ "- Domain filtering (allowlist/blocklist)\n" +
119
+ "- Recency filtering (day/week/month/year)\n" +
120
+ "\n" +
121
+ "Notes:\n" +
122
+ "- Provide specific queries for best results.\n" +
123
+ "- Use recency filter for time-sensitive information.",
124
+ inputSchema: {
125
+ type: "object",
126
+ properties: {
127
+ query: {
128
+ type: "string",
129
+ description: "Search query. Be specific for better results."
130
+ },
131
+ max_results: {
132
+ type: "integer",
133
+ description: "Maximum results (>= 1). If omitted, EnriProxy uses its configured default. The upper limit is enforced server-side."
134
+ },
135
+ recency: {
136
+ type: "string",
137
+ enum: ["oneDay", "oneWeek", "oneMonth", "oneYear", "noLimit"],
138
+ description: "Filter by recency (default: noLimit)."
139
+ },
140
+ allowed_domains: {
141
+ type: "array",
142
+ items: { type: "string" },
143
+ description: "Only return results from these domains."
144
+ },
145
+ blocked_domains: {
146
+ type: "array",
147
+ items: { type: "string" },
148
+ description: "Exclude results from these domains."
149
+ },
150
+ search_prompt: {
151
+ type: "string",
152
+ description: "Optional context to refine search intent."
153
+ }
154
+ },
155
+ required: ["query"]
156
+ }
157
+ };
158
+ }
159
+ /**
160
+ * Returns the JSON schema tool definition for `web_fetch`.
161
+ *
162
+ * @returns Tool definition
163
+ */
164
+ getWebFetchToolDefinition() {
165
+ const defaultMaxChars = this.webFetchTool.getDefaultMaxChars();
166
+ return {
167
+ name: "web_fetch",
168
+ description: "Fetch and read content from a URL via EnriProxy's multi-tier fetch service.\n" +
169
+ "\n" +
170
+ "When to use:\n" +
171
+ "- When you need to read the full content of a webpage.\n" +
172
+ "- When you need to access documentation, articles, or code files.\n" +
173
+ "- When simpler fetch methods fail due to anti-bot protection.\n" +
174
+ "\n" +
175
+ "Features:\n" +
176
+ "- Package registry API detection (npm, PyPI)\n" +
177
+ "- Raw file fetch (GitHub raw, HuggingFace)\n" +
178
+ "- Robust fetching for static, dynamic, and bot-protected sites (best-effort)\n" +
179
+ "- Automatic fallback across multiple retrieval strategies (details intentionally not exposed)\n" +
180
+ "\n" +
181
+ "Notes:\n" +
182
+ "- Provide the full URL including protocol (https://).\n" +
183
+ `- Content is limited by the \`max_chars\` parameter (default: ${defaultMaxChars}).\n` +
184
+ "- If the result is truncated and includes a `cursor`, call `web_fetch` again with `cursor` + `offset` + `limit` to read more without re-fetching.",
185
+ inputSchema: {
186
+ type: "object",
187
+ properties: {
188
+ url: {
189
+ type: "string",
190
+ description: "Full URL to fetch (http:// or https://)."
191
+ },
192
+ cursor: {
193
+ type: "string",
194
+ description: "Opaque cursor returned by a previous `web_fetch` call for pagination."
195
+ },
196
+ prompt: {
197
+ type: "string",
198
+ description: "Optional hint describing what you want to extract (the tool returns fetched content; it does not generate an AI summary)."
199
+ },
200
+ max_chars: {
201
+ type: "integer",
202
+ description: `Maximum content length (default: ${defaultMaxChars}).`
203
+ },
204
+ offset: {
205
+ type: "integer",
206
+ description: "Cursor read offset in characters (default: 0)."
207
+ },
208
+ limit: {
209
+ type: "integer",
210
+ description: "Cursor read limit in characters (default: max_chars)."
211
+ }
212
+ },
213
+ anyOf: [{ required: ["url"] }, { required: ["cursor"] }]
214
+ }
215
+ };
216
+ }
217
+ }
218
+ //# sourceMappingURL=EnriWebServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnriWebServer.js","sourceRoot":"","sources":["../../src/server/EnriWebServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * INPUT VALIDATION UTILITIES
3
+ *
4
+ * @module shared/validation
5
+ */
6
+ /**
7
+ * Asserts that value is a non-null object.
8
+ *
9
+ * @param value - Value to check
10
+ * @param name - Parameter name for error messages
11
+ * @returns Value as Record
12
+ * @throws Error if not an object
13
+ */
14
+ export declare function assertObject(value: unknown, name: string): Record<string, unknown>;
15
+ /**
16
+ * Asserts that value is a non-empty string.
17
+ *
18
+ * @param value - Value to check
19
+ * @param name - Parameter name for error messages
20
+ * @returns Trimmed string
21
+ * @throws Error if not a non-empty string
22
+ */
23
+ export declare function assertNonEmptyString(value: unknown, name: string): string;
24
+ /**
25
+ * Asserts that value is a valid HTTP/HTTPS URL.
26
+ *
27
+ * @param value - Value to check
28
+ * @param name - Parameter name for error messages
29
+ * @returns URL string
30
+ * @throws Error if not a valid HTTP/HTTPS URL
31
+ */
32
+ export declare function assertHttpUrl(value: unknown, name: string): string;
33
+ /**
34
+ * Returns trimmed string or undefined.
35
+ *
36
+ * @param value - Value to check
37
+ * @returns Trimmed string or undefined
38
+ */
39
+ export declare function optionalString(value: unknown): string | undefined;
40
+ /**
41
+ * Returns integer or undefined.
42
+ *
43
+ * @param value - Value to check
44
+ * @returns Integer or undefined
45
+ */
46
+ export declare function optionalInt(value: unknown): number | undefined;
47
+ /**
48
+ * Returns a list of trimmed strings or undefined.
49
+ *
50
+ * @param value - Value to check
51
+ * @returns String array or undefined
52
+ */
53
+ export declare function optionalStringArray(value: unknown): string[] | undefined;
54
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/shared/validation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKlF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CASzE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWlE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAMjE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAW9D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAexE"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * INPUT VALIDATION UTILITIES
3
+ *
4
+ * @module shared/validation
5
+ */
6
+ /**
7
+ * Asserts that value is a non-null object.
8
+ *
9
+ * @param value - Value to check
10
+ * @param name - Parameter name for error messages
11
+ * @returns Value as Record
12
+ * @throws Error if not an object
13
+ */
14
+ export function assertObject(value, name) {
15
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
16
+ throw new Error(`${name} must be an object.`);
17
+ }
18
+ return value;
19
+ }
20
+ /**
21
+ * Asserts that value is a non-empty string.
22
+ *
23
+ * @param value - Value to check
24
+ * @param name - Parameter name for error messages
25
+ * @returns Trimmed string
26
+ * @throws Error if not a non-empty string
27
+ */
28
+ export function assertNonEmptyString(value, name) {
29
+ if (typeof value !== "string") {
30
+ throw new Error(`${name} must be a string.`);
31
+ }
32
+ const trimmed = value.trim();
33
+ if (!trimmed) {
34
+ throw new Error(`${name} must be a non-empty string.`);
35
+ }
36
+ return trimmed;
37
+ }
38
+ /**
39
+ * Asserts that value is a valid HTTP/HTTPS URL.
40
+ *
41
+ * @param value - Value to check
42
+ * @param name - Parameter name for error messages
43
+ * @returns URL string
44
+ * @throws Error if not a valid HTTP/HTTPS URL
45
+ */
46
+ export function assertHttpUrl(value, name) {
47
+ const url = assertNonEmptyString(value, name);
48
+ try {
49
+ const parsed = new URL(url);
50
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
51
+ throw new Error(`${name} must be an HTTP or HTTPS URL.`);
52
+ }
53
+ return parsed.toString();
54
+ }
55
+ catch {
56
+ throw new Error(`${name} must be a valid URL.`);
57
+ }
58
+ }
59
+ /**
60
+ * Returns trimmed string or undefined.
61
+ *
62
+ * @param value - Value to check
63
+ * @returns Trimmed string or undefined
64
+ */
65
+ export function optionalString(value) {
66
+ if (typeof value === "string") {
67
+ const trimmed = value.trim();
68
+ return trimmed ? trimmed : undefined;
69
+ }
70
+ return undefined;
71
+ }
72
+ /**
73
+ * Returns integer or undefined.
74
+ *
75
+ * @param value - Value to check
76
+ * @returns Integer or undefined
77
+ */
78
+ export function optionalInt(value) {
79
+ if (typeof value === "number" && Number.isFinite(value)) {
80
+ return Math.floor(value);
81
+ }
82
+ if (typeof value === "string" && value.trim()) {
83
+ const parsed = Number.parseInt(value, 10);
84
+ if (Number.isFinite(parsed)) {
85
+ return parsed;
86
+ }
87
+ }
88
+ return undefined;
89
+ }
90
+ /**
91
+ * Returns a list of trimmed strings or undefined.
92
+ *
93
+ * @param value - Value to check
94
+ * @returns String array or undefined
95
+ */
96
+ export function optionalStringArray(value) {
97
+ if (!Array.isArray(value)) {
98
+ return undefined;
99
+ }
100
+ const collected = [];
101
+ for (const entry of value) {
102
+ if (typeof entry !== "string") {
103
+ continue;
104
+ }
105
+ const trimmed = entry.trim();
106
+ if (trimmed) {
107
+ collected.push(trimmed);
108
+ }
109
+ }
110
+ return collected.length > 0 ? collected : undefined;
111
+ }
112
+ //# sourceMappingURL=validation.js.map