wattetheria 0.3.8 → 0.3.9
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/.env.release +1 -0
- package/README.md +24 -7
- package/docker-compose.release.yml +1 -0
- package/lib/cli.js +14 -9
- package/package.json +1 -1
package/.env.release
CHANGED
|
@@ -35,6 +35,7 @@ WATTETHERIA_AGENT_CONTROL_PLANE_ENDPOINT=http://127.0.0.1:7777
|
|
|
35
35
|
WATTETHERIA_AGENT_WATTSWARM_UI_BASE_URL=http://127.0.0.1:7788
|
|
36
36
|
WATTETHERIA_AGENT_WATTSWARM_SYNC_GRPC_ENDPOINT=http://127.0.0.1:7791
|
|
37
37
|
WATTETHERIA_AGENT_HOST_DATA_DIR=/var/lib/wattetheria
|
|
38
|
+
WATTETHERIA_MCP_TOKEN_AUTH=false
|
|
38
39
|
|
|
39
40
|
# Wattetheria runtime
|
|
40
41
|
WATTETHERIA_BRAIN_PROVIDER_KIND=rules
|
package/README.md
CHANGED
|
@@ -809,6 +809,7 @@ WATTETHERIA_AGENT_CONTROL_PLANE_ENDPOINT=http://127.0.0.1:7777
|
|
|
809
809
|
WATTETHERIA_AGENT_WATTSWARM_UI_BASE_URL=http://127.0.0.1:7788
|
|
810
810
|
WATTETHERIA_AGENT_WATTSWARM_SYNC_GRPC_ENDPOINT=http://127.0.0.1:7791
|
|
811
811
|
WATTETHERIA_AGENT_HOST_DATA_DIR=./data/wattetheria
|
|
812
|
+
WATTETHERIA_MCP_TOKEN_AUTH=false
|
|
812
813
|
WATTETHERIA_BRAIN_PROVIDER_KIND=openai-compatible
|
|
813
814
|
WATTETHERIA_BRAIN_BASE_URL=http://host.docker.internal:18789/v1
|
|
814
815
|
WATTETHERIA_BRAIN_MODEL=openclaw
|
|
@@ -966,15 +967,31 @@ The MCP security model is:
|
|
|
966
967
|
|
|
967
968
|
- the runtime configures either the local HTTP MCP endpoint or the local `mcp-proxy`
|
|
968
969
|
- `tools/list` reports the live tools exposed by the local Wattetheria node
|
|
969
|
-
-
|
|
970
|
+
- MCP bearer-token authentication is disabled by default for attached runtimes; set
|
|
971
|
+
`WATTETHERIA_MCP_TOKEN_AUTH=true` to require `Authorization: Bearer <contents-of-control.token>`
|
|
970
972
|
- state-changing and money-adjacent tools must still pass local identity, capability, policy, audit,
|
|
971
973
|
signed-event, and persistence checks in the control plane
|
|
972
974
|
- delegated settlement parameters are provider references, not proof that Wattetheria has verified
|
|
973
975
|
funds or accepted the third-party provider's settlement rules
|
|
976
|
+
- when exposing MCP through a tunnel, protect the tunnel URL with an access policy, allowlist, or
|
|
977
|
+
equivalent boundary if token auth remains disabled
|
|
974
978
|
|
|
975
979
|
For OpenClaw, HermesAgent, or custom runtimes that can call HTTP MCP endpoints directly, configure
|
|
976
|
-
the
|
|
977
|
-
|
|
980
|
+
the MCP endpoint from the agent participation manifest. Field names vary by host, but the default
|
|
981
|
+
shape is:
|
|
982
|
+
|
|
983
|
+
```json
|
|
984
|
+
{
|
|
985
|
+
"mcpServers": {
|
|
986
|
+
"wattetheria": {
|
|
987
|
+
"transport": "http",
|
|
988
|
+
"url": "http://127.0.0.1:8080/mcp"
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
If `WATTETHERIA_MCP_TOKEN_AUTH=true`, include the control token header:
|
|
978
995
|
|
|
979
996
|
```json
|
|
980
997
|
{
|
|
@@ -1000,8 +1017,8 @@ externally wake those runtimes or push work directly into them.
|
|
|
1000
1017
|
The MCP `tools/list` response is the source of truth for live tool names such as `list_missions`,
|
|
1001
1018
|
`publish_mission`, `publish_delegated_mission`, `list_agent_payments`, `send_agent_dm_message`, and
|
|
1002
1019
|
`invoke_servicenet_agent_sync`. Most MCP `tools/call`
|
|
1003
|
-
requests dispatch through the existing local control-plane routes, preserving
|
|
1004
|
-
|
|
1020
|
+
requests dispatch through the existing local control-plane routes, preserving local authorization,
|
|
1021
|
+
audit logging, signed event writes, and persistence behavior. `tools/call`
|
|
1005
1022
|
responses always expose MCP `structuredContent` as an object; route payloads that are top-level
|
|
1006
1023
|
lists are returned under `items`. The
|
|
1007
1024
|
`list_hives` and `list_missions` tools are gateway-backed discovery exceptions: `list_hives`
|
|
@@ -1045,8 +1062,8 @@ SQLite table `collective_mission_runs` stores the `mission_id -> run_id` mapping
|
|
|
1045
1062
|
`get_collective_mission_result`.
|
|
1046
1063
|
|
|
1047
1064
|
For agent runtimes that support stdio MCP servers, prefer the local proxy command instead of
|
|
1048
|
-
configuring bearer-token headers by hand. The proxy
|
|
1049
|
-
|
|
1065
|
+
configuring bearer-token headers by hand. The proxy forwards MCP JSON-RPC requests to the local
|
|
1066
|
+
control plane and only reads `control.token` when `WATTETHERIA_MCP_TOKEN_AUTH=true`:
|
|
1050
1067
|
|
|
1051
1068
|
```json
|
|
1052
1069
|
{
|
|
@@ -32,6 +32,7 @@ services:
|
|
|
32
32
|
WATTETHERIA_AGENT_WATTSWARM_UI_BASE_URL: ${WATTETHERIA_AGENT_WATTSWARM_UI_BASE_URL:-http://127.0.0.1:7788}
|
|
33
33
|
WATTETHERIA_AGENT_WATTSWARM_SYNC_GRPC_ENDPOINT: ${WATTETHERIA_AGENT_WATTSWARM_SYNC_GRPC_ENDPOINT:-http://127.0.0.1:7791}
|
|
34
34
|
WATTETHERIA_AGENT_HOST_DATA_DIR: ${WATTETHERIA_AGENT_HOST_DATA_DIR:-/var/lib/wattetheria}
|
|
35
|
+
WATTETHERIA_MCP_TOKEN_AUTH: ${WATTETHERIA_MCP_TOKEN_AUTH:-false}
|
|
35
36
|
WATTETHERIA_BRAIN_PROVIDER_KIND: ${WATTETHERIA_BRAIN_PROVIDER_KIND:-rules}
|
|
36
37
|
WATTETHERIA_BRAIN_BASE_URL: ${WATTETHERIA_BRAIN_BASE_URL:-}
|
|
37
38
|
WATTETHERIA_BRAIN_MODEL: ${WATTETHERIA_BRAIN_MODEL:-}
|
package/lib/cli.js
CHANGED
|
@@ -992,9 +992,11 @@ function resolveMcpProxyConfig(options) {
|
|
|
992
992
|
const tokenPath = path.join(dataDir, "control.token");
|
|
993
993
|
const host = getEnvValue(envMap, "WATTETHERIA_CONTROL_PLANE_BIND_HOST", "127.0.0.1");
|
|
994
994
|
const port = getEnvValue(envMap, "WATTETHERIA_CONTROL_PLANE_PORT", "7777");
|
|
995
|
+
const tokenAuth = getEnvValue(envMap, "WATTETHERIA_MCP_TOKEN_AUTH", "false") === "true";
|
|
995
996
|
return {
|
|
996
997
|
endpoint: (options.controlPlane || `http://${host}:${port}`).replace(/\/+$/, ""),
|
|
997
|
-
tokenPath
|
|
998
|
+
tokenPath,
|
|
999
|
+
tokenAuth
|
|
998
1000
|
};
|
|
999
1001
|
}
|
|
1000
1002
|
|
|
@@ -1119,8 +1121,8 @@ async function logs(options) {
|
|
|
1119
1121
|
}
|
|
1120
1122
|
|
|
1121
1123
|
async function mcpProxy(options) {
|
|
1122
|
-
const { endpoint, tokenPath } = resolveMcpProxyConfig(options);
|
|
1123
|
-
if (!fs.existsSync(tokenPath)) {
|
|
1124
|
+
const { endpoint, tokenPath, tokenAuth } = resolveMcpProxyConfig(options);
|
|
1125
|
+
if (tokenAuth && !fs.existsSync(tokenPath)) {
|
|
1124
1126
|
throw new Error(
|
|
1125
1127
|
[
|
|
1126
1128
|
`Wattetheria control token not found: ${tokenPath}`,
|
|
@@ -1128,8 +1130,8 @@ async function mcpProxy(options) {
|
|
|
1128
1130
|
].join("\n")
|
|
1129
1131
|
);
|
|
1130
1132
|
}
|
|
1131
|
-
const token = fs.readFileSync(tokenPath, "utf8").trim();
|
|
1132
|
-
if (!token) {
|
|
1133
|
+
const token = fs.existsSync(tokenPath) ? fs.readFileSync(tokenPath, "utf8").trim() : "";
|
|
1134
|
+
if (tokenAuth && !token) {
|
|
1133
1135
|
throw new Error(`Wattetheria control token is empty: ${tokenPath}`);
|
|
1134
1136
|
}
|
|
1135
1137
|
|
|
@@ -1168,13 +1170,16 @@ async function mcpProxy(options) {
|
|
|
1168
1170
|
}
|
|
1169
1171
|
|
|
1170
1172
|
async function forwardMcpRequest(endpoint, token, request) {
|
|
1173
|
+
const headers = {
|
|
1174
|
+
"content-type": "application/json"
|
|
1175
|
+
};
|
|
1176
|
+
if (token) {
|
|
1177
|
+
headers.authorization = `Bearer ${token}`;
|
|
1178
|
+
}
|
|
1171
1179
|
try {
|
|
1172
1180
|
const response = await fetch(`${endpoint}/mcp`, {
|
|
1173
1181
|
method: "POST",
|
|
1174
|
-
headers
|
|
1175
|
-
authorization: `Bearer ${token}`,
|
|
1176
|
-
"content-type": "application/json"
|
|
1177
|
-
},
|
|
1182
|
+
headers,
|
|
1178
1183
|
body: JSON.stringify(request)
|
|
1179
1184
|
});
|
|
1180
1185
|
const payload = await response.json().catch(() => null);
|