Skip to main content
Glama
README.md
# Memory Tracker MCP

An MCP server that gives an AI assistant persistent memory, backed by an OpenAI vector store.

Memories are plain text. `save_memory` uploads each one as a file into a vector store named `MEMORIES`; `search_memory` runs a semantic search over that store and returns the matching chunks. The store is created on first use and reused after that, so memories persist across sessions and across clients.

## Requirements

- Python 3.14+
- [uv](https://docs.astral.sh/uv/)
- An OpenAI API key

## Setup

```bash
uv sync
```

Create a `.env` file in the project root:

```
OPENAI_API_KEY=sk-...
```

`.env` is gitignored. The server calls `load_dotenv()` at import, which resolves relative to the working directory — this is why the client configs below pass `--directory`.

## Tools

| Tool | Argument | Returns |
| --- | --- | --- |
| `save_memory` | `memory: str` — the text to remember | `{"status": "saved", "vector store id": ...}` |
| `search_memory` | `query: str` — what to look for | `{"results": [chunk, ...]}` |

## Running it

Development, with the MCP Inspector:

```bash
uv run mcp dev server.py
```

Directly over stdio (what MCP clients do):

```bash
uv run python server.py
```

## Client configuration

### Claude Code

[`.mcp.json`](.mcp.json) in this repo is picked up automatically when you start Claude Code in this directory. No further setup.

### Claude Desktop

Add the block below to `claude_desktop_config.json`, then fully quit Claude Desktop (right-click the system tray icon → Quit — closing the window is not enough) and relaunch.

```json
{
  "mcpServers": {
    "memory-tracker": {
      "command": "C:\\Users\\shivu\\.local\\bin\\uv.exe",
      "args": [
        "run",
        "--directory",
        "f:\\Agentic AI\\Memory_tracker_mcp",
        "python",
        "server.py"
      ]
    }
  }
}
```

Two things differ from the Claude Code config:

- **Absolute path to `uv.exe`.** Claude Desktop launches servers with a minimal `PATH` that usually excludes `~\.local\bin`, so a bare `uv` fails to spawn. Claude Code inherits your shell's `PATH`, so the short form works there.
- **Where the config file lives.** For the standard installer it is `%APPDATA%\Claude\claude_desktop_config.json`. For the **Microsoft Store (MSIX) build**, AppData is redirected and the real path is:

  ```
  %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json
  ```

  Editing the non-packaged path on a Store install has no effect. Reach it from the app instead via Settings → Developer → Edit Config.

## Troubleshooting

**`Failed to build ... Expected a Python module at src\memory_tracker_mcp\__init__.py`**

`pyproject.toml` sets `package = false` under `[tool.uv]`, which tells uv to treat this as a flat script project rather than build it as a package. Without it, every `uv run` tries to build an installable package and fails, because the server is a single `server.py` at the repo root and there is no `src/` layout. Note that `[project.scripts]` still declares a `memory_tracker_mcp:main` entry point that does not exist — harmless while `package = false` is set, but it will break the build again if that line is ever removed.

**Tools appear in the client but every call errors**

Almost always a missing `OPENAI_API_KEY`. The `--directory` argument is what lets `load_dotenv()` find `.env`; drop it and the server still starts, but the OpenAI client has no key. As a fallback, pass the key through the config instead:

```json
"env": { "OPENAI_API_KEY": "sk-..." }
```

That hardcodes the key into the config file, so prefer `.env` when it works.

**Server shows as failed to start**

Check the client's MCP log — for Claude Desktop, `logs\mcp-server-memory-tracker.log` in the same config directory. A spawn/ENOENT error means the `uv.exe` path is wrong; confirm it with `where uv`.

## Notes

- Every `save_memory` call writes a temp file with `delete=False` and opens it without closing the handle, so temp files accumulate in `%TEMP%`. Passing the text directly (`file=("memory.txt", memory.encode())`) would avoid the temp file entirely.
- `get_or_create_vector_store` scans stores by name on every call, so each tool invocation costs an extra list request.

TDQS

C2.3/5.0

Scored across 2 tools

Disambiguation5/5

The two tools, save_memory and search_memory, have clearly distinct purposes: one writes a memory and the other reads/retrieves them. No overlap or ambiguity exists.

Naming Consistency5/5

Both tool names follow a consistent verb_noun pattern (save_memory, search_memory), using the same resource noun. The naming is predictable and uniform.

Tool Count3/5

With only two tools, the set is at the low end of what is reasonable. For a memory tracker, save and search are core operations, so the count is borderline but acceptable.

Completeness3/5

The server covers the primary create and read/search operations, but it lacks update, delete, or list-all functionality. These are significant gaps for a complete memory management lifecycle.