@tangle-network/tcloud 0.4.13 → 0.4.14

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/index.cjs CHANGED
@@ -1057,6 +1057,26 @@ var TCloudClient = class _TCloudClient {
1057
1057
  })
1058
1058
  });
1059
1059
  }
1060
+ /** Run a multi-step deep-research task through Tangle Router billing and
1061
+ * provider routing (POST /v1/research). Slower and costlier than `search` —
1062
+ * the provider synthesizes an answer over many fetches. Pick depth with
1063
+ * `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
1064
+ async research(options) {
1065
+ return this._request(`${this.baseURL}/research`, {
1066
+ method: "POST",
1067
+ body: JSON.stringify({
1068
+ query: options.query,
1069
+ provider: options.provider,
1070
+ model: options.model,
1071
+ effort: options.effort,
1072
+ maxResults: options.maxResults,
1073
+ searchRecency: options.searchRecency,
1074
+ includeDomains: options.includeDomains,
1075
+ excludeDomains: options.excludeDomains,
1076
+ outputSchema: options.outputSchema
1077
+ })
1078
+ });
1079
+ }
1060
1080
  /** Text-to-speech */
1061
1081
  async speech(options) {
1062
1082
  const res = await this._requestRaw(`${this.baseURL}/audio/speech`, {
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ShieldedWallet, generateWallet } from './shielded.cjs';
2
2
  export { createShieldedClient, estimateCost, signSpendAuth } from './shielded.cjs';
3
- import { T as TCloudClient, a as TCloudConfig, R as RotatingClientConfig } from './client-CaD5Oal0.cjs';
4
- export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as ChatPlugin, m as CompletionOptions, n as CompletionResponse, o as CreateKeyOptions, p as CreatedKey, q as CreditBalance, E as EmbeddingOptions, r as EmbeddingResponse, F as FineTuningJob, s as FineTuningJobOptions, G as GatewayOptions, I as ImageEditAttachment, t as ImageEditOptions, u as ImageGenerateOptions, v as ImageResponse, J as JobEvent, M as Model, O as Operator, w as OperatorInfo, P as PricingTier, x as PrivacyConfig, y as PrivateRouter, z as PrivateRouterConfig, D as RerankOptions, H as RerankResponse, K as RetryConfig, L as RotatingRoutingConfig, N as RotationStats, Q as RoutingConfig, S as RoutingStrategy, U as SandboxChatOptions, V as SearchHit, W as SearchOptions, X as SearchProvider, Y as SearchRecency, Z as SearchResponse, _ as ShieldedConfig, $ as SpendAuth, a0 as SpendingLimits, a1 as TCloudError, a2 as TierConfig, a3 as TranscriptionResponse, a4 as UpdateKeyOptions, a5 as VideoGenerateOptions, a6 as VideoResponse, a7 as WatchJobOptions, a8 as WebSearchPlugin } from './client-CaD5Oal0.cjs';
3
+ import { a as TCloudClient, T as TCloudConfig, R as RotatingClientConfig } from './client-CaPP4njg.cjs';
4
+ export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as ChatPlugin, m as CompletionOptions, n as CompletionResponse, o as CreateKeyOptions, p as CreatedKey, q as CreditBalance, E as EmbeddingOptions, r as EmbeddingResponse, F as FineTuningJob, s as FineTuningJobOptions, G as GatewayOptions, I as ImageEditAttachment, t as ImageEditOptions, u as ImageGenerateOptions, v as ImageResponse, J as JobEvent, M as Model, O as Operator, w as OperatorInfo, P as PricingTier, x as PrivacyConfig, y as PrivateRouter, z as PrivateRouterConfig, D as RerankOptions, H as RerankResponse, K as ResearchHit, L as ResearchOptions, N as ResearchProvider, Q as ResearchResponse, S as RetryConfig, U as RotatingRoutingConfig, V as RotationStats, W as RoutingConfig, X as RoutingStrategy, Y as SandboxChatOptions, Z as SearchHit, _ as SearchOptions, $ as SearchProvider, a0 as SearchRecency, a1 as SearchResponse, a2 as ShieldedConfig, a3 as SpendAuth, a4 as SpendingLimits, a5 as TCloudError, a6 as TierConfig, a7 as TranscriptionResponse, a8 as UpdateKeyOptions, a9 as VideoGenerateOptions, aa as VideoResponse, ab as WatchJobOptions, ac as WebSearchPlugin } from './client-CaPP4njg.cjs';
5
5
  import { TCloudSandboxConfig, TCloudSandbox } from './sandbox.cjs';
6
6
  export { TCloudSandboxAttestationStatus, TCloudSandboxCreateOptions, TCloudSandboxCreateResult, TCloudSandboxTee, TCloudTeeAttestationChallenge, TCloudTeeAttestationHeartbeat, TCloudTeeAttestationHeartbeatOptions, TCloudTeeAttestationHeartbeatSample, createTeeAttestationChallenge, generateAttestationNonce, startTeeAttestationHeartbeat } from './sandbox.cjs';
7
7
  export { AsyncAttestationPolicy, AsyncHardwareVerifier, AttestationPolicy, AttestationVerificationResult, HardwareVerifier, HardwareVerifierResult, NitroAttestationDocument, NitroVerifierOptions, ParsedAttestation, SevSnpReport, SevSnpVerifierOptions, TeeType, assertAttestation, createNitroHardwareVerifier, createSevSnpHardwareVerifier, createTdxHardwareVerifier, normalizeTeeType, parseAttestation, parseNitroAttestationDocument, parseSevSnpReport, toHex, verifyAttestation, verifyAttestationAsync } from '@tangle-network/tcloud-attestation';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ShieldedWallet, generateWallet } from './shielded.js';
2
2
  export { createShieldedClient, estimateCost, signSpendAuth } from './shielded.js';
3
- import { T as TCloudClient, a as TCloudConfig, R as RotatingClientConfig } from './client-CaD5Oal0.js';
4
- export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as ChatPlugin, m as CompletionOptions, n as CompletionResponse, o as CreateKeyOptions, p as CreatedKey, q as CreditBalance, E as EmbeddingOptions, r as EmbeddingResponse, F as FineTuningJob, s as FineTuningJobOptions, G as GatewayOptions, I as ImageEditAttachment, t as ImageEditOptions, u as ImageGenerateOptions, v as ImageResponse, J as JobEvent, M as Model, O as Operator, w as OperatorInfo, P as PricingTier, x as PrivacyConfig, y as PrivateRouter, z as PrivateRouterConfig, D as RerankOptions, H as RerankResponse, K as RetryConfig, L as RotatingRoutingConfig, N as RotationStats, Q as RoutingConfig, S as RoutingStrategy, U as SandboxChatOptions, V as SearchHit, W as SearchOptions, X as SearchProvider, Y as SearchRecency, Z as SearchResponse, _ as ShieldedConfig, $ as SpendAuth, a0 as SpendingLimits, a1 as TCloudError, a2 as TierConfig, a3 as TranscriptionResponse, a4 as UpdateKeyOptions, a5 as VideoGenerateOptions, a6 as VideoResponse, a7 as WatchJobOptions, a8 as WebSearchPlugin } from './client-CaD5Oal0.js';
3
+ import { a as TCloudClient, T as TCloudConfig, R as RotatingClientConfig } from './client-CaPP4njg.js';
4
+ export { A as ApiKeyInfo, b as AvatarGenerateRequest, c as AvatarGenerateResponse, d as AvatarJobStatus, e as AvatarResult, B as BatchJobResponse, f as BatchRequest, g as BridgeOptions, h as BridgeSession, C as ChatCompletion, i as ChatCompletionChunk, j as ChatMessage, k as ChatOptions, l as ChatPlugin, m as CompletionOptions, n as CompletionResponse, o as CreateKeyOptions, p as CreatedKey, q as CreditBalance, E as EmbeddingOptions, r as EmbeddingResponse, F as FineTuningJob, s as FineTuningJobOptions, G as GatewayOptions, I as ImageEditAttachment, t as ImageEditOptions, u as ImageGenerateOptions, v as ImageResponse, J as JobEvent, M as Model, O as Operator, w as OperatorInfo, P as PricingTier, x as PrivacyConfig, y as PrivateRouter, z as PrivateRouterConfig, D as RerankOptions, H as RerankResponse, K as ResearchHit, L as ResearchOptions, N as ResearchProvider, Q as ResearchResponse, S as RetryConfig, U as RotatingRoutingConfig, V as RotationStats, W as RoutingConfig, X as RoutingStrategy, Y as SandboxChatOptions, Z as SearchHit, _ as SearchOptions, $ as SearchProvider, a0 as SearchRecency, a1 as SearchResponse, a2 as ShieldedConfig, a3 as SpendAuth, a4 as SpendingLimits, a5 as TCloudError, a6 as TierConfig, a7 as TranscriptionResponse, a8 as UpdateKeyOptions, a9 as VideoGenerateOptions, aa as VideoResponse, ab as WatchJobOptions, ac as WebSearchPlugin } from './client-CaPP4njg.js';
5
5
  import { TCloudSandboxConfig, TCloudSandbox } from './sandbox.js';
6
6
  export { TCloudSandboxAttestationStatus, TCloudSandboxCreateOptions, TCloudSandboxCreateResult, TCloudSandboxTee, TCloudTeeAttestationChallenge, TCloudTeeAttestationHeartbeat, TCloudTeeAttestationHeartbeatOptions, TCloudTeeAttestationHeartbeatSample, createTeeAttestationChallenge, generateAttestationNonce, startTeeAttestationHeartbeat } from './sandbox.js';
7
7
  export { AsyncAttestationPolicy, AsyncHardwareVerifier, AttestationPolicy, AttestationVerificationResult, HardwareVerifier, HardwareVerifierResult, NitroAttestationDocument, NitroVerifierOptions, ParsedAttestation, SevSnpReport, SevSnpVerifierOptions, TeeType, assertAttestation, createNitroHardwareVerifier, createSevSnpHardwareVerifier, createTdxHardwareVerifier, normalizeTeeType, parseAttestation, parseNitroAttestationDocument, parseSevSnpReport, toHex, verifyAttestation, verifyAttestationAsync } from '@tangle-network/tcloud-attestation';
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  toHex,
12
12
  verifyAttestation,
13
13
  verifyAttestationAsync
14
- } from "./chunk-UBUCUSCF.js";
14
+ } from "./chunk-ZJCWJGPM.js";
15
15
  import {
16
16
  TCloudSandbox,
17
17
  createTeeAttestationChallenge,
@@ -23,13 +23,13 @@ import {
23
23
  estimateCost,
24
24
  generateWallet,
25
25
  signSpendAuth
26
- } from "./chunk-THOMQXU5.js";
26
+ } from "./chunk-26M4HGWE.js";
27
27
  import {
28
28
  BridgeSession,
29
29
  PrivateRouter,
30
30
  TCloudClient,
31
31
  TCloudError
32
- } from "./chunk-U4VOGRVW.js";
32
+ } from "./chunk-LUJXMUH5.js";
33
33
  export {
34
34
  BridgeSession,
35
35
  PrivateRouter,
package/dist/instance.cjs CHANGED
@@ -1041,6 +1041,26 @@ var TCloudClient = class _TCloudClient {
1041
1041
  })
1042
1042
  });
1043
1043
  }
1044
+ /** Run a multi-step deep-research task through Tangle Router billing and
1045
+ * provider routing (POST /v1/research). Slower and costlier than `search` —
1046
+ * the provider synthesizes an answer over many fetches. Pick depth with
1047
+ * `effort` (provider-specific vocabulary; see {@link ResearchOptions.effort}). */
1048
+ async research(options) {
1049
+ return this._request(`${this.baseURL}/research`, {
1050
+ method: "POST",
1051
+ body: JSON.stringify({
1052
+ query: options.query,
1053
+ provider: options.provider,
1054
+ model: options.model,
1055
+ effort: options.effort,
1056
+ maxResults: options.maxResults,
1057
+ searchRecency: options.searchRecency,
1058
+ includeDomains: options.includeDomains,
1059
+ excludeDomains: options.excludeDomains,
1060
+ outputSchema: options.outputSchema
1061
+ })
1062
+ });
1063
+ }
1044
1064
  /** Text-to-speech */
1045
1065
  async speech(options) {
1046
1066
  const res = await this._requestRaw(`${this.baseURL}/audio/speech`, {
@@ -1,4 +1,4 @@
1
- import { a as TCloudConfig, T as TCloudClient } from './client-CaD5Oal0.cjs';
1
+ import { T as TCloudConfig, a as TCloudClient } from './client-CaPP4njg.cjs';
2
2
  import '@tangle-network/sandbox';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { a as TCloudConfig, T as TCloudClient } from './client-CaD5Oal0.js';
1
+ import { T as TCloudConfig, a as TCloudClient } from './client-CaPP4njg.js';
2
2
  import '@tangle-network/sandbox';
3
3
 
4
4
  /**
package/dist/instance.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TCloudClient
3
- } from "./chunk-U4VOGRVW.js";
3
+ } from "./chunk-LUJXMUH5.js";
4
4
 
5
5
  // src/instance.ts
6
6
  import { spawn } from "child_process";
package/dist/mcp.cjs ADDED
@@ -0,0 +1,254 @@
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
+ // src/version.ts
39
+ var fs = __toESM(require("fs"), 1);
40
+ var import_meta = {};
41
+ function packageVersion() {
42
+ try {
43
+ const packageJson = JSON.parse(
44
+ fs.readFileSync(new URL("../package.json", import_meta.url), "utf-8")
45
+ );
46
+ if (typeof packageJson.version === "string") return packageJson.version;
47
+ } catch {
48
+ }
49
+ return "0.0.0";
50
+ }
51
+
52
+ // src/mcp.ts
53
+ var SEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily", "brave"]);
54
+ var RESEARCH_PROVIDERS = /* @__PURE__ */ new Set(["perplexity", "exa", "you", "parallel", "tavily"]);
55
+ var RECENCY_WINDOWS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
56
+ var SUPPORTED_PROTOCOL_VERSIONS = /* @__PURE__ */ new Set(["2025-06-18", "2025-03-26"]);
57
+ var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
58
+ var DOMAIN_FILTER_SCHEMA = {
59
+ type: "array",
60
+ items: { type: "string" }
61
+ };
62
+ var TOOLS = [
63
+ {
64
+ name: "web_search",
65
+ 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.",
66
+ inputSchema: {
67
+ type: "object",
68
+ properties: {
69
+ query: { type: "string", description: "The search query." },
70
+ provider: {
71
+ type: "string",
72
+ description: "Optional provider: exa | parallel | perplexity | tavily | brave | you."
73
+ },
74
+ maxResults: { type: "number", description: "Optional max number of results." },
75
+ recency: { type: "string", description: "Optional recency window: day | week | month | year." },
76
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict results to these domains." },
77
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop results from these domains." }
78
+ },
79
+ required: ["query"]
80
+ }
81
+ },
82
+ {
83
+ name: "deep_research",
84
+ 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.',
85
+ inputSchema: {
86
+ type: "object",
87
+ properties: {
88
+ query: { type: "string", description: "The research question." },
89
+ provider: {
90
+ type: "string",
91
+ description: "Optional provider: you | exa | perplexity | tavily | parallel."
92
+ },
93
+ effort: {
94
+ type: "string",
95
+ 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."
96
+ },
97
+ maxResults: { type: "number", description: "Optional max number of supporting sources." },
98
+ searchRecency: { type: "string", description: "Optional recency window: day | week | month | year." },
99
+ includeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: restrict sources to these domains." },
100
+ excludeDomains: { ...DOMAIN_FILTER_SCHEMA, description: "Optional: drop sources from these domains." },
101
+ outputSchema: {
102
+ type: "object",
103
+ description: "Optional JSON schema requesting structured output from the provider."
104
+ }
105
+ },
106
+ required: ["query"]
107
+ }
108
+ }
109
+ ];
110
+ var InvalidParams = class extends Error {
111
+ };
112
+ function optionalMaxResults(value) {
113
+ if (value == null) return void 0;
114
+ const n = Number(value);
115
+ return Number.isFinite(n) && n >= 0 ? n : void 0;
116
+ }
117
+ function requireEnum(value, allowed, label) {
118
+ if (value == null) return void 0;
119
+ if (typeof value !== "string" || !allowed.has(value)) {
120
+ throw new InvalidParams(`invalid ${label}: ${String(value)}`);
121
+ }
122
+ return value;
123
+ }
124
+ function optionalDomains(value) {
125
+ if (!Array.isArray(value)) return void 0;
126
+ const domains = value.filter((d) => typeof d === "string");
127
+ return domains.length ? domains : void 0;
128
+ }
129
+ async function runMcpServer(client, opts = {}) {
130
+ const input = opts.input ?? process.stdin;
131
+ const output = opts.output ?? process.stdout;
132
+ const rl = readline.createInterface({ input });
133
+ const send = (msg) => {
134
+ output.write(`${JSON.stringify(msg)}
135
+ `);
136
+ };
137
+ const ok = (id, result) => send({ jsonrpc: "2.0", id, result });
138
+ const fail = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
139
+ const toolError = (id, message) => ok(id, { content: [{ type: "text", text: message }], isError: true });
140
+ process.stderr.write("tcloud mcp: web_search + deep_research server ready (stdio)\n");
141
+ async function handleRequest(req) {
142
+ const { id, method, params } = req;
143
+ try {
144
+ if (method === "initialize") {
145
+ const requested = params?.protocolVersion ?? DEFAULT_PROTOCOL_VERSION;
146
+ const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requested) ? requested : DEFAULT_PROTOCOL_VERSION;
147
+ ok(id, {
148
+ protocolVersion,
149
+ capabilities: { tools: {} },
150
+ serverInfo: { name: "tangle-tcloud", version: packageVersion() }
151
+ });
152
+ } else if (method === "tools/list") {
153
+ ok(id, { tools: TOOLS });
154
+ } else if (method === "tools/call") {
155
+ const name = params?.name;
156
+ if (name === "web_search") {
157
+ await handleWebSearch(id, params?.arguments ?? {});
158
+ } else if (name === "deep_research") {
159
+ await handleDeepResearch(id, params?.arguments ?? {});
160
+ } else {
161
+ fail(id, -32602, `unknown tool: ${String(name)}`);
162
+ }
163
+ } else {
164
+ fail(id, -32601, `method not found: ${String(method)}`);
165
+ }
166
+ } catch (e) {
167
+ if (e instanceof InvalidParams) {
168
+ fail(id, -32602, e.message);
169
+ } else {
170
+ fail(id, -32603, e instanceof Error ? e.message : String(e));
171
+ }
172
+ }
173
+ }
174
+ async function handleWebSearch(id, args) {
175
+ const query = String(args.query ?? "").trim();
176
+ if (!query) {
177
+ fail(id, -32602, 'web_search requires a non-empty "query"');
178
+ return;
179
+ }
180
+ const provider = requireEnum(args.provider, SEARCH_PROVIDERS, "provider");
181
+ const searchRecency = requireEnum(args.recency, RECENCY_WINDOWS, "recency");
182
+ const maxResults = optionalMaxResults(args.maxResults);
183
+ const includeDomains = optionalDomains(args.includeDomains);
184
+ const excludeDomains = optionalDomains(args.excludeDomains);
185
+ try {
186
+ const resp = await client.search({
187
+ query,
188
+ ...provider ? { provider } : {},
189
+ ...maxResults != null ? { maxResults } : {},
190
+ ...searchRecency ? { searchRecency } : {},
191
+ ...includeDomains ? { includeDomains } : {},
192
+ ...excludeDomains ? { excludeDomains } : {}
193
+ });
194
+ const hits = resp.data ?? [];
195
+ const text = hits.length ? hits.map((h, i) => `${i + 1}. ${h.title}
196
+ ${h.url}${h.snippet ? `
197
+ ${h.snippet}` : ""}`).join("\n\n") : `No results for "${resp.query ?? query}".`;
198
+ ok(id, { content: [{ type: "text", text }] });
199
+ } catch (e) {
200
+ toolError(id, e instanceof Error ? e.message : String(e));
201
+ }
202
+ }
203
+ async function handleDeepResearch(id, args) {
204
+ const query = String(args.query ?? "").trim();
205
+ if (!query) {
206
+ fail(id, -32602, 'deep_research requires a non-empty "query"');
207
+ return;
208
+ }
209
+ const provider = requireEnum(args.provider, RESEARCH_PROVIDERS, "provider");
210
+ const searchRecency = requireEnum(args.searchRecency, RECENCY_WINDOWS, "searchRecency");
211
+ const maxResults = optionalMaxResults(args.maxResults);
212
+ const includeDomains = optionalDomains(args.includeDomains);
213
+ const excludeDomains = optionalDomains(args.excludeDomains);
214
+ try {
215
+ const resp = await client.research({
216
+ query,
217
+ ...provider ? { provider } : {},
218
+ ...typeof args.effort === "string" ? { effort: args.effort } : {},
219
+ ...maxResults != null ? { maxResults } : {},
220
+ ...searchRecency ? { searchRecency } : {},
221
+ ...includeDomains ? { includeDomains } : {},
222
+ ...excludeDomains ? { excludeDomains } : {},
223
+ ...args.outputSchema !== void 0 ? { outputSchema: args.outputSchema } : {}
224
+ });
225
+ const sources = resp.results ?? [];
226
+ const sourceList = sources.length ? `
227
+
228
+ Sources:
229
+ ${sources.map((h, i) => `${i + 1}. ${h.title}
230
+ ${h.url}`).join("\n")}` : "";
231
+ const text = `${resp.answer ?? ""}${sourceList}`.trim() || `No research result for "${resp.query ?? query}".`;
232
+ ok(id, { content: [{ type: "text", text }] });
233
+ } catch (e) {
234
+ toolError(id, e instanceof Error ? e.message : String(e));
235
+ }
236
+ }
237
+ for await (const line of rl) {
238
+ const trimmed = line.trim();
239
+ if (!trimmed) continue;
240
+ let req;
241
+ try {
242
+ req = JSON.parse(trimmed);
243
+ } catch {
244
+ send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } });
245
+ continue;
246
+ }
247
+ if (req.id === void 0 || req.id === null) continue;
248
+ void handleRequest(req);
249
+ }
250
+ }
251
+ // Annotate the CommonJS export names for ESM import in node:
252
+ 0 && (module.exports = {
253
+ runMcpServer
254
+ });
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-CaPP4njg.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-CaPP4njg.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-GHMW4RWJ.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
+ };