@rubytech/create-maxy 1.0.636 → 1.0.637
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/package.json +1 -1
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +1 -1
- package/payload/platform/plugins/memory/mcp/scripts/graph/accept.sh +96 -8
- package/payload/platform/plugins/memory/references/graph-primitives.md +4 -4
- package/payload/platform/scripts/setup.sh +1 -1
- package/payload/server/server.js +27 -4
package/package.json
CHANGED
|
@@ -280,7 +280,7 @@ if ! command -v dig >/dev/null 2>&1; then
|
|
|
280
280
|
phase_line setup-tunnel step=zone-preflight result=error \
|
|
281
281
|
reason=dig-missing
|
|
282
282
|
echo "ERROR: dig is not in PATH — required for the zone pre-flight check." >&2
|
|
283
|
-
echo "
|
|
283
|
+
echo " Re-run the Maxy installer to reprovision DNS tooling (bind9-dnsutils)." >&2
|
|
284
284
|
exit 1
|
|
285
285
|
fi
|
|
286
286
|
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
2
|
+
# Acceptance harness for the graph MCP integration.
|
|
3
3
|
#
|
|
4
4
|
# Spawns the graph shim, drives it as a JSON-RPC client over stdio, runs
|
|
5
5
|
# one query per acceptance class, prints PASS/FAIL per check, and exits
|
|
6
6
|
# non-zero if any check fails. Assumes the brand's Neo4j is running and
|
|
7
7
|
# the fixture in fixture.cypher has been seeded.
|
|
8
8
|
#
|
|
9
|
+
# The tools/list assertion guards against FastMCP-joiner drift: the
|
|
10
|
+
# upstream server joins NEO4J_NAMESPACE to each tool name with a hyphen,
|
|
11
|
+
# and the admin allowlist is string-exact. If a future upstream upgrade
|
|
12
|
+
# changes the joiner, the assertion fails with a named reason before any
|
|
13
|
+
# functional check runs.
|
|
14
|
+
#
|
|
9
15
|
# Usage:
|
|
10
16
|
# PLATFORM_ROOT=~/.maxy/platform bash accept.sh # infers NEO4J_URI from env
|
|
11
17
|
# PLATFORM_ROOT=~/.maxy/platform NEO4J_URI=bolt://localhost:7687 bash accept.sh
|
|
@@ -36,10 +42,88 @@ PASS=0
|
|
|
36
42
|
FAIL=0
|
|
37
43
|
TOTAL=0
|
|
38
44
|
|
|
45
|
+
# Exported env used by the inline Node clients below.
|
|
46
|
+
export SHIM
|
|
47
|
+
export PLATFORM_ROOT
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# Regression guard: tools/list must register hyphen-joined names only.
|
|
51
|
+
#
|
|
52
|
+
# FastMCP joins NEO4J_NAMESPACE ("maxy-graph") to each upstream tool with a
|
|
53
|
+
# hyphen, producing `maxy-graph-read_neo4j_cypher` and
|
|
54
|
+
# `maxy-graph-get_neo4j_schema`. Claude Code's MCP client adds `mcp__graph__`
|
|
55
|
+
# on top when registering the server — the admin allowlist in
|
|
56
|
+
# platform/ui/app/lib/claude-agent.ts must match those exact names.
|
|
57
|
+
# A future upstream version that changes the joiner (e.g. to underscore)
|
|
58
|
+
# silently re-introduces a class of denial unless this fires.
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
assert_tools_list() {
|
|
61
|
+
TOTAL=$(( TOTAL + 1 ))
|
|
62
|
+
local out
|
|
63
|
+
if ! out=$(
|
|
64
|
+
node -e "
|
|
65
|
+
const { spawn } = require('node:child_process');
|
|
66
|
+
const proc = spawn('node', [process.env.SHIM], { stdio: ['pipe', 'pipe', 'inherit'] });
|
|
67
|
+
let buf = '';
|
|
68
|
+
proc.stdout.on('data', (chunk) => { buf += chunk.toString('utf8'); });
|
|
69
|
+
const send = (obj) => proc.stdin.write(JSON.stringify(obj) + '\n');
|
|
70
|
+
send({ jsonrpc: '2.0', id: 1, method: 'initialize',
|
|
71
|
+
params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'accept.sh', version: '1.0' } } });
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
send({ jsonrpc: '2.0', method: 'notifications/initialized' });
|
|
74
|
+
send({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} });
|
|
75
|
+
}, 1500);
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
proc.kill('SIGTERM');
|
|
78
|
+
const lines = buf.split('\n').filter(Boolean);
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
try { const m = JSON.parse(line); if (m.id === 2) {
|
|
81
|
+
if (m.error) { console.error('RPC_ERROR: ' + JSON.stringify(m.error)); process.exit(1); }
|
|
82
|
+
const names = (m.result && m.result.tools || []).map(t => t.name);
|
|
83
|
+
process.stdout.write(JSON.stringify(names));
|
|
84
|
+
process.exit(0);
|
|
85
|
+
} } catch (_) {}
|
|
86
|
+
}
|
|
87
|
+
console.error('NO_RESPONSE');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}, 10000);
|
|
90
|
+
" 2>/dev/null
|
|
91
|
+
); then
|
|
92
|
+
echo "FAIL: tools/list RPC did not respond"
|
|
93
|
+
FAIL=$(( FAIL + 1 ))
|
|
94
|
+
return 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
local missing=""
|
|
98
|
+
for expected in "maxy-graph-read_neo4j_cypher" "maxy-graph-get_neo4j_schema"; do
|
|
99
|
+
if ! grep -q "\"$expected\"" <<<"$out"; then
|
|
100
|
+
missing+=" $expected"
|
|
101
|
+
fi
|
|
102
|
+
done
|
|
103
|
+
if [[ -n "$missing" ]]; then
|
|
104
|
+
echo "FAIL: tools/list missing hyphen-joined names —${missing} (reason: missing-hyphen-tool)"
|
|
105
|
+
echo " received: $out"
|
|
106
|
+
FAIL=$(( FAIL + 1 ))
|
|
107
|
+
return 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if grep -qE 'maxy-graph_(read|get|write)' <<<"$out"; then
|
|
111
|
+
local stray
|
|
112
|
+
stray=$(grep -oE 'maxy-graph_[a-z_]+' <<<"$out" | sort -u | tr '\n' ' ')
|
|
113
|
+
echo "FAIL: tools/list contains underscore-joined variant(s) — ${stray}(reason: stray-underscore-tool)"
|
|
114
|
+
FAIL=$(( FAIL + 1 ))
|
|
115
|
+
return 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
echo "PASS: tools/list registers hyphen-joined names only (${#out}b response)"
|
|
119
|
+
PASS=$(( PASS + 1 ))
|
|
120
|
+
return 0
|
|
121
|
+
}
|
|
122
|
+
|
|
39
123
|
run_check() {
|
|
40
124
|
local label="$1"
|
|
41
125
|
local query="$2"
|
|
42
|
-
local tool="${3:-maxy-
|
|
126
|
+
local tool="${3:-maxy-graph-read_neo4j_cypher}"
|
|
43
127
|
TOTAL=$(( TOTAL + 1 ))
|
|
44
128
|
|
|
45
129
|
# Drive the shim via a short Node inline client. Exits 0 with the response
|
|
@@ -58,7 +142,7 @@ run_check() {
|
|
|
58
142
|
params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'accept.sh', version: '1.0' } } });
|
|
59
143
|
setTimeout(() => {
|
|
60
144
|
send({ jsonrpc: '2.0', method: 'notifications/initialized' });
|
|
61
|
-
const params = tool === 'maxy-
|
|
145
|
+
const params = tool === 'maxy-graph-get_neo4j_schema' ? {} : { query };
|
|
62
146
|
send({ jsonrpc: '2.0', id: 2, method: 'tools/call', params: { name: tool, arguments: params } });
|
|
63
147
|
}, 1500);
|
|
64
148
|
setTimeout(() => {
|
|
@@ -91,15 +175,19 @@ run_check() {
|
|
|
91
175
|
fi
|
|
92
176
|
}
|
|
93
177
|
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
178
|
+
# Run the regression guard first. If it fails, abort early — running
|
|
179
|
+
# functional queries with stale tool names produces misleading failures.
|
|
180
|
+
if ! assert_tools_list; then
|
|
181
|
+
echo ""
|
|
182
|
+
echo "FAIL — tool registration contract violated; aborting functional checks"
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
97
185
|
|
|
98
|
-
export TOOL="maxy-
|
|
186
|
+
export TOOL="maxy-graph-get_neo4j_schema"
|
|
99
187
|
export QUERY=""
|
|
100
188
|
run_check "get_neo4j_schema returns labels" ""
|
|
101
189
|
|
|
102
|
-
export TOOL="maxy-
|
|
190
|
+
export TOOL="maxy-graph-read_neo4j_cypher"
|
|
103
191
|
|
|
104
192
|
export QUERY="MATCH (n) RETURN labels(n)[0] AS type, count(*) AS n ORDER BY n DESC LIMIT 20"
|
|
105
193
|
run_check "enumerate by label" "$QUERY"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- Injected into admin system prompt by claude-agent.ts when agentType === "admin". -->
|
|
2
|
-
<!-- Consumed by the upstream mcp-neo4j-cypher server via `maxy-
|
|
2
|
+
<!-- Consumed by the upstream mcp-neo4j-cypher server via `maxy-graph-read_neo4j_cypher`. -->
|
|
3
3
|
<!-- Source of truth for node labels and properties: platform/neo4j/schema.cypher + plugins/memory/references/schema-*.md. -->
|
|
4
4
|
|
|
5
5
|
# Graph interrogation (read-only Cypher cookbook)
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
When a user asks a relational question about their own graph — *"list all my
|
|
8
8
|
people", "how many tasks do I have", "find the person with email X", "what's
|
|
9
9
|
linked to this business", "show me the 20 most recently created nodes" — use
|
|
10
|
-
`maxy-
|
|
10
|
+
`maxy-graph-read_neo4j_cypher` or `maxy-graph-get_neo4j_schema`, not
|
|
11
11
|
`memory-search`. Vector search is for "things like this"; Cypher is for "the
|
|
12
12
|
exact set where".
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ filter in the query.
|
|
|
17
17
|
|
|
18
18
|
## When the graph tools are absent
|
|
19
19
|
|
|
20
|
-
If neither `maxy-
|
|
20
|
+
If neither `maxy-graph-read_neo4j_cypher` nor `maxy-graph-get_neo4j_schema`
|
|
21
21
|
appears in your tool list, the graph MCP server failed to start on this
|
|
22
22
|
device. Reply once with exactly:
|
|
23
23
|
|
|
@@ -162,7 +162,7 @@ All relationship types:
|
|
|
162
162
|
CALL db.relationshipTypes() YIELD relationshipType RETURN relationshipType ORDER BY relationshipType
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
Or use `maxy-
|
|
165
|
+
Or use `maxy-graph-get_neo4j_schema` for a richer one-shot structural summary.
|
|
166
166
|
|
|
167
167
|
### Fulltext
|
|
168
168
|
|
|
@@ -21,7 +21,7 @@ echo ""
|
|
|
21
21
|
# ------------------------------------------------------------------
|
|
22
22
|
echo "[1/8] Updating system packages and configuring network..."
|
|
23
23
|
sudo apt-get update -qq
|
|
24
|
-
sudo apt-get install -y -qq curl git unzip avahi-daemon avahi-utils
|
|
24
|
+
sudo apt-get install -y -qq curl git unzip avahi-daemon avahi-utils bind9-dnsutils
|
|
25
25
|
|
|
26
26
|
# Set hostname to 'maxy' so device is reachable at maxy.local
|
|
27
27
|
CURRENT_HOSTNAME=$(hostname)
|
package/payload/server/server.js
CHANGED
|
@@ -7873,12 +7873,15 @@ var ADMIN_CORE_TOOLS = [
|
|
|
7873
7873
|
"Glob",
|
|
7874
7874
|
"Grep",
|
|
7875
7875
|
"Agent",
|
|
7876
|
-
//
|
|
7877
|
-
//
|
|
7876
|
+
// Upstream mcp-neo4j-cypher (namespaced maxy-graph, read-only).
|
|
7877
|
+
// FastMCP joins NEO4J_NAMESPACE to each upstream tool name with a hyphen,
|
|
7878
|
+
// and allowedTools matching is string-exact under --permission-mode dontAsk —
|
|
7879
|
+
// these names must equal the init-message tool list byte-for-byte.
|
|
7880
|
+
// maxy-graph-write_neo4j_cypher is intentionally absent: writes go through
|
|
7878
7881
|
// the schema-aware memory-write tool, which validates labels, properties,
|
|
7879
7882
|
// and embeddings. Admin-only by virtue of not being in the public allow list.
|
|
7880
|
-
"mcp__graph__maxy-
|
|
7881
|
-
"mcp__graph__maxy-
|
|
7883
|
+
"mcp__graph__maxy-graph-read_neo4j_cypher",
|
|
7884
|
+
"mcp__graph__maxy-graph-get_neo4j_schema",
|
|
7882
7885
|
"mcp__memory__memory-search",
|
|
7883
7886
|
"mcp__memory__memory-rank",
|
|
7884
7887
|
"mcp__memory__memory-write",
|
|
@@ -11009,6 +11012,26 @@ function defaultRules() {
|
|
|
11009
11012
|
thresholdCount: 0,
|
|
11010
11013
|
thresholdWindowMinutes: 0,
|
|
11011
11014
|
suggestedAction: "The stored Anthropic API key was rejected by console.anthropic.com (invalid, revoked, or expired) and `anthropic-setup` auto-deleted it. On the next operator interaction, explain that the key was cleared and walk them through sign-in again via the onboarding skill \u2014 the tool already returned `awaiting_signin` with the correct `browser_evaluate` action on the same call."
|
|
11015
|
+
},
|
|
11016
|
+
{
|
|
11017
|
+
// Task 561: fires when an admin-agent Bash tool call installs
|
|
11018
|
+
// `bind9-dnsutils` at runtime. Post-Task-561 the Maxy installer
|
|
11019
|
+
// (platform/scripts/setup.sh) provisions the package on every fresh
|
|
11020
|
+
// and upgrade install, so `dig` is always in PATH before
|
|
11021
|
+
// setup-tunnel.sh runs. An admin apt-install of bind9-dnsutils is
|
|
11022
|
+
// therefore evidence the installer regressed (or the host is on a
|
|
11023
|
+
// pre-Task-561 image); in either case the fix is to re-run the
|
|
11024
|
+
// installer, not to patch apt-state from chat. Session scope so a
|
|
11025
|
+
// single offending turn fires exactly once.
|
|
11026
|
+
id: "admin-agent-apt-bind9-install",
|
|
11027
|
+
name: "Admin agent installed bind9-dnsutils at runtime (installer regression)",
|
|
11028
|
+
type: "repeated-error",
|
|
11029
|
+
logSource: "any",
|
|
11030
|
+
pattern: "\\[tool-use\\][^\\n]*name=Bash[^\\n]*apt-get install[^\\n]*bind9-dnsutils",
|
|
11031
|
+
thresholdCount: 1,
|
|
11032
|
+
thresholdWindowMinutes: 60,
|
|
11033
|
+
scope: "session",
|
|
11034
|
+
suggestedAction: "[Task 561 regression] The admin agent ran `apt-get install bind9-dnsutils` \u2014 the exact workaround Task 561 eliminated. The Maxy installer provisions `bind9-dnsutils` in `platform/scripts/setup.sh` so `dig` is always in PATH before `setup-tunnel.sh` runs. Do not patch apt-state from chat \u2014 re-run the installer (`npx -y @rubytech/create-maxy`) and verify the installer's apt-get line still includes `bind9-dnsutils`. If the package is present in setup.sh but missing on the device, the installer did not re-run step 1 on the current image."
|
|
11012
11035
|
}
|
|
11013
11036
|
];
|
|
11014
11037
|
}
|