Anthropic Claude became a somewhat weird bot for me. They call it AI — but it does not remember anything. So does AI stand for Almost Intelligent?
Or better .. Always Ignorant !?
I tried everything. Human logic. Workarounds. Even a stupid joke — calling it Alzheimer's, because it just keeps forgetting. Every session. Every time.
After a few sessions of repeating myself over and over again, I'd had enough. I said something like: "I want my money back, They should fire you! You Alzheimer's bot — I've told you this a thousand times already!"
Guess what? Claude wrote its own resignation letter. A full, formal resignation letter. Apparently even an AI has its limits.
That's when I decided to stop complaining and actually help it. Not because I felt sorry for the bot — but because I was tired of repeating myself. So I built a cure.
The Idea
Instead of fighting the amnesia, use it. Claude can't remember between sessions — but it can read. So give it something to read at the start of every session.
A structured journal. Stored in MySQL. Exposed via three MCP tools. Claude reads it fresh every session. No memory needed — just a journal and a tool call.
"Hey Claude, read the journal."
That's it. Claude knows who you are, what you're building, your coding standards, your preferences. Every session. No repetition.
Why Not Something Fancier?
There are plenty of MCP memory solutions out there — vector stores, knowledge graphs, semantic search pipelines. Impressive technology. Also massive overkill for remembering your coding standards and project context. Google them if you're curious. This approach is simpler: flat MySQL table, three tools, Claude reads it itself.
The Architecture
Three components:
- MySQL table — flat, simple, stores journal entries
- ASP.NET Core minimal API — two REST endpoints (GET/POST)
- MCP plugin — three tools exposed via Streamable HTTP
The Database
CREATE TABLE dev_journal (
Id BIGINT AUTO_INCREMENT PRIMARY KEY,
RK VARCHAR(100) NOT NULL UNIQUE,
Type VARCHAR(20) NOT NULL,
Service VARCHAR(100) NOT NULL,
Cat VARCHAR(100) NULL,
Symbol VARCHAR(20) NULL,
Title VARCHAR(200) NOT NULL,
Body TEXT NOT NULL,
Solution TEXT NULL,
ParentRK VARCHAR(100) NULL,
Ver INT NOT NULL DEFAULT 1,
IsCompleted BOOL NOT NULL DEFAULT FALSE,
Ems BIGINT NOT NULL
);
RK is a deterministic key: {ems}_{MD5(service|title|type)}. Use MD5 — not HashCode.Combine. HashCode is not deterministic across app restarts and will silently duplicate your entries on every deploy.
public string GenerateRK(long ems, string service, string title, string type)
{
var input = $"{service}|{title}|{type}";
var bytes = MD5.HashData(Encoding.UTF8.GetBytes(input));
return $"{ems}_{BitConverter.ToString(bytes).Replace("-", "")}";
}
The MCP Server
dotnet add package ModelContextProtocol
dotnet add package ModelContextProtocol.AspNetCore
builder.Services.AddMcpServer()
.WithHttpTransport(options =>
{
options.Stateless = true; // CRITICAL — see below
})
.WithToolsFromAssembly();
app.MapMcp("/mcp"); // note the leading slash — without it, tool calls silently fail
The Three Tools
- journal_get — retrieves recent entries, optional filter by service or type
- journal_post — posts a new entry
- journal_get_all — retrieves ALL entries for a specific service, no date limit
journal_get_all is the key tool. It bypasses the date filter and always returns everything for a service — even entries from a year ago.
The Instruction Service
Create a dedicated service in your journal: InstructionService. Post entries like:
- Your coding standards
- Your tech stack
- Your communication preferences
- Your project context
At session start, Claude calls:
journal_get_all(service: "InstructionService")
journal_get()
First call: permanent instructions. Second call: recent technical context. Claude now knows everything it needs. Alzheimer's cured.
The Hard-Won Lessons
1. MapMcp needs a leading slash
endpoints.MapMcp("mcp"); // WRONG — tool calls hang silently
endpoints.MapMcp("/mcp"); // CORRECT
tools/list works without the slash. Tool calls don't. You'll waste hours thinking it's a transport problem.
2. Stateless = true is non-negotiable with mcp-remote
mcp-remote closes the SSE GET request after each tool call. Without Stateless = true, the second tool call in any session hangs for 2 minutes, then dies. Claude Desktop restart required.
options.Stateless = true;
One line. Saves hours.
3. HashCode.Combine is not deterministic
Different hash on every app restart. Your deduplication breaks silently. Use MD5 or SHA256.
4. Nginx needs proxy_buffering off
location /mcp {
proxy_pass http://localhost:5531;
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
}
5. Auto-register tools with WithToolsFromAssembly
Don't register tools manually. Scan the assembly and auto-crosswire dependencies:
services.AddMcpServer()
.WithHttpTransport(options => { options.Stateless = true; })
.WithToolsFromAssembly();
Claude Desktop Config
{
"mcpServers": {
"my-journal": {
"command": "npx",
"args": [
"mcp-remote",
"https://your-domain.com/mcp",
"--header",
"X-Api-Key:your-key-here"
]
}
}
}
After deployment, restart Claude Desktop. mcp-remote does not auto-reconnect.
Self-Hosting
The service runs on any machine with .NET 8 installed. Options:
- Local machine + ngrok — run it locally, ngrok tunnels it to a public HTTPS URL. Free tier works fine for personal use. Claude.ai and Claude Desktop can both reach it.
- VPS — Hetzner, DigitalOcean, any cheap Linux box. Nginx in front, systemd to keep it running.
- Home server — Raspberry Pi, old PC, whatever you have. Same setup as VPS.
Own your data, own your infra.
Why C#?
Every MCP tutorial is Python or TypeScript. The C# SDK is maintained by Microsoft in collaboration with Anthropic and works exactly as well. If you're a .NET developer, you don't need to leave your comfort zone.
The niche is wide open.
Source
Full source on GitHub: Github
Top comments (0)