Project Description
ContextBase is a Model Context Protocol (MCP) server designed to store, retrieve, and manage per-user context for AI applications.
It provides a simple API for AI agents and assistants to maintain user-specific context across interactions, enabling more personalized
and contextually aware AI experiences.
The system uses a combination of Redis for high-performance caching and PostgreSQL for persistent storage, with a secure authentication
system to ensure that context data is properly isolated between users.
Key Features
Authentication System
Secure user authentication using JWT tokens and bcrypt password hashing ensures that only authorized users can access their context data.
- User registration and login
- JWT-based authentication
- Password hashing with bcrypt
- Token verification middleware
Memory Management
Efficient storage and retrieval of context data with Redis for high-performance caching and flexible TTL support.
- Create/read/update/delete operations
- Namespace isolation per user
- Optional TTL for expiring context
- Search capabilities
Logging System
Comprehensive logging of user actions for auditing, debugging, and analytics purposes.
- Action tracking (create, update, delete)
- Timestamp recording
- User association
- Key-based filtering
Modern Tech Stack
Built with cutting-edge technologies for performance, type safety, and developer experience.
- TypeScript for type safety
- Fastify for high-performance API
- Prisma ORM for database access
- Zod for request validation
Database Integration
PostgreSQL for reliable, persistent storage of user data and action logs.
- Prisma migrations
- Relational data model
- Efficient queries
- Data integrity
Caching
Redis for lightning-fast in-memory caching of context data with minimal latency.
- In-memory key-value store
- Sub-millisecond response times
- Expiration policies
- Pattern-based key search
Technology Stack
TypeScript
Node.js
Fastify
Prisma ORM
PostgreSQL
Redis
JWT
Docker
Zod
High-Level Architecture
graph TD
Client[Client Applications] --- API[ContextBase API]
API --- Auth[Authentication Service]
API --- Memory[Memory Service]
API --- Logs[Logging Service]
Memory --- Redis[Redis Cache]
Logs --- PostgreSQL[PostgreSQL Database]
Auth --- PostgreSQL
subgraph "Core Components"
APIRoutes[API Routes] --- Controllers[Controllers]
Controllers --- Services[Services]
Services --- Models[Data Models]
Models --- Database[Database Layer]
end
API --- Core_Components[Core Components]
classDef client fill:#d1e7dd,stroke:#20c997;
classDef api fill:#cfe2ff,stroke:#0d6efd;
classDef service fill:#e2e3e5,stroke:#6c757d;
classDef storage fill:#f8d7da,stroke:#dc3545;
class Client client;
class API api;
class Auth,Memory,Logs service;
class Redis,PostgreSQL storage;
Detailed Component Architecture
graph TD
subgraph "API Layer"
Routes[API Routes] --> AuthRoutes[Auth Routes]
Routes --> MemoryRoutes[Memory Routes]
Routes --> LogRoutes[Log Routes]
AuthRoutes --> Register[Register Endpoint]
AuthRoutes --> Login[Login Endpoint]
MemoryRoutes --> CreateMemory[Create Memory]
MemoryRoutes --> GetMemory[Get Memory]
MemoryRoutes --> UpdateMemory[Update Memory]
MemoryRoutes --> DeleteMemory[Delete Memory]
MemoryRoutes --> ListMemories[List Memories]
MemoryRoutes --> SearchMemories[Search Memories]
LogRoutes --> GetLogs[Get User Logs]
end
subgraph "Service Layer"
AuthService[Auth Service] --> HashPassword[Hash Password]
AuthService --> VerifyPassword[Verify Password]
AuthService --> GenerateToken[Generate JWT]
MemoryService[Memory Service] --> StoreContext[Store Context]
MemoryService --> GetContext[Get Context]
MemoryService --> UpdateContext[Update Context]
MemoryService --> DeleteContext[Delete Context]
MemoryService --> ListContextKeys[List Context Keys]
MemoryService --> SearchContext[Search Context]
LogService[Log Service] --> LogAction[Log User Action]
LogService --> GetUserLogs[Get User Logs]
end
subgraph "Data Layer"
Redis[Redis Cache] --> KeyValueStore[Key-Value Store]
Redis --> TTLSupport[TTL Support]
PostgreSQL[PostgreSQL] --> UserModel[User Model]
PostgreSQL --> LogModel[Log Model]
end
AuthRoutes --> AuthService
MemoryRoutes --> MemoryService
LogRoutes --> LogService
MemoryService --> Redis
LogService --> PostgreSQL
AuthService --> PostgreSQL
classDef api fill:#f0f7ff,stroke:#3b82f6;
classDef service fill:#f0fdf4,stroke:#22c55e;
classDef data fill:#fef3c7,stroke:#d97706;
class API_Layer api;
class Service_Layer service;
class Data_Layer data;
Project Structure
mcp/
├── mcp-server/ # Main server application
│ ├── prisma/ # Database schema and migrations
│ │ ├── migrations/ # Database migrations
│ │ └── schema.prisma # Prisma schema definition
│ ├── src/ # Source code
│ │ ├── api/ # API routes
│ │ │ ├── auth.ts # Authentication routes
│ │ │ ├── index.ts # API routes index
│ │ │ ├── logs.ts # Logging routes
│ │ │ └── memory.ts # Memory management routes
│ │ ├── config/ # Configuration files
│ │ ├── db/ # Database connections
│ │ │ ├── postgres.ts # PostgreSQL connection
│ │ │ └── redis.ts # Redis connection
│ │ ├── middleware/ # Custom middleware
│ │ │ └── auth.ts # Authentication middleware
│ │ ├── models/ # Data models
│ │ ├── services/ # Business logic
│ │ │ ├── logService.ts # Logging service
│ │ │ └── memoryService.ts # Memory service
│ │ ├── utils/ # Utility functions
│ │ └── index.ts # Application entry point
│ ├── scripts/ # Helper scripts
│ ├── .env # Environment variables
│ ├── docker-compose.yml # Docker configuration
│ ├── package.json # Dependencies and scripts
│ └── tsconfig.json # TypeScript configuration
├── .env.example # Example environment variables
├── .gitignore # Git ignore file
├── LICENSE # License file
└── README.md # Project documentation
Data Flow Diagram
sequenceDiagram
participant Client as Client Application
participant API as ContextBase API
participant Auth as Auth Service
participant Memory as Memory Service
participant Redis as Redis Cache
participant DB as PostgreSQL
participant Logs as Logging Service
Note over Client,Logs: Authentication Flow
Client->>API: Register (email, password)
API->>Auth: Hash Password & Create User
Auth->>DB: Store User Data
DB->>Auth: User Created
Auth->>API: User Created
API->>Client: Registration Success
Client->>API: Login (email, password)
API->>Auth: Verify Credentials
Auth->>DB: Fetch User Data
DB->>Auth: User Data
Auth->>Auth: Verify Password
Auth->>API: Generate JWT Token
API->>Client: Return JWT Token
Note over Client,Logs: Memory Operations Flow
Client->>API: Store Context (with JWT)
API->>Auth: Validate JWT
Auth->>API: User Authenticated
API->>Memory: Store Context
Memory->>Redis: Set Key-Value
Memory->>Logs: Log Action
Logs->>DB: Store Log Entry
Redis->>Memory: Storage Confirmed
Memory->>API: Context Stored
API->>Client: Success Response
Client->>API: Get Context (with JWT)
API->>Auth: Validate JWT
Auth->>API: User Authenticated
API->>Memory: Get Context
Memory->>Redis: Get Value by Key
Redis->>Memory: Return Value
Memory->>API: Return Context
API->>Client: Context Data
API Endpoints
graph LR
subgraph "Authentication API"
Register["/api/auth/register"] --- RegisterPost["POST - Register User"]
Login["/api/auth/login"] --- LoginPost["POST - Login User"]
end
subgraph "Memory API"
MemoryRoot["/api/memory"] --- MemoryGet["GET - List All Memories"]
MemoryRoot --- MemoryPost["POST - Create Memory"]
MemoryKey["/api/memory/:key"] --- MemoryKeyGet["GET - Get Memory"]
MemoryKey --- MemoryKeyPatch["PATCH - Update Memory"]
MemoryKey --- MemoryKeyDelete["DELETE - Delete Memory"]
MemorySearch["/api/memory/search/:query"] --- MemorySearchGet["GET - Search Memories"]
MemoryDelete["/api/memory/delete"] --- MemoryDeletePost["POST - Delete Memory (Alternative)"]
end
subgraph "Logs API"
LogsRoot["/api/logs"] --- LogsGet["GET - Get User Logs"]
end
classDef auth fill:#dbeafe,stroke:#3b82f6;
classDef memory fill:#dcfce7,stroke:#22c55e;
classDef logs fill:#fef3c7,stroke:#d97706;
class Authentication_API auth;
class Memory_API memory;
class Logs_API logs;
Authentication Flow
graph LR
A["Start"] --> B["User Registration"]
B --> C["Hash Password"]
C --> D["Store User in DB"]
D --> E["User Created"]
F["Login Request"] --> G["Fetch User from DB"]
G --> H["Verify Password"]
H --> I["Generate JWT Token"]
I --> J["Return Token to Client"]
K["Protected API Request"] --> L["Extract JWT from Header"]
L --> M["Verify Token"]
M --> N["Decode User ID"]
N --> O["Attach User to Request"]
O --> P["Process Request"]
style A fill:#d4f4e2,stroke:#34d399,stroke-width:3px,color:#065f46,font-weight:bold
style E fill:#d4f4e2,stroke:#34d399,stroke-width:3px,color:#065f46,font-weight:bold
style J fill:#d4f4e2,stroke:#34d399,stroke-width:3px,color:#065f46,font-weight:bold
style P fill:#d4f4e2,stroke:#34d399,stroke-width:3px,color:#065f46,font-weight:bold
Authentication Implementation
sequenceDiagram
participant Client as Client
participant Auth as Auth API
participant Bcrypt as Password Hasher
participant DB as PostgreSQL
participant JWT as JWT Service
Note over Client,JWT: User Registration Flow
Client->>Auth: POST /api/auth/register
Note right of Client: {email: "user@example.com", password: "securepassword"}
Auth->>Bcrypt: Hash Password
Bcrypt->>Auth: Return Hashed Password
Auth->>DB: Create User Record
DB->>Auth: User Created
Auth->>Client: Return User ID
Note over Client,JWT: User Login Flow
Client->>Auth: POST /api/auth/login
Note right of Client: {email: "user@example.com", password: "securepassword"}
Auth->>DB: Find User by Email
DB->>Auth: Return User Record
Auth->>Bcrypt: Compare Passwords
Bcrypt->>Auth: Password Valid/Invalid
Auth->>JWT: Generate Token
JWT->>Auth: Return JWT Token
Auth->>Client: Return JWT Token
Note over Client,JWT: Request Authentication
Client->>Auth: Request Protected Endpoint
Note right of Client: Authorization: Bearer {token}
Auth->>JWT: Verify Token
JWT->>Auth: Token Valid/Invalid
Auth->>Auth: Extract User ID
Auth->>Client: Process Request
Authentication Components
graph TD
subgraph "Authentication System"
Register["User Registration"] --> ValidateInput["Validate Input Data"]
ValidateInput --> CheckExisting["Check Existing User"]
CheckExisting --> HashPassword["Hash Password"]
HashPassword --> StoreUser["Store User in Database"]
Login["User Login"] --> FindUser["Find User by Email"]
FindUser --> VerifyPassword["Verify Password"]
VerifyPassword --> GenerateToken["Generate JWT Token"]
Middleware["Auth Middleware"] --> ExtractToken["Extract Token from Header"]
ExtractToken --> VerifyToken["Verify Token Signature"]
VerifyToken --> DecodePayload["Decode Token Payload"]
DecodePayload --> AttachUser["Attach User to Request"]
end
subgraph "Security Features"
PasswordHashing["Password Hashing"] --> Bcrypt["Bcrypt Algorithm"]
Bcrypt --> SaltRounds["10 Salt Rounds"]
TokenSecurity["Token Security"] --> JWTAlgorithm["HS256 Algorithm"]
JWTAlgorithm --> TokenExpiry["7 Day Expiry"]
TokenExpiry --> SecretKey["Environment Secret Key"]
end
Register -.-> PasswordHashing
Login -.-> PasswordHashing
Login -.-> TokenSecurity
Middleware -.-> TokenSecurity
classDef auth fill:#f0f7ff,stroke:#3b82f6;
classDef security fill:#dcfce7,stroke:#22c55e;
class Authentication_System auth;
class Security_Features security;
API Usage Examples
sequenceDiagram
participant Client as Client Application
participant Auth as Auth API
participant Memory as Memory API
participant Redis as Redis Cache
participant DB as PostgreSQL
Note over Client,DB: Authentication Flow
Client->>Auth: POST /api/auth/register
Note right of Client: {email: "user@example.com", password: "securepassword"}
Auth->>Client: {success: true, userId: "123e4567-e89b-12d3-a456-426614174000"}
Client->>Auth: POST /api/auth/login
Note right of Client: {email: "user@example.com", password: "securepassword"}
Auth->>Client: {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
Note over Client,DB: Memory Operations
Client->>Memory: POST /api/memory
Note right of Client: Authorization: Bearer {token}
{key: "user_preferences", value: {theme: "dark"}}
Memory->>Redis: Store Key-Value
Memory->>DB: Log Action
Memory->>Client: {success: true}
Client->>Memory: GET /api/memory/user_preferences
Note right of Client: Authorization: Bearer {token}
Memory->>Redis: Get Value
Redis->>Memory: Return Value
Memory->>Client: {value: {theme: "dark"}}
Client->>Memory: PATCH /api/memory/user_preferences
Note right of Client: Authorization: Bearer {token}
{value: {theme: "light"}}
Memory->>Redis: Update Value
Memory->>DB: Log Action
Memory->>Client: {success: true}
Client->>Memory: GET /api/memory
Note right of Client: Authorization: Bearer {token}
Memory->>Redis: List Keys
Redis->>Memory: Return Keys
Memory->>Client: {keys: ["user_preferences", "conversation_history"]}
Client->>Memory: DELETE /api/memory/user_preferences
Note right of Client: Authorization: Bearer {token}
Memory->>Redis: Delete Key
Memory->>DB: Log Action
Memory->>Client: {success: true}
Client->>Memory: GET /api/memory/search/user
Note right of Client: Authorization: Bearer {token}
Memory->>Redis: Pattern Search
Redis->>Memory: Return Matching Keys
Memory->>Client: {results: ["user_preferences", "user_history"]}
API Endpoints Visual Map
graph TD
subgraph "Authentication API"
AuthRoot["Authentication API
/api/auth"] --> Register["POST /register
Create new user account"]
AuthRoot --> Login["POST /login
Authenticate and get token"]
end
subgraph "Memory API"
MemoryRoot["Memory API
/api/memory"] --> CreateMemory["POST /
Create new memory entry"]
MemoryRoot --> ListMemories["GET /
List all memory keys"]
MemoryRoot --> GetMemory["GET /:key
Get specific memory value"]
MemoryRoot --> UpdateMemory["PATCH /:key
Update memory value"]
MemoryRoot --> DeleteMemory["DELETE /:key
Delete memory entry"]
MemoryRoot --> SearchMemory["GET /search/:query
Search memory keys"]
MemoryRoot --> PostDelete["POST /delete
Alternative delete method"]
end
subgraph "Logs API"
LogsRoot["Logs API
/api/logs"] --> GetLogs["GET /
Get user action logs"]
end
AuthRoot -.-> MemoryRoot
AuthRoot -.-> LogsRoot
classDef auth fill:#f0f7ff,stroke:#3b82f6;
classDef memory fill:#dcfce7,stroke:#22c55e;
classDef logs fill:#fef3c7,stroke:#d97706;
class Authentication_API,Register,Login auth;
class Memory_API,CreateMemory,ListMemories,GetMemory,UpdateMemory,DeleteMemory,SearchMemory,PostDelete memory;
class Logs_API,GetLogs logs;
Memory Service Implementation
graph TD
subgraph "Memory Service Functions"
StoreContext["storeContext()"] --> NamespaceKey1["Create Namespaced Key
userId:key"]
NamespaceKey1 --> SetRedis["Set in Redis
JSON.stringify(value)"]
SetRedis --> SetTTL["Set TTL (Optional)
redis.expire(key, ttl)"]
SetTTL --> LogCreate["Log Action
logAction(userId, 'create', key)"]
GetContext["getContext()"] --> NamespaceKey2["Create Namespaced Key
userId:key"]
NamespaceKey2 --> GetRedis["Get from Redis
redis.get(key)"]
GetRedis --> ParseJSON["Parse JSON Value
JSON.parse(value)"]
UpdateContext["updateContext()"] --> NamespaceKey3["Create Namespaced Key
userId:key"]
NamespaceKey3 --> CheckExists["Check if Key Exists
redis.exists(key)"]
CheckExists --> UpdateRedis["Update in Redis
redis.set(key, JSON.stringify(newValue))"]
UpdateRedis --> LogUpdate["Log Action
logAction(userId, 'update', key)"]
DeleteContext["deleteContext()"] --> NamespaceKey4["Create Namespaced Key
userId:key"]
NamespaceKey4 --> DeleteRedis["Delete from Redis
redis.del(key)"]
DeleteRedis --> LogDelete["Log Action
logAction(userId, 'delete', key)"]
ListContextKeys["listContextKeys()"] --> GetAllKeys["Get All User Keys
redis.keys(`${userId}:*`)"]
GetAllKeys --> RemoveNamespace["Remove Namespace Prefix
key.split(':')[1]"]
SearchContext["searchContext()"] --> GetAllKeys2["Get All User Keys
redis.keys(`${userId}:*`)"]
GetAllKeys2 --> RemoveNamespace2["Remove Namespace Prefix
key.replace(`${userId}:`, '')"]
RemoveNamespace2 --> FilterByQuery["Filter by Search Query
key.includes(query)"]
end
classDef memory fill:#f0f7ff,stroke:#3b82f6;
class Memory_Service_Functions memory;
Memory Service Architecture
graph TD
subgraph "Client Request Flow"
APIRequest["API Request"] --> MemoryController["Memory Controller
(API Routes)"]
MemoryController --> MemoryService["Memory Service
(Business Logic)"]
MemoryService --> RedisAdapter["Redis Adapter
(Data Access)"]
MemoryService --> LoggingService["Logging Service
(Audit Trail)"]
RedisAdapter --> RedisDB["Redis Database
(Key-Value Store)"]
LoggingService --> PostgresDB["PostgreSQL
(Persistent Storage)"]
end
subgraph "Key Namespacing"
UserID["User ID
(From JWT Token)"] --> KeyPrefix["Key Prefix
userId:"]
KeyPrefix --> KeyName["Key Name
(From Request)"]
KeyName --> FullKey["Full Key
userId:keyName"]
FullKey --> RedisKey["Redis Key"]
end
subgraph "Value Serialization"
ValueObject["Value Object
(JavaScript Object)"] --> JSONString["JSON String
JSON.stringify()"]
JSONString --> RedisValue["Redis Value
(String)"]
RedisValue --> RetrievedString["Retrieved String"]
RetrievedString --> ParsedObject["Parsed Object
JSON.parse()"]
end
MemoryService -.-> UserID
MemoryService -.-> ValueObject
RedisAdapter -.-> FullKey
RedisAdapter -.-> JSONString
classDef flow fill:#f0f7ff,stroke:#3b82f6;
classDef keys fill:#dcfce7,stroke:#22c55e;
classDef values fill:#fef3c7,stroke:#d97706;
class Client_Request_Flow flow;
class Key_Namespacing keys;
class Value_Serialization values;
Logging System
sequenceDiagram
participant Memory as Memory Service
participant Log as Log Service
participant DB as PostgreSQL
Note over Memory,DB: Logging User Actions
Memory->>Log: logAction(userId, 'create', key)
Log->>DB: Insert Log Entry
DB->>Log: Log Created
Log->>Memory: Action Logged
Memory->>Log: logAction(userId, 'update', key)
Log->>DB: Insert Log Entry
DB->>Log: Log Created
Log->>Memory: Action Logged
Memory->>Log: logAction(userId, 'delete', key)
Log->>DB: Insert Log Entry
DB->>Log: Log Created
Log->>Memory: Action Logged
Redis Implementation
graph TD
subgraph "Redis Operations"
Connect["Connect to Redis"] --> ClientConfig["Configure Redis Client"]
ClientConfig --> ConnectionPool["Setup Connection Pool"]
Set["SET Operation"] --> NamespaceKey["Namespace Key with UserID"]
NamespaceKey --> SerializeValue["Serialize Value to JSON"]
SerializeValue --> StoreKeyValue["Store Key-Value Pair"]
Get["GET Operation"] --> NamespaceKey2["Namespace Key with UserID"]
NamespaceKey2 --> FetchValue["Fetch Value by Key"]
FetchValue --> DeserializeValue["Deserialize JSON Value"]
TTL["TTL Support"] --> SetExpiry["Set Key Expiration"]
SetExpiry --> AutoDelete["Automatic Deletion"]
Keys["KEYS Operation"] --> PatternMatch["Pattern Matching"]
PatternMatch --> UserKeysPattern["User-specific Pattern"]
UserKeysPattern --> ReturnMatchingKeys["Return Matching Keys"]
end
classDef redis fill:#f0f7ff,stroke:#3b82f6;
class Redis_Operations redis;
Development Workflow
sequenceDiagram
participant Dev as Developer
participant Git as Git Repository
participant NPM as NPM
participant TS as TypeScript Compiler
participant Server as ContextBase Server
participant DB as Database
Dev->>Git: Clone Repository
Dev->>NPM: npm install
NPM->>Dev: Dependencies Installed
Dev->>Dev: Configure .env
Dev->>DB: Run Migrations (npx prisma migrate dev)
DB->>Dev: Database Schema Created
Dev->>NPM: npm run dev
NPM->>TS: Compile TypeScript
TS->>Server: Start Development Server
Server->>Dev: Server Running
Dev->>Server: Make API Requests
Server->>Dev: API Responses
Dev->>Git: Commit Changes
Deployment Architecture
graph TD
subgraph "Docker Compose Environment"
API["ContextBase API Container"] --- Redis["Redis Container"]
API --- Postgres["PostgreSQL Container"]
API --- NodeJS["Node.js Runtime"]
API --- TypeScript["TypeScript"]
API --- Fastify["Fastify Server"]
Redis --- RedisVolume["Redis Volume"]
Postgres --- PostgresVolume["PostgreSQL Volume"]
end
Client["Client Applications"] --- API
classDef container fill:#dbeafe,stroke:#3b82f6;
classDef volume fill:#dcfce7,stroke:#22c55e;
classDef external fill:#f0f7ff,stroke:#6c757d;
class API,Redis,Postgres container;
class RedisVolume,PostgresVolume volume;
class Client external;
Getting Started
To run the ContextBase server locally:
- Clone the repository
git clone https://github.com/imfeniljikadara/contextbase.git
cd mcp
- Install dependencies
cd mcp-server
npm install
- Configure environment variables
- Create a
.env
file in the mcp-server
directory
- Use the
.env.example
file as a template
- Run database migrations
- Start the server
- Development mode:
npm run dev
- Production mode:
npm start
- Using Docker:
docker-compose up
Conclusion
ContextBase is a powerful and flexible Model Context Protocol (MCP) server designed to enhance AI applications with persistent
user context. Its architecture leverages modern technologies like Fastify, Redis, and PostgreSQL to provide a scalable and
efficient solution for context management.
The system's key strengths include:
- Secure per-user context isolation through authentication
- High-performance context storage and retrieval using Redis
- Comprehensive action logging for auditing and debugging
- Simple and intuitive API for easy integration
- Containerized deployment for simplified operations
By providing these capabilities, ContextBase enables AI applications to maintain contextual awareness across user interactions,
resulting in more personalized and effective AI experiences.