@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.
- package/LICENSE +619 -0
- package/README.md +182 -0
- package/dist/client/EnriProxyClient.d.ts +271 -0
- package/dist/client/EnriProxyClient.d.ts.map +1 -0
- package/dist/client/EnriProxyClient.js +221 -0
- package/dist/client/EnriProxyClient.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/package-info.d.ts +8 -0
- package/dist/package-info.d.ts.map +1 -0
- package/dist/package-info.js +28 -0
- package/dist/package-info.js.map +1 -0
- package/dist/server/EnriWebServer.d.ts +70 -0
- package/dist/server/EnriWebServer.d.ts.map +1 -0
- package/dist/server/EnriWebServer.js +218 -0
- package/dist/server/EnriWebServer.js.map +1 -0
- package/dist/shared/validation.d.ts +54 -0
- package/dist/shared/validation.d.ts.map +1 -0
- package/dist/shared/validation.js +112 -0
- package/dist/shared/validation.js.map +1 -0
- package/dist/tools/WebFetchTool.d.ts +232 -0
- package/dist/tools/WebFetchTool.d.ts.map +1 -0
- package/dist/tools/WebFetchTool.js +429 -0
- package/dist/tools/WebFetchTool.js.map +1 -0
- package/dist/tools/WebSearchRegistryVerifier.d.ts +323 -0
- package/dist/tools/WebSearchRegistryVerifier.d.ts.map +1 -0
- package/dist/tools/WebSearchRegistryVerifier.js +890 -0
- package/dist/tools/WebSearchRegistryVerifier.js.map +1 -0
- package/dist/tools/WebSearchTool.d.ts +132 -0
- package/dist/tools/WebSearchTool.d.ts.map +1 -0
- package/dist/tools/WebSearchTool.js +101 -0
- package/dist/tools/WebSearchTool.js.map +1 -0
- 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 @@
|
|
|
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
|