plain-text-memory-mcp 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.
- plain_text_memory_mcp-0.1.0/LICENSE +21 -0
- plain_text_memory_mcp-0.1.0/PKG-INFO +215 -0
- plain_text_memory_mcp-0.1.0/README.md +192 -0
- plain_text_memory_mcp-0.1.0/pyproject.toml +73 -0
- plain_text_memory_mcp-0.1.0/setup.cfg +4 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/__init__.py +1 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/agent.py +24 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/graph.py +320 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/prompts/cleanup.md +37 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/prompts/export.md +20 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/records.py +233 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/server.py +753 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/storage.py +312 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp/taxonomy.json +503 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/PKG-INFO +215 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/SOURCES.txt +28 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/dependency_links.txt +1 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/entry_points.txt +2 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/requires.txt +1 -0
- plain_text_memory_mcp-0.1.0/src/plain_text_memory_mcp.egg-info/top_level.txt +1 -0
- plain_text_memory_mcp-0.1.0/tests/test_agent.py +32 -0
- plain_text_memory_mcp-0.1.0/tests/test_export.py +157 -0
- plain_text_memory_mcp-0.1.0/tests/test_graph.py +172 -0
- plain_text_memory_mcp-0.1.0/tests/test_header.py +97 -0
- plain_text_memory_mcp-0.1.0/tests/test_records.py +110 -0
- plain_text_memory_mcp-0.1.0/tests/test_repo_guard.py +165 -0
- plain_text_memory_mcp-0.1.0/tests/test_server.py +566 -0
- plain_text_memory_mcp-0.1.0/tests/test_stdio.py +93 -0
- plain_text_memory_mcp-0.1.0/tests/test_storage.py +218 -0
- plain_text_memory_mcp-0.1.0/tests/test_taxonomy.py +230 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Plain Text Office LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plain-text-memory-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Knowledge-graph memory MCP server that tags entries with date and agent
|
|
5
|
+
Author: Plain Text Office LLC
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/PlainTxtOffice/plain-text-memory-mcp
|
|
8
|
+
Project-URL: Issues, https://github.com/PlainTxtOffice/plain-text-memory-mcp/issues
|
|
9
|
+
Keywords: mcp,model-context-protocol,memory,knowledge-graph,claude-code,codex
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: mcp<3,>=2.2
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# plain-text-memory-mcp
|
|
25
|
+
|
|
26
|
+
Knowledge-graph memory MCP server that tags every entry with the date it was
|
|
27
|
+
added and the agent that added it. Memory lives in a plain JSONL file inside
|
|
28
|
+
each repo, so every agent working in that repo shares it.
|
|
29
|
+
|
|
30
|
+
It is a drop-in replacement for `@modelcontextprotocol/server-memory`: the
|
|
31
|
+
same nine tools and input keys, and it reads files written by the original
|
|
32
|
+
server. It adds `initialize_memory` and `export_taxonomy`, the `cleanup` and
|
|
33
|
+
`export` prompts, and the `memory://taxonomy` resource.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
The server runs with [uv](https://docs.astral.sh/uv/); `uvx` downloads and
|
|
38
|
+
starts it on demand, so there is nothing else to install.
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
uvx plain-text-memory-mcp
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Started by hand, it waits for an MCP client on stdin; press Ctrl+C to stop.
|
|
45
|
+
|
|
46
|
+
## Configure
|
|
47
|
+
|
|
48
|
+
Add the server to each agent's MCP config. The server finds the repo from the
|
|
49
|
+
folder the agent starts it in, so register it per project, or set
|
|
50
|
+
`MEMORY_FILE_PATH` if a client starts servers somewhere else.
|
|
51
|
+
|
|
52
|
+
Claude Code, `.mcp.json` in the repo:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"plain-text-memory": {
|
|
58
|
+
"type": "stdio",
|
|
59
|
+
"command": "uvx",
|
|
60
|
+
"args": ["plain-text-memory-mcp"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Codex, `.codex/config.toml`:
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[mcp_servers.plain-text-memory]
|
|
70
|
+
command = "uvx"
|
|
71
|
+
args = ["plain-text-memory-mcp"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Cursor, `.cursor/mcp.json` in the repo:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"plain-text-memory": {
|
|
80
|
+
"command": "uvx",
|
|
81
|
+
"args": ["plain-text-memory-mcp"]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
VS Code, `.vscode/mcp.json` in the repo:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"servers": {
|
|
92
|
+
"plain-text-memory": {
|
|
93
|
+
"type": "stdio",
|
|
94
|
+
"command": "uvx",
|
|
95
|
+
"args": ["plain-text-memory-mcp"]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Where memory is stored
|
|
102
|
+
|
|
103
|
+
1. `MEMORY_FILE_PATH`, if set. A relative path resolves against the folder
|
|
104
|
+
the agent starts the server in.
|
|
105
|
+
1. `<git root>/.agents/memory.local.jsonl`.
|
|
106
|
+
1. `<start folder>/.agents/memory.local.jsonl` outside a git repo.
|
|
107
|
+
|
|
108
|
+
Writes hold a lock on `memory.local.jsonl.lock` beside the memory file, so
|
|
109
|
+
Claude Code and Codex can write to the same repo's memory at the same time
|
|
110
|
+
without losing each other's changes. The file stays after the server exits;
|
|
111
|
+
leave it in place.
|
|
112
|
+
|
|
113
|
+
## Tags
|
|
114
|
+
|
|
115
|
+
Every entity, relation, and observation carries `added_at` (local time with
|
|
116
|
+
UTC offset) and `agent` (`claude-code`, `codex`, or the client's own name).
|
|
117
|
+
Set `MEMORY_AGENT` to override the agent name. Entries written by the original
|
|
118
|
+
server show `null` for both.
|
|
119
|
+
|
|
120
|
+
## Repo guard
|
|
121
|
+
|
|
122
|
+
The first write adds a header line recording which repo the memory file
|
|
123
|
+
belongs to. If the file is later found in a different repo, for example after
|
|
124
|
+
copying `.agents/` from a template, every tool returns an error instead of
|
|
125
|
+
serving the other repo's memories. Resolve it with the `initialize_memory`
|
|
126
|
+
tool:
|
|
127
|
+
|
|
128
|
+
- `mode: "fresh"` renames the old file to `memory.local.jsonl.bak-<time>` and
|
|
129
|
+
starts an empty graph.
|
|
130
|
+
- `mode: "adopt"` keeps the memories and points the header at this repo, for
|
|
131
|
+
a repo that was moved or renamed.
|
|
132
|
+
|
|
133
|
+
Files without a header, including ones written by the original server, are
|
|
134
|
+
claimed by the repo that writes to them first.
|
|
135
|
+
|
|
136
|
+
## Prompts
|
|
137
|
+
|
|
138
|
+
The server publishes two MCP prompts, which clients offer as commands; Claude
|
|
139
|
+
Code shows them as `/mcp__plain-text-memory__cleanup` and
|
|
140
|
+
`/mcp__plain-text-memory__export`.
|
|
141
|
+
|
|
142
|
+
| Prompt | Use |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| `cleanup` | Propose deletions and merges; nothing is deleted until approved |
|
|
145
|
+
| `export` | Write the repo's taxonomy and usage to `.agents/` and report it |
|
|
146
|
+
|
|
147
|
+
## Guidance for agents
|
|
148
|
+
|
|
149
|
+
On connect, the server sends every MCP client instructions for using memory
|
|
150
|
+
well: search before planning, verify what memory says against the repo, save
|
|
151
|
+
only lasting facts, and resolve the repo guard. Tool and parameter
|
|
152
|
+
descriptions say what each tool does and returns, and the prompts above
|
|
153
|
+
carry the cleanup and export workflows. No agent-specific setup is needed.
|
|
154
|
+
|
|
155
|
+
## Taxonomy
|
|
156
|
+
|
|
157
|
+
[taxonomy.json](src/plain_text_memory_mcp/taxonomy.json) lists every record
|
|
158
|
+
type with its purpose and fields, every tool with its parameters and results,
|
|
159
|
+
every MCP resource and prompt, and the allowed values for enum fields such
|
|
160
|
+
as `agent` and `initialize_memory.mode`. It is generated from the code; do
|
|
161
|
+
not edit it by hand. Record type purposes live in `RECORD_PURPOSES`
|
|
162
|
+
in `records.py`. The file ships inside the package, where the server's
|
|
163
|
+
`export_taxonomy` tool reads it. MCP clients can also read it as the
|
|
164
|
+
resource `memory://taxonomy`.
|
|
165
|
+
|
|
166
|
+
`taxonomy_version` follows semantic versioning and bumps itself: a removed
|
|
167
|
+
item, section, or changed type is major, an added item is minor, and a
|
|
168
|
+
description, purpose, title, or package version change is patch. Each bump
|
|
169
|
+
adds a `changelog` entry listing what changed.
|
|
170
|
+
|
|
171
|
+
Regenerate it with:
|
|
172
|
+
|
|
173
|
+
```powershell
|
|
174
|
+
.venv/Scripts/python.exe scripts/build_taxonomy.py
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The pre-commit hook runs this and stops the commit when the file changes, so
|
|
178
|
+
the new version is reviewed and staged. A test also fails when the committed
|
|
179
|
+
file is stale. Enable the hook once per clone:
|
|
180
|
+
|
|
181
|
+
```powershell
|
|
182
|
+
git config core.hooksPath .githooks
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Exporting to a repo
|
|
186
|
+
|
|
187
|
+
Ask an agent to call the `export_taxonomy` tool. It writes
|
|
188
|
+
`.agents/memory.local.taxonomy.jsonc` beside the repo's memory file, holding
|
|
189
|
+
the versioned schema above plus this repo's usage: entry counts, the entity
|
|
190
|
+
and relation types in use, and entries per agent. `//` comments explain each
|
|
191
|
+
section and each record type's purpose. Use it to keep type names consistent
|
|
192
|
+
within a repo. The export is local, like the memory file; ignore both with
|
|
193
|
+
`.agents/*memory.local.*`.
|
|
194
|
+
|
|
195
|
+
## Develop
|
|
196
|
+
|
|
197
|
+
```powershell
|
|
198
|
+
py -3.13 -m venv .venv
|
|
199
|
+
.venv/Scripts/python.exe -m pip install -e . --group dev
|
|
200
|
+
.venv/Scripts/python.exe -m pytest
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
To have agents run your working copy instead of the published package,
|
|
204
|
+
install it as an editable tool and use `plain-text-memory-mcp` as the
|
|
205
|
+
config's command, with no args:
|
|
206
|
+
|
|
207
|
+
```powershell
|
|
208
|
+
uv tool install -e .
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Code changes then take effect the next time an agent starts the server.
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
MIT, copyright Plain Text Office LLC. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# plain-text-memory-mcp
|
|
2
|
+
|
|
3
|
+
Knowledge-graph memory MCP server that tags every entry with the date it was
|
|
4
|
+
added and the agent that added it. Memory lives in a plain JSONL file inside
|
|
5
|
+
each repo, so every agent working in that repo shares it.
|
|
6
|
+
|
|
7
|
+
It is a drop-in replacement for `@modelcontextprotocol/server-memory`: the
|
|
8
|
+
same nine tools and input keys, and it reads files written by the original
|
|
9
|
+
server. It adds `initialize_memory` and `export_taxonomy`, the `cleanup` and
|
|
10
|
+
`export` prompts, and the `memory://taxonomy` resource.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
The server runs with [uv](https://docs.astral.sh/uv/); `uvx` downloads and
|
|
15
|
+
starts it on demand, so there is nothing else to install.
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
uvx plain-text-memory-mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Started by hand, it waits for an MCP client on stdin; press Ctrl+C to stop.
|
|
22
|
+
|
|
23
|
+
## Configure
|
|
24
|
+
|
|
25
|
+
Add the server to each agent's MCP config. The server finds the repo from the
|
|
26
|
+
folder the agent starts it in, so register it per project, or set
|
|
27
|
+
`MEMORY_FILE_PATH` if a client starts servers somewhere else.
|
|
28
|
+
|
|
29
|
+
Claude Code, `.mcp.json` in the repo:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"plain-text-memory": {
|
|
35
|
+
"type": "stdio",
|
|
36
|
+
"command": "uvx",
|
|
37
|
+
"args": ["plain-text-memory-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Codex, `.codex/config.toml`:
|
|
44
|
+
|
|
45
|
+
```toml
|
|
46
|
+
[mcp_servers.plain-text-memory]
|
|
47
|
+
command = "uvx"
|
|
48
|
+
args = ["plain-text-memory-mcp"]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Cursor, `.cursor/mcp.json` in the repo:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"plain-text-memory": {
|
|
57
|
+
"command": "uvx",
|
|
58
|
+
"args": ["plain-text-memory-mcp"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
VS Code, `.vscode/mcp.json` in the repo:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"servers": {
|
|
69
|
+
"plain-text-memory": {
|
|
70
|
+
"type": "stdio",
|
|
71
|
+
"command": "uvx",
|
|
72
|
+
"args": ["plain-text-memory-mcp"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Where memory is stored
|
|
79
|
+
|
|
80
|
+
1. `MEMORY_FILE_PATH`, if set. A relative path resolves against the folder
|
|
81
|
+
the agent starts the server in.
|
|
82
|
+
1. `<git root>/.agents/memory.local.jsonl`.
|
|
83
|
+
1. `<start folder>/.agents/memory.local.jsonl` outside a git repo.
|
|
84
|
+
|
|
85
|
+
Writes hold a lock on `memory.local.jsonl.lock` beside the memory file, so
|
|
86
|
+
Claude Code and Codex can write to the same repo's memory at the same time
|
|
87
|
+
without losing each other's changes. The file stays after the server exits;
|
|
88
|
+
leave it in place.
|
|
89
|
+
|
|
90
|
+
## Tags
|
|
91
|
+
|
|
92
|
+
Every entity, relation, and observation carries `added_at` (local time with
|
|
93
|
+
UTC offset) and `agent` (`claude-code`, `codex`, or the client's own name).
|
|
94
|
+
Set `MEMORY_AGENT` to override the agent name. Entries written by the original
|
|
95
|
+
server show `null` for both.
|
|
96
|
+
|
|
97
|
+
## Repo guard
|
|
98
|
+
|
|
99
|
+
The first write adds a header line recording which repo the memory file
|
|
100
|
+
belongs to. If the file is later found in a different repo, for example after
|
|
101
|
+
copying `.agents/` from a template, every tool returns an error instead of
|
|
102
|
+
serving the other repo's memories. Resolve it with the `initialize_memory`
|
|
103
|
+
tool:
|
|
104
|
+
|
|
105
|
+
- `mode: "fresh"` renames the old file to `memory.local.jsonl.bak-<time>` and
|
|
106
|
+
starts an empty graph.
|
|
107
|
+
- `mode: "adopt"` keeps the memories and points the header at this repo, for
|
|
108
|
+
a repo that was moved or renamed.
|
|
109
|
+
|
|
110
|
+
Files without a header, including ones written by the original server, are
|
|
111
|
+
claimed by the repo that writes to them first.
|
|
112
|
+
|
|
113
|
+
## Prompts
|
|
114
|
+
|
|
115
|
+
The server publishes two MCP prompts, which clients offer as commands; Claude
|
|
116
|
+
Code shows them as `/mcp__plain-text-memory__cleanup` and
|
|
117
|
+
`/mcp__plain-text-memory__export`.
|
|
118
|
+
|
|
119
|
+
| Prompt | Use |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `cleanup` | Propose deletions and merges; nothing is deleted until approved |
|
|
122
|
+
| `export` | Write the repo's taxonomy and usage to `.agents/` and report it |
|
|
123
|
+
|
|
124
|
+
## Guidance for agents
|
|
125
|
+
|
|
126
|
+
On connect, the server sends every MCP client instructions for using memory
|
|
127
|
+
well: search before planning, verify what memory says against the repo, save
|
|
128
|
+
only lasting facts, and resolve the repo guard. Tool and parameter
|
|
129
|
+
descriptions say what each tool does and returns, and the prompts above
|
|
130
|
+
carry the cleanup and export workflows. No agent-specific setup is needed.
|
|
131
|
+
|
|
132
|
+
## Taxonomy
|
|
133
|
+
|
|
134
|
+
[taxonomy.json](src/plain_text_memory_mcp/taxonomy.json) lists every record
|
|
135
|
+
type with its purpose and fields, every tool with its parameters and results,
|
|
136
|
+
every MCP resource and prompt, and the allowed values for enum fields such
|
|
137
|
+
as `agent` and `initialize_memory.mode`. It is generated from the code; do
|
|
138
|
+
not edit it by hand. Record type purposes live in `RECORD_PURPOSES`
|
|
139
|
+
in `records.py`. The file ships inside the package, where the server's
|
|
140
|
+
`export_taxonomy` tool reads it. MCP clients can also read it as the
|
|
141
|
+
resource `memory://taxonomy`.
|
|
142
|
+
|
|
143
|
+
`taxonomy_version` follows semantic versioning and bumps itself: a removed
|
|
144
|
+
item, section, or changed type is major, an added item is minor, and a
|
|
145
|
+
description, purpose, title, or package version change is patch. Each bump
|
|
146
|
+
adds a `changelog` entry listing what changed.
|
|
147
|
+
|
|
148
|
+
Regenerate it with:
|
|
149
|
+
|
|
150
|
+
```powershell
|
|
151
|
+
.venv/Scripts/python.exe scripts/build_taxonomy.py
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The pre-commit hook runs this and stops the commit when the file changes, so
|
|
155
|
+
the new version is reviewed and staged. A test also fails when the committed
|
|
156
|
+
file is stale. Enable the hook once per clone:
|
|
157
|
+
|
|
158
|
+
```powershell
|
|
159
|
+
git config core.hooksPath .githooks
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Exporting to a repo
|
|
163
|
+
|
|
164
|
+
Ask an agent to call the `export_taxonomy` tool. It writes
|
|
165
|
+
`.agents/memory.local.taxonomy.jsonc` beside the repo's memory file, holding
|
|
166
|
+
the versioned schema above plus this repo's usage: entry counts, the entity
|
|
167
|
+
and relation types in use, and entries per agent. `//` comments explain each
|
|
168
|
+
section and each record type's purpose. Use it to keep type names consistent
|
|
169
|
+
within a repo. The export is local, like the memory file; ignore both with
|
|
170
|
+
`.agents/*memory.local.*`.
|
|
171
|
+
|
|
172
|
+
## Develop
|
|
173
|
+
|
|
174
|
+
```powershell
|
|
175
|
+
py -3.13 -m venv .venv
|
|
176
|
+
.venv/Scripts/python.exe -m pip install -e . --group dev
|
|
177
|
+
.venv/Scripts/python.exe -m pytest
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
To have agents run your working copy instead of the published package,
|
|
181
|
+
install it as an editable tool and use `plain-text-memory-mcp` as the
|
|
182
|
+
config's command, with no args:
|
|
183
|
+
|
|
184
|
+
```powershell
|
|
185
|
+
uv tool install -e .
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Code changes then take effect the next time an agent starts the server.
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT, copyright Plain Text Office LLC. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#:schema https://json.schemastore.org/pyproject.json
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools>=77"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "plain-text-memory-mcp"
|
|
9
|
+
version = "0.1.0"
|
|
10
|
+
description = "Knowledge-graph memory MCP server that tags entries with date and agent"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.12"
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["LICENSE"]
|
|
15
|
+
authors = [{ name = "Plain Text Office LLC" }]
|
|
16
|
+
keywords = [
|
|
17
|
+
"mcp",
|
|
18
|
+
"model-context-protocol",
|
|
19
|
+
"memory",
|
|
20
|
+
"knowledge-graph",
|
|
21
|
+
"claude-code",
|
|
22
|
+
"codex",
|
|
23
|
+
]
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Development Status :: 3 - Alpha",
|
|
26
|
+
"Environment :: Console",
|
|
27
|
+
"Intended Audience :: Developers",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Topic :: Software Development",
|
|
33
|
+
]
|
|
34
|
+
dependencies = ["mcp>=2.2,<3"]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/PlainTxtOffice/plain-text-memory-mcp"
|
|
38
|
+
Issues = "https://github.com/PlainTxtOffice/plain-text-memory-mcp/issues"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
plain-text-memory-mcp = "plain_text_memory_mcp.server:main"
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = ["pytest>=8"]
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
where = ["src"]
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.package-data]
|
|
50
|
+
plain_text_memory_mcp = ["taxonomy.json", "prompts/*.md"]
|
|
51
|
+
|
|
52
|
+
[tool.pytest.ini_options]
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
pythonpath = ["scripts"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
[tool.mypy]
|
|
58
|
+
exclude = ['(^|[\\/])tests([\\/]|$)']
|
|
59
|
+
ignore_missing_imports = true
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 80
|
|
62
|
+
|
|
63
|
+
[tool.rumdl]
|
|
64
|
+
line-length = 80
|
|
65
|
+
respect-gitignore = true
|
|
66
|
+
exclude = [".venv", "build", "dist"]
|
|
67
|
+
|
|
68
|
+
[tool.rumdl.MD029]
|
|
69
|
+
style = "one"
|
|
70
|
+
|
|
71
|
+
[tool.rumdl.MD013]
|
|
72
|
+
code-blocks = false
|
|
73
|
+
tables = false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Knowledge-graph memory MCP server with date and agent tags."""
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Name the agent that is calling the memory server."""
|
|
2
|
+
|
|
3
|
+
UNKNOWN_AGENT = "unknown"
|
|
4
|
+
|
|
5
|
+
KNOWN_AGENTS = (("claude", "claude-code"), ("codex", "codex"))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def calc_agent_name(client_name: str | None, override: str | None) -> str:
|
|
9
|
+
"""Return the agent name recorded in memory tags.
|
|
10
|
+
|
|
11
|
+
- A non-blank override, from `MEMORY_AGENT`, always wins.
|
|
12
|
+
- Client names containing "claude" or "codex" map to `claude-code` and
|
|
13
|
+
`codex`; any other name is recorded as sent.
|
|
14
|
+
- A missing or blank client name records `unknown`.
|
|
15
|
+
"""
|
|
16
|
+
if override and override.strip():
|
|
17
|
+
return override.strip()
|
|
18
|
+
if not client_name or not client_name.strip():
|
|
19
|
+
return UNKNOWN_AGENT
|
|
20
|
+
lowered = client_name.lower()
|
|
21
|
+
for marker, agent_name in KNOWN_AGENTS:
|
|
22
|
+
if marker in lowered:
|
|
23
|
+
return agent_name
|
|
24
|
+
return client_name.strip()
|