AgentCloak is an MCP (Model Context Protocol) proxy between AI agents and email. It holds credentials server-side, filters sensitive content, redacts PII, and sanitizes for prompt injection.
Monorepo using pnpm workspaces with four packages:
- packages/server — Hono HTTP server + MCP SDK (Streamable HTTP transport), SQLite storage, Gmail/IMAP/Apps Script providers, content filter pipeline
- packages/web — React + Tailwind + Vite SPA dashboard (login, connections, filters, API keys)
- packages/cli — Commander CLI for setup, key management, filters, password reset
- packages/mcp-stdio — Stdio-to-HTTP proxy for MCP clients that don't support HTTP transport (not needed for Claude Code)
packages/server/src/index.ts— HTTP server entry point, MCP route handler (bypasses Hono for POST /mcp)packages/server/src/mcp/route.ts— MCP request handler, creates per-request StreamableHTTPServerTransportpackages/server/src/mcp/tools/— MCP tool definitions (search, read, threads, drafts, labels)packages/server/src/routes/auth.ts— Email/password register + login endpointspackages/server/src/routes/oauth.ts— Google OAuth login + Gmail connection flowpackages/server/src/routes/api.ts— Dashboard API routes (session-authenticated)packages/server/src/storage/sqlite.ts— SQLite storage implementation (schema v5)packages/server/src/config.ts— Zod-validated config from env vars (Google OAuth fields are optional)packages/server/src/auth/password.ts— scrypt password hashingpackages/server/src/auth/rate-limit.ts— In-memory sliding-window rate limiterpackages/web/src/pages/LoginPage.tsx— Login/register page (email/password + optional Google OAuth)packages/web/src/pages/ConnectionsPage.tsx— Connection management with Add dropdown
pnpm install # Install all dependencies
pnpm build # Build all packages (server, web, cli, mcp-stdio)
pnpm dev # Start dev server on localhost:3000
pnpm -C packages/server exec tsc -b # Type-check server only
pnpm -C packages/web exec vite build # Build web dashboard onlySQLite at data/agentcloak.db (or DATABASE_PATH env var). Schema version 5. Migrations run automatically on startup in sqlite.ts. Key tables: accounts, sessions, email_connections, api_keys, filter_configs. Note: email_connections has no UNIQUE constraint on (email, provider) — multiple connections to the same email are allowed.
- Dashboard: Session cookies (email/password or Google OAuth)
- MCP endpoint: API keys (prefixed
ac_, hashed with SHA-256, stored in api_keys table) - Google OAuth: Optional — config fields are
.optional()in Zod schema.isGoogleOAuthConfigured()guards all OAuth routes.
See .claude-private.md (not tracked in git) for production deployment details.
The MCP SDK's StreamableHTTPServerTransport requires clients to send Accept: application/json, text/event-stream. Some MCP clients (including Claude Code) only send Accept: application/json. The server patches req.headers.accept AND req.rawHeaders before passing to the transport — both must be patched because Hono's @hono/node-server reads from rawHeaders, not headers.
Claude Code connects directly to the MCP endpoint over HTTP. All configuration lives in ~/.claude.json.
When the same MCP server is defined in multiple scopes, the highest-priority scope wins. Only configure each server in one scope to avoid confusion when updating API keys.
In ~/.claude.json, under projects["/path/to/project"].mcpServers:
{
"projects": {
"/Users/you/DevProjects/PersonalAgent": {
"mcpServers": {
"agentcloak": {
"type": "http",
"url": "https://agentcloak.up.railway.app/mcp",
"headers": {
"Authorization": "Bearer ac_your_key_here"
}
}
}
}
}
}This scope only applies when Claude Code is launched from the matching project directory. Use this when different projects need different API keys (e.g., different email accounts).
Create .mcp.json in the project root. Do not put API keys here since it's committed to git — use this for servers that don't require secrets.
In ~/.claude.json, at the top level:
{
"mcpServers": {
"agentcloak": {
"type": "http",
"url": "https://agentcloak.up.railway.app/mcp",
"headers": {
"Authorization": "Bearer ac_your_key_here"
}
}
}
}This scope applies to all projects. Use this when you want the same server available everywhere.
# Project-level (for current project only)
claude mcp add --transport http agentcloak --scope project <url> --header "Authorization: Bearer ac_..."
# Global (all projects)
claude mcp add --transport http agentcloak --scope user <url> --header "Authorization: Bearer ac_..."~/.claude/mcp.jsonis NOT a recognized config file. Don't put MCP configs there.- Don't define the same server in multiple scopes. If you put agentcloak in both project-level and global, updating the global key won't take effect because the project-level config takes priority. Pick one scope per server.
- When updating an API key, verify which scope the server is configured in by searching
~/.claude.jsonfor the server name before making changes.