3.7 KiB
Architecture
Cortex is a small domain-specific MCP server.
flowchart LR
Client["MCP client"] -->|Streamable HTTP| App["Cortex .NET 10 app"]
Browser["Browser"] --> Web["Cortex Blazor web UI"]
Web --> Db
Web --> Embed
App --> Db["PostgreSQL + pgvector"]
App --> Embed["Text Embeddings Inference"]
Embed --> Model["BAAI/bge-small-en-v1.5"]
Runtime
The app is an ASP.NET Core service hosted by Kestrel. MCP is exposed over Streamable HTTP at:
/mcp
Health is exposed at:
/health
Optional Web UI
The web UI is a separate Blazor Server project and Docker container. It is optional and not needed for MCP clients.
The UI talks to the same PostgreSQL database and embedding service through the existing Cortex service layer. It is intended for manual browsing, adding memories, searching, editing, and soft-deleting during local development.
Dev URL:
http://localhost:5118
Test URL:
http://localhost:5218
Data Model
Project
Projects are mandatory and explicit. There is no default project.
Fields:
idnameslugcreated_atupdated_at
Memory Item
Memory items belong to exactly one project. EF Core maps them with table-per-type inheritance: shared fields live in memory_items, and each category has a subtype table with required category-specific columns.
Base fields:
idproject_idcategorytitlecontenttagsstatuscreated_atupdated_atdeleted_at
Memory Item Embedding
Embeddings are stored separately from items so a large item can expose additional targeted discoverability text without changing its canonical description.
Fields:
idmemory_item_idpositionlabeltextembeddingembedding_modelcreated_atupdated_at
The embedding column is a vector(384) pgvector column. Position 0 is the generated default embedding. Additional embeddings use position 1 and above.
Categories
| Category | Table | Required fields |
|---|---|---|
requirement |
requirement_memory_items |
statement, context |
location |
location_memory_items |
item_name, place |
todo |
todo_memory_items |
task, priority |
note |
note_memory_items |
subject, body |
Search
Search is hybrid:
- PostgreSQL full-text ranking over
titleandcontent - pgvector cosine similarity over all embeddings linked to each item
- Project and category filters
- Recency as a secondary sort
FindItems accepts one to four query texts. Cortex embeds each query, scores every query against every item embedding, and returns each item once using its best matching query/embedding pair.
Normal search requires a project. Global search requires searchAllProjects = true.
Embeddings
The embedding model is:
BAAI/bge-small-en-v1.5
The model produces 384-dimensional vectors. That dimension is part of the embedding table schema, so changing models later requires a planned re-embedding migration or a parallel embedding table/column strategy.
Embeddings are generated for:
- new items
- category-specific field changes
- tag changes
Additional embeddings are generated when they are added or when their text changes. Additional embedding text is only for discoverability; the item still has one canonical title/content description.
Status changes do not regenerate embeddings.
Deletes
Deletes are soft deletes. DeleteItem sets:
deleted_atstatus = "deleted"
Search excludes deleted items.
Migrations
EF Core migrations are applied by running the app in migration mode:
.\scripts\migrate-db.ps1
In Docker, deploy-all.ps1 runs migrations before starting the app.