@minhpnq1807/contextos 0.1.8 → 0.1.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/CHANGELOG.md +5 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/plugins/ctx/lib/mcp-proxy-install.js +13 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.9
|
|
4
|
+
|
|
5
|
+
- Proxies all configured MCP servers except ContextOS' own `ctx-mcp` server.
|
|
6
|
+
- Preserves each original MCP command after the proxy separator and forwards it unchanged, including RTK-managed commands.
|
|
7
|
+
|
|
3
8
|
## 0.1.8
|
|
4
9
|
|
|
5
10
|
- Limits automatic MCP telemetry wrapping to `code-review-graph` only.
|
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ node bin/ctx.js install
|
|
|
105
105
|
3. Downloads and caches the required local MiniLM embedding model under `~/.ctx/contextos/models`.
|
|
106
106
|
4. Warms `~/.ctx/contextos/embeddings.db` for AGENTS rules and project file paths.
|
|
107
107
|
5. Registers the `ctx-mcp` MCP server and merges ContextOS global hooks into `$CODEX_HOME/hooks.json`.
|
|
108
|
-
6. Wraps
|
|
108
|
+
6. Wraps configured local MCP servers, except ContextOS' own `ctx-mcp`, with a transparent telemetry proxy so `tools/call` events can be measured. The original MCP command is preserved after the proxy separator and executed unchanged.
|
|
109
109
|
|
|
110
110
|
Restart Codex after installing.
|
|
111
111
|
|
|
@@ -290,7 +290,7 @@ unknown = the rule was relevant, but the diff does not prove either way
|
|
|
290
290
|
|
|
291
291
|
For runtime-only rules, ContextOS also checks `telemetry.jsonl` for hook-visible tool names, MCP server names, and command metadata. A rule like "use code-review-graph before reading files" can be marked `followed` when telemetry contains a matching `code-review-graph` signal.
|
|
292
292
|
|
|
293
|
-
`ctx install` wraps
|
|
293
|
+
`ctx install` wraps configured stdio MCP servers with a transparent proxy. Codex will show `node .../proxy.js` as the launched command because that is how stdio can be intercepted, but the original MCP command is kept after `--` and executed unchanged, including RTK-managed commands. The proxy forwards MCP JSON-RPC unchanged and records `tools/call` requests such as `code-review-graph.detect_changes_tool` to workspace telemetry.
|
|
294
294
|
|
|
295
295
|
Host/session setup rules such as "run shell commands as user X", `sudo su - user`, `sudo -i -u user`, and `sudo -u user` are filtered before scoring. They are not injected and do not count toward `unknown` outcomes because they describe the agent runtime environment rather than project behavior.
|
|
296
296
|
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const DEFAULT_EXCLUDES = new Set(["ctx-mcp"]);
|
|
5
5
|
|
|
6
|
-
export function installMcpTelemetryProxies({ codexHome, marketplaceRoot, targets =
|
|
6
|
+
export function installMcpTelemetryProxies({ codexHome, marketplaceRoot, targets = null, excludes = DEFAULT_EXCLUDES } = {}) {
|
|
7
7
|
const configPath = path.join(codexHome, "config.toml");
|
|
8
8
|
if (!fs.existsSync(configPath)) return { wrapped: [], skipped: [], configPath };
|
|
9
9
|
|
|
10
10
|
const original = fs.readFileSync(configPath, "utf8");
|
|
11
11
|
const proxyPath = path.join(marketplaceRoot, "plugins", "ctx", "mcp", "proxy.js");
|
|
12
|
-
const result = rewriteMcpTelemetryProxies(original, { proxyPath, targets });
|
|
12
|
+
const result = rewriteMcpTelemetryProxies(original, { proxyPath, targets, excludes });
|
|
13
13
|
if (result.content !== original) {
|
|
14
14
|
fs.writeFileSync(configPath, result.content, "utf8");
|
|
15
15
|
}
|
|
16
16
|
return { ...result, configPath };
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets =
|
|
19
|
+
export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = null, excludes = DEFAULT_EXCLUDES } = {}) {
|
|
20
20
|
const lines = String(toml || "").split(/\r?\n/);
|
|
21
21
|
const sections = findMcpServerSections(lines);
|
|
22
22
|
const wrapped = [];
|
|
@@ -26,8 +26,9 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
26
26
|
const body = lines.slice(section.start + 1, section.end);
|
|
27
27
|
const command = findStringValue(body, "command");
|
|
28
28
|
const args = findArrayValue(body, "args") || [];
|
|
29
|
+
const shouldProxy = shouldProxyServer(section.name, { targets, excludes });
|
|
29
30
|
|
|
30
|
-
if (command === "node" && args[0] === proxyPath && !
|
|
31
|
+
if (command === "node" && args[0] === proxyPath && !shouldProxy) {
|
|
31
32
|
const original = unwrapProxyArgs(args);
|
|
32
33
|
if (original) {
|
|
33
34
|
const nextBody = replaceOrInsertServerField(
|
|
@@ -41,7 +42,7 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
if (!
|
|
45
|
+
if (!shouldProxy) {
|
|
45
46
|
skipped.push({ name: section.name, reason: "not-targeted" });
|
|
46
47
|
continue;
|
|
47
48
|
}
|
|
@@ -54,10 +55,6 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
54
55
|
skipped.push({ name: section.name, reason: "already-wrapped" });
|
|
55
56
|
continue;
|
|
56
57
|
}
|
|
57
|
-
if (command === "rtk") {
|
|
58
|
-
skipped.push({ name: section.name, reason: "rtk-managed" });
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
58
|
|
|
62
59
|
const nextBody = replaceOrInsertServerField(
|
|
63
60
|
replaceOrInsertServerField(body, "command", tomlString("node")),
|
|
@@ -71,6 +68,12 @@ export function rewriteMcpTelemetryProxies(toml, { proxyPath, targets = DEFAULT_
|
|
|
71
68
|
return { content: lines.join("\n"), wrapped: wrapped.reverse(), skipped: skipped.reverse() };
|
|
72
69
|
}
|
|
73
70
|
|
|
71
|
+
function shouldProxyServer(name, { targets, excludes }) {
|
|
72
|
+
if (targets instanceof Set) return targets.has(name);
|
|
73
|
+
if (Array.isArray(targets)) return targets.includes(name);
|
|
74
|
+
return !(excludes || DEFAULT_EXCLUDES).has(name);
|
|
75
|
+
}
|
|
76
|
+
|
|
74
77
|
function unwrapProxyArgs(args) {
|
|
75
78
|
const separator = args.indexOf("--");
|
|
76
79
|
if (separator < 0 || separator >= args.length - 1) return null;
|