@tangle-network/hub-sdk 1.0.4 → 1.0.5
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/README.md +25 -0
- package/dist/bridge-D8_lAKaW.js +81 -0
- package/dist/bridge-D8_lAKaW.js.map +1 -0
- package/dist/client-BH3gTLjN.d.ts +2571 -0
- package/dist/client-BH3gTLjN.d.ts.map +1 -0
- package/dist/client-CsdLLECZ.js +1574 -0
- package/dist/client-CsdLLECZ.js.map +1 -0
- package/dist/index.d.ts +3 -2568
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1568
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +119 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +482 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/stdio.d.ts +1 -0
- package/dist/mcp/stdio.js +16 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -420,3 +420,28 @@ const result = await broker.invoke(grant.grantId, connectionId, "github.issues.l
|
|
|
420
420
|
```
|
|
421
421
|
|
|
422
422
|
`invoke` mints a fresh one-use, 60-second broker token and checks its selected scope before execution. The host application must recheck its own current customer enrollment on every call and revoke the app grant when access ends. Do not return broker tokens or application secrets to a browser or persist them in agent profiles.
|
|
423
|
+
|
|
424
|
+
## Embedded Node MCP hosts
|
|
425
|
+
|
|
426
|
+
`@tangle-network/hub-sdk/mcp` owns `HubMcpScope`, connection resolution,
|
|
427
|
+
`createHubMcpRoutes`, the HTTP bridge and `lowerProfileConnections`. The root
|
|
428
|
+
client export remains browser/Worker-safe.
|
|
429
|
+
|
|
430
|
+
Create one scope for the host's lifetime with its existing canonical hash and
|
|
431
|
+
credential-renewal function. Mount `createHubMcpRoutes(scope)` on the host's
|
|
432
|
+
existing listener. `scope.resolveConnectionsToMcp(client, refs, serverForGrant)`
|
|
433
|
+
validates the connections, provider and tool allowlists, rolls back partial
|
|
434
|
+
allocation, and gives the host its native MCP representation. Only a pure
|
|
435
|
+
attach-all request can return an explicitly degraded empty result; required
|
|
436
|
+
connections remain errors. The host surfaces degradation and recovery.
|
|
437
|
+
|
|
438
|
+
Revoke each resolution's `grantTokens` when its run settles. `scope.close()`
|
|
439
|
+
revokes the remaining grants of that instance and prevents new allocation.
|
|
440
|
+
Other scopes and their borrowed clients remain independent.
|
|
441
|
+
|
|
442
|
+
The published `@tangle-network/hub-sdk/mcp/stdio` entry reads only
|
|
443
|
+
`TANGLE_HUB_MCP_ENDPOINT`. Launch it through Node with the opaque callback
|
|
444
|
+
endpoint; do not forward the Hub credential. `lowerProfileConnections` keeps
|
|
445
|
+
the authored adapter profile separate from the ephemeral workspace profile.
|
|
446
|
+
Grant endpoints belong to runtime materialization, never persisted authored
|
|
447
|
+
profiles or trace metadata.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import https from "node:https";
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
//#region src/mcp/bridge.ts
|
|
6
|
+
var HttpHubMcpBridgeClient = class {
|
|
7
|
+
endpoint;
|
|
8
|
+
constructor(endpoint) {
|
|
9
|
+
if (!endpoint || endpoint.trim().length === 0) throw new Error("TANGLE_HUB_MCP_ENDPOINT is required");
|
|
10
|
+
this.endpoint = endpoint.replace(/\/+$/, "");
|
|
11
|
+
}
|
|
12
|
+
async listTools() {
|
|
13
|
+
return (await requestJson("GET", `${this.endpoint}/tools`)).tools;
|
|
14
|
+
}
|
|
15
|
+
async callTool(name, args) {
|
|
16
|
+
return requestJson("POST", `${this.endpoint}/call`, {
|
|
17
|
+
name,
|
|
18
|
+
arguments: args ?? {}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function createHubMcpBridgeServer(client) {
|
|
23
|
+
const server = new Server({
|
|
24
|
+
name: "tangle-hub",
|
|
25
|
+
version: "0.1.0"
|
|
26
|
+
}, { capabilities: { tools: {} } });
|
|
27
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
+
return { tools: (await client.listTools()).map((tool) => ({
|
|
29
|
+
name: tool.name,
|
|
30
|
+
description: tool.description,
|
|
31
|
+
inputSchema: tool.inputSchema
|
|
32
|
+
})) };
|
|
33
|
+
});
|
|
34
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => client.callTool(request.params.name, request.params.arguments ?? {}));
|
|
35
|
+
return server;
|
|
36
|
+
}
|
|
37
|
+
function requestJson(method, url, body) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const parsed = new URL(url);
|
|
40
|
+
const payload = body ? JSON.stringify(body) : void 0;
|
|
41
|
+
const request = (parsed.protocol === "https:" ? https : http).request({
|
|
42
|
+
protocol: parsed.protocol,
|
|
43
|
+
hostname: parsed.hostname,
|
|
44
|
+
port: parsed.port,
|
|
45
|
+
path: `${parsed.pathname}${parsed.search}`,
|
|
46
|
+
method,
|
|
47
|
+
rejectUnauthorized: parsed.hostname !== "127.0.0.1",
|
|
48
|
+
headers: {
|
|
49
|
+
Accept: "application/json",
|
|
50
|
+
...payload ? {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
"Content-Length": Buffer.byteLength(payload).toString()
|
|
53
|
+
} : {}
|
|
54
|
+
}
|
|
55
|
+
}, (response) => {
|
|
56
|
+
const chunks = [];
|
|
57
|
+
response.on("data", (chunk) => {
|
|
58
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
59
|
+
});
|
|
60
|
+
response.on("end", () => {
|
|
61
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
62
|
+
if ((response.statusCode ?? 500) >= 400) {
|
|
63
|
+
reject(new Error(text || `Hub MCP request failed: ${response.statusCode}`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
resolve(JSON.parse(text));
|
|
68
|
+
} catch (error) {
|
|
69
|
+
reject(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
request.on("error", reject);
|
|
74
|
+
if (payload) request.write(payload);
|
|
75
|
+
request.end();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { createHubMcpBridgeServer as n, HttpHubMcpBridgeClient as t };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=bridge-D8_lAKaW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-D8_lAKaW.js","names":[],"sources":["../src/mcp/bridge.ts"],"sourcesContent":["import http from \"node:http\";\nimport https from \"node:https\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { HubMcpToolDescriptor, HubMcpToolResult } from \"./tools.js\";\n\ntype JsonObject = Record<string, unknown>;\n\ninterface HubMcpBridgeClient {\n listTools(): Promise<HubMcpToolDescriptor[]>;\n callTool(name: string, args: unknown): Promise<HubMcpToolResult>;\n}\n\nexport class HttpHubMcpBridgeClient implements HubMcpBridgeClient {\n private readonly endpoint: string;\n\n constructor(endpoint: string) {\n if (!endpoint || endpoint.trim().length === 0) {\n throw new Error(\"TANGLE_HUB_MCP_ENDPOINT is required\");\n }\n this.endpoint = endpoint.replace(/\\/+$/, \"\");\n }\n\n async listTools(): Promise<HubMcpToolDescriptor[]> {\n const response = await requestJson<{ tools: HubMcpToolDescriptor[] }>(\n \"GET\",\n `${this.endpoint}/tools`,\n );\n return response.tools;\n }\n\n async callTool(name: string, args: unknown): Promise<HubMcpToolResult> {\n return requestJson<HubMcpToolResult>(\"POST\", `${this.endpoint}/call`, {\n name,\n arguments: args ?? {},\n });\n }\n}\n\nexport function createHubMcpBridgeServer(client: HubMcpBridgeClient): Server {\n const server = new Server(\n { name: \"tangle-hub\", version: \"0.1.0\" },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n const tools = await client.listTools();\n return {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n client.callTool(request.params.name, request.params.arguments ?? {}),\n );\n\n return server;\n}\n\nfunction requestJson<T>(\n method: \"GET\" | \"POST\",\n url: string,\n body?: JsonObject,\n) {\n return new Promise<T>((resolve, reject) => {\n const parsed = new URL(url);\n const payload = body ? JSON.stringify(body) : undefined;\n const transport = parsed.protocol === \"https:\" ? https : http;\n const request = transport.request(\n {\n protocol: parsed.protocol,\n hostname: parsed.hostname,\n port: parsed.port,\n path: `${parsed.pathname}${parsed.search}`,\n method,\n rejectUnauthorized: parsed.hostname !== \"127.0.0.1\",\n headers: {\n Accept: \"application/json\",\n ...(payload\n ? {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(payload).toString(),\n }\n : {}),\n },\n },\n (response) => {\n const chunks: Buffer[] = [];\n response.on(\"data\", (chunk) => {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n });\n response.on(\"end\", () => {\n const text = Buffer.concat(chunks).toString(\"utf8\");\n if ((response.statusCode ?? 500) >= 400) {\n reject(\n new Error(\n text || `Hub MCP request failed: ${response.statusCode}`,\n ),\n );\n return;\n }\n try {\n resolve(JSON.parse(text) as T);\n } catch (error) {\n reject(error);\n }\n });\n },\n );\n request.on(\"error\", reject);\n if (payload) request.write(payload);\n request.end();\n });\n}\n"],"mappings":";;;;;AAgBA,IAAa,yBAAb,MAAkE;CAChE;CAEA,YAAY,UAAkB;AAC5B,MAAI,CAAC,YAAY,SAAS,MAAM,CAAC,WAAW,EAC1C,OAAM,IAAI,MAAM,sCAAsC;AAExD,OAAK,WAAW,SAAS,QAAQ,QAAQ,GAAG;;CAG9C,MAAM,YAA6C;AAKjD,UAAO,MAJgB,YACrB,OACA,GAAG,KAAK,SAAS,QAClB,EACe;;CAGlB,MAAM,SAAS,MAAc,MAA0C;AACrE,SAAO,YAA8B,QAAQ,GAAG,KAAK,SAAS,QAAQ;GACpE;GACA,WAAW,QAAQ,EAAE;GACtB,CAAC;;;AAIN,SAAgB,yBAAyB,QAAoC;CAC3E,MAAM,SAAS,IAAI,OACjB;EAAE,MAAM;EAAc,SAAS;EAAS,EACxC,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE,EAAE,CAChC;AAED,QAAO,kBAAkB,wBAAwB,YAAY;AAE3D,SAAO,EACL,QAAO,MAFW,OAAO,WAAW,EAEvB,KAAK,UAAU;GAC1B,MAAM,KAAK;GACX,aAAa,KAAK;GAClB,aAAa,KAAK;GACnB,EAAE,EACJ;GACD;AAEF,QAAO,kBAAkB,uBAAuB,OAAO,YACrD,OAAO,SAAS,QAAQ,OAAO,MAAM,QAAQ,OAAO,aAAa,EAAE,CAAC,CACrE;AAED,QAAO;;AAGT,SAAS,YACP,QACA,KACA,MACA;AACA,QAAO,IAAI,SAAY,SAAS,WAAW;EACzC,MAAM,SAAS,IAAI,IAAI,IAAI;EAC3B,MAAM,UAAU,OAAO,KAAK,UAAU,KAAK,GAAG,KAAA;EAE9C,MAAM,WADY,OAAO,aAAa,WAAW,QAAQ,MAC/B,QACxB;GACE,UAAU,OAAO;GACjB,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,MAAM,GAAG,OAAO,WAAW,OAAO;GAClC;GACA,oBAAoB,OAAO,aAAa;GACxC,SAAS;IACP,QAAQ;IACR,GAAI,UACA;KACE,gBAAgB;KAChB,kBAAkB,OAAO,WAAW,QAAQ,CAAC,UAAU;KACxD,GACD,EAAE;IACP;GACF,GACA,aAAa;GACZ,MAAM,SAAmB,EAAE;AAC3B,YAAS,GAAG,SAAS,UAAU;AAC7B,WAAO,KAAK,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM,CAAC;KAChE;AACF,YAAS,GAAG,aAAa;IACvB,MAAM,OAAO,OAAO,OAAO,OAAO,CAAC,SAAS,OAAO;AACnD,SAAK,SAAS,cAAc,QAAQ,KAAK;AACvC,YACE,IAAI,MACF,QAAQ,2BAA2B,SAAS,aAC7C,CACF;AACD;;AAEF,QAAI;AACF,aAAQ,KAAK,MAAM,KAAK,CAAM;aACvB,OAAO;AACd,YAAO,MAAM;;KAEf;IAEL;AACD,UAAQ,GAAG,SAAS,OAAO;AAC3B,MAAI,QAAS,SAAQ,MAAM,QAAQ;AACnC,UAAQ,KAAK;GACb"}
|