Picard MCP is a complete memory management system built on the Model Context Protocol (MCP) standard. It consists of two main components: an MCP server that provides secure memory storage and retrieval services, and a Django client application that demonstrates how to integrate with the MCP server. The system enables users to store, retrieve, and manage their memories while controlling access permissions, and allows for semantic search and AI-powered queries based on stored memories.
MCP Compliance
This implementation follows the Model Context Protocol standard, which allows LLM applications to interact with the server in a standardized way. The MCP server exposes:
Resources: Read-only endpoints that provide data to LLMs (memory content)
Tools: Functional endpoints that perform actions (memory creation, updates, queries)
Authentication: OAuth 2.0 implementation for secure access to protected resources
Key Components
MCP Server: A FastAPI-based implementation of the Model Context Protocol that provides:
✅ OAuth 2.0 authentication and authorization with PKCE support
✅ Memory storage with PostgreSQL and pgvector extension
✅ Permission-based memory access control (private/public)
✅ Vector embeddings for semantic search using OpenAI's text-embedding-3-small model
🔄 LLM integration for memory-based queries (framework ready, advanced features planned)
Django Client: A web application that demonstrates integration with the MCP server:
User registration and authentication
OAuth 2.0 client implementation
Memory creation, retrieval, and management UI
Persona-based querying interface
System Architecture
Overall Architecture
The Picard MCP system follows a client-server architecture with the following components:
MCP Server: Core backend service that handles memory storage, retrieval, and AI operations
Built with FastAPI (FastMCP) for high performance and async support
Uses PostgreSQL with pgvector extension for vector storage and semantic search
Implements data models for Users, Memories (with vector embeddings), OAuth Clients, and Tokens
Uses SQLAlchemy ORM with Alembic migrations for database management
Implements OAuth 2.0 for secure authentication and authorization
Integrates with OpenAI API for memory embeddings (text-embedding-3-small)
Uses LangChain for LLM operations when available
Provides both stateful and stateless operation modes
Supports streamable HTTP transport for better scalability
Django Client: Web application that demonstrates integration with the MCP server
Provides user registration, authentication, and profile management
Implements OAuth 2.0 client for secure communication with the MCP server
Offers a user-friendly interface for memory management and querying
Uses its own PostgreSQL database separate from the MCP server
Docker Infrastructure: Containerized deployment for easy setup and scaling
Separate containers for MCP server (port 8001), Django client (port 8000), and PostgreSQL databases
Configured networking for secure inter-container communication
Volume mounting for persistent data storage
Compatible with both local Docker deployment and Render cloud deployment
Authentication Approaches
The system offers two main authentication approaches:
1. Direct Connect with User Context Token Flow (Recommended)
This simplified approach allows users to authenticate only once with the Django client, avoiding the need for separate MCP server authentication:
Client Registration:
The Django client registers with the MCP server using the /api/admin/clients/register endpoint
Registration requires admin authentication and includes client name, redirect URIs, and requested scopes
The MCP server issues a UUID-based client ID and cryptographically secure client secret
Client credentials should be stored securely and never exposed in client-side code
User Authentication Flow:
User authenticates only with the Django client
When the user initiates connection to the MCP server, the Django client makes a server-side request to the MCP's /api/user-tokens/user-token endpoint
The request includes:
Client credentials (client_id and client_secret)
User information (username and email)
Option to create user if not exists
The MCP server verifies client credentials and either finds or creates a corresponding user
MCP server issues access and refresh tokens for the user
Django client securely stores these tokens and uses them for API requests
API Access:
Client includes the access token in the Authorization header (Authorization: Bearer {token}) for all API requests
MCP server validates the token signature, expiration, and audience claims
MCP server enforces scope-based permissions for each endpoint
When the access token expires, client uses the refresh token to obtain a new one
Security Features:
Only confidential clients can use this method, providing server-to-server security
Client credentials are verified for each token request
Tokens are blacklisted after use to prevent replay attacks
Refresh tokens use rotation: each use generates a new refresh token and invalidates the old one
2. Standard OAuth 2.0 Authorization Code Flow with PKCE (Legacy)
The system also supports the standard OAuth 2.0 Authorization Code flow with PKCE for enhanced security, following RFC 6749 and RFC 7636 standards. This approach requires users to authenticate with both the client and the MCP server:
Authorization Flow:
User initiates login through the Django client
Client generates a cryptographically secure random state parameter for CSRF protection
Client generates a random PKCE code_verifier and derives code_challenge using SHA-256
Client redirects to MCP server's /authorize endpoint with:
{"data":{"memories":[{"id":"550e8400-e29b-41d4-a716-446655440000","text":"I think AI will revolutionize how we work...","permission":"private","similarity":0.85,"created_at":"2024-01-15T10:30:00Z","updated_at":"2024-01-15T10:30:00Z"}]}}
Query User: /api/tools (tool: query_user)
Method: POST
Description: Query a user's persona based on memories (public for other users, public+private for self)
Authentication: Bearer token
Request: User UUID and query prompt
Response: JSON containing non-expired memories, either all valid memories or top-N most similar to query
Response: AI-generated response based on user's memories
Example Request:
hljs language-json
{"tool":"query_user","data":{"user_id":"550e8400-e29b-41d4-a716-446655440000","prompt":"What are your thoughts on artificial intelligence?"}}
Setup and Deployment
Prerequisites
Docker and Docker Compose
Python 3.10+
OpenAI API key
Complete Setup Guide
Clone the repository:
hljs language-bash
git clone https://github.com/yourusername/picard_mcp.git
cd picard_mcp
Create environment files for both components:
hljs language-bash
# For MCP servercp mcp_server/.env.example mcp_server/.env
# For Django clientcp django_client/.env.example django_client/.env
Edit the environment files to set your configuration:
In mcp_server/.env: Set your database credentials, OpenAI API key, and admin credentials
In django_client/.env: Set your database credentials and OAuth settings
Start the services using Docker Compose:
hljs language-bash
docker-compose up -d
This will start the following services:
db-mcp: PostgreSQL database for the MCP server
db-django: PostgreSQL database for the Django client
Memory text content is encrypted at rest using Python's Fernet symmetric encryption (AES-128 in CBC mode with PKCS7 padding) while metadata remains searchable
Personal identifiable information (PII) is protected through text field encryption
Access tokens have a 1-hour expiration time to limit exposure
Refresh tokens are long-lived but use rotation: each use generates a new refresh token and invalidates the old one
OAuth tokens are securely stored in the Django client's PostgreSQL database
UUID Usage
All identifiers in the system use UUID v4 format instead of sequential integers for several reasons:
Security: UUIDs don't expose system information or record counts
Scalability: UUIDs can be generated without database coordination, enabling distributed systems
Non-guessability: UUIDs are practically impossible to guess, preventing enumeration attacks
Consistency: Using UUIDs throughout the system simplifies integration with other services
All IDs in the API (user_id, memory_id, client_id, etc.) must be in UUID format.
OAuth Best Practices
All OAuth communication must use HTTPS in production environments
Authorization codes are single-use and short-lived (max 5 minutes)
PKCE is required for all clients, even confidential ones, for defense in depth
Refresh tokens are long-lived but can be revoked by users or administrators
The system maintains a token blacklist for revoked tokens
Documentation
API Documentation
The MCP server includes Swagger/OpenAPI documentation for all endpoints:
Access the Swagger UI at /docs when the server is running
The OpenAPI specification is available at /openapi.json
All API endpoints are fully documented with request/response schemas and examples
Additional Documentation Files
TESTING.md: Comprehensive guide to testing the application
Describes all implemented tests and their purposes
Instructions for running tests locally and in CI/CD
Documents test coverage and identifies areas needing additional testing
DEBUGGING.md: Tracks issues and their resolutions
Logs known bugs that have not yet been fixed
Documents previously solved bugs and their solutions
Provides troubleshooting guidance for common issues
PLANNING.md: Tracks the breakdown of tasks required to implement the site
Lists tasks and subtasks required to implement the site
Documents if a task has been completed with a checkbox
Deployment
This project includes a docker-compose.yml for local development and render.yaml blueprint for deploying to Render. The same codebase works both locally in Docker containers and when deployed to Render cloud services.
MCP Server Deployment
Docker Deployment (recommended for production):
hljs language-bash
docker-compose up -d
The Docker Compose configuration includes:
Network configuration for inter-container communication
Volume mounts for persistent data storage
Environment variable configuration from .env files
Port mappings (8000 for Django client, 8001 for MCP server)
Health checks for service dependencies
Render Cloud Deployment:
Use the included render.yaml blueprint to deploy to Render.