@techsologic/unolock-agent-mcp 0.1.13 → 0.1.15

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 CHANGED
@@ -2,8 +2,30 @@
2
2
 
3
3
  This repository is the dedicated home for UnoLock's Python agent/MCP client.
4
4
 
5
+ UnoLock was built to protect you. Now it can protect both you and your agent.
6
+
5
7
  UnoLock Agent MCP is currently in alpha. It is available for evaluation and early testing, but it is not ready for broad production rollout yet.
6
8
 
9
+ ## Why Use UnoLock For An Agent
10
+
11
+ UnoLock Agent MCP is not only about protecting secrets.
12
+
13
+ It gives an agent a safer place to keep and use:
14
+
15
+ * secrets
16
+ * durable memory
17
+ * structured notes
18
+ * checklists
19
+ * space-scoped working data
20
+
21
+ Compared to local memory files or plaintext secret storage, UnoLock gives the agent:
22
+
23
+ * encrypted storage
24
+ * controlled access to only the Spaces it should use
25
+ * persistence beyond a single local machine or process
26
+ * safer recovery from host loss, reset, or replacement
27
+ * a stronger access model than reusable API keys or plaintext config secrets
28
+
7
29
  ## Security Requirement
8
30
 
9
31
  UnoLock Agent MCP is built for customers who want the strongest practical protection for AI-accessed secrets.
@@ -44,10 +66,18 @@ Official GitHub repository:
44
66
  * `https://github.com/TechSologic/unolock-agent-mcp`
45
67
  * Releases: `https://github.com/TechSologic/unolock-agent-mcp/releases`
46
68
 
69
+ Agent-first onboarding site:
70
+
71
+ * `https://unolock.ai/index.html`
72
+ * `https://unolock.ai/install-mcp.html`
73
+ * `https://unolock.ai/connect-agent.html`
74
+ * `https://unolock.ai/agent-explanation-kit.html`
75
+
47
76
  Recommended customer install source:
48
77
 
78
+ * `mcporter` keep-alive plus `npx @techsologic/unolock-agent-mcp@latest` when available
49
79
  * GitHub Releases binaries
50
- * `npx @techsologic/unolock-agent-mcp` as the Node/npm wrapper path
80
+ * `npx @techsologic/unolock-agent-mcp@latest` as the Node/npm wrapper path
51
81
  * `pipx install` as the fallback source install path when no release binary is available yet
52
82
 
53
83
  If you are new to UnoLock itself, start with these docs first:
@@ -58,6 +88,11 @@ If you are new to UnoLock itself, start with these docs first:
58
88
  * Spaces: `https://docs.unolock.com/features/spaces.html`
59
89
  * Connect an AI Agent to a Safe: `https://docs.unolock.com/howto/connecting-an-ai-agent.html`
60
90
 
91
+ Prerequisite:
92
+
93
+ * Free and Inheritance can share their single included Safe space with one extra Agent Key.
94
+ * Sovereign and HighRisk are still the right tiers for broader multi-Space and collaboration-heavy agent workflows.
95
+
61
96
  The current MCP proves the hardest integration seam first:
62
97
 
63
98
  * live local `/start` flow compatibility
@@ -72,7 +107,7 @@ Safe creation remains a human/browser responsibility, matching the product model
72
107
  * human admin creates a Safe
73
108
  * human admin creates an agent access key for that Safe
74
109
  * MCP registers to the existing Safe
75
- * MCP later authenticates and uses the shared Safe API surface
110
+ * MCP later authenticates and uses the shared Safe API surface for agent memory, notes, checklists, and secrets
76
111
 
77
112
  ## Quick start
78
113
 
@@ -91,12 +126,16 @@ For real MCP hosts, see:
91
126
  * [macOS Quick Start](docs/macos.md)
92
127
  * [Supported Environments](docs/supported-environments.md)
93
128
  * [MCP Host Config](docs/host-config.md)
129
+ * [mcporter keep-alive setup](docs/mcporter.md)
94
130
  * [Support Matrix](docs/support-matrix.md)
95
131
  * [Tool Catalog](docs/tool-catalog.md)
96
132
  * [Claude Desktop example](examples/claude-desktop-config.json)
97
133
  * [Cursor example](examples/cursor-mcp.json)
134
+ * [mcporter example](examples/mcporter.json)
98
135
  * [Config file example](examples/unolock-agent-config.json)
99
136
 
137
+ `mcporter` is the preferred path when it is available. The user PIN is kept only in MCP process memory, so keeping the MCP alive means lower latency, fewer repeat PIN prompts, and less pressure for the agent to store the PIN persistently.
138
+
100
139
  If you prefer manual install from source:
101
140
 
102
141
  ```bash
@@ -122,6 +161,12 @@ For the best customer experience, prefer GitHub Release binaries over source ins
122
161
 
123
162
  ## Preferred Customer Install
124
163
 
164
+ When available, prefer `mcporter` keep-alive plus the npm wrapper or release binary instead of a cold-start bare MCP process.
165
+
166
+ For an agent-first public onboarding flow, send users or agents to:
167
+
168
+ * `https://unolock.ai/index.html`
169
+
125
170
  When available, prefer the standalone GitHub Release binaries instead of installing from Git.
126
171
 
127
172
  That avoids most of the Python packaging and source-build overhead for customers.
@@ -129,11 +174,13 @@ That avoids most of the Python packaging and source-build overhead for customers
129
174
  If your host environment is already Node/npm-oriented, you can also use the npm wrapper:
130
175
 
131
176
  ```bash
132
- npx @techsologic/unolock-agent-mcp --version
177
+ npx @techsologic/unolock-agent-mcp@latest --version
133
178
  ```
134
179
 
135
180
  The wrapper downloads the correct GitHub Release binary for the current platform on first use and then reuses the cached copy.
136
181
 
182
+ On restart, the npm wrapper now checks GitHub Releases for a newer stable binary and will update its cached binary between tasks when a newer release is available.
183
+
137
184
  The npm package is an OpenClaw-friendly install and launch path for the external UnoLock MCP binary.
138
185
 
139
186
  It is **not** an OpenClaw plugin package for `openclaw plugins install ...`.
@@ -145,15 +192,62 @@ Project home:
145
192
  Use it as a command that OpenClaw can launch, for example:
146
193
 
147
194
  ```bash
148
- npx @techsologic/unolock-agent-mcp mcp
195
+ npx @techsologic/unolock-agent-mcp@latest mcp
149
196
  ```
150
197
 
151
198
  With no arguments, the npm wrapper starts the MCP server by default:
152
199
 
153
200
  ```bash
154
- npx @techsologic/unolock-agent-mcp
201
+ npx @techsologic/unolock-agent-mcp@latest
202
+ ```
203
+
204
+ Preferred keep-alive example with `mcporter`:
205
+
206
+ ```json
207
+ {
208
+ "servers": {
209
+ "unolock-agent": {
210
+ "command": "npx",
211
+ "args": ["@techsologic/unolock-agent-mcp@latest"],
212
+ "lifecycle": "keep-alive"
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ## Update Policy
219
+
220
+ UnoLock Agent MCP should not replace itself in the middle of an active session or write flow.
221
+
222
+ The intended update model is:
223
+
224
+ * the MCP reports update status
225
+ * the wrapper or runner applies updates
226
+ * the runner restarts between tasks so in-memory PINs and sessions can be re-established cleanly
227
+
228
+ Check update status with:
229
+
230
+ ```bash
231
+ unolock-agent-mcp check-update --json
155
232
  ```
156
233
 
234
+ Or, through the MCP itself, call:
235
+
236
+ * `unolock_get_update_status`
237
+
238
+ Preferred channel behavior:
239
+
240
+ * `mcporter` + `npx @techsologic/unolock-agent-mcp@latest`
241
+ * preferred low-friction path
242
+ * on restart, the npm wrapper checks GitHub Releases and can fetch the latest stable binary
243
+ * npm publishing is only needed when the wrapper itself changes
244
+ * direct GitHub Release binary
245
+ * replace the binary manually, then restart the MCP runner
246
+ * Python package install
247
+ * upgrade the package in that environment, then restart the runner
248
+
249
+ For the best user experience, do updates between tasks, not while an enrollment flow, authentication flow, or sensitive write flow is active.
250
+
157
251
  ## Standalone config
158
252
 
159
253
  When the MCP runs outside the main UnoLock monorepo, it can usually derive its UnoLock runtime config from the UnoLock agent key connection URL. Environment variables and config files are primarily for overrides and custom deployments.
@@ -170,12 +264,11 @@ Override example:
170
264
  {
171
265
  "base_url": "https://api.unolock.example",
172
266
  "transparency_origin": "https://safe.unolock.example",
173
- "app_version": "1.2.3",
174
267
  "signing_public_key_b64": "BASE64_SERVER_PQ_SIGNING_PUBLIC_KEY"
175
268
  }
176
269
  ```
177
270
 
178
- For the standard hosted UnoLock deployment, the MCP can derive the API origin, UnoLock app version, and PQ validation key from the user-provided agent key connection URL automatically. If you want to force the same hosted deployment without waiting for a connection URL, this also works:
271
+ For the standard hosted UnoLock deployment, the MCP can derive the API origin and PQ validation key from the user-provided agent key connection URL automatically. If you want to force the same hosted deployment without waiting for a connection URL, this also works:
179
272
 
180
273
  ```json
181
274
  {
@@ -183,7 +276,7 @@ For the standard hosted UnoLock deployment, the MCP can derive the API origin, U
183
276
  }
184
277
  ```
185
278
 
186
- the MCP will derive `https://safe.unolock.com`, fetch `/unolock-client.json`, and read the published app version and `serverPQValidationKey`. If that hosted file is unavailable, it falls back to the transparency bundle.
279
+ the MCP will derive `https://safe.unolock.com`, fetch `/unolock-client.json`, and read the published `serverPQValidationKey`. If that hosted file is unavailable, it falls back to the transparency bundle.
187
280
 
188
281
  Use this command to verify what the MCP resolved:
189
282
 
@@ -191,13 +284,6 @@ Use this command to verify what the MCP resolved:
191
284
  python3 -m unolock_mcp config-check
192
285
  ```
193
286
 
194
- Versioning is intentionally split:
195
-
196
- * MCP package version: the version of `unolock-agent-mcp` itself
197
- * UnoLock app version: the Safe client/server compatibility version sent as `x-app-version`
198
-
199
- For the standard hosted UnoLock deployment, the MCP resolves the UnoLock app version from the hosted client metadata rather than reusing the MCP package version.
200
-
201
287
  TPM provider selection:
202
288
 
203
289
  * default: `UNOLOCK_TPM_PROVIDER=auto`
@@ -7,8 +7,8 @@ const path = require("path");
7
7
  const https = require("https");
8
8
  const { spawn } = require("child_process");
9
9
 
10
- const PACKAGE_VERSION = "0.1.13";
11
- const BINARY_VERSION = "0.1.11";
10
+ const PACKAGE_VERSION = "0.1.15";
11
+ const FALLBACK_BINARY_VERSION = "0.1.15";
12
12
  const REPO = "TechSologic/unolock-agent-mcp";
13
13
 
14
14
  function platformAssetInfo() {
@@ -36,17 +36,21 @@ function cacheRoot() {
36
36
  return process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache");
37
37
  }
38
38
 
39
- function binaryPath() {
39
+ function metadataPath() {
40
+ return path.join(cacheRoot(), "unolock-agent-mcp", "release.json");
41
+ }
42
+
43
+ function binaryPath(releaseVersion) {
40
44
  const { executable } = platformAssetInfo();
41
- return path.join(cacheRoot(), "unolock-agent-mcp", BINARY_VERSION, executable);
45
+ return path.join(cacheRoot(), "unolock-agent-mcp", releaseVersion, executable);
42
46
  }
43
47
 
44
- function binaryUrl() {
48
+ function binaryUrl(releaseVersion) {
45
49
  if (process.env.UNOLOCK_AGENT_MCP_BINARY_URL) {
46
50
  return process.env.UNOLOCK_AGENT_MCP_BINARY_URL;
47
51
  }
48
52
  const { asset } = platformAssetInfo();
49
- return `https://github.com/${REPO}/releases/download/v${BINARY_VERSION}/${asset}`;
53
+ return `https://github.com/${REPO}/releases/download/v${releaseVersion}/${asset}`;
50
54
  }
51
55
 
52
56
  function ensureDir(dir) {
@@ -95,23 +99,126 @@ function fetchToFile(url, dest) {
95
99
  });
96
100
  }
97
101
 
102
+ function fetchJson(url) {
103
+ return new Promise((resolve, reject) => {
104
+ const request = https.get(
105
+ url,
106
+ {
107
+ headers: {
108
+ "Accept": "application/vnd.github+json",
109
+ "User-Agent": "unolock-agent-mcp-npm-wrapper"
110
+ }
111
+ },
112
+ (response) => {
113
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
114
+ response.resume();
115
+ fetchJson(response.headers.location).then(resolve, reject);
116
+ return;
117
+ }
118
+ if (response.statusCode !== 200) {
119
+ response.resume();
120
+ reject(new Error(`Failed to query UnoLock Agent MCP latest release: HTTP ${response.statusCode}`));
121
+ return;
122
+ }
123
+ let body = "";
124
+ response.setEncoding("utf8");
125
+ response.on("data", (chunk) => {
126
+ body += chunk;
127
+ });
128
+ response.on("end", () => {
129
+ try {
130
+ resolve(JSON.parse(body));
131
+ } catch (error) {
132
+ reject(error);
133
+ }
134
+ });
135
+ }
136
+ );
137
+ request.on("error", reject);
138
+ });
139
+ }
140
+
141
+ function normalizeVersion(value) {
142
+ if (!value || typeof value !== "string") {
143
+ return null;
144
+ }
145
+ const trimmed = value.trim();
146
+ if (!trimmed) {
147
+ return null;
148
+ }
149
+ return trimmed.startsWith("v") ? trimmed.slice(1) : trimmed;
150
+ }
151
+
152
+ function readReleaseMetadata() {
153
+ try {
154
+ return JSON.parse(fs.readFileSync(metadataPath(), "utf8"));
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+
160
+ function writeReleaseMetadata(releaseVersion) {
161
+ ensureDir(path.dirname(metadataPath()));
162
+ fs.writeFileSync(
163
+ metadataPath(),
164
+ JSON.stringify(
165
+ {
166
+ releaseVersion,
167
+ checkedAt: Date.now()
168
+ },
169
+ null,
170
+ 2
171
+ ),
172
+ "utf8"
173
+ );
174
+ }
175
+
176
+ async function resolveReleaseVersion() {
177
+ const override = normalizeVersion(process.env.UNOLOCK_AGENT_MCP_BINARY_VERSION);
178
+ if (override) {
179
+ return override;
180
+ }
181
+ const metadata = readReleaseMetadata();
182
+ try {
183
+ const payload = await fetchJson(`https://api.github.com/repos/${REPO}/releases/latest`);
184
+ const latest = normalizeVersion(payload && payload.tag_name);
185
+ if (latest) {
186
+ writeReleaseMetadata(latest);
187
+ return latest;
188
+ }
189
+ } catch (error) {
190
+ if (metadata && typeof metadata.releaseVersion === "string" && fs.existsSync(binaryPath(metadata.releaseVersion))) {
191
+ return metadata.releaseVersion;
192
+ }
193
+ process.stderr.write(`Warning: ${error.message}. Falling back to bundled release ${FALLBACK_BINARY_VERSION}.\n`);
194
+ }
195
+ writeReleaseMetadata(FALLBACK_BINARY_VERSION);
196
+ return FALLBACK_BINARY_VERSION;
197
+ }
198
+
98
199
  async function ensureBinary() {
99
- const dest = binaryPath();
200
+ const releaseVersion = await resolveReleaseVersion();
201
+ const dest = binaryPath(releaseVersion);
100
202
  if (fs.existsSync(dest)) {
101
- return dest;
203
+ return { dest, releaseVersion };
102
204
  }
103
205
  ensureDir(path.dirname(dest));
104
- process.stderr.write(`Downloading UnoLock Agent MCP ${BINARY_VERSION} for ${process.platform}/${process.arch}...\n`);
105
- await fetchToFile(binaryUrl(), dest);
106
- return dest;
206
+ process.stderr.write(`Downloading UnoLock Agent MCP ${releaseVersion} for ${process.platform}/${process.arch}...\n`);
207
+ await fetchToFile(binaryUrl(releaseVersion), dest);
208
+ return { dest, releaseVersion };
107
209
  }
108
210
 
109
211
  async function main() {
110
- const dest = await ensureBinary();
212
+ const { dest, releaseVersion } = await ensureBinary();
111
213
  const forwardedArgs = process.argv.length > 2 ? process.argv.slice(2) : ["mcp"];
112
214
  const child = spawn(dest, forwardedArgs, {
113
215
  stdio: "inherit",
114
- env: process.env
216
+ env: {
217
+ ...process.env,
218
+ UNOLOCK_AGENT_MCP_INSTALL_CHANNEL: "npm-wrapper",
219
+ UNOLOCK_AGENT_MCP_WRAPPER_VERSION: PACKAGE_VERSION,
220
+ UNOLOCK_AGENT_MCP_BINARY_VERSION: releaseVersion
221
+ }
115
222
  });
116
223
  child.on("exit", (code, signal) => {
117
224
  if (signal) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@techsologic/unolock-agent-mcp",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "npx wrapper for the official UnoLock Agent MCP release binaries",
5
- "license": "SEE LICENSE IN README.md",
5
+ "license": "UNLICENSED",
6
6
  "homepage": "https://github.com/TechSologic/unolock-agent-mcp",
7
7
  "repository": {
8
8
  "type": "git",