openclaw-channel-basicops 0.1.5 → 0.1.7
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/basicops-mcp.js +48 -57
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
package/dist/basicops-mcp.js
CHANGED
|
@@ -1,37 +1,26 @@
|
|
|
1
|
-
// Minimal BasicOps MCP-over-SSE client
|
|
1
|
+
// Minimal BasicOps MCP-over-SSE client
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// -
|
|
5
|
-
//
|
|
6
|
-
// -
|
|
3
|
+
// Correct transport (BasicOps):
|
|
4
|
+
// - GET the SSE URL (text/event-stream) with Bearer token
|
|
5
|
+
// - Read until we receive a "data: <endpoint>" line
|
|
6
|
+
// - POST JSON-RPC to that endpoint
|
|
7
|
+
//
|
|
8
|
+
// This client is intentionally simple: one call opens one SSE stream.
|
|
7
9
|
const DEFAULT_SSE_URL = "https://app.basicops.com/mcp/sse";
|
|
8
10
|
const DEFAULT_PROTOCOL_VERSION = "2024-11-05";
|
|
9
|
-
async function
|
|
10
|
-
const initPayload = {
|
|
11
|
-
jsonrpc: "2.0",
|
|
12
|
-
id: 1,
|
|
13
|
-
method: "initialize",
|
|
14
|
-
params: {
|
|
15
|
-
protocolVersion: opts.protocolVersion,
|
|
16
|
-
capabilities: {},
|
|
17
|
-
clientInfo: { name: "OpenClaw", version: "0.1" },
|
|
18
|
-
},
|
|
19
|
-
};
|
|
11
|
+
async function getMessageEndpoint(opts) {
|
|
20
12
|
const res = await fetch(opts.baseUrl, {
|
|
21
|
-
method: "
|
|
13
|
+
method: "GET",
|
|
22
14
|
headers: {
|
|
23
15
|
Authorization: `Bearer ${opts.accessToken}`,
|
|
24
16
|
Accept: "text/event-stream",
|
|
25
|
-
"Content-Type": "application/json",
|
|
26
17
|
"Cache-Control": "no-cache",
|
|
27
18
|
},
|
|
28
|
-
body: JSON.stringify(initPayload),
|
|
29
19
|
});
|
|
30
20
|
if (!res.ok || !res.body) {
|
|
31
21
|
const body = await res.text().catch(() => "");
|
|
32
|
-
throw new Error(`MCP
|
|
22
|
+
throw new Error(`MCP SSE connect failed (${res.status}): ${body}`);
|
|
33
23
|
}
|
|
34
|
-
// Read SSE lines until we see the first `data: ...` line (endpoint)
|
|
35
24
|
const reader = res.body.getReader();
|
|
36
25
|
const decoder = new TextDecoder();
|
|
37
26
|
let buf = "";
|
|
@@ -41,13 +30,12 @@ async function handshake(opts) {
|
|
|
41
30
|
if (done)
|
|
42
31
|
break;
|
|
43
32
|
buf += decoder.decode(value, { stream: true });
|
|
44
|
-
// SSE lines end with \n. We'll parse line-by-line.
|
|
45
33
|
let idx;
|
|
46
34
|
while ((idx = buf.indexOf("\n")) !== -1) {
|
|
47
35
|
const line = buf.slice(0, idx).trimEnd();
|
|
48
36
|
buf = buf.slice(idx + 1);
|
|
49
|
-
if (line.startsWith("data:
|
|
50
|
-
let endpoint = line.slice("data:
|
|
37
|
+
if (line.startsWith("data:")) {
|
|
38
|
+
let endpoint = line.slice("data:".length).trim();
|
|
51
39
|
if (!endpoint)
|
|
52
40
|
continue;
|
|
53
41
|
if (endpoint.startsWith("/"))
|
|
@@ -56,16 +44,48 @@ async function handshake(opts) {
|
|
|
56
44
|
}
|
|
57
45
|
}
|
|
58
46
|
}
|
|
59
|
-
throw new Error("MCP
|
|
47
|
+
throw new Error("MCP SSE connect failed: no endpoint returned");
|
|
48
|
+
}
|
|
49
|
+
async function postJsonRpc(opts) {
|
|
50
|
+
const res = await fetch(opts.endpoint, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${opts.accessToken}`,
|
|
54
|
+
Accept: "application/json",
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify(opts.payload),
|
|
58
|
+
});
|
|
59
|
+
const raw = await res.text().catch(() => "");
|
|
60
|
+
if (!res.ok)
|
|
61
|
+
throw new Error(`MCP POST failed (${res.status}): ${raw}`);
|
|
62
|
+
try {
|
|
63
|
+
return raw ? JSON.parse(raw) : {};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw new Error(`MCP returned non-JSON: ${raw.slice(0, 400)}`);
|
|
67
|
+
}
|
|
60
68
|
}
|
|
61
69
|
export async function callMcpTool(opts) {
|
|
62
70
|
const baseUrl = opts.mcp.baseUrl || DEFAULT_SSE_URL;
|
|
63
71
|
const accessToken = opts.mcp.accessToken;
|
|
64
72
|
const protocolVersion = opts.mcp.protocolVersion || DEFAULT_PROTOCOL_VERSION;
|
|
65
73
|
if (!accessToken) {
|
|
66
|
-
throw new Error("Missing BasicOps MCP access token (
|
|
74
|
+
throw new Error("Missing BasicOps MCP access token (plugins.entries.basicops.config.accounts.<id>.mcp.accessToken)");
|
|
67
75
|
}
|
|
68
|
-
const endpoint = await
|
|
76
|
+
const endpoint = await getMessageEndpoint({ baseUrl, accessToken });
|
|
77
|
+
// Initialize (some MCP servers require this before tools/call)
|
|
78
|
+
const initPayload = {
|
|
79
|
+
jsonrpc: "2.0",
|
|
80
|
+
id: 1,
|
|
81
|
+
method: "initialize",
|
|
82
|
+
params: {
|
|
83
|
+
protocolVersion,
|
|
84
|
+
capabilities: {},
|
|
85
|
+
clientInfo: { name: "openclaw-channel-basicops", version: "0.1" },
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
await postJsonRpc({ endpoint, accessToken, payload: initPayload });
|
|
69
89
|
const payload = {
|
|
70
90
|
jsonrpc: "2.0",
|
|
71
91
|
id: opts.requestId ?? 2,
|
|
@@ -75,34 +95,5 @@ export async function callMcpTool(opts) {
|
|
|
75
95
|
arguments: opts.args ?? {},
|
|
76
96
|
},
|
|
77
97
|
};
|
|
78
|
-
|
|
79
|
-
method: "POST",
|
|
80
|
-
headers: {
|
|
81
|
-
Authorization: `Bearer ${accessToken}`,
|
|
82
|
-
Accept: "application/json",
|
|
83
|
-
"Content-Type": "application/json",
|
|
84
|
-
},
|
|
85
|
-
body: JSON.stringify(payload),
|
|
86
|
-
});
|
|
87
|
-
const raw = await res.text().catch(() => "");
|
|
88
|
-
if (!res.ok) {
|
|
89
|
-
throw new Error(`MCP tool call failed (${res.status}): ${raw}`);
|
|
90
|
-
}
|
|
91
|
-
let json;
|
|
92
|
-
try {
|
|
93
|
-
json = raw ? JSON.parse(raw) : {};
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
throw new Error(`MCP tool call returned non-JSON: ${raw.slice(0, 400)}`);
|
|
97
|
-
}
|
|
98
|
-
// BasicOps MCP may return { result: { isError: true, content: [...] } }
|
|
99
|
-
const isError = Boolean(json?.result?.isError);
|
|
100
|
-
if (isError) {
|
|
101
|
-
const content = json?.result?.content;
|
|
102
|
-
const text = Array.isArray(content)
|
|
103
|
-
? content.map((c) => (c && typeof c === "object" ? c.text : "")).join(" ")
|
|
104
|
-
: "";
|
|
105
|
-
throw new Error(`MCP tool error: ${text || "(unknown)"}`);
|
|
106
|
-
}
|
|
107
|
-
return json;
|
|
98
|
+
return postJsonRpc({ endpoint, accessToken, payload });
|
|
108
99
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "basicops",
|
|
2
|
+
"id": "openclaw-channel-basicops",
|
|
3
3
|
"name": "BasicOps",
|
|
4
4
|
"description": "BasicOps messaging channel connector (webhooks inbound + MCP outbound)",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.7",
|
|
6
6
|
"entry": "dist/index.js",
|
|
7
7
|
"tags": [
|
|
8
8
|
"channel",
|