ContextBase - Project Overview

A Model Context Protocol (MCP) server for AI agents, assistants, and apps

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.

Memory Management

Efficient storage and retrieval of context data with Redis for high-performance caching and flexible TTL support.

Logging System

Comprehensive logging of user actions for auditing, debugging, and analytics purposes.

Modern Tech Stack

Built with cutting-edge technologies for performance, type safety, and developer experience.

Database Integration

PostgreSQL for reliable, persistent storage of user data and action logs.

Caching

Redis for lightning-fast in-memory caching of context data with minimal latency.

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:

  1. Clone the repository
  2. Install dependencies
  3. Configure environment variables
  4. Run database migrations
  5. Start the server

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:

By providing these capabilities, ContextBase enables AI applications to maintain contextual awareness across user interactions, resulting in more personalized and effective AI experiences.