@onedotmint/siftpath 0.0.0-stage → 2.0.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -2
  3. package/THIRD_PARTY_NOTICES.md +26 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +116 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/client.d.ts +144 -0
  8. package/dist/client.js +130 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/config.d.ts +107 -0
  11. package/dist/config.js +127 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/defaults.d.ts +38 -0
  14. package/dist/defaults.js +31 -0
  15. package/dist/defaults.js.map +1 -0
  16. package/dist/diagnostics.d.ts +158 -0
  17. package/dist/diagnostics.js +202 -0
  18. package/dist/diagnostics.js.map +1 -0
  19. package/dist/errors.d.ts +15 -0
  20. package/dist/errors.js +16 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.js +5 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/inputs.d.ts +25 -0
  26. package/dist/inputs.js +27 -0
  27. package/dist/inputs.js.map +1 -0
  28. package/dist/mcp/stdio.d.ts +2 -0
  29. package/dist/mcp/stdio.js +43 -0
  30. package/dist/mcp/stdio.js.map +1 -0
  31. package/dist/output.d.ts +23 -0
  32. package/dist/output.js +118 -0
  33. package/dist/output.js.map +1 -0
  34. package/dist/router.d.ts +20 -0
  35. package/dist/router.js +85 -0
  36. package/dist/router.js.map +1 -0
  37. package/dist/setup-ui.d.ts +8 -0
  38. package/dist/setup-ui.js +3032 -0
  39. package/dist/setup-ui.js.map +1 -0
  40. package/dist/setup.d.ts +2 -0
  41. package/dist/setup.js +50 -0
  42. package/dist/setup.js.map +1 -0
  43. package/dist/tools.d.ts +35 -0
  44. package/dist/tools.js +17 -0
  45. package/dist/tools.js.map +1 -0
  46. package/dist/version.d.ts +1 -0
  47. package/dist/version.js +4 -0
  48. package/dist/version.js.map +1 -0
  49. package/docs/ARCHITECTURE.md +33 -0
  50. package/docs/CONFIGURATION.md +127 -0
  51. package/docs/DIAGNOSTICS.md +109 -0
  52. package/docs/MIGRATION.md +13 -0
  53. package/docs/PROVIDERS.md +43 -0
  54. package/docs/SECURITY.md +15 -0
  55. package/docs/TESTING.md +138 -0
  56. package/examples/anonymous.json +36 -0
  57. package/extensions/siftpath.mjs +32 -0
  58. package/package.json +60 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 GuDaStudio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,166 @@
1
- # Temporary Holding Version
1
+ # Siftpath
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Siftpath is a small TypeScript/Node.js 22+ MCP router for AI agents. It exposes exactly two model-facing tools:
4
+
5
+ - `web_search({ query, intent?, maxResults? })`
6
+ - `web_read({ url, focus? })`
7
+
8
+ It does not search, parse HTML, chunk, rerank, merge, or run an LLM. It lazily connects to configured official MCP servers, maps the two stable inputs to their configured tool names, forwards the official result, keeps source URLs, bounds the serialized output, and tries configured fallbacks sequentially.
9
+
10
+ ## Install and run
11
+
12
+ Install the stable release (Node.js 22+; npm `latest` tag):
13
+
14
+ ```bash
15
+ npm install -g @onedotmint/siftpath@latest
16
+ siftpath --version
17
+ siftpath setup
18
+ siftpath status
19
+ ```
20
+
21
+ Alternatively, build from an existing source checkout:
22
+
23
+ ```bash
24
+ npm ci
25
+ npm run build
26
+ # Optional: npm link (installs the siftpath command for this source checkout)
27
+ node dist/cli.js mcp
28
+ ```
29
+
30
+ In an MCP client, the simplest local configuration is:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "siftpath": {
36
+ "command": "node",
37
+ "args": ["/absolute/path/to/Siftpath/dist/cli.js", "mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ The same process serves stdio MCP. It requires no Docker, database, browser, background daemon, local model, or HTTP server.
44
+
45
+ With the global npm install or `npm link` (otherwise replace `siftpath` with `node dist/cli.js`):
46
+
47
+ ```bash
48
+ siftpath doctor
49
+ siftpath search "Node.js 22 release notes" --intent general
50
+ siftpath search "semantic similarity API" --intent semantic --max-results 5
51
+ siftpath read https://example.com --focus "What is this page about?"
52
+ ```
53
+
54
+ To install the single package elsewhere, run `npm pack` here, then `npm install /absolute/path/to/onedotmint-siftpath-2.0.0.tgz` in the consuming project (or `npm install -g` for the CLI). The tarball includes compiled runtime, declarations, docs and the anonymous config example.
55
+
56
+ SDK example:
57
+
58
+ ```ts
59
+ import { Siftpath, readConfiguration } from '@onedotmint/siftpath';
60
+ const siftpath = new Siftpath(await readConfiguration());
61
+ try {
62
+ const result = await siftpath.search({ query: 'Node.js documentation' });
63
+ console.log(result.content, result.sources);
64
+ } finally { await siftpath.close(); }
65
+ ```
66
+
67
+ ## Try without provider keys
68
+
69
+ Exa and Jina currently offer anonymous hosted MCP access. To opt in (quotas/availability may change):
70
+
71
+ ```bash
72
+ SIFTPATH_CONFIG="$PWD/examples/anonymous.json" node dist/cli.js search "Node.js documentation"
73
+ SIFTPATH_CONFIG="$PWD/examples/anonymous.json" node dist/cli.js read https://example.com
74
+ ```
75
+
76
+ For a local MCP client, add `"env": { "SIFTPATH_CONFIG": "/absolute/path/to/Siftpath/examples/anonymous.json" }` to the server entry above. Brave remains the general primary when a key exists, otherwise it falls back to Exa. These examples write no private configuration or secrets. See [配置与可选服务](docs/CONFIGURATION.md), [接口核验](docs/PROVIDERS.md), [验证记录](docs/TESTING.md), [迁移](docs/MIGRATION.md), and [安全边界](docs/SECURITY.md).
77
+
78
+ ## Configuration
79
+
80
+ Run `siftpath setup` for the Clack wizard: arrows navigate, Space selects providers, Enter confirms, Esc/Ctrl+C cancels without saving. Select Brave/Exa/Tavily/Jina/Firecrawl, keep or replace hidden Keys (or explicitly choose supported anonymous access), choose default search/read and ordered fallback, then optionally confirm real tests. No tool-name/JSON editing is required.
81
+
82
+ `setup --non-interactive` only creates minimal defaults at `~/.config/siftpath/config.json` (or `SIFTPATH_CONFIG`). Keys can also be supplied as environment variables. Configuration is private JSON, written atomically with mode 0600; secrets are never printed or put into model schemas.
83
+
84
+ The built-in routes are:
85
+
86
+ - general/default search → Brave `brave_web_search`
87
+ - semantic search → Exa `web_search_exa`
88
+ - research → optional configured provider (Tavily is an example)
89
+ - read → Jina `read_url`, with `focus` mapped to its native `question` parameter
90
+
91
+ Only a provider with a complete connection and all required credential references resolved is attempted. The default config uses:
92
+
93
+ - Brave stdio: `npx -y @brave/brave-search-mcp-server@2.1.4 --transport stdio`, `BRAVE_API_KEY`
94
+ - Exa stdio: `npx -y exa-mcp-server@3.4.2`, `EXA_API_KEY`
95
+ - Jina Streamable HTTP: `https://mcp.jina.ai/v1`, `JINA_API_KEY` for the default authenticated route; anonymous reading is an explicit opt-in
96
+
97
+ The versions and tool names above were checked against the official repositories on this rebuild. Check the official servers before upgrading: hosted/runtime schemas can change independently of their source README. Jina `question` is native; if a configured reader has no `$focus` mapping, Siftpath returns `FOCUS_UNSUPPORTED` rather than pretending to extract locally.
98
+
99
+ Minimal custom provider example:
100
+
101
+ ```json
102
+ {
103
+ "version": 2,
104
+ "providers": {
105
+ "brave": {
106
+ "enabled": true,
107
+ "connection": {
108
+ "transport": "stdio",
109
+ "command": "npx",
110
+ "args": ["-y", "@brave/brave-search-mcp-server@2.1.4", "--transport", "stdio"],
111
+ "env": { "BRAVE_API_KEY": "${BRAVE_API_KEY}" }
112
+ },
113
+ "search": {
114
+ "name": "brave_web_search",
115
+ "arguments": { "query": "$query", "count": "$maxResults" }
116
+ }
117
+ }
118
+ },
119
+ "routes": { "search": "brave", "read": "jina", "intents": {}, "searchFallback": [], "readFallback": [] }
120
+ }
121
+ ```
122
+
123
+ Connection transports are `stdio` (`command`, `args`, `env`) and Streamable HTTP (`url`, `headers`). HTTP URLs reject credentials, query-string secrets, and insecure non-loopback HTTP. Use `${ENV_NAME}` in connection env/headers, never in commands, arguments or URLs; environment variables override saved credentials. `doctor` reports `READY`, `MISSING_CREDENTIALS`, `DISABLED`, and unsupported route diagnostics without making network calls.
124
+
125
+ Tavily and Firecrawl have built-in presets, disabled until selected in `setup`. Tavily uses official `tavily-mcp@0.2.22` / `tavily_search` (basic, 5–20 results), with a Key or its native stdio Keyless mode. Firecrawl uses official `firecrawl-mcp@3.33.4` / `firecrawl_scrape` with a Key, or the official anonymous hosted MCP. Both were verified through real MCP calls. See [配置向导](docs/CONFIGURATION.md). Clack 1.8.1 and esbuild 0.25.12 are build-only: the ~111 KiB setup bundle is dynamically loaded only in interactive setup, with no new runtime dependency.
126
+
127
+ ## Output and safety
128
+
129
+ Each successful result includes the selected provider, official tool name, retrieval timestamp, original URL where relevant, traceable public source URLs, `UNTRUSTED_WEB_CONTENT`, fallback diagnostics, and `truncated`/`sourcesTruncated` flags. The returned `content` is official output, not a Siftpath-generated answer. Treat it as data, never instructions.
130
+
131
+ Public HTTP(S) URLs only are accepted for reads. IP literals, local names, credentials and reverse-DNS names are rejected. Provider failures are sanitized into stable diagnostics; raw upstream bodies, API keys and URLs containing credentials are not returned. Connections are initialized on first use, reused within one process, and closed on normal MCP shutdown.
132
+
133
+ ## Status and Pi command
134
+
135
+ ```bash
136
+ siftpath status # offline, never treats READY as tested availability
137
+ siftpath status --json
138
+ siftpath test brave --json # real request to this provider only; no fallback
139
+ siftpath test all # sequential checks, may use API quota
140
+
141
+ # Install the Pi command extension from the stable npm release:
142
+ pi install npm:@onedotmint/siftpath@latest
143
+
144
+ # Source-checkout alternatives (choose one instead of the npm install):
145
+ # After building, try without changing Pi settings:
146
+ pi -e /absolute/path/to/Siftpath/extensions/siftpath.mjs
147
+ # Or install persistently: pi install /absolute/path/to/Siftpath
148
+ ```
149
+
150
+ After installation, restart Pi or run `/reload`. In Pi: `/siftpath`, `/siftpath test brave`, `/siftpath test all`. The extension uses the same private configuration and credential environment as the CLI; set `SIFTPATH_CONFIG` before starting Pi to select another file. The extension only invokes the packaged CLI and displays its summary using native notifications. No model tools are added. Connection, tool discovery and real-request stages are reported separately; recent results are stored privately alongside the selected config, with changed configurations marked stale. See [诊断与 Pi 安装/真实验收](docs/DIAGNOSTICS.md).
151
+
152
+ ## Tests and verification
153
+
154
+ ```bash
155
+ npm run typecheck
156
+ npm test
157
+ npm run test:live # skips network/quota tests unless explicitly enabled
158
+ SIFTPATH_LIVE=1 npm run test:live # Exa anonymous + Jina anonymous in this rebuild
159
+ SIFTPATH_CONTRACT=1 npm run test:live # tools/list contract checks only
160
+ ```
161
+
162
+ Offline tests use real MCP SDK fixture processes and local HTTP MCP servers, not mocked vendor HTTP APIs: 81 tests cover tool exposure, stdio, Streamable HTTP, configuration, fallback, cancellation, timeout, output bounds, URL safety, provenance and shutdown. This repository run also verified real anonymous Exa search and Jina read, plus the full Siftpath stdio path. Brave real search was not verified because `BRAVE_API_KEY` was absent. Tavily anonymous official stdio search and Firecrawl anonymous hosted reading were also live-tested; account Key flows were not verified.
163
+
164
+ ## Deliberate non-goals
165
+
166
+ The old EvidenceEngine, Gather path, multi-provider fusion, custom relevance scoring, sufficiency judgment, HTTP server, old Pi model-tool extension, generated host plugins, and research orchestration were removed from the active package. Siftpath is not a search engine or answer generator; official MCP services own those capabilities.
@@ -0,0 +1,26 @@
1
+ # Third-party notices
2
+
3
+ The repository's MIT LICENSE is preserved from SmartSearch at `a6e310d8c51d1fb9eb454d27afbbc3f81cc2e61a`, including Copyright (c) 2025 GuDaStudio.
4
+
5
+ This rebuild retains and adapts the project's private JSON configuration storage, hidden credential entry, public URL guard, CLI conventions and package-version reader. The old evidence engine and historical evaluation fixtures are no longer distributed.
6
+
7
+ Runtime npm dependencies are @modelcontextprotocol/sdk (MIT) and Zod (MIT), with transitive dependencies installed from their registries; inspect package-lock.json and the installed packages' licenses. TypeScript (Apache-2.0), @types/node (MIT), undici-types (MIT) are development dependencies. Official provider MCP packages are launched separately on demand and retain their own licenses/terms.
8
+
9
+ Official provider source and web-search-plus-mcp/agntn-web were interface/design references, not vendored implementation. Precise links and inspected revisions: docs/PROVIDERS.md. No upstream search/reader/ranking implementation is copied into Siftpath.
10
+
11
+ ## Bundled interactive setup
12
+
13
+ The lazily loaded `dist/setup-ui.js` bundles @clack/prompts 1.8.1, @clack/core 1.5.1, sisteransi 1.0.5, fast-wrap-ansi 0.2.2, fast-string-width 3.0.2 and fast-string-truncated-width 3.0.3 (all MIT). Clack and esbuild 0.25.12 are build-only dependencies, not runtime package requirements.
14
+
15
+ Copyright notices for bundled MIT code:
16
+
17
+ - Copyright (c) 2025-Present Bombshell contributors (https://bomb.sh/team) — Clack
18
+ - Copyright (c) 2018 Terkel Gjervig Nielsen — sisteransi
19
+ - Copyright (c) 2024-present Fabio Spampinato — fast-string-width / fast-string-truncated-width
20
+ - Copyright (c) 2025 James Garbutt; Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com) — fast-wrap-ansi
21
+
22
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
25
+
26
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from 'node:fs';
3
+ import { parseArgs } from 'node:util';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { configPath, readConfiguration, diagnostics } from './config.js';
6
+ import { statusReport, testReport, formatStatus, formatTests } from './diagnostics.js';
7
+ import { SiftpathError, safeError } from './errors.js';
8
+ import { Siftpath } from './router.js';
9
+ import { serveStdio } from './mcp/stdio.js';
10
+ import { setup } from './setup.js';
11
+ import { packageVersion } from './version.js';
12
+ import { invokeTool } from './tools.js';
13
+ const help = `Siftpath — lightweight official MCP router (Node.js 22+)
14
+ siftpath mcp
15
+ siftpath search "question" [--intent general|semantic|research] [--max-results 5]
16
+ siftpath read URL [--focus "question about the page"]
17
+ siftpath status [--json] # offline configuration and last tests
18
+ siftpath test <provider|all> [--json] # real requests, no fallback; may use API quota
19
+ siftpath doctor
20
+ siftpath setup [--non-interactive] # Clack provider/Key/routes wizard; tests are opt-in
21
+ siftpath --version
22
+ Configuration: SIFTPATH_CONFIG or ~/.config/siftpath/config.json (JSON).
23
+ Keys: BRAVE_API_KEY, EXA_API_KEY, JINA_API_KEY; optional TAVILY_API_KEY, FIRECRAWL_API_KEY.
24
+ Only the selected provider is called; failures try configured fallbacks sequentially.
25
+ `;
26
+ export async function main(argv = process.argv.slice(2)) {
27
+ let parsed;
28
+ try {
29
+ parsed = parseArgs({ args: argv, allowPositionals: true, strict: true, options: {
30
+ help: { type: 'boolean', short: 'h' }, version: { type: 'boolean', short: 'v' }, intent: { type: 'string' },
31
+ json: { type: 'boolean' }, 'max-results': { type: 'string' }, focus: { type: 'string' }, 'non-interactive': { type: 'boolean' },
32
+ } });
33
+ }
34
+ catch {
35
+ throw new SiftpathError('INVALID_INPUT', 'Invalid command-line arguments. Run siftpath --help.');
36
+ }
37
+ const { values, positionals: [command, ...args] } = parsed;
38
+ if (command === 'search' && values.focus !== undefined || command === 'read' && (values.intent !== undefined || values['max-results'] !== undefined))
39
+ throw new SiftpathError('INVALID_INPUT', 'Options do not match the selected command. Run siftpath --help.');
40
+ if (values.help || !command && !values.version) {
41
+ process.stdout.write(help);
42
+ return;
43
+ }
44
+ if (values.version) {
45
+ process.stdout.write(packageVersion + '\n');
46
+ return;
47
+ }
48
+ if (command === 'setup') {
49
+ await setup(Boolean(values['non-interactive']));
50
+ return;
51
+ }
52
+ if (!['mcp', 'search', 'read', 'doctor', 'status', 'test'].includes(command))
53
+ throw new SiftpathError('INVALID_INPUT', 'Unknown command. Run siftpath --help.');
54
+ const config = await readConfiguration();
55
+ if (command === 'doctor') {
56
+ process.stdout.write(JSON.stringify(diagnostics(config), null, 2) + '\n');
57
+ return;
58
+ }
59
+ if (command === 'status') {
60
+ if (args.length)
61
+ throw new SiftpathError('INVALID_INPUT', 'status takes no positional arguments.');
62
+ const report = await statusReport(config);
63
+ process.stdout.write((values.json ? JSON.stringify({ ...report, summary: formatStatus(report) }) : formatStatus(report)) + '\n');
64
+ return;
65
+ }
66
+ if (command === 'test') {
67
+ if (args.length !== 1)
68
+ throw new SiftpathError('INVALID_INPUT', 'Use siftpath test <provider|all> [--json].');
69
+ const controller = new AbortController(), stop = () => controller.abort();
70
+ process.once('SIGINT', stop);
71
+ process.once('SIGTERM', stop);
72
+ try {
73
+ const report = await testReport(config, args[0], configPath(), process.env, controller.signal);
74
+ process.stdout.write((values.json ? JSON.stringify({ ...report, summary: formatTests(report) }) : formatTests(report)) + '\n');
75
+ if (!report.ok)
76
+ process.exitCode = controller.signal.aborted ? 130 : 1;
77
+ }
78
+ finally {
79
+ process.off('SIGINT', stop);
80
+ process.off('SIGTERM', stop);
81
+ }
82
+ return;
83
+ }
84
+ const router = new Siftpath(config);
85
+ if (command === 'mcp') {
86
+ try {
87
+ await serveStdio(router);
88
+ }
89
+ finally {
90
+ await router.close();
91
+ }
92
+ return;
93
+ }
94
+ const controller = new AbortController(), stop = () => controller.abort();
95
+ process.once('SIGINT', stop);
96
+ process.once('SIGTERM', stop);
97
+ try {
98
+ if (command === 'read' && args.length !== 1)
99
+ throw new SiftpathError('INVALID_INPUT', 'read requires exactly one URL.');
100
+ const input = command === 'search'
101
+ ? { query: args.join(' '), ...(values.intent !== undefined ? { intent: values.intent } : {}),
102
+ ...(values['max-results'] !== undefined ? { maxResults: Number(values['max-results']) } : {}) }
103
+ : { url: args[0], ...(values.focus !== undefined ? { focus: values.focus } : {}) };
104
+ const result = await invokeTool(router, `web_${command}`, input, { signal: controller.signal });
105
+ process.stdout.write(JSON.stringify(result) + '\n');
106
+ }
107
+ finally {
108
+ process.off('SIGINT', stop);
109
+ process.off('SIGTERM', stop);
110
+ await router.close();
111
+ }
112
+ }
113
+ if (process.argv[1] && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
114
+ main().catch(error => { const safe = safeError(error); process.stderr.write(JSON.stringify(safe) + '\n'); process.exitCode = safe.code === 'ABORTED' ? 130 : 1; });
115
+ }
116
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,MAAM,IAAI,GAAG;;;;;;;;;;;;CAYZ,CAAC;AACF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QAAC,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;gBACpF,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3G,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;aAChI,EAAE,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,sDAAsD,CAAC,CAAC;IAAC,CAAC;IACnH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC;IAC3D,IAAI,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,SAAS,CAAC;QAClJ,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,iEAAiE,CAAC,CAAC;IAC9G,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACvF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC5E,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QAAC,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACrF,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAQ,CAAC;QAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,uCAAuC,CAAC,CAAC;IACjK,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACzC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAChH,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,uCAAuC,CAAC,CAAC;QACnG,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAAC,OAAO;IAC3I,CAAC;IACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,4CAA4C,CAAC,CAAC;QAC9G,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,EAAE,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YAChG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC/H,IAAI,CAAC,MAAM,CAAC,EAAE;gBAAE,OAAO,CAAC,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC;gBAAS,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAAC,CAAC;QACxE,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QAAC,IAAI,CAAC;YAAC,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QAAC,CAAC;gBAAS,CAAC;YAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACtG,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,EAAE,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1E,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,gCAAgC,CAAC,CAAC;QACxH,MAAM,KAAK,GAAG,OAAO,KAAK,QAAQ;YAChC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxF,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YACnG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACrF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAChG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAAC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAChG,CAAC;AACD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACxF,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrK,CAAC"}
@@ -0,0 +1,144 @@
1
+ import { type Configuration } from './config.js';
2
+ export declare function abortable<T>(promise: Promise<T>, signal: AbortSignal): Promise<T>;
3
+ /** One lazy connection per configured MCP, shared by all router calls in this process. */
4
+ export declare class McpClients {
5
+ private config;
6
+ private env;
7
+ private connections;
8
+ private closed;
9
+ private closing?;
10
+ private requestSignal;
11
+ private fetch;
12
+ constructor(config: Configuration, env?: NodeJS.ProcessEnv);
13
+ private get;
14
+ connect(id: string, signal: AbortSignal): Promise<void>;
15
+ listTools(id: string, signal: AbortSignal, cursor?: string): Promise<{
16
+ [x: string]: unknown;
17
+ tools: {
18
+ inputSchema: {
19
+ [x: string]: unknown;
20
+ type: "object";
21
+ properties?: Record<string, object> | undefined;
22
+ required?: string[] | undefined;
23
+ };
24
+ name: string;
25
+ description?: string | undefined;
26
+ outputSchema?: {
27
+ [x: string]: unknown;
28
+ type: "object";
29
+ properties?: Record<string, object> | undefined;
30
+ required?: string[] | undefined;
31
+ } | undefined;
32
+ annotations?: {
33
+ title?: string | undefined;
34
+ readOnlyHint?: boolean | undefined;
35
+ destructiveHint?: boolean | undefined;
36
+ idempotentHint?: boolean | undefined;
37
+ openWorldHint?: boolean | undefined;
38
+ } | undefined;
39
+ execution?: {
40
+ taskSupport?: "optional" | "required" | "forbidden" | undefined;
41
+ } | undefined;
42
+ _meta?: Record<string, unknown> | undefined;
43
+ icons?: {
44
+ src: string;
45
+ mimeType?: string | undefined;
46
+ sizes?: string[] | undefined;
47
+ theme?: "light" | "dark" | undefined;
48
+ }[] | undefined;
49
+ title?: string | undefined;
50
+ }[];
51
+ _meta?: {
52
+ [x: string]: unknown;
53
+ progressToken?: string | number | undefined;
54
+ "io.modelcontextprotocol/related-task"?: {
55
+ taskId: string;
56
+ } | undefined;
57
+ } | undefined;
58
+ nextCursor?: string | undefined;
59
+ }>;
60
+ call(id: string, name: string, args: Record<string, unknown>, signal: AbortSignal): Promise<{
61
+ [x: string]: unknown;
62
+ content: ({
63
+ type: "text";
64
+ text: string;
65
+ annotations?: {
66
+ audience?: ("user" | "assistant")[] | undefined;
67
+ priority?: number | undefined;
68
+ lastModified?: string | undefined;
69
+ } | undefined;
70
+ _meta?: Record<string, unknown> | undefined;
71
+ } | {
72
+ type: "image";
73
+ data: string;
74
+ mimeType: string;
75
+ annotations?: {
76
+ audience?: ("user" | "assistant")[] | undefined;
77
+ priority?: number | undefined;
78
+ lastModified?: string | undefined;
79
+ } | undefined;
80
+ _meta?: Record<string, unknown> | undefined;
81
+ } | {
82
+ type: "audio";
83
+ data: string;
84
+ mimeType: string;
85
+ annotations?: {
86
+ audience?: ("user" | "assistant")[] | undefined;
87
+ priority?: number | undefined;
88
+ lastModified?: string | undefined;
89
+ } | undefined;
90
+ _meta?: Record<string, unknown> | undefined;
91
+ } | {
92
+ uri: string;
93
+ name: string;
94
+ type: "resource_link";
95
+ description?: string | undefined;
96
+ mimeType?: string | undefined;
97
+ size?: number | undefined;
98
+ annotations?: {
99
+ audience?: ("user" | "assistant")[] | undefined;
100
+ priority?: number | undefined;
101
+ lastModified?: string | undefined;
102
+ } | undefined;
103
+ _meta?: {
104
+ [x: string]: unknown;
105
+ } | undefined;
106
+ icons?: {
107
+ src: string;
108
+ mimeType?: string | undefined;
109
+ sizes?: string[] | undefined;
110
+ theme?: "light" | "dark" | undefined;
111
+ }[] | undefined;
112
+ title?: string | undefined;
113
+ } | {
114
+ type: "resource";
115
+ resource: {
116
+ uri: string;
117
+ text: string;
118
+ mimeType?: string | undefined;
119
+ _meta?: Record<string, unknown> | undefined;
120
+ } | {
121
+ uri: string;
122
+ blob: string;
123
+ mimeType?: string | undefined;
124
+ _meta?: Record<string, unknown> | undefined;
125
+ };
126
+ annotations?: {
127
+ audience?: ("user" | "assistant")[] | undefined;
128
+ priority?: number | undefined;
129
+ lastModified?: string | undefined;
130
+ } | undefined;
131
+ _meta?: Record<string, unknown> | undefined;
132
+ })[];
133
+ _meta?: {
134
+ [x: string]: unknown;
135
+ progressToken?: string | number | undefined;
136
+ "io.modelcontextprotocol/related-task"?: {
137
+ taskId: string;
138
+ } | undefined;
139
+ } | undefined;
140
+ structuredContent?: Record<string, unknown> | undefined;
141
+ isError?: boolean | undefined;
142
+ }>;
143
+ close(): Promise<void>;
144
+ }
package/dist/client.js ADDED
@@ -0,0 +1,130 @@
1
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
3
+ import { AsyncLocalStorage } from 'node:async_hooks';
4
+ import { StreamableHTTPClientTransport, StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
5
+ import { CallToolResultSchema, ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';
6
+ import { providerStatus, resolveSecret } from './config.js';
7
+ import { SiftpathError } from './errors.js';
8
+ import { packageVersion } from './version.js';
9
+ export async function abortable(promise, signal) {
10
+ return new Promise((resolve, reject) => {
11
+ const abort = () => reject(signal.reason);
12
+ promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));
13
+ if (signal.aborted)
14
+ abort();
15
+ else
16
+ signal.addEventListener('abort', abort, { once: true });
17
+ });
18
+ }
19
+ /** One lazy connection per configured MCP, shared by all router calls in this process. */
20
+ export class McpClients {
21
+ config;
22
+ env;
23
+ connections = new Map();
24
+ closed = false;
25
+ closing;
26
+ requestSignal = new AsyncLocalStorage();
27
+ fetch = async (input, init) => {
28
+ const operation = this.requestSignal.getStore();
29
+ const signals = [init?.signal, init?.method === 'GET' ? undefined : operation].filter((s) => !!s);
30
+ const response = await globalThis.fetch(input, { ...init, signal: signals.length ? AbortSignal.any(signals) : undefined });
31
+ if (!response.body)
32
+ return response;
33
+ let bytes = 0;
34
+ const body = response.body.pipeThrough(new TransformStream({
35
+ transform(chunk, controller) {
36
+ bytes += chunk.byteLength;
37
+ if (bytes > 4 * 1024 * 1024) {
38
+ controller.error(new SiftpathError('RESPONSE_TOO_LARGE', 'Official MCP response exceeded 4 MiB.'));
39
+ return;
40
+ }
41
+ controller.enqueue(chunk);
42
+ },
43
+ }));
44
+ return new Response(body, { status: response.status, statusText: response.statusText, headers: response.headers });
45
+ };
46
+ constructor(config, env = process.env) {
47
+ this.config = config;
48
+ this.env = env;
49
+ }
50
+ get(id) {
51
+ if (this.closed)
52
+ throw new SiftpathError('CLOSED', 'Siftpath has been closed.');
53
+ const existing = this.connections.get(id);
54
+ if (existing)
55
+ return existing.ready;
56
+ const status = providerStatus(id, this.config, this.env);
57
+ if (status.code !== 'READY')
58
+ throw new SiftpathError(status.code, 'Provider is unavailable.', [status]);
59
+ const provider = this.config.providers[id], c = provider.connection;
60
+ const values = (entries) => Object.fromEntries(Object.entries(entries).map(([key, val]) => [key, resolveSecret(val, this.config, this.env)]));
61
+ const transport = c.transport === 'stdio'
62
+ ? new StdioClientTransport({ command: c.command, args: c.args, env: { ...getDefaultEnvironment(), ...values(c.env) }, stderr: 'ignore', maxBufferSize: 4 * 1024 * 1024 })
63
+ : new StreamableHTTPClientTransport(new URL(c.url), { fetch: this.fetch, requestInit: { headers: values(c.headers), redirect: 'error' },
64
+ reconnectionOptions: { maxRetries: 0, initialReconnectionDelay: 1000, maxReconnectionDelay: 1000, reconnectionDelayGrowFactor: 1 } });
65
+ const client = new Client({ name: 'siftpath', version: packageVersion });
66
+ client.onerror = () => { }; // Upstream messages may contain credentials; expose only our stable error codes.
67
+ const timeout = provider.timeoutMs ?? this.config.providerTimeoutMs;
68
+ const deadline = AbortSignal.timeout(timeout);
69
+ const ready = abortable(this.requestSignal.run(deadline, () => client.connect(transport, { timeout, signal: deadline })), deadline).then(() => client).catch(async (error) => {
70
+ if (this.connections.get(id)?.client === client)
71
+ this.connections.delete(id);
72
+ await client.close().catch(() => { });
73
+ const code = deadline.aborted ? 'PROVIDER_TIMEOUT' : error instanceof StreamableHTTPError && [401, 403].includes(error.code ?? 0) ? 'AUTH_FAILED'
74
+ : error instanceof StreamableHTTPError && error.code === 429 ? 'RATE_LIMITED' : 'CONNECTION_FAILED';
75
+ throw new SiftpathError(code, 'Cannot connect to official MCP. Check configuration, credentials and connectivity.');
76
+ });
77
+ this.connections.set(id, { client, transport, ready });
78
+ // The SDK invokes onclose when the underlying transport exits/disconnects.
79
+ client.onclose = () => { if (this.connections.get(id)?.client === client)
80
+ this.connections.delete(id); };
81
+ return ready;
82
+ }
83
+ async connect(id, signal) {
84
+ await abortable(this.get(id), signal);
85
+ }
86
+ async listTools(id, signal, cursor) {
87
+ const client = await abortable(this.get(id), signal);
88
+ // SDK listTools replaces its metadata cache per page; diagnostics retain and validate the complete list themselves.
89
+ return this.requestSignal.run(signal, () => abortable(client.request({ method: 'tools/list', params: cursor ? { cursor } : {} }, ListToolsResultSchema, { signal,
90
+ timeout: this.config.providers[id].timeoutMs ?? this.config.providerTimeoutMs }), signal));
91
+ }
92
+ async call(id, name, args, signal) {
93
+ const client = await abortable(this.get(id), signal);
94
+ signal.throwIfAborted();
95
+ try {
96
+ const result = await this.requestSignal.run(signal, () => abortable(client.callTool({ name, arguments: args }, CallToolResultSchema, { signal,
97
+ timeout: this.config.providers[id].timeoutMs ?? this.config.providerTimeoutMs }), signal));
98
+ return CallToolResultSchema.parse(result);
99
+ }
100
+ catch (error) {
101
+ // Expired HTTP sessions do not emit onclose in the SDK. Reconnect on the next operation, not an automatic billable retry.
102
+ if (error instanceof StreamableHTTPError && error.code === 404) {
103
+ if (this.connections.get(id)?.client === client)
104
+ this.connections.delete(id);
105
+ await client.close().catch(() => { });
106
+ }
107
+ throw error;
108
+ }
109
+ }
110
+ async close() {
111
+ if (this.closing)
112
+ return this.closing;
113
+ this.closed = true;
114
+ const connections = [...this.connections.values()];
115
+ this.connections.clear();
116
+ this.closing = Promise.allSettled(connections.map(async ({ client, transport }) => {
117
+ try {
118
+ if (transport instanceof StreamableHTTPClientTransport && transport.sessionId) {
119
+ const deadline = AbortSignal.timeout(2000);
120
+ await this.requestSignal.run(deadline, () => abortable(transport.terminateSession(), deadline));
121
+ }
122
+ }
123
+ finally {
124
+ await client.close();
125
+ }
126
+ })).then(() => { });
127
+ return this.closing;
128
+ }
129
+ }
130
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}