@tangle-network/tcloud 0.4.13 → 0.5.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/dist/mcp.cjs ADDED
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/mcp.ts
31
+ var mcp_exports = {};
32
+ __export(mcp_exports, {
33
+ runMcpServer: () => runMcpServer
34
+ });
35
+ module.exports = __toCommonJS(mcp_exports);
36
+ var readline = __toESM(require("readline"), 1);
37
+
38
+ // package.json
39
+ var version = "0.5.0";
40
+
41
+ // src/version.ts
42
+ function packageVersion() {
43
+ return version;
44
+ }
45
+
46
+ // src/mcp.ts
47
+ var SEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily", "brave"]);
48
+ var RESEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily"]);
49
+ var RECENCY_WINDOWS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
50
+ var SUPPORTED_PROTOCOL_VERSIONS = /* @__PURE__ */ new Set(["2025-06-18", "2025-03-26"]);
51
+ var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
52
+ var DOMAIN_FILTER_SCHEMA = {
53
+ type: "array",
54
+ items: { type: "string" }
55
+ };
56
+ var TOOLS = [
57
+ {
58
+ name: "web_search",
59
+ description: "Search the web via the Tangle router and return live results (title, url, snippet). Use it to find primary sources and to VERIFY that a citation (paper, PMID/DOI, patent, fact) actually exists before relying on it.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ query: { type: "string", description: "The search query." },
64
+ provider: {
65
+ type: "string",
66
+ description: "Optional provider: exa | parallel | perplexity | tavily | brave | you."
67
+ },
68
+ maxResults: { type: "number", description: "Optional max number of results." },
69
+ recency: { type: "string", description: "Optional recency window: day | week | month | year." },
70
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict results to these domains." },
71
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop results from these domains." }
72
+ },
73
+ required: ["query"]
74
+ }
75
+ },
76
+ {
77
+ name: "deep_research",
78
+ description: 'Run a multi-step DEEP RESEARCH task via the Tangle router: the provider reads many sources and returns one synthesized answer with citations. Slower and costlier than web_search \u2014 use it for questions that need cross-source synthesis (current API/version landscapes, comparisons, "state of X"), not single-fact lookups.',
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ query: { type: "string", description: "The research question." },
83
+ provider: {
84
+ type: "string",
85
+ description: "Optional provider: you | exa | perplexity | tavily | parallel."
86
+ },
87
+ effort: {
88
+ type: "string",
89
+ description: "Optional depth/cost dial (provider-specific): you lite|standard|deep|exhaustive \xB7 perplexity minimal|low|medium|high \xB7 exa deep-lite|deep|deep-reasoning \xB7 tavily mini|pro|auto \xB7 parallel lite|base|core|pro|ultra."
90
+ },
91
+ maxResults: { type: "number", description: "Optional max number of supporting sources." },
92
+ searchRecency: { type: "string", description: "Optional recency window: day | week | month | year." },
93
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict sources to these domains." },
94
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop sources from these domains." },
95
+ outputSchema: {
96
+ type: "object",
97
+ description: "Optional JSON schema requesting structured output from the provider."
98
+ }
99
+ },
100
+ required: ["query"]
101
+ }
102
+ }
103
+ ];
104
+ var InvalidParams = class extends Error {
105
+ };
106
+ function optionalMaxResults(value) {
107
+ if (value == null) return void 0;
108
+ const n = Number(value);
109
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
110
+ }
111
+ function requireEnum(value, allowed, label) {
112
+ if (value == null) return void 0;
113
+ if (typeof value !== "string" || !allowed.has(value)) {
114
+ throw new InvalidParams(`invalid ${label}: ${String(value)}`);
115
+ }
116
+ return value;
117
+ }
118
+ function optionalDomains(value) {
119
+ if (!Array.isArray(value)) return void 0;
120
+ const domains = value.filter((d) => typeof d === "string");
121
+ return domains.length ? domains : void 0;
122
+ }
123
+ async function runMcpServer(client, opts = {}) {
124
+ const input = opts.input ?? process.stdin;
125
+ const output = opts.output ?? process.stdout;
126
+ const rl = readline.createInterface({ input });
127
+ const send = (msg) => {
128
+ output.write(`${JSON.stringify(msg)}
129
+ `);
130
+ };
131
+ const ok = (id, result) => send({ jsonrpc: "2.0", id, result });
132
+ const fail = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
133
+ const toolError = (id, message) => ok(id, { content: [{ type: "text", text: message }], isError: true });
134
+ process.stderr.write("tcloud mcp: web_search + deep_research server ready (stdio)\n");
135
+ async function handleRequest(req) {
136
+ const { id, method, params } = req;
137
+ try {
138
+ if (method === "initialize") {
139
+ const requested = params?.protocolVersion ?? DEFAULT_PROTOCOL_VERSION;
140
+ const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requested) ? requested : DEFAULT_PROTOCOL_VERSION;
141
+ ok(id, {
142
+ protocolVersion,
143
+ capabilities: { tools: {} },
144
+ serverInfo: { name: "tangle-tcloud", version: packageVersion() }
145
+ });
146
+ } else if (method === "tools/list") {
147
+ ok(id, { tools: TOOLS });
148
+ } else if (method === "tools/call") {
149
+ const name = params?.name;
150
+ if (name === "web_search") {
151
+ await handleWebSearch(id, params?.arguments ?? {});
152
+ } else if (name === "deep_research") {
153
+ await handleDeepResearch(id, params?.arguments ?? {});
154
+ } else {
155
+ fail(id, -32602, `unknown tool: ${String(name)}`);
156
+ }
157
+ } else {
158
+ fail(id, -32601, `method not found: ${String(method)}`);
159
+ }
160
+ } catch (e) {
161
+ if (e instanceof InvalidParams) {
162
+ fail(id, -32602, e.message);
163
+ } else {
164
+ fail(id, -32603, e instanceof Error ? e.message : String(e));
165
+ }
166
+ }
167
+ }
168
+ async function handleWebSearch(id, args) {
169
+ const query = String(args.query ?? "").trim();
170
+ if (!query) {
171
+ fail(id, -32602, 'web_search requires a non-empty "query"');
172
+ return;
173
+ }
174
+ const provider = requireEnum(args.provider, SEARCH_PROVIDERS, "provider");
175
+ const searchRecency = requireEnum(args.recency, RECENCY_WINDOWS, "recency");
176
+ const maxResults = optionalMaxResults(args.maxResults);
177
+ const includeDomains = optionalDomains(args.includeDomains);
178
+ const excludeDomains = optionalDomains(args.excludeDomains);
179
+ try {
180
+ const resp = await client.search({
181
+ query,
182
+ ...provider ? { provider } : {},
183
+ ...maxResults != null ? { maxResults } : {},
184
+ ...searchRecency ? { searchRecency } : {},
185
+ ...includeDomains ? { includeDomains } : {},
186
+ ...excludeDomains ? { excludeDomains } : {}
187
+ });
188
+ const hits = resp.data ?? [];
189
+ const text = hits.length ? hits.map((h, i) => `${i + 1}. ${h.title}
190
+ ${h.url}${h.snippet ? `
191
+ ${h.snippet}` : ""}`).join("\n\n") : `No results for "${resp.query ?? query}".`;
192
+ ok(id, { content: [{ type: "text", text }] });
193
+ } catch (e) {
194
+ toolError(id, e instanceof Error ? e.message : String(e));
195
+ }
196
+ }
197
+ async function handleDeepResearch(id, args) {
198
+ const query = String(args.query ?? "").trim();
199
+ if (!query) {
200
+ fail(id, -32602, 'deep_research requires a non-empty "query"');
201
+ return;
202
+ }
203
+ const provider = requireEnum(args.provider, RESEARCH_PROVIDERS, "provider");
204
+ const searchRecency = requireEnum(args.searchRecency, RECENCY_WINDOWS, "searchRecency");
205
+ const maxResults = optionalMaxResults(args.maxResults);
206
+ const includeDomains = optionalDomains(args.includeDomains);
207
+ const excludeDomains = optionalDomains(args.excludeDomains);
208
+ try {
209
+ const resp = await client.research({
210
+ query,
211
+ ...provider ? { provider } : {},
212
+ ...typeof args.effort === "string" ? { effort: args.effort } : {},
213
+ ...maxResults != null ? { maxResults } : {},
214
+ ...searchRecency ? { searchRecency } : {},
215
+ ...includeDomains ? { includeDomains } : {},
216
+ ...excludeDomains ? { excludeDomains } : {},
217
+ ...args.outputSchema !== void 0 ? { outputSchema: args.outputSchema } : {}
218
+ });
219
+ const sources = resp.results ?? [];
220
+ const sourceList = sources.length ? `
221
+
222
+ Sources:
223
+ ${sources.map((h, i) => `${i + 1}. ${h.title}
224
+ ${h.url}`).join("\n")}` : "";
225
+ const text = `${resp.answer ?? ""}${sourceList}`.trim() || `No research result for "${resp.query ?? query}".`;
226
+ ok(id, { content: [{ type: "text", text }] });
227
+ } catch (e) {
228
+ toolError(id, e instanceof Error ? e.message : String(e));
229
+ }
230
+ }
231
+ for await (const line of rl) {
232
+ const trimmed = line.trim();
233
+ if (!trimmed) continue;
234
+ let req;
235
+ try {
236
+ req = JSON.parse(trimmed);
237
+ } catch {
238
+ send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } });
239
+ continue;
240
+ }
241
+ if (req.id === void 0 || req.id === null) continue;
242
+ void handleRequest(req);
243
+ }
244
+ }
245
+ // Annotate the CommonJS export names for ESM import in node:
246
+ 0 && (module.exports = {
247
+ runMcpServer
248
+ });
package/dist/mcp.d.cts ADDED
@@ -0,0 +1,27 @@
1
+ import { Readable, Writable } from 'node:stream';
2
+ import { TCloud } from './index.cjs';
3
+ import './shielded.cjs';
4
+ import 'viem';
5
+ import './client-CAedbgfN.cjs';
6
+ import '@tangle-network/sandbox';
7
+ import './sandbox.cjs';
8
+ import '@tangle-network/tcloud-attestation';
9
+
10
+ /** Transport streams the server reads/writes. Defaults bind to the process
11
+ * stdio; tests inject in-memory streams. */
12
+ interface McpServerOptions {
13
+ input?: Readable;
14
+ output?: Writable;
15
+ }
16
+ /**
17
+ * Run the MCP stdio server against an authenticated TCloud client. Resolves when input closes.
18
+ * Handles `initialize`, `tools/list`, `tools/call` (+ ignores notifications, which carry no id).
19
+ *
20
+ * Requests are dispatched without blocking the read loop, so a slow `deep_research`
21
+ * call cannot stall concurrent `web_search` requests — each response carries its
22
+ * own id. Pass `{ input, output }` to drive the transport over arbitrary streams
23
+ * (tests inject in-memory streams); both default to the process stdio.
24
+ */
25
+ declare function runMcpServer(client: TCloud, opts?: McpServerOptions): Promise<void>;
26
+
27
+ export { type McpServerOptions, runMcpServer };
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { Readable, Writable } from 'node:stream';
2
+ import { TCloud } from './index.js';
3
+ import './shielded.js';
4
+ import 'viem';
5
+ import './client-CAedbgfN.js';
6
+ import '@tangle-network/sandbox';
7
+ import './sandbox.js';
8
+ import '@tangle-network/tcloud-attestation';
9
+
10
+ /** Transport streams the server reads/writes. Defaults bind to the process
11
+ * stdio; tests inject in-memory streams. */
12
+ interface McpServerOptions {
13
+ input?: Readable;
14
+ output?: Writable;
15
+ }
16
+ /**
17
+ * Run the MCP stdio server against an authenticated TCloud client. Resolves when input closes.
18
+ * Handles `initialize`, `tools/list`, `tools/call` (+ ignores notifications, which carry no id).
19
+ *
20
+ * Requests are dispatched without blocking the read loop, so a slow `deep_research`
21
+ * call cannot stall concurrent `web_search` requests — each response carries its
22
+ * own id. Pass `{ input, output }` to drive the transport over arbitrary streams
23
+ * (tests inject in-memory streams); both default to the process stdio.
24
+ */
25
+ declare function runMcpServer(client: TCloud, opts?: McpServerOptions): Promise<void>;
26
+
27
+ export { type McpServerOptions, runMcpServer };
package/dist/mcp.js ADDED
@@ -0,0 +1,207 @@
1
+ import {
2
+ packageVersion
3
+ } from "./chunk-YK2SGW76.js";
4
+
5
+ // src/mcp.ts
6
+ import * as readline from "readline";
7
+ var SEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily", "brave"]);
8
+ var RESEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily"]);
9
+ var RECENCY_WINDOWS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
10
+ var SUPPORTED_PROTOCOL_VERSIONS = /* @__PURE__ */ new Set(["2025-06-18", "2025-03-26"]);
11
+ var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
12
+ var DOMAIN_FILTER_SCHEMA = {
13
+ type: "array",
14
+ items: { type: "string" }
15
+ };
16
+ var TOOLS = [
17
+ {
18
+ name: "web_search",
19
+ description: "Search the web via the Tangle router and return live results (title, url, snippet). Use it to find primary sources and to VERIFY that a citation (paper, PMID/DOI, patent, fact) actually exists before relying on it.",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ query: { type: "string", description: "The search query." },
24
+ provider: {
25
+ type: "string",
26
+ description: "Optional provider: exa | parallel | perplexity | tavily | brave | you."
27
+ },
28
+ maxResults: { type: "number", description: "Optional max number of results." },
29
+ recency: { type: "string", description: "Optional recency window: day | week | month | year." },
30
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict results to these domains." },
31
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop results from these domains." }
32
+ },
33
+ required: ["query"]
34
+ }
35
+ },
36
+ {
37
+ name: "deep_research",
38
+ description: 'Run a multi-step DEEP RESEARCH task via the Tangle router: the provider reads many sources and returns one synthesized answer with citations. Slower and costlier than web_search \u2014 use it for questions that need cross-source synthesis (current API/version landscapes, comparisons, "state of X"), not single-fact lookups.',
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ query: { type: "string", description: "The research question." },
43
+ provider: {
44
+ type: "string",
45
+ description: "Optional provider: you | exa | perplexity | tavily | parallel."
46
+ },
47
+ effort: {
48
+ type: "string",
49
+ description: "Optional depth/cost dial (provider-specific): you lite|standard|deep|exhaustive \xB7 perplexity minimal|low|medium|high \xB7 exa deep-lite|deep|deep-reasoning \xB7 tavily mini|pro|auto \xB7 parallel lite|base|core|pro|ultra."
50
+ },
51
+ maxResults: { type: "number", description: "Optional max number of supporting sources." },
52
+ searchRecency: { type: "string", description: "Optional recency window: day | week | month | year." },
53
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict sources to these domains." },
54
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop sources from these domains." },
55
+ outputSchema: {
56
+ type: "object",
57
+ description: "Optional JSON schema requesting structured output from the provider."
58
+ }
59
+ },
60
+ required: ["query"]
61
+ }
62
+ }
63
+ ];
64
+ var InvalidParams = class extends Error {
65
+ };
66
+ function optionalMaxResults(value) {
67
+ if (value == null) return void 0;
68
+ const n = Number(value);
69
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
70
+ }
71
+ function requireEnum(value, allowed, label) {
72
+ if (value == null) return void 0;
73
+ if (typeof value !== "string" || !allowed.has(value)) {
74
+ throw new InvalidParams(`invalid ${label}: ${String(value)}`);
75
+ }
76
+ return value;
77
+ }
78
+ function optionalDomains(value) {
79
+ if (!Array.isArray(value)) return void 0;
80
+ const domains = value.filter((d) => typeof d === "string");
81
+ return domains.length ? domains : void 0;
82
+ }
83
+ async function runMcpServer(client, opts = {}) {
84
+ const input = opts.input ?? process.stdin;
85
+ const output = opts.output ?? process.stdout;
86
+ const rl = readline.createInterface({ input });
87
+ const send = (msg) => {
88
+ output.write(`${JSON.stringify(msg)}
89
+ `);
90
+ };
91
+ const ok = (id, result) => send({ jsonrpc: "2.0", id, result });
92
+ const fail = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
93
+ const toolError = (id, message) => ok(id, { content: [{ type: "text", text: message }], isError: true });
94
+ process.stderr.write("tcloud mcp: web_search + deep_research server ready (stdio)\n");
95
+ async function handleRequest(req) {
96
+ const { id, method, params } = req;
97
+ try {
98
+ if (method === "initialize") {
99
+ const requested = params?.protocolVersion ?? DEFAULT_PROTOCOL_VERSION;
100
+ const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requested) ? requested : DEFAULT_PROTOCOL_VERSION;
101
+ ok(id, {
102
+ protocolVersion,
103
+ capabilities: { tools: {} },
104
+ serverInfo: { name: "tangle-tcloud", version: packageVersion() }
105
+ });
106
+ } else if (method === "tools/list") {
107
+ ok(id, { tools: TOOLS });
108
+ } else if (method === "tools/call") {
109
+ const name = params?.name;
110
+ if (name === "web_search") {
111
+ await handleWebSearch(id, params?.arguments ?? {});
112
+ } else if (name === "deep_research") {
113
+ await handleDeepResearch(id, params?.arguments ?? {});
114
+ } else {
115
+ fail(id, -32602, `unknown tool: ${String(name)}`);
116
+ }
117
+ } else {
118
+ fail(id, -32601, `method not found: ${String(method)}`);
119
+ }
120
+ } catch (e) {
121
+ if (e instanceof InvalidParams) {
122
+ fail(id, -32602, e.message);
123
+ } else {
124
+ fail(id, -32603, e instanceof Error ? e.message : String(e));
125
+ }
126
+ }
127
+ }
128
+ async function handleWebSearch(id, args) {
129
+ const query = String(args.query ?? "").trim();
130
+ if (!query) {
131
+ fail(id, -32602, 'web_search requires a non-empty "query"');
132
+ return;
133
+ }
134
+ const provider = requireEnum(args.provider, SEARCH_PROVIDERS, "provider");
135
+ const searchRecency = requireEnum(args.recency, RECENCY_WINDOWS, "recency");
136
+ const maxResults = optionalMaxResults(args.maxResults);
137
+ const includeDomains = optionalDomains(args.includeDomains);
138
+ const excludeDomains = optionalDomains(args.excludeDomains);
139
+ try {
140
+ const resp = await client.search({
141
+ query,
142
+ ...provider ? { provider } : {},
143
+ ...maxResults != null ? { maxResults } : {},
144
+ ...searchRecency ? { searchRecency } : {},
145
+ ...includeDomains ? { includeDomains } : {},
146
+ ...excludeDomains ? { excludeDomains } : {}
147
+ });
148
+ const hits = resp.data ?? [];
149
+ const text = hits.length ? hits.map((h, i) => `${i + 1}. ${h.title}
150
+ ${h.url}${h.snippet ? `
151
+ ${h.snippet}` : ""}`).join("\n\n") : `No results for "${resp.query ?? query}".`;
152
+ ok(id, { content: [{ type: "text", text }] });
153
+ } catch (e) {
154
+ toolError(id, e instanceof Error ? e.message : String(e));
155
+ }
156
+ }
157
+ async function handleDeepResearch(id, args) {
158
+ const query = String(args.query ?? "").trim();
159
+ if (!query) {
160
+ fail(id, -32602, 'deep_research requires a non-empty "query"');
161
+ return;
162
+ }
163
+ const provider = requireEnum(args.provider, RESEARCH_PROVIDERS, "provider");
164
+ const searchRecency = requireEnum(args.searchRecency, RECENCY_WINDOWS, "searchRecency");
165
+ const maxResults = optionalMaxResults(args.maxResults);
166
+ const includeDomains = optionalDomains(args.includeDomains);
167
+ const excludeDomains = optionalDomains(args.excludeDomains);
168
+ try {
169
+ const resp = await client.research({
170
+ query,
171
+ ...provider ? { provider } : {},
172
+ ...typeof args.effort === "string" ? { effort: args.effort } : {},
173
+ ...maxResults != null ? { maxResults } : {},
174
+ ...searchRecency ? { searchRecency } : {},
175
+ ...includeDomains ? { includeDomains } : {},
176
+ ...excludeDomains ? { excludeDomains } : {},
177
+ ...args.outputSchema !== void 0 ? { outputSchema: args.outputSchema } : {}
178
+ });
179
+ const sources = resp.results ?? [];
180
+ const sourceList = sources.length ? `
181
+
182
+ Sources:
183
+ ${sources.map((h, i) => `${i + 1}. ${h.title}
184
+ ${h.url}`).join("\n")}` : "";
185
+ const text = `${resp.answer ?? ""}${sourceList}`.trim() || `No research result for "${resp.query ?? query}".`;
186
+ ok(id, { content: [{ type: "text", text }] });
187
+ } catch (e) {
188
+ toolError(id, e instanceof Error ? e.message : String(e));
189
+ }
190
+ }
191
+ for await (const line of rl) {
192
+ const trimmed = line.trim();
193
+ if (!trimmed) continue;
194
+ let req;
195
+ try {
196
+ req = JSON.parse(trimmed);
197
+ } catch {
198
+ send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } });
199
+ continue;
200
+ }
201
+ if (req.id === void 0 || req.id === null) continue;
202
+ void handleRequest(req);
203
+ }
204
+ }
205
+ export {
206
+ runMcpServer
207
+ };
package/dist/shielded.cjs CHANGED
@@ -259,48 +259,43 @@ var PrivateRouter = class {
259
259
  }
260
260
  };
261
261
 
262
+ // package.json
263
+ var version = "0.5.0";
264
+
265
+ // src/version.ts
266
+ function packageVersion() {
267
+ return version;
268
+ }
269
+
262
270
  // src/client.ts
263
271
  var ROTATING_MARKER = "__tcloudRotating";
264
272
  var DIRECT_CLI_BRIDGE_MARKER = "__tcloudDirectCliBridge";
265
273
  var DEFAULT_BASE_URL = "https://router.tangle.tools/v1";
266
- var SDK_VERSION = "0.4.0";
267
274
  async function proxiedFetch(privacy, url, init, streaming) {
268
275
  if (!privacy || privacy.mode === "direct") {
269
276
  return fetch(url, init);
270
277
  }
271
- if (privacy.mode === "relayer") {
272
- if (!privacy.relayerUrl) {
273
- throw new Error('relayerUrl is required when privacy mode is "relayer"');
274
- }
275
- const proxyPath = streaming ? "/relay/proxy-stream" : "/relay/proxy";
276
- const hdrs = {};
277
- if (init.headers) {
278
- const entries = init.headers instanceof Headers ? Array.from(init.headers.entries()) : Object.entries(init.headers);
279
- for (const [k, v] of entries) hdrs[k] = v;
280
- }
281
- return fetch(`${privacy.relayerUrl}${proxyPath}`, {
282
- method: "POST",
283
- headers: { "Content-Type": "application/json" },
284
- body: JSON.stringify({
285
- target: url,
286
- body: typeof init.body === "string" ? JSON.parse(init.body) : init.body,
287
- headers: hdrs
288
- })
289
- });
278
+ if (privacy.mode !== "relayer") {
279
+ throw new Error(`Unsupported privacy mode: ${String(privacy.mode)}`);
290
280
  }
291
- if (privacy.mode === "socks5") {
292
- if (!privacy.socksProxy) {
293
- throw new Error('socksProxy is required when privacy mode is "socks5"');
294
- }
295
- const { SocksProxyAgent } = await import("socks-proxy-agent");
296
- const agent = new SocksProxyAgent(privacy.socksProxy);
297
- return fetch(url, {
298
- ...init,
299
- // @ts-expect-error agent is supported by Node's undici but not in the standard RequestInit type
300
- agent
301
- });
281
+ if (!privacy.relayerUrl) {
282
+ throw new Error('relayerUrl is required when privacy mode is "relayer"');
302
283
  }
303
- return fetch(url, init);
284
+ const proxyPath = streaming ? "/relay/proxy-stream" : "/relay/proxy";
285
+ const headers = {};
286
+ if (init.headers) {
287
+ const entries = init.headers instanceof Headers ? Array.from(init.headers.entries()) : Object.entries(init.headers);
288
+ for (const [key, value] of entries) headers[key] = value;
289
+ }
290
+ return fetch(`${privacy.relayerUrl}${proxyPath}`, {
291
+ method: "POST",
292
+ headers: { "Content-Type": "application/json" },
293
+ body: JSON.stringify({
294
+ target: url,
295
+ body: typeof init.body === "string" ? JSON.parse(init.body) : init.body,
296
+ headers
297
+ })
298
+ });
304
299
  }
305
300
  var DEFAULT_RETRY = {
306
301
  maxRetries: 3,
@@ -465,7 +460,7 @@ var TCloudClient = class _TCloudClient {
465
460
  this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
466
461
  this.headers = {
467
462
  "Content-Type": "application/json",
468
- "X-Tangle-Client": `tcloud-sdk/${SDK_VERSION}`
463
+ "X-Tangle-Client": `tcloud-sdk/${packageVersion()}`
469
464
  };
470
465
  if (this.apiKey) {
471
466
  this.headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -1039,6 +1034,26 @@ var TCloudClient = class _TCloudClient {
1039
1034
  })
1040
1035
  });
1041
1036
  }
1037
+ /** Run a multi-step deep-research task through Tangle Router billing and
1038
+ * provider routing (POST /v1/research). Slower and costlier than `search` —
1039
+ * the provider synthesizes an answer over many fetches. Pick depth with
1040
+ * `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
1041
+ async research(options) {
1042
+ return this._request(`${this.baseURL}/research`, {
1043
+ method: "POST",
1044
+ body: JSON.stringify({
1045
+ query: options.query,
1046
+ provider: options.provider,
1047
+ model: options.model,
1048
+ effort: options.effort,
1049
+ maxResults: options.maxResults,
1050
+ searchRecency: options.searchRecency,
1051
+ includeDomains: options.includeDomains,
1052
+ excludeDomains: options.excludeDomains,
1053
+ outputSchema: options.outputSchema
1054
+ })
1055
+ });
1056
+ }
1042
1057
  /** Text-to-speech */
1043
1058
  async speech(options) {
1044
1059
  const res = await this._requestRaw(`${this.baseURL}/audio/speech`, {
@@ -1,5 +1,5 @@
1
1
  import { Hex } from 'viem';
2
- import { a as TCloudConfig, T as TCloudClient, $ as SpendAuth } from './client-CaD5Oal0.cjs';
2
+ import { T as TCloudConfig, a as TCloudClient, a3 as SpendAuth } from './client-CAedbgfN.cjs';
3
3
  import '@tangle-network/sandbox';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { Hex } from 'viem';
2
- import { a as TCloudConfig, T as TCloudClient, $ as SpendAuth } from './client-CaD5Oal0.js';
2
+ import { T as TCloudConfig, a as TCloudClient, a3 as SpendAuth } from './client-CAedbgfN.js';
3
3
  import '@tangle-network/sandbox';
4
4
 
5
5
  /**
package/dist/shielded.js CHANGED
@@ -3,8 +3,9 @@ import {
3
3
  estimateCost,
4
4
  generateWallet,
5
5
  signSpendAuth
6
- } from "./chunk-THOMQXU5.js";
7
- import "./chunk-U4VOGRVW.js";
6
+ } from "./chunk-GDGQQRE3.js";
7
+ import "./chunk-H3K3A3EI.js";
8
+ import "./chunk-YK2SGW76.js";
8
9
  export {
9
10
  createShieldedClient,
10
11
  estimateCost,