Structured, disk-based project memory for enterprise LLMs. Seamless M365 integration. Zero database.
Enterprise teams lose institutional knowledge. Project context lives scattered across:
- Email threads (Outlook) — hard to search, tied to individuals
- SharePoint documents — version-controlled but siloed
- Teams messages — ephemeral, context-dependent
- Meeting notes — often forgotten or stuck in personal notebooks
- Decisions and architecture — rarely documented, often re-discussed
When an LLM needs to understand a project, it either:
- Reads everything (slow, expensive, noisy)
- Reads nothing (useless, blind)
- Re-syncs M365 sources repeatedly (wastes quotas and tokens)
Project Memory MCP solves this: Treat your project memory as a single source of truth — one central place where all knowledge lives, processed once, reused forever.
Enterprise teams need:
- ✅ Local-first knowledge — Process M365 sources once, store summaries locally, avoid re-fetching
- ✅ Structured memory — Predictable, navigable folder layout that LLMs understand
- ✅ Local RAG + semantic search — Use
--rag-backend embeddingsfor semantic retrieval with automatic indexing on MCP writes - ✅ M365 sync — Automatic or manual ingestion from Outlook, Teams, SharePoint
- ✅ Token efficiency — Manifest-based
read_whenhints guide LLMs to load only what's needed - ✅ Human readable and editable — Plain Markdown and YAML files, no proprietary formats, edit in any text editor
- ✅ Full control — Plain files on disk, no vendor lock-in, git-versionable
- ✅ Zero database — No migrations, no ORM, no complex schemas
Project Memory MCP is a Model Context Protocol server that enables LLMs (especially Claude) to maintain and query structured project memory integrated with M365.
Every project organizes as a navigable folder hierarchy on plain disk:
projects/databuddy/
├── _status.md # Current blockers, wins, next steps (read first)
├── decisions.md # Append-only decision log with rationale
├── knowledge/ # Processed knowledge from M365 sources
│ ├── deployment.md # [sp:sp-contracts/deployment-reqs.pdf]
│ └── architecture.md # Generated from [tm:teams-arch/msg-123]
├── correspondence/ # Summaries of emails, calls, messages
├── updates/ # Chronological change log (append-only)
└── people.md # Team members (auto-updated from global links)
Key innovation: Every knowledge entry stores where it came from:
source: "[sp:sp-contracts/deployment-reqs.pdf]" # Points back to SharePoint
processed: 2026-03-29
method: summaryLLMs read the local summary instead of re-fetching. Token costs drop by 80%+.
Three integration patterns:
- Automated sync pipeline — Scheduled job reads M365, summarizes via LLM, stores locally
- Manual fetch — LLM calls M365 MCP when needed, processes, stores result
- Hybrid — Mix of both (most common)
All patterns feed knowledge into the same local store. Once processed, the LLM uses only the local summary.
The server tracks sources from three M365 services:
Automatic sync pipeline — Scheduled job on a dedicated VM:
- Reads from Outlook (emails, threads)
- Reads from Teams (channels, messages)
- Reads from SharePoint (documents, libraries)
- Summarizes via Claude API
- Stores locally with source reference
Manual fetch — LLM-initiated (on demand):
- LLM calls M365 MCP to fetch raw content
- LLM processes and summarizes
- LLM stores via memory MCP with source tracking
Result: All M365 data is indexed and never re-fetched. After first processing, the LLM uses only the local summary.
pip install -r requirements.txt
python src/server.py --rag-backend embeddingsRequirements: Python 3.13+, fastmcp>=2.0.0, pyyaml>=6.0, pydantic>=2.0
pip install -r requirements.txt
python src/server.py --rag-backend embeddings # RecommendedAdd to claude_desktop_config.json:
{
"mcpServers": {
"project-memory": {
"command": "python",
"args": ["/path/to/src/server.py", "--rag-backend", "embeddings"]
}
}
}npx @modelcontextprotocol/inspector python src/server.py --rag-backend embeddings
# Visit http://localhost:5173The server supports an HTTP transport mode for exposing it over the internet (e.g. for remote Claude clients). Bearer-token authentication is required for safe exposure.
-
Copy the environment template and set a token:
cp .env.example .env # Generate a strong random token: python -c "import secrets; print(secrets.token_hex(32))" # Paste the result as AUTH_TOKEN in .env
-
Start the server in HTTP mode:
python src/server.py --rag-backend embeddings --transport http --host 0.0.0.0 --port 8000
The server prints `[auth] Bearer token auth enabled` when the token is loaded.
1. **Recommended: use a tunnel instead of direct port forwarding.**
[cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/) provides a secure, zero-config HTTPS tunnel:
```bash
# Install cloudflared (once)
# https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
# Expose the local HTTP server
cloudflared tunnel --url http://localhost:8000
Cloudflared prints a public https://…trycloudflare.com URL. Use that URL in your MCP client config — no port forwarding or firewall rules required.
Add to claude_desktop_config.json:
{
"mcpServers": {
"project-memory": {
"type": "streamable-http",
"url": "https://<your-tunnel-url>/mcp/",
"headers": {
"Authorization": "Bearer <your-auth-token>"
}
}
}
}Note: Only use HTTP transport with a tunnel (cloudflared) or a reverse proxy that terminates TLS. Never expose the plain HTTP port directly to the internet.
Every project is a folder with predictable structure:
| Element | Purpose |
|---|---|
_status.md |
Always-current status (read first by LLM) |
decisions.md |
Append-only decision log |
knowledge/ |
Processed knowledge from M365 or manual entry |
correspondence/ |
Email, call, message summaries with dates |
updates/ |
Chronological changelog (append-only) |
people.md |
Team members (auto-generated from links) |
Every knowledge entry points back to its source:
source: "[sp:sp-contracts/msa.pdf]" # SharePoint file
# or "[tm:teams-sales/msg-123]" # Teams message
# or "[ol:outlook-sales/thread-456]" # Outlook email
processed: 2026-03-29
method: summaryLLMs use the local summary. No re-fetching. Saves 80%+ in tokens.
The server maintains three indexes:
| Index | What it tracks |
|---|---|
_index.yaml |
File descriptions + read_when hints (per folder) |
_projects-index.json |
Fast project listing |
_refs-index.json |
@person, @company, [[link]] references |
The read_when field guides LLM loading:
knowledge/deployment.md:
description: "Deployment requirements and SLA"
read_when: "When planning releases or understanding constraints"LLMs skip files they don't need → cheaper, faster.
All project files (except _index.yaml) are automatically indexed using TF-IDF (or embeddings)
for fast semantic search:
{
"_rag_index.json": {
"docs": {
"projects/databuddy/knowledge/architecture.md": {
"tf": { "snowflake": 0.045, "migration": 0.032, ... },
"mtime": 1774796858.3323283,
"indexed_at": "2026-03-29T18:49:17.855188+00:00"
}
}
}
}Every file in these directories is automatically indexed and searchable:
| Directory | Indexed | Purpose |
|---|---|---|
_global/people/ |
✅ All .md files |
Team member profiles (auto-indexed) |
_global/companies/ |
✅ All .md files |
Partner and client information |
projects/{slug}/knowledge/ |
✅ All .md files |
Processed knowledge and summaries |
projects/{slug}/correspondence/ |
✅ All .md files |
Email, call, and message digests |
projects/{slug}/updates/ |
✅ All .md files |
Chronological project updates |
projects/{slug}/decisions.md |
✅ Single file | Decision log (append-only) |
_index.yaml files |
❌ Never | Auto-managed manifests (excluded) |
Indexes are updated automatically when files change. Use the index for:
- Semantic search — Find relevant context by meaning, not keywords
- Link discovery — Understand what's related without reading everything
- Context routing — Route LLM queries to the most relevant files
- Token efficiency — Read only what matters for the current task
The server includes 5 built-in MCP resources (served automatically):
| Resource | Purpose |
|---|---|
memory://quick-reference |
Token syntax, filesystem rules, parameters |
memory://guide |
Complete server guide and tool inventory |
memory://m365 |
M365 sync pipeline and source registration |
memory://skill |
Pre-flight checklist for new users |
memory://new-project |
12-step project setup walkthrough |
All resources live in skill/ and auto-update when you edit them.
project-memory-mcp/
├── src/
│ ├── server.py # MCP server + tools + resources
│ ├── filesystem.py # MemoryFS class + all file operations
│ ├── guide.py # Resource generators
│ ├── models.py # Pydantic data models for all schemas
│ └── templates.py # Template strings for scaffolded files
├── skill/ # Claude skill documentation (upload as .zip)
│ ├── SKILL.md # Skill frontmatter + pre-flight checklist
│ └── references/
│ ├── quick-reference.md # Token syntax, filesystem rules, parameters
│ ├── guide.md # Server guide, tool inventory, folder routing
│ ├── m365-guide.md # M365 sync pipeline and integration
│ └── creating-new-project.md # 12-step project setup guide
├── scripts/
│ └── migrate_newlines.py # Fix escaped newlines in markdown files (one-time use)
├── tests/
│ ├── conftest.py # Test configuration
│ └── tests.py # Full test suite (130+ tests)
├── docs/
│ ├── tool-reference.md # Complete tool reference (legacy, see skill/ instead)
│ ├── memory-root-schema.md # File/folder schemas with examples
│ └── filesystem-rules.md # Enforcement rules and triggers
├── memory-root/ # Example projects and global entities
├── README.md
├── LICENSE # MIT License
└── requirements.txt
Primary documentation is now in the skill/ folder as Markdown resources that are automatically served by the server:
| Resource | Read from | Topic |
|---|---|---|
memory://quick-reference |
skill/references/quick-reference.md |
Token syntax, filesystem rules, tool parameters |
memory://guide |
skill/references/guide.md |
Complete server guide, folder routing, tool inventory |
memory://m365 |
skill/references/m365-guide.md |
M365 sync pipeline, source registration, reference syntax |
memory://skill |
skill/SKILL.md |
Pre-flight checklist for new users |
memory://new-project |
skill/references/creating-new-project.md |
12-step project initialization walkthrough |
Reference documentation (kept for backwards compatibility):
| Document | Contents |
|---|---|
| docs/tool-reference.md | Tool parameters and return shapes (superseded by resources) |
| docs/memory-root-schema.md | File and folder schema definitions with YAML examples |
| docs/filesystem-rules.md | Enforcement rules: what triggers errors vs. warnings |
The skill/ folder is a standalone Claude skill. To use it with Claude:
Step 1: Create the ZIP archive
# Windows PowerShell
Compress-Archive -Path .\skill\* -DestinationPath .\project-memory-mcp-skill.zip -Force# macOS / Linux
cd skill && zip -r ../project-memory-mcp-skill.zip . && cd ..Step 2: Upload to Claude
- Go to Claude.ai
- Open settings (⚙️) → Manage custom skills
- Click "Create skill" → Upload ZIP
- Select the generated
project-memory-mcp-skill.zip
The skill is now available in all Claude conversations.
If you accidentally write files with escaped newline sequences (\n instead of actual newlines):
python scripts/migrate_newlines.py --dry-run # Preview changes
python scripts/migrate_newlines.py # Apply fixesThe normalization also runs automatically on all write_file and append_to_file operations going forward.
# Install test dependencies
pip install -r requirements.txt pytest
# Run all tests
python -m pytest tests/ -v
# Run specific test suite
python -m pytest tests/tests.py::TestGuideResource -v
# Run with coverage
python -m pytest tests/ --cov=srcPlain Markdown and YAML files are:
- Human-readable — edit or read directly in any text editor
- Git-versionable — full audit trail, easy collaboration
- Schema-stable — no database migrations when requirements change
- LLM-native — Claude can read and write them directly
The manifest stores the read_when hint per file. This is the primary signal an LLM uses to decide what to load:
- Without manifests: Every call either reads everything (slow, expensive) or reads nothing (blind)
- With manifests: LLM skips files it doesn't need, reducing latency and token cost
- RAG-compatible: Manifests become the pre-filter for semantic search — embed
description + read_when, narrow the set, load only relevant files
Files moved to _trash/ are:
- Recoverable — restore files that were deleted by mistake
- Auditable — full history of what was removed and when
- Reversible — unlike permanent deletion, this is an MCP operation (no disk-level action required)
The server is designed to minimize token usage:
- Manifests guide loading — LLMs use
read_whenhints to skip unnecessary files - Local-first principle — Store processed knowledge locally; avoid re-fetching same M365 content
- Quick reference — Consolidated
memory://quick-referenceresource replaces scattered documentation - Append-only logs — Only changed entries are re-read, not entire files
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please include tests for new functionality and update documentation as needed.
This project is licensed under the MIT License — see LICENSE file for details.
MIT License grants you the freedom to use, modify, and distribute this software for any purpose, with or without modification, under the simple condition that you include the original license and copyright notice in any copies or substantial portions of the software.
- GitHub Issues — Report bugs or request features here
- Discussions — Ask questions or share ideas here
- Documentation — See the
skill/guides for detailed reference material
Built with FastMCP and designed for Claude by Anthropic.
Made with ❤️ for LLM-assisted project management