@marsnme/mcp-gateway 0.1.1

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.
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
7
+ OUTPUT_DIR="${SCRIPT_DIR}/../artifacts"
8
+
9
+ while [[ $# -gt 0 ]]; do
10
+ case "$1" in
11
+ --output-dir)
12
+ OUTPUT_DIR="$2"
13
+ shift 2
14
+ ;;
15
+ *)
16
+ echo "unknown arg: $1" >&2
17
+ echo "usage: $0 [--output-dir <dir>]" >&2
18
+ exit 1
19
+ ;;
20
+ esac
21
+ done
22
+
23
+ mkdir -p "${OUTPUT_DIR}"
24
+
25
+ TS="$(date -u +%Y%m%dT%H%M%SZ)"
26
+ COMMIT_HASH="$(git -C "${REPO_ROOT}" rev-parse HEAD)"
27
+ COMMIT_SHORT="${COMMIT_HASH:0:12}"
28
+
29
+ ARTIFACT_BASENAME="mars-memory-mcp-${TS}-${COMMIT_SHORT}"
30
+ ARTIFACT_PATH="${OUTPUT_DIR}/${ARTIFACT_BASENAME}.tar.gz"
31
+ MANIFEST_PATH="${OUTPUT_DIR}/${ARTIFACT_BASENAME}.manifest.json"
32
+
33
+ tar -C "${REPO_ROOT}" -czf "${ARTIFACT_PATH}" \
34
+ --exclude='soul-memory/deploy/artifacts' \
35
+ --exclude='soul-memory/deploy/phase0/ct101-baseline-*' \
36
+ README.md \
37
+ soul-memory \
38
+ supabase/config.toml \
39
+ supabase/migrations
40
+
41
+ ARTIFACT_SHA256="$(shasum -a 256 "${ARTIFACT_PATH}" | awk '{print $1}')"
42
+ SERVER_SHA256="$(shasum -a 256 "${REPO_ROOT}/soul-memory/server.mjs" | awk '{print $1}')"
43
+
44
+ cat > "${MANIFEST_PATH}" <<EOF
45
+ {
46
+ "created_at_utc": "${TS}",
47
+ "commit_hash": "${COMMIT_HASH}",
48
+ "artifact_path": "${ARTIFACT_PATH}",
49
+ "artifact_sha256": "${ARTIFACT_SHA256}",
50
+ "server_path": "soul-memory/server.mjs",
51
+ "server_sha256": "${SERVER_SHA256}"
52
+ }
53
+ EOF
54
+
55
+ printf '%s\n' "artifact=${ARTIFACT_PATH}"
56
+ printf '%s\n' "manifest=${MANIFEST_PATH}"
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
7
+
8
+ COCO_URL="http://127.0.0.1:18790"
9
+ TOTO_URL="http://127.0.0.1:18791"
10
+ SPAWN_LOCAL="false"
11
+ OUTPUT_PATH=""
12
+ REMOTE_SERVER_SHA256=""
13
+ REMOTE_SERVER_SHA256_CMD=""
14
+ SUPABASE_BASE_URL_FOR_LOCAL="${SUPABASE_BASE_URL:-http://127.0.0.1:54321}"
15
+
16
+ usage() {
17
+ cat <<EOF
18
+ usage: $0 [--spawn-local] [--coco-url <url>] [--toto-url <url>] [--output <path>] [--remote-server-sha256 <sha>] [--remote-server-sha256-cmd <cmd>]
19
+
20
+ examples:
21
+ $0 --spawn-local
22
+ $0 --coco-url http://127.0.0.1:18790 --toto-url http://127.0.0.1:18791 --output /tmp/mars-memory-smoke.json
23
+ EOF
24
+ }
25
+
26
+ while [[ $# -gt 0 ]]; do
27
+ case "$1" in
28
+ --spawn-local)
29
+ SPAWN_LOCAL="true"
30
+ shift
31
+ ;;
32
+ --coco-url)
33
+ COCO_URL="$2"
34
+ shift 2
35
+ ;;
36
+ --toto-url)
37
+ TOTO_URL="$2"
38
+ shift 2
39
+ ;;
40
+ --output)
41
+ OUTPUT_PATH="$2"
42
+ shift 2
43
+ ;;
44
+ --remote-server-sha256)
45
+ REMOTE_SERVER_SHA256="$2"
46
+ shift 2
47
+ ;;
48
+ --remote-server-sha256-cmd)
49
+ REMOTE_SERVER_SHA256_CMD="$2"
50
+ shift 2
51
+ ;;
52
+ -h|--help)
53
+ usage
54
+ exit 0
55
+ ;;
56
+ *)
57
+ echo "unknown arg: $1" >&2
58
+ usage >&2
59
+ exit 1
60
+ ;;
61
+ esac
62
+ done
63
+
64
+ if [[ -n "${REMOTE_SERVER_SHA256_CMD}" ]]; then
65
+ REMOTE_SERVER_SHA256="$(bash -lc "${REMOTE_SERVER_SHA256_CMD}" | tr -d '\r\n')"
66
+ fi
67
+
68
+ cleanup() {
69
+ if [[ -n "${COCO_PID:-}" ]]; then
70
+ kill "${COCO_PID}" >/dev/null 2>&1 || true
71
+ fi
72
+ if [[ -n "${TOTO_PID:-}" ]]; then
73
+ kill "${TOTO_PID}" >/dev/null 2>&1 || true
74
+ fi
75
+ }
76
+ trap cleanup EXIT
77
+
78
+ wait_for_health() {
79
+ local base_url="$1"
80
+ local process_id="${2:-}"
81
+ local process_log="${3:-}"
82
+ for _ in $(seq 1 30); do
83
+ if curl -sSf "${base_url}/health" >/dev/null; then
84
+ return 0
85
+ fi
86
+ if [[ -n "${process_id}" ]] && ! kill -0 "${process_id}" >/dev/null 2>&1; then
87
+ echo "process exited before healthy: ${base_url}" >&2
88
+ if [[ -n "${process_log}" && -f "${process_log}" ]]; then
89
+ echo "---- ${process_log} (tail) ----" >&2
90
+ tail -n 20 "${process_log}" >&2 || true
91
+ echo "---- end ----" >&2
92
+ fi
93
+ return 1
94
+ fi
95
+ sleep 1
96
+ done
97
+ if [[ -n "${process_log}" && -f "${process_log}" ]]; then
98
+ echo "health check timeout: ${base_url}" >&2
99
+ echo "---- ${process_log} (tail) ----" >&2
100
+ tail -n 20 "${process_log}" >&2 || true
101
+ echo "---- end ----" >&2
102
+ fi
103
+ return 1
104
+ }
105
+
106
+ mcp_jsonrpc() {
107
+ local base_url="$1"
108
+ local payload="$2"
109
+ curl -sS -H 'content-type: application/json' -d "${payload}" "${base_url}/mcp"
110
+ }
111
+
112
+ if [[ "${SPAWN_LOCAL}" == "true" ]]; then
113
+ COCO_LOG="/tmp/mars-memory-coco-smoke.log"
114
+ TOTO_LOG="/tmp/mars-memory-toto-smoke.log"
115
+ MCP_PROFILE=coco PORT=18790 SUPABASE_BASE_URL="${SUPABASE_BASE_URL_FOR_LOCAL}" MCP_REQUIRE_BEARER=false node "${REPO_ROOT}/soul-memory/server.mjs" >"${COCO_LOG}" 2>&1 &
116
+ COCO_PID="$!"
117
+ MCP_PROFILE=toto PORT=18791 SUPABASE_BASE_URL="${SUPABASE_BASE_URL_FOR_LOCAL}" MCP_REQUIRE_BEARER=false node "${REPO_ROOT}/soul-memory/server.mjs" >"${TOTO_LOG}" 2>&1 &
118
+ TOTO_PID="$!"
119
+ sleep 2
120
+ fi
121
+
122
+ if [[ "${SPAWN_LOCAL}" == "true" ]]; then
123
+ wait_for_health "${COCO_URL}" "${COCO_PID}" "${COCO_LOG}"
124
+ wait_for_health "${TOTO_URL}" "${TOTO_PID}" "${TOTO_LOG}"
125
+ else
126
+ wait_for_health "${COCO_URL}"
127
+ wait_for_health "${TOTO_URL}"
128
+ fi
129
+
130
+ COCO_TOOLS_JSON="$(mcp_jsonrpc "${COCO_URL}" '{"jsonrpc":"2.0","id":"coco-tools-list","method":"tools/list","params":{}}')"
131
+ TOTO_TOOLS_JSON="$(mcp_jsonrpc "${TOTO_URL}" '{"jsonrpc":"2.0","id":"toto-tools-list","method":"tools/list","params":{}}')"
132
+
133
+ COCO_TOOLS_CHECK="$(TOOLS_PAYLOAD="${COCO_TOOLS_JSON}" node -e '
134
+ const expected = ["insert_memory", "list_memories", "search_memories", "recall", "health_check", "session_boot", "session_close", "dream_ingest", "memory_ingest"];
135
+ const payload = JSON.parse(process.env.TOOLS_PAYLOAD || "{}");
136
+ if (payload.error) throw new Error("tools/list error: " + JSON.stringify(payload.error));
137
+ const tools = payload.result?.tools;
138
+ if (!Array.isArray(tools)) throw new Error("tools/list missing result.tools");
139
+ const names = tools.map((item) => item?.name).filter(Boolean);
140
+ const missing = expected.filter((name) => !names.includes(name));
141
+ if (missing.length > 0) throw new Error("missing tools: " + missing.join(","));
142
+ process.stdout.write(JSON.stringify({ tool_count: names.length, tools: names }));
143
+ ')"
144
+
145
+ TOTO_TOOLS_CHECK="$(TOOLS_PAYLOAD="${TOTO_TOOLS_JSON}" node -e '
146
+ const expected = ["insert_memory", "list_memories", "search_memories", "recall", "health_check", "session_boot", "session_close", "dream_ingest", "memory_ingest"];
147
+ const payload = JSON.parse(process.env.TOOLS_PAYLOAD || "{}");
148
+ if (payload.error) throw new Error("tools/list error: " + JSON.stringify(payload.error));
149
+ const tools = payload.result?.tools;
150
+ if (!Array.isArray(tools)) throw new Error("tools/list missing result.tools");
151
+ const names = tools.map((item) => item?.name).filter(Boolean);
152
+ const missing = expected.filter((name) => !names.includes(name));
153
+ if (missing.length > 0) throw new Error("missing tools: " + missing.join(","));
154
+ process.stdout.write(JSON.stringify({ tool_count: names.length, tools: names }));
155
+ ')"
156
+
157
+ COCO_TOOL_CALL_JSON="$(mcp_jsonrpc "${COCO_URL}" '{"jsonrpc":"2.0","id":"coco-list-memories","method":"tools/call","params":{"name":"list_memories","arguments":{"limit":1}}}')"
158
+ TOTO_TOOL_CALL_JSON="$(mcp_jsonrpc "${TOTO_URL}" '{"jsonrpc":"2.0","id":"toto-list-memories","method":"tools/call","params":{"name":"list_memories","arguments":{"limit":1}}}')"
159
+
160
+ COCO_CALL_CHECK="$(CALL_PAYLOAD="${COCO_TOOL_CALL_JSON}" node -e '
161
+ const payload = JSON.parse(process.env.CALL_PAYLOAD || "{}");
162
+ if (payload.error) throw new Error("tools/call error: " + JSON.stringify(payload.error));
163
+ const content = payload.result?.content;
164
+ if (!Array.isArray(content) || content.length === 0) throw new Error("tools/call missing content");
165
+ const text = content[0]?.text ?? "";
166
+ const parsed = JSON.parse(text);
167
+ if (parsed.ok !== true) throw new Error("list_memories response missing ok=true");
168
+ process.stdout.write(JSON.stringify({ count: parsed.count ?? null }));
169
+ ')"
170
+
171
+ TOTO_CALL_CHECK="$(CALL_PAYLOAD="${TOTO_TOOL_CALL_JSON}" node -e '
172
+ const payload = JSON.parse(process.env.CALL_PAYLOAD || "{}");
173
+ if (payload.error) throw new Error("tools/call error: " + JSON.stringify(payload.error));
174
+ const content = payload.result?.content;
175
+ if (!Array.isArray(content) || content.length === 0) throw new Error("tools/call missing content");
176
+ const text = content[0]?.text ?? "";
177
+ const parsed = JSON.parse(text);
178
+ if (parsed.ok !== true) throw new Error("list_memories response missing ok=true");
179
+ process.stdout.write(JSON.stringify({ count: parsed.count ?? null }));
180
+ ')"
181
+
182
+ TS="$(date -u +%Y%m%dT%H%M%SZ)"
183
+ if [[ -z "${OUTPUT_PATH}" ]]; then
184
+ OUTPUT_PATH="${SCRIPT_DIR}/smoke-report-${TS}.json"
185
+ fi
186
+
187
+ COMMIT_HASH="$(git -C "${REPO_ROOT}" rev-parse HEAD)"
188
+ LOCAL_SERVER_SHA256="$(shasum -a 256 "${REPO_ROOT}/soul-memory/server.mjs" | awk '{print $1}')"
189
+
190
+ if [[ -n "${REMOTE_SERVER_SHA256}" ]]; then
191
+ REMOTE_SERVER_SHA256_VALUE="\"${REMOTE_SERVER_SHA256}\""
192
+ else
193
+ REMOTE_SERVER_SHA256_VALUE="null"
194
+ fi
195
+
196
+ cat > "${OUTPUT_PATH}" <<EOF
197
+ {
198
+ "ok": true,
199
+ "created_at_utc": "${TS}",
200
+ "commit_hash": "${COMMIT_HASH}",
201
+ "local_server_sha256": "${LOCAL_SERVER_SHA256}",
202
+ "remote_server_sha256": ${REMOTE_SERVER_SHA256_VALUE},
203
+ "spawn_local": ${SPAWN_LOCAL},
204
+ "targets": {
205
+ "coco_url": "${COCO_URL}",
206
+ "toto_url": "${TOTO_URL}"
207
+ },
208
+ "checks": {
209
+ "coco": {
210
+ "health": true,
211
+ "tools_list": ${COCO_TOOLS_CHECK},
212
+ "list_memories_call": ${COCO_CALL_CHECK}
213
+ },
214
+ "toto": {
215
+ "health": true,
216
+ "tools_list": ${TOTO_TOOLS_CHECK},
217
+ "list_memories_call": ${TOTO_CALL_CHECK}
218
+ }
219
+ }
220
+ }
221
+ EOF
222
+
223
+ printf '%s\n' "smoke_report=${OUTPUT_PATH}"
@@ -0,0 +1,26 @@
1
+ [Unit]
2
+ Description=Mars Memory MCP Gateway (%i)
3
+ After=network-online.target docker.service
4
+ Wants=network-online.target
5
+ Requires=docker.service
6
+
7
+ [Service]
8
+ Type=simple
9
+ WorkingDirectory=/opt/mars-memory-mcp/current-%i/soul-memory
10
+ EnvironmentFile=-/opt/mars-memory-mcp/shared/.env
11
+ EnvironmentFile=-/opt/mars-memory-mcp/shared/.env.%i
12
+ EnvironmentFile=-/opt/mars-memory-mcp/current-%i/soul-memory/.env
13
+ EnvironmentFile=-/opt/mars-memory-mcp/current-%i/soul-memory/.env.%i
14
+ EnvironmentFile=-/opt/mars-memory-mcp/current/soul-memory/.env
15
+ EnvironmentFile=-/opt/mars-memory-mcp/current/soul-memory/.env.%i
16
+ Environment=MCP_PROFILE=%i
17
+ Environment=MCP_REQUIRE_BEARER=true
18
+ Environment=JINA_EMBEDDING_API_URL=https://api.jina.ai/v1/embeddings
19
+ Environment=JINA_EMBEDDING_MODEL=jina-embeddings-v3
20
+ Environment=JINA_EMBEDDING_DIMENSIONS=1024
21
+ ExecStart=/usr/bin/node /opt/mars-memory-mcp/current-%i/soul-memory/server.mjs
22
+ Restart=always
23
+ RestartSec=3
24
+
25
+ [Install]
26
+ WantedBy=multi-user.target
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@marsnme/mcp-gateway",
3
+ "version": "0.1.1",
4
+ "mcpName": "io.github.Marsmanleo/marsnme",
5
+ "private": false,
6
+ "description": "Agent-agnostic, LLM-agnostic memory backend for MCP-compatible tools",
7
+ "license": "Apache-2.0",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Marsmanleo/MarsNMe.git"
11
+ },
12
+ "author": "Mars Group",
13
+ "keywords": [
14
+ "mcp",
15
+ "memory",
16
+ "ai",
17
+ "symbiosis",
18
+ "embedding",
19
+ "supabase"
20
+ ],
21
+ "bin": {
22
+ "marsnme": "server.mjs"
23
+ },
24
+ "files": [
25
+ "server.mjs",
26
+ "scripts/",
27
+ "deploy/phase2/",
28
+ "deploy/phase3/smoke_gate.sh",
29
+ "deploy/systemd/"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "type": "module",
35
+ "scripts": {
36
+ "start": "node server.mjs"
37
+ },
38
+ "engines": {
39
+ "node": ">=20"
40
+ }
41
+ }