mag-memory 0.1.0__tar.gz

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,18 @@
1
+ /target
2
+ .cargo-cache/
3
+
4
+ .env
5
+ .env.local
6
+ # Local provenance / legal notes (not published)
7
+ PROVENANCE.local.md
8
+
9
+ # Claude Code worktrees (agent isolation)
10
+ .claude/worktrees/
11
+
12
+ # Local MCP config (machine-specific paths)
13
+ .mcp.json
14
+
15
+ # Benchmark datasets (large, downloaded separately)
16
+ data/*
17
+ # But track the local benchmark definition
18
+ !data/local_benchmark.json
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: mag-memory
3
+ Version: 0.1.0
4
+ Summary: PyPI wrapper for the mag MCP memory server (Rust binary)
5
+ Project-URL: Homepage, https://github.com/George-RD/mag
6
+ Project-URL: Repository, https://github.com/George-RD/mag
7
+ Project-URL: Issues, https://github.com/George-RD/mag/issues
8
+ Author: George-RD
9
+ License-Expression: MIT
10
+ Keywords: ai,llm,mcp,memory,semantic-search,sqlite
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Rust
26
+ Classifier: Topic :: Software Development :: Libraries
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+
30
+ # mag-memory
31
+
32
+ PyPI wrapper for [mag](https://github.com/George-RD/mag), a Rust-based MCP memory server.
33
+
34
+ mag stores memories in SQLite with ONNX embeddings for semantic search, exposing 16 MCP tools via stdio protocol. No external services required.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install mag-memory
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ```bash
45
+ # Start the MCP server
46
+ mag serve
47
+
48
+ # The native binary is downloaded automatically on first run.
49
+ # All CLI arguments are passed through to the Rust binary.
50
+ ```
51
+
52
+ ## How it works
53
+
54
+ This package does not bundle the native binary. On first run, it detects your platform (Linux/macOS/Windows, x86_64/ARM64), downloads the correct prebuilt binary from [GitHub Releases](https://github.com/George-RD/mag/releases), and caches it locally. Subsequent runs use the cached binary with zero overhead (Unix `exec`).
55
+
56
+ ## Supported platforms
57
+
58
+ | OS | Architecture |
59
+ |---------|-------------|
60
+ | Linux | x86_64, aarch64 |
61
+ | macOS | x86_64, Apple Silicon (aarch64) |
62
+ | Windows | x86_64 |
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,37 @@
1
+ # mag-memory
2
+
3
+ PyPI wrapper for [mag](https://github.com/George-RD/mag), a Rust-based MCP memory server.
4
+
5
+ mag stores memories in SQLite with ONNX embeddings for semantic search, exposing 16 MCP tools via stdio protocol. No external services required.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install mag-memory
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ # Start the MCP server
17
+ mag serve
18
+
19
+ # The native binary is downloaded automatically on first run.
20
+ # All CLI arguments are passed through to the Rust binary.
21
+ ```
22
+
23
+ ## How it works
24
+
25
+ This package does not bundle the native binary. On first run, it detects your platform (Linux/macOS/Windows, x86_64/ARM64), downloads the correct prebuilt binary from [GitHub Releases](https://github.com/George-RD/mag/releases), and caches it locally. Subsequent runs use the cached binary with zero overhead (Unix `exec`).
26
+
27
+ ## Supported platforms
28
+
29
+ | OS | Architecture |
30
+ |---------|-------------|
31
+ | Linux | x86_64, aarch64 |
32
+ | macOS | x86_64, Apple Silicon (aarch64) |
33
+ | Windows | x86_64 |
34
+
35
+ ## License
36
+
37
+ MIT
@@ -0,0 +1,75 @@
1
+ """
2
+ mag-memory: PyPI wrapper for the mag MCP memory server.
3
+
4
+ On first run, the native binary is downloaded from GitHub Releases
5
+ for the current platform. Subsequent runs use the cached binary.
6
+ """
7
+
8
+ import os
9
+ import shutil
10
+ import subprocess
11
+ import sys
12
+
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ # Version of the Rust binary to download (kept in sync with __version__)
17
+ _BINARY_VERSION = "0.1.0"
18
+
19
+
20
+ def _binary_dir():
21
+ # type: () -> str
22
+ """Return the directory where the mag binary is stored."""
23
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
24
+
25
+
26
+ def _binary_name():
27
+ # type: () -> str
28
+ """Return the platform-appropriate binary filename."""
29
+ if sys.platform == "win32":
30
+ return "mag.exe"
31
+ return "mag"
32
+
33
+
34
+ def _find_binary():
35
+ # type: () -> str | None
36
+ """Locate the mag binary: package dir first, then PATH."""
37
+ # 1. Check package bin directory
38
+ packaged = os.path.join(_binary_dir(), _binary_name())
39
+ if os.path.isfile(packaged) and os.access(packaged, os.X_OK):
40
+ return packaged
41
+
42
+ # 2. Fall back to PATH
43
+ found = shutil.which("mag")
44
+ return found
45
+
46
+
47
+ def main():
48
+ # type: () -> None
49
+ """Entry point: find (or download) the mag binary and exec it."""
50
+ binary = _find_binary()
51
+
52
+ if binary is None:
53
+ # Download on first run
54
+ sys.stderr.write("mag: binary not found, downloading for this platform...\n")
55
+ try:
56
+ from mag_memory._download import download_binary
57
+
58
+ binary = download_binary(_BINARY_VERSION)
59
+ except Exception as exc:
60
+ sys.stderr.write("mag: failed to download binary: {}\n".format(exc))
61
+ sys.stderr.write(
62
+ "mag: install manually from "
63
+ "https://github.com/George-RD/mag/releases\n"
64
+ )
65
+ sys.exit(1)
66
+
67
+ # Replace this process with the binary (Unix) or subprocess (Windows)
68
+ args = [binary] + sys.argv[1:]
69
+
70
+ if sys.platform != "win32":
71
+ os.execvp(binary, args)
72
+ else:
73
+ # os.execvp is unreliable on Windows; use subprocess instead
74
+ result = subprocess.run(args)
75
+ sys.exit(result.returncode)
@@ -0,0 +1,186 @@
1
+ """
2
+ Download the correct mag binary for the current platform from GitHub Releases.
3
+ """
4
+
5
+ import io
6
+ import os
7
+ import platform
8
+ import stat
9
+ import sys
10
+ import tarfile
11
+ import zipfile
12
+
13
+ try:
14
+ from urllib.request import urlopen, Request
15
+ from urllib.error import URLError, HTTPError
16
+ except ImportError:
17
+ # Python 2 fallback (shouldn't happen with >=3.8, but defensive)
18
+ from urllib2 import urlopen, Request, URLError, HTTPError # type: ignore[no-redef]
19
+
20
+
21
+ _GITHUB_RELEASE_URL = (
22
+ "https://github.com/George-RD/mag/releases/download/"
23
+ "v{version}/mag-{target}.{ext}"
24
+ )
25
+
26
+ # Mapping: (sys.platform, platform.machine()) -> Rust target triple
27
+ _TARGET_MAP = {
28
+ ("linux", "x86_64"): "x86_64-unknown-linux-gnu",
29
+ ("linux", "aarch64"): "aarch64-unknown-linux-gnu",
30
+ ("linux", "arm64"): "aarch64-unknown-linux-gnu",
31
+ ("darwin", "x86_64"): "x86_64-apple-darwin",
32
+ ("darwin", "arm64"): "aarch64-apple-darwin",
33
+ ("darwin", "aarch64"): "aarch64-apple-darwin",
34
+ ("win32", "AMD64"): "x86_64-pc-windows-msvc",
35
+ ("win32", "x86_64"): "x86_64-pc-windows-msvc",
36
+ }
37
+
38
+
39
+ def _detect_target():
40
+ # type: () -> tuple[str, str]
41
+ """Detect the Rust target triple and archive extension for this platform.
42
+
43
+ Returns:
44
+ (target_triple, archive_extension)
45
+ """
46
+ plat = sys.platform
47
+ # Normalize platform string
48
+ if plat.startswith("linux"):
49
+ plat = "linux"
50
+
51
+ machine = platform.machine()
52
+
53
+ key = (plat, machine)
54
+ target = _TARGET_MAP.get(key)
55
+ if target is None:
56
+ raise RuntimeError(
57
+ "Unsupported platform: {} / {} (machine={})".format(
58
+ sys.platform, platform.system(), machine
59
+ )
60
+ )
61
+
62
+ ext = "zip" if plat == "win32" else "tar.gz"
63
+ return target, ext
64
+
65
+
66
+ def _download_url(url):
67
+ # type: (str) -> bytes
68
+ """Download a URL and return its content as bytes."""
69
+ req = Request(url, headers={"User-Agent": "mag-memory-pypi-installer"})
70
+ try:
71
+ resp = urlopen(req, timeout=120)
72
+ return resp.read()
73
+ except HTTPError as exc:
74
+ raise RuntimeError(
75
+ "HTTP {} downloading {}: {}".format(exc.code, url, exc.reason)
76
+ )
77
+ except URLError as exc:
78
+ raise RuntimeError("Failed to download {}: {}".format(url, exc.reason))
79
+
80
+
81
+ def _extract_tar_gz(data, dest_dir):
82
+ # type: (bytes, str) -> str
83
+ """Extract a .tar.gz archive, find the mag binary, place it in dest_dir."""
84
+ binary_name = "mag"
85
+ with tarfile.open(fileobj=io.BytesIO(data), mode="r:gz") as tar:
86
+ # Find the mag binary in the archive
87
+ members = tar.getnames()
88
+ binary_member = None
89
+ for name in members:
90
+ basename = os.path.basename(name)
91
+ if basename == binary_name:
92
+ binary_member = name
93
+ break
94
+
95
+ if binary_member is None:
96
+ raise RuntimeError(
97
+ "Could not find '{}' in archive. Contents: {}".format(
98
+ binary_name, members
99
+ )
100
+ )
101
+
102
+ # Extract just the binary
103
+ member = tar.getmember(binary_member)
104
+ fileobj = tar.extractfile(member)
105
+ if fileobj is None:
106
+ raise RuntimeError("Could not extract '{}'".format(binary_member))
107
+
108
+ dest_path = os.path.join(dest_dir, binary_name)
109
+ with open(dest_path, "wb") as f:
110
+ f.write(fileobj.read())
111
+
112
+ return dest_path
113
+
114
+
115
+ def _extract_zip(data, dest_dir):
116
+ # type: (bytes, str) -> str
117
+ """Extract a .zip archive, find the mag binary, place it in dest_dir."""
118
+ binary_name = "mag.exe"
119
+ with zipfile.ZipFile(io.BytesIO(data)) as zf:
120
+ names = zf.namelist()
121
+ binary_member = None
122
+ for name in names:
123
+ basename = os.path.basename(name)
124
+ if basename == binary_name:
125
+ binary_member = name
126
+ break
127
+
128
+ if binary_member is None:
129
+ raise RuntimeError(
130
+ "Could not find '{}' in archive. Contents: {}".format(
131
+ binary_name, names
132
+ )
133
+ )
134
+
135
+ dest_path = os.path.join(dest_dir, binary_name)
136
+ with open(dest_path, "wb") as f:
137
+ f.write(zf.read(binary_member))
138
+
139
+ return dest_path
140
+
141
+
142
+ def download_binary(version):
143
+ # type: (str) -> str
144
+ """Download the mag binary for this platform and return its path.
145
+
146
+ Args:
147
+ version: The version string (e.g. "0.1.0")
148
+
149
+ Returns:
150
+ Absolute path to the downloaded binary.
151
+ """
152
+ target, ext = _detect_target()
153
+ url = _GITHUB_RELEASE_URL.format(version=version, target=target, ext=ext)
154
+
155
+ sys.stderr.write("mag: downloading {} ...\n".format(url))
156
+ data = _download_url(url)
157
+ sys.stderr.write(
158
+ "mag: downloaded {:.1f} MB\n".format(len(data) / (1024.0 * 1024.0))
159
+ )
160
+
161
+ # Ensure destination directory exists
162
+ from mag_memory import _binary_dir
163
+
164
+ dest_dir = _binary_dir()
165
+ os.makedirs(dest_dir, exist_ok=True)
166
+
167
+ # Extract
168
+ if ext == "zip":
169
+ binary_path = _extract_zip(data, dest_dir)
170
+ else:
171
+ binary_path = _extract_tar_gz(data, dest_dir)
172
+
173
+ # Make executable (Unix)
174
+ if sys.platform != "win32":
175
+ st = os.stat(binary_path)
176
+ os.chmod(binary_path, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
177
+
178
+ sys.stderr.write("mag: installed to {}\n".format(binary_path))
179
+ return binary_path
180
+
181
+
182
+ if __name__ == "__main__":
183
+ # Allow running directly: python -m mag_memory._download [version]
184
+ ver = sys.argv[1] if len(sys.argv) > 1 else "0.1.0"
185
+ path = download_binary(ver)
186
+ print("Downloaded: {}".format(path))
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "mag-memory"
7
+ version = "0.1.0"
8
+ description = "PyPI wrapper for the mag MCP memory server (Rust binary)"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [{ name = "George-RD" }]
13
+ keywords = ["mcp", "memory", "ai", "llm", "semantic-search", "sqlite"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: Microsoft :: Windows",
21
+ "Operating System :: POSIX :: Linux",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Rust",
30
+ "Topic :: Software Development :: Libraries",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/George-RD/mag"
35
+ Repository = "https://github.com/George-RD/mag"
36
+ Issues = "https://github.com/George-RD/mag/issues"
37
+
38
+ [project.scripts]
39
+ mag = "mag_memory:main"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["mag_memory"]