Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Personal Server

БесплатноНе проверен

Private MCP server for managing Gmail, custom IMAP/SMTP email, Slack notifications, and personal notes stored in SQLite.

GitHubEmbed

Описание

Private MCP server for managing Gmail, custom IMAP/SMTP email, Slack notifications, and personal notes stored in SQLite.

README

A private, single-user MCP (Model Context Protocol) server that gives AI agents access to your email, Slack notifications, and a personal knowledge base ("soul docs"). Written in TypeScript, runs over Streamable HTTP or stdio.

Capabilities at a glance:

  • Search and read Gmail or any IMAP mailbox
  • Send email via Gmail API or custom SMTP (with a prepare→confirm safety flow)
  • Post Slack notifications via incoming webhooks
  • CRUD a personal knowledge base backed by SQLite or Turso/libSQL
  • Configure all credentials at runtime via MCP tools — no .env editing required

Tools

Mail — Gmail

Tool Summary
gmail_search_messages Search Gmail with typed filters (from, to, subject, text, label, unread, date range). Returns summaries.
gmail_get_message Fetch a full Gmail message by ID — headers, plain text body, HTML body.

Mail — Custom IMAP / SMTP

Tool Summary
custom_mail_search_messages Search a custom IMAP mailbox with the same typed filters.
custom_mail_get_message Fetch a full message from the custom IMAP mailbox by UID.
email_prepare_send Validate and stage an email draft. Returns a confirmation ID; does not send.
email_confirm_send Send a previously staged email using its confirmation ID. The two-step flow prevents accidental sends.

Slack

Tool Summary
send_slack_notification Post a message (plain text or Block Kit blocks) to a configured Slack incoming webhook.

Soul Docs (personal knowledge base)

Tool Summary
get_my_soul_docs Search docs by full-text query (title, content, source) or filter by tag. Returns newest first.
write_my_soul_doc Create or update a doc. Pass an id to upsert (preserves original created_at); omit to create new. Each doc has a title, body content, tags, an optional source reference, and arbitrary metadata.

Setup (runtime configuration)

When MCP_ENABLE_SETUP_TOOLS=true (the default), these tools let you configure every service at runtime and test connections immediately. All changes are in-memory — they override .env values but reset on restart.

Tool Summary
setup_status Show which services are configured (no secrets exposed).
setup_database Set a Turso/libSQL URL or local file path, then test the connection. Accepts libsql://, file:, or plain paths like /data/db.sqlite.
setup_gmail_oauth_start Generate a Google OAuth authorization URL. Optionally override client ID, secret, and redirect URI.
setup_gmail_oauth_complete Exchange the OAuth authorization code for a refresh token and store it in the runtime config.
setup_custom_mail_imap Set IMAP host, port, credentials, and mailbox — then test the connection.
setup_custom_mail_smtp Set SMTP host, port, credentials, and default from address — then verify the connection.
setup_slack_webhook Set a Slack incoming webhook URL and send a test notification.

Set MCP_ENABLE_SETUP_TOOLS=false to disable all setup tools and use .env-only configuration.


Configuration reference

Every setting can be provided via .env or overridden at runtime by the corresponding setup_* tool.

Runtime

Variable Default Notes
MCP_TRANSPORT streamable-http streamable-http, http (alias), or stdio
MCP_PORT 3000 HTTP listen port
MCP_HOST 127.0.0.1 Set to 0.0.0.0 for remote access
MCP_BEARER_TOKEN Optional. When set, requires Authorization: Bearer <token> on all requests
MCP_ALLOWED_ORIGINS * Comma-separated origins or * for all
MCP_ENABLE_SETUP_TOOLS true Set to false to remove setup_* tools

Database

Variable Default Notes
TURSO_DATABASE_URL file:local.db file: for local SQLite, libsql:// for Turso, or a plain path
TURSO_AUTH_TOKEN Required for Turso remote databases
TURSO_SYNC_URL Sync endpoint for embedded replicas
TURSO_SYNC_INTERVAL_MS Sync interval in ms for embedded replicas

Gmail OAuth

Variable Required Notes
GOOGLE_CLIENT_ID Yes From Google Cloud Console
GOOGLE_CLIENT_SECRET Yes From Google Cloud Console
GOOGLE_REDIRECT_URI Yes e.g. http://127.0.0.1:3000/oauth/google/callback
GOOGLE_REFRESH_TOKEN Obtained via OAuth flow; stored at runtime by setup_gmail_oauth_complete
GOOGLE_OAUTH_STATE Optional CSRF state string

Scopes requested: gmail.readonly, gmail.send.

Custom IMAP

Variable Default Notes
CUSTOM_IMAP_HOST IMAP server hostname
CUSTOM_IMAP_PORT 993
CUSTOM_IMAP_SECURE true TLS
CUSTOM_IMAP_USER Usually the full email address
CUSTOM_IMAP_PASSWORD App password recommended
CUSTOM_IMAP_MAILBOX INBOX

Custom SMTP

Variable Default Notes
CUSTOM_SMTP_HOST SMTP server hostname
CUSTOM_SMTP_PORT 587
CUSTOM_SMTP_SECURE false true for port 465, false for 587 (STARTTLS)
CUSTOM_SMTP_USER Optional
CUSTOM_SMTP_PASSWORD Optional
EMAIL_DEFAULT_FROM Default sender address
EMAIL_CONFIRMATION_TTL_SECONDS 600 Expiry for staged-but-unsent emails

Slack

Variable Notes
SLACK_WEBHOOK_URL Incoming webhook URL

Getting started

Path A: .env (static config)

npm install
cp .env.example .env
# Edit .env with your credentials
npm run build
npm start                   # HTTP on port 3000
# or: npm run start:stdio   # stdio transport

Path B: setup tools (runtime config)

npm install
npm run build
npm start

Then, from your MCP client, call the setup_* tools in any order:

  1. setup_database — point to your DB (or skip; file:local.db is the default)
  2. setup_gmail_oauth_start → open the URL → setup_gmail_oauth_complete with the code
  3. setup_custom_mail_imap + setup_custom_mail_smtp — configure mail
  4. setup_slack_webhook — configure Slack
  5. setup_status — verify everything is wired up

Endpoints

Method Path Description
POST /mcp MCP Streamable HTTP — requires Accept: application/json, text/event-stream
GET /healthz Health check
GET /oauth/google/start Start Gmail OAuth flow (HTTP mode only)
GET /oauth/google/callback Gmail OAuth callback (HTTP mode only)

Architecture

src/
├── config.ts          Env parsing (Zod), defaults, setConfigValue helper
├── index.ts           Entry point — loads config, creates services, starts transport
├── runtime.ts         Service factory — wires up all services with shared config
├── server.ts          MCP server — registers all tools, conditionally includes setup tools
├── setup-tools.ts     Runtime config tools — mutate config, test connections
├── tools.ts           Core tool handlers — email, Slack, soul docs
├── errors.ts          Custom error classes
├── logger.ts          Structured JSON logging
├── types.ts           Shared TypeScript interfaces
├── transports/
│   ├── http.ts        Streamable HTTP transport + OAuth callback routes
│   └── stdio.ts       Stdio transport
├── services/
│   ├── database.ts    Turso/libSQL client — soul_docs, send_confirmations, audit_log
│   ├── gmail-api.ts   Thin Gmail REST wrapper via google-auth-library + fetch (replaces googleapis)
│   ├── gmail.ts       Gmail service — search, read, send, OAuth
│   ├── custom-mail.ts IMAP (imapflow) + SMTP (nodemailer) — search, read, send
│   ├── email-sender.tsComposite — delegates to Gmail or SMTP based on provider
│   └── slack.ts       Slack incoming webhook via fetch
└── utils/
    ├── email.ts       MIME builder, base64url helpers
    └── mcp.ts         jsonText() response formatter

Key design choices:

  • Shared mutable config — All services hold a reference to the same AppConfig object. Setup tools mutate it directly; lazy services (Gmail, IMAP, SMTP, Slack) pick up changes on the next call. Only DatabaseService needs an explicit reconnect() since it creates the libSQL client eagerly.
  • Audit logging — Every tool call is logged to the audit_log table with success/failure, args (secrets redacted), and a timestamp.
  • Two-step email sendemail_prepare_send stages a draft (stored in DB with a TTL), email_confirm_send consumes it. Prevents accidental sends and gives the agent a chance to review.
  • OAuth works in both transports — Streamable HTTP mode has dedicated callback routes; stdio mode uses the setup_gmail_oauth_start / setup_gmail_oauth_complete tools where the user copies the code manually.

Database

Three tables are created automatically on startup:

Table Purpose
soul_docs Personal knowledge base — title, content, tags, source, metadata, timestamps
send_confirmations Staged email drafts with expiry and single-use tokens
audit_log Immutable record of every tool invocation

Local vs remote

# Local SQLite (relative to working directory)
TURSO_DATABASE_URL=file:local.db

# Local SQLite (absolute — for pods/containers that need persistent state)
TURSO_DATABASE_URL=file:/data/my-server.db

# Remote Turso DB
TURSO_DATABASE_URL=libsql://your-db.turso.io
TURSO_AUTH_TOKEN=your-token

Plain paths passed to setup_database are auto-prefixed with file: — so /data/db.sqlite becomes file:/data/db.sqlite.


Deployment

Docker (GHCR)

Pre-built multi-arch images (linux/amd64, linux/arm64) are published to GitHub Container Registry on every push to main.

# Pull and run
docker run -d --name personal-mcp \
  --env-file .env \
  -p 3000:3000 \
  -v "$(pwd)/data:/app/data" \
  ghcr.io/olamide226/personal-mcp-server:latest

# Or with a specific version
docker run -d --name personal-mcp \
  --env-file .env \
  -p 3000:3000 \
  -v "$(pwd)/data:/app/data" \
  ghcr.io/olamide226/personal-mcp-server:v1.0.0

Docker Compose (local build)

docker compose up --build

To pull from GHCR instead of building locally, swap the build: . line in docker-compose.yml for:

image: ghcr.io/olamide226/personal-mcp-server:latest

Bare metal / pod

npm ci --omit=dev
npm run build
MCP_HOST=0.0.0.0 MCP_PORT=3000 TURSO_DATABASE_URL=file:/data/server.db node dist/index.js

For production, set a strong MCP_BEARER_TOKEN and restrict MCP_ALLOWED_ORIGINS to your client origin(s).

Image tags

Tag When
latest Every push to main
<full-sha> Every push to main
v1.2.3 Version tag (e.g. v1.2.3)
1.2 Major.minor alias
1 Major alias

Semantic releases

Merging a PR to main triggers the release.yml workflow which parses conventional commits since the last tag:

Commit prefix Version bump
feat: ... minor
fix: ..., perf: ... patch
BREAKING CHANGE: ... or feat!: ... major

If any meaningful commits are found, a vX.Y.Z tag is created and pushed — which triggers a Docker build with semver tags.

Health check

curl http://localhost:3000/healthz
# {"ok":true,"name":"personal-mcp-server","version":"0.1.0"}

Development

npm install
npm run dev          # tsx watch — auto-reload on changes
npm run build        # tsc
npm test             # vitest
npm run lint         # eslint
npm run typecheck    # tsc --noEmit (includes tests/)

from github.com/olamide226/personal-mcp-server

Установка Personal Server

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/olamide226/personal-mcp-server

FAQ

Personal Server MCP бесплатный?

Да, Personal Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Personal Server?

Нет, Personal Server работает без API-ключей и переменных окружения.

Personal Server — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Personal Server в Claude Desktop, Claude Code или Cursor?

Открой Personal Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Personal Server with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории communication