brandvoice-mcp
An MCP server that learns your writing style and makes every AI client sound like you.
Quick start
Install
pip install brandvoice-mcp
Configure Claude Desktop
Add to your claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"brandvoice": {
"command": "python",
"args": ["-m", "brandvoice_mcp"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-...",
"OPENAI_API_KEY": "sk-..."
}
}
}
}
Set ANTHROPIC_API_KEY and OPENAI_API_KEY in the env block (both required for normal use: Claude for analysis/alignment, OpenAI for chunk embeddings). The server will exit with a clear error if either is missing.
Teach it your voice
In Claude Desktop, ask the model to use ingest_samples with real writing:
Use the
ingest_samplestool to learn my writing style from this blog post: [paste content]
The server chunks the text, stores embeddings in ChromaDB, and (for samples of about 50+ words) runs LLM style analysis. Shorter snippets are still stored for retrieval but skip style analysis to avoid unreliable profiles.
Write in your voice
Before any writing task, call get_voice_context with your task and platform. The returned prompt_injection is wrapped in <voice_context>...</voice_context> — prepend it to your request or system prompt.
Use
get_voice_contextfor a LinkedIn post about React performance, then write it in my voice.
Check alignment
After drafting text, call check_alignment with the draft. You get a 0–100 score, drift flags, and rewrite hints against your stored profile and samples.
Use
check_alignmenton this draft: [paste text]
Tools reference
| Tool | Description |
|---|---|
ingest_samples |
Ingest writing; chunk, embed, and update style profile when thresholds are met |
get_voice_context |
Voice guidelines, similar samples, and prompt_injection for a task |
set_guidelines |
Merge explicit brand voice rules (pillars, tone, vocabulary, etc.) |
check_alignment |
Score how well content matches your voice |
get_profile |
Full profile: learned style (including profile_source), guidelines, counts |
list_samples |
Paginated list of ingested samples (each row includes the Chroma document id for delete_samples) |
delete_samples |
Delete samples by sample_ids (from list_samples) or set all to true to clear the collection; refreshes or resets the learned profile |
How it works
Ingestion: Text is split into chunks, embedded with OpenAI (default text-embedding-3-small), and stored in a local ChromaDB collection (writing_samples) for similarity search. The aggregate learned style and explicit guidelines live in ~/.brandvoice/profile.json (human-readable, separate from vectors) so a vector DB issue does not silently wipe your profile alongside embeddings.
Style analysis: For sufficiently long samples, Claude analyzes tone and patterns (including humor, technical depth, and warmth scores used in get_voice_context). If the API fails, a heuristic fallback runs; profile_source records "llm" vs "heuristic". After enough stored chunks (see BRANDVOICE_PROFILE_THRESHOLD), each qualifying ingest re-merges the corpus via Claude (prompts/corpus_aggregate.md) into a single aggregate profile; on failure, the latest per-sample LLM snapshot is used when available.
Writing assistance: For a task, the server retrieves your profile and the top similar chunks, then builds prompt_injection from markdown templates under brandvoice_mcp/prompts/.
Configuration
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
(required) | Anthropic API key (style analysis, alignment) |
OPENAI_API_KEY |
(required) | OpenAI API key (chunk embeddings; Anthropic has no embeddings API) |
BRANDVOICE_DATA_DIR |
~/.brandvoice |
Data directory (profile.json, Chroma persistence) |
BRANDVOICE_EMBEDDING_MODEL |
text-embedding-3-small |
OpenAI embedding model name |
BRANDVOICE_ANALYSIS_MODEL |
claude-sonnet-4-6 |
Model for style analysis |
BRANDVOICE_PROFILE_THRESHOLD |
5 |
Minimum stored samples before aggregate profile can update after an LLM-analyzed ingest |
Model deprecation: If the default
claude-sonnet-4-6is deprecated or unavailable in your region, setBRANDVOICE_ANALYSIS_MODELto a supported model ID (e.g.claude-opus-4-6orclaude-haiku-4-5-20251001). Claude 4 model IDs use no date suffix; check Anthropic's model documentation for the current list.
Limitations
- Single client: Designed for one MCP client at a time. Multiple clients sharing the same
~/.brandvoicedirectory may hit SQLite/Chroma lock errors. - API costs: Style analysis and alignment use Anthropic; chunk embeddings use OpenAI. Each
ingest_samplesandcheck_alignmentconsumes tokens; budget accordingly.
Requirements
- Python 3.11+
- Anthropic API key (
ANTHROPIC_API_KEY) — LLM calls - OpenAI API key (
OPENAI_API_KEY) — embeddings for ChromaDB similarity search
Development
git clone https://github.com/jsliapark/brandvoice-mcp.git
cd brandvoice-mcp
pip install -e ".[dev]"
pytest
Architecture (overview)
MCP client (Claude Desktop, Cursor, …)
│ stdio
▼
brandvoice-mcp server
│
├── profile.json ← aggregate learned style + explicit guidelines
└── ChromaDB ← writing_samples (embeddings + chunks)
Manual testing in a terminal
The server speaks JSON-RPC on stdin/stdout. When you run python -m brandvoice_mcp, it should block until the client disconnects or you press Ctrl+C — there is no interactive prompt.
- Do not type in that terminal while the server is running; random text is not valid JSON-RPC and you will see errors like
Invalid JSON/JSONRPCMessagevalidation errors. - Do not run two copies of the server on the same stdio session.
- If you use Cursor / Claude Desktop with this project, let only the IDE spawn the process — don’t also run
python -m brandvoice_mcpin a terminal unless you are debugging with a real MCP client attached.
If python -m brandvoice_mcp crashes with Server has no attribute tool, your checkout is on the old low-level Server API — use FastMCP (from mcp.server import FastMCP) and sync __main__.py to call run_server() without asyncio.run (see current server.py on main).
For a local run, export both ANTHROPIC_API_KEY and OPENAI_API_KEY (see Configuration above).
License
MIT — see LICENSE.
Metadata
Release files for brandvoice-mcp 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| brandvoice_mcp-0.2.0.tar.gz | 39.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| brandvoice_mcp-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 78.8 kB
Release files / brandvoice_mcp-0.2.0.tar.gz
| Download URL | brandvoice_mcp-0.2.0.tar.gz |
|---|---|
| Size | 39.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b670844f3268fb49bb8b9b85bf49f2ee7c90a2c96dae4da27355b95ca4016466
|
|
BLAKE2b-256 checksum How to use checksums |
f2470ebf638b4c3666315806a6d49ec6a63c6320d8848ad357e3a4a25377bc8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|
Release files / brandvoice_mcp-0.2.0-py3-none-any.whl
| Download URL | brandvoice_mcp-0.2.0-py3-none-any.whl |
|---|---|
| Size | 39.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a5f7f6edf571f2a7dceded95d8fc9e08a5ef25381346ec67b4cbb64ccc4c235
|
|
BLAKE2b-256 checksum How to use checksums |
a87dc7d3044bf2c1232d892e5b8dc79820f492f45f7b59e89626be589099c23f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|