Writing Tools MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Writing Tools MCP ServerCheck for spelling mistakes and readability."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Writing Tools MCP Server
This is a Model Context Protocol (MCP) server designed to provide various text analysis tools, assisting users in improving their writing. It is optimized for Claude Desktop with one-click installation via MCP bundles, and also works with other MCP-compatible tools like Cursor and Windsurf.
MCP servers act as a secure bridge or interface, enabling AI models and language assistants to interact with local applications, tools, or data on a user's machine. This server leverages that protocol to offer its specialized writing-specific analysis capabilities to connected AI clients.
Features
This server provides the following text analysis tools:
list_tools: List all available tools in this server.character_count: Return the number of characters in the input text.word_count: Return the number of words in the input text.spellcheck: Return a list of misspelled words in the input text.readability_score: Return readability scores (Flesch, Kincaid, Fog) for the text, section, or paragraph level.reading_time: Return the estimated reading time for the text, section, or paragraph level.keyword_density: Calculate the density of a given keyword in the text.keyword_frequency: Count how often each keyword appears in the text (optionally removing stopwords).top_keywords: Identify the most frequently used keywords in the text.keyword_context: Extract sentences or phrases where a specific keyword appears.passive_voice_detection: Detect passive voice constructions in the text.perplexity_analysis: Analyze text for perplexity and burstiness to detect AI-generated content using GPT-2.stylometric_analysis: Analyze stylometric features (sentence length, length-robust lexical diversity and vocabulary rarity, POS ratios and bigrams, six readability grade-level formulas, syntactic complexity, punctuation idiosyncrasies, hedge/booster rate, per-function-word/Burrows' Delta profile, character n-gram profile) for AI detection, against a built-in or custom baseline.
Related MCP server: hypernym-mcp-server
Install
# Run directly from GitHub (no install needed)
uvx --from git+https://github.com/wdm0006/writing-tools-mcp writing-tools-mcp
# Or install from source
git clone https://github.com/wdm0006/writing-tools-mcp
cd writing-tools-mcp
uv sync
uv run run_server.pyMCP Client Configuration
{
"mcpServers": {
"writingtools": {
"command": "uvx",
"args": ["--from", "git+https://github.com/wdm0006/writing-tools-mcp", "writing-tools-mcp"]
}
}
}Server Configuration
The server reads an optional .mcp-config.yaml from its working directory. Unknown keys and
wrongly typed values are ignored with a warning on stderr, and every missing key falls back to
the default below.
perplexity:
model_name: "gpt2" # Hugging Face model used for perplexity analysis
max_length: 512 # Token window per chunk
overlap: 50 # Token overlap between chunks
device: "cpu" # "cpu" pins the model to CPU
language: "en" # Only "en" is supported
thresholds:
ppl_max: 25.0 # Perplexity at or below this counts as an AI signal
burstiness_min: 2.5 # Burstiness below this counts as an AI signal
stylometry:
default_baseline: "brown_corpus"
custom_baselines_dir: "data/baselines/custom_baselines"
thresholds:
warning_z: 2.0 # |z| for a warning
error_z: 3.0 # |z| for an error
ai_confidence_threshold: 0.7 # Confidence needed to flag AI authorship
features:
enabled: ["sentence_length", "ttr", "hapax", "pos_ratios", "punctuation", "function_words"]
pos_tags: ["NOUN", "VERB", "ADJ", "ADV", "ADP", "DET", "PRON", "CONJ", "NUM", "PART"]
logging:
level: "INFO" # CRITICAL, ERROR, WARNING, INFO, or DEBUG
format: "%(asctime)s - %(levelname)s - %(message)s" # Standard `logging` format stringSet logging.level: "DEBUG" when reporting a problem. Logs are always written to stderr — stdout
carries the MCP JSON-RPC stream — and an unrecognized level falls back to INFO with a warning
rather than stopping the server.
perplexity.language, stylometry.default_baseline, stylometry.custom_baselines_dir and
stylometry.features are accepted and type-checked, but nothing reads them yet; the baseline and
language are chosen per call through the stylometric_analysis and perplexity_analysis
arguments.
Custom Baselines
stylometric_analysis compares a text's features against a baseline (brown_corpus by default)
and flags whatever is an outlier relative to it. Brown Corpus is 1961 published news and fiction;
it answers "does this read like typical published prose," which is often not the question you
actually want answered. A more useful question for judging your own drafts is "does this read like
my own pre-existing writing" - answered by building a baseline from a corpus of your own text.
uv run scripts/build_baseline.py my_own_voice path/to/txt/files/Each *.txt file in the directory is treated as one document (strip front matter, markdown, and
code fences first - the script analyzes exactly the text it's given). The baseline is saved under
data/baselines/custom_baselines/ and is immediately usable:
stylometric_analysis(text, baseline="my_own_voice")By default the builder (server.stylometry.build_baseline_from_texts) only computes mean/std for
a curated, length-robust feature set: avg_sentence_len, sentence_len_std, fog/kincaid/smog/
coleman_liau/ari/dale_chall (six readability grade-level formulas), mtld/mattr/mtld_lemma
(length-robust lexical diversity, on surface forms and lemmas respectively), mean_word_frequency
(vocabulary rarity, via wordfreq - distinct from diversity: how common the words used are, not
how many distinct words there are), word_len_std, lexical_density, five punctuation-idiosyncrasy
ratios (semicolon_ratio, em_dash_ratio, ellipsis_ratio, exclamation_ratio,
parenthetical_rate), hedge_rate/booster_rate (epistemic-marker word categories),
mean_dependency_distance/subordinate_clause_ratio (syntactic complexity read off the dependency
parse), the ADP/DET POS ratios, a curated 10-bigram POS-sequence profile (see below), a
Burrows'-Delta-style per-function-word frequency profile (see below), and a character n-gram
orthographic profile (see below). Type-token ratio and the hapax legomena rate are deliberately left
out: both fall monotonically as a document gets longer, for any author, so comparing them across a
corpus of mixed document lengths mostly measures length rather than style - mtld/mattr/mtld_lemma
exist specifically as length-robust replacements for them (McCarthy & Jarvis 2010; Covington & McFall
2010). fourgram_repetition_rate and zipf_slope are computed but not in the default set: unlike
ttr/hapax, we haven't verified whether they vary with length, so they're opt-in only. Pass
--all-features to include every feature extract_features computes, length-confounded or not.
Burrows' Delta. Rather than one aggregate function_word_ratio, the builder also tracks each of
StylemetricAnalyzer's ~100 function words individually (mean/std per word across the corpus).
stylometric_analysis z-scores each word against its own baseline entry, then reduces all of them
to one number - burrows_delta, the mean absolute z-score across every word scored - the classic
Burrows' Delta statistic (Burrows 2002), built for exactly this kind of small, single-author corpus.
A large burrows_delta (above the usual warning z-threshold) raises a distinct_function_word_profile
flag. Pass function_words=[] to build_baseline_from_texts (or a custom word list) to change or
skip this dimension.
POS bigrams. Published authorship-attribution work reports POS-tag bigrams/trigrams
discriminating authors substantially better than single-tag POS ratios alone. The builder tracks a
small, curated 10-bigram subset by default (DEFAULT_ROBUST_POS_BIGRAMS - noun- and
verb-phrase-initiation patterns like DET_NOUN, VERB_ADP), scored the same way as pos_ratios
under a posbi_ prefix, rather than all ~289 possible tag combinations - most bigrams are too sparse
per document (a handful of occurrences in an 800-word post) to average reliably. Pass pos_bigrams=
to change the tracked set, or [] to skip this dimension.
Character n-gram profile. A PAN/CLEF-style orthographic fingerprint: character 4-gram relative
frequencies, normalized per document. Individual n-grams are too sparse to z-score the way pos_ratios
or function words are (most 4-grams occur 0-2 times in a typical post), so this is compared as a
whole profile instead - calculate_char_ngram_similarity computes the cosine similarity between a
draft's profile and the baseline's aggregate profile (kept to the top char_ngram_top_k n-grams by
corpus-wide frequency, default 300, to bound the baseline's file size). stylometric_analysis surfaces
this as a top-level char_ngram_similarity (not part of z_scores or flags - there's no calibrated
threshold for it yet). Note this is sensitive to vocabulary/topic, not just style: a post using very
different subject-matter vocabulary from the baseline corpus will score a low similarity for that
reason alone, not necessarily because of authorship. Pass char_ngram_top_k=0 to skip this dimension.
data/baselines/custom_baselines/mcginniscommawill_pre2020.json ships as a worked example: 102
pre-2020 posts from mcginniscommawill.com, built with this script.
Building the Bundle
To create a .mcpb bundle for distribution:
make build-mcpbThis creates writing-tools-mcp.mcpb which can be installed in Claude Desktop.
Usage Examples
You can configure any MCP client (like Claude.ai, Windsurf, or Cursor) to connect to it. Here are some example prompts you could give to an AI assistant connected to this MCP server:
General Analysis:
"List the available writing tools." (Calls
list_tools)"Analyze the text below for readability using the standard scores." (Provide text, calls
readability_score)"Check this document for spelling mistakes." (Provide text, calls
spellcheck)"How long would it take someone to read this blog post?" (Provide text, calls
reading_time)
Keyword Analysis:
"What are the top 5 keywords in the following abstract?" (Provide text, calls
top_keywordswithtop_n=5)"Calculate the keyword density for 'artificial intelligence' in this paper." (Provide text, calls
keyword_densitywithkeyword="artificial intelligence")"Show me all sentences containing the term 'MCP'." (Provide text, calls
keyword_contextwithkeyword="MCP")"Search the web for pages based on the top 5 keyworkds in this text, and compare those pages to mine" (Provide text, calls
top_keywordswithtop_n=5, then passes that to a different web search tool if available)
Style and Structure:
"Identify any sentences using passive voice in my draft." (Provide text, calls
passive_voice_detection)"What's the word count for this paragraph?" (Provide text, calls
word_count)"Get the readability scores for each section of this document." (Provide markdown text, calls
readability_scorewithlevel="section")
AI Detection:
"Analyze this text for signs of AI generation using perplexity analysis." (Provide text, calls
perplexity_analysis)"Check if this essay was written by AI using stylometric analysis." (Provide text, calls
stylometric_analysis)"Compare the writing style of this text against human writing baselines." (Provide text, calls
stylometric_analysis)"Is this text too uniform in sentence structure to be human-written?" (Provide text, calls both AI detection tools)
Tool Reference
Below is a detailed reference for each tool provided by the server.
list_tools
Description: List all available tools in this server.
Parameters: None
Returns:
list[str]- A list of tool names.
character_count
Description: Return the number of characters in the input text.
Parameters:
text(str): The input text.
Returns:
int- The total character count.
word_count
Description: Return the number of words in the input text.
Parameters:
text(str): The input text.
Returns:
int- The total word count (based on whitespace splitting).
spellcheck
Description: Return a list of misspelled words in the input text.
Parameters:
text(str): The input text.
Returns:
list[str]- A list of words identified as potentially misspelled.
readability_score
Description: Return readability scores using Flesch Reading Ease, Flesch-Kincaid Grade Level, and Gunning Fog index.
Parameters:
text(str): The text to analyze.level(str, optional): Granularity of analysis. Options:"full"(default): Score the entire text."section": Score the full text and each markdown section (identified by#headings) separately."paragraph": Score the full text and each paragraph (separated by blank lines) separately.
Returns:
dict- A dictionary containing the scores. Structure depends on thelevelparameter. For"full", it returns{"flesch": float, "kincaid": float, "fog": float}. For other levels, it returns nested dictionaries. ReturnsNonefor scores if the text segment is too short.
reading_time
Description: Return the estimated reading time for the input text (based on
textstat). Markdown markup is stripped before estimating, so syntax characters and link/image target URLs do not count toward the time.Parameters:
text(str): The text to analyze.level(str, optional): Granularity of analysis. Options:"full"(default): Calculate for the entire text."section": Calculate for the full text and each markdown section."paragraph": Calculate for the full text and each paragraph.
Returns:
dict- A dictionary containing the estimated reading time in minutes. Structure depends on thelevelparameter.
keyword_density
Description: Calculate the density of a given keyword in the text (case-insensitive, lemmatized). Multi-word keywords are matched as complete, contiguous phrases.
Parameters:
text(str): The text to analyze.keyword(str): The keyword or phrase to search for.
Returns:
float- The density percentage ( (keyword count / total words) * 100 ).
keyword_frequency
Description: Count how often each keyword (token) appears in the text.
Parameters:
text(str): The text to analyze.remove_stopwords(bool, optional, default=True): Whether to exclude common English stopwords (e.g., 'the', 'a', 'is').
Returns:
dict- A dictionary mapping each keyword (or lemma) to its frequency count.
top_keywords
Description: Identify the most frequently used keywords in the text.
Parameters:
text(str): The text to analyze.top_n(int, optional, default=10): The number of top keywords to return.remove_stopwords(bool, optional, default=True): Whether to exclude common English stopwords.
Returns:
list[tuple[str, int]]- A list of tuples, where each tuple contains a keyword (or lemma) and its count, sorted by frequency in descending order.
keyword_context
Description: Extract sentences where a specific keyword (case-insensitive, lemmatized) appears. Multi-word keywords are matched as complete, contiguous phrases.
Parameters:
text(str): The text to search within.keyword(str): The keyword or phrase to find.
Returns:
list[str]- A list of sentences containing the keyword or phrase, matched on lemmas.
passive_voice_detection
Description: Detect sentences containing passive voice constructions (based on a simplified pattern matching using spaCy).
Parameters:
text(str): The text to analyze.
Returns:
list[str]- A list of sentences identified as potentially containing passive voice.
perplexity_analysis
Description: Analyze text for perplexity and burstiness to detect AI-generated content using GPT-2. Computes document-level and sentence-level perplexity along with burstiness (variance of perplexity across sentences). Low perplexity combined with low burstiness is a statistical signal used by AI detectors.
Parameters:
text(str): The text to analyze.language(str, optional, default="en"): Language code (only "en" supported currently).
Returns:
dict- Analysis results including:doc_ppl(float | null): Document-level perplexity score;nullwhen no sentence could be scoreddoc_burstiness(float | null): Burstiness score (standard deviation of sentence perplexities);nullwhen fewer than two sentences were scored, since the standard deviation is undefined theresentences(list): Sentence-level perplexity scoresconfig(dict): Model configuration and thresholdsflags(dict): AI detection flags with confidence and explanations
stylometric_analysis
Description: Analyze text for stylometric features and detect AI-generated content. Computes sentence length distribution, lexical diversity (TTR/Hapax, plus the length-robust
mtld/mattr/mtld_lemma) and vocabulary rarity (mean_word_frequency, viawordfreq), POS ratios and a curated POS-bigram profile, six readability grade-level formulas (Fog, Kincaid, SMOG, Coleman-Liau, ARI, Dale-Chall), syntactic complexity from the dependency parse (mean_dependency_distance,subordinate_clause_ratio), punctuation idiosyncrasies (semicolon/em-dash/ellipsis/exclamation/parenthetical rate), hedge/booster epistemic-marker rates, n-gram repetition and Zipf-slope, a per-function-word frequency profile reduced to a Burrows' Delta score, and a character n-gram orthographic profile compared via cosine similarity. Flags outliers relative to a baseline (built-inbrown_corpus, or a custom baseline built from your own writing) using z-score analysis.Parameters:
text(str): The text to analyze.baseline(str, optional, default="brown_corpus"): Baseline corpus name for comparison. See Custom Baselines to build your own.language(str, optional, default="en"): Language code (only "en" supported currently).
Returns:
dict- Stylometric analysis including:features(dict): Extracted stylometric features (sentence length, TTR/hapax/mtld/mattr/mtld_lemma,mean_word_frequency,word_len_std,lexical_density, POS ratios,pos_bigram_ratios,fog/kincaid/smog/coleman_liau/ari/dale_chall,mean_dependency_distance,subordinate_clause_ratio, punctuation-idiosyncrasy ratios,hedge_rate/booster_rate,fourgram_repetition_rate,zipf_slope,function_word_freqs, etc. -char_ngram_profileis computed internally forchar_ngram_similaritybelow but omitted here, as a several-hundred-entry intermediate)z_scores(dict): Z-scores of features against the baseline, including per-wordfw_<word>scores and the aggregateburrows_delta, and per-bigramposbi_<tag>_<tag>scoresflags(dict): AI detection flags with confidence levels and explanationssentence_analysis(list): Per-sentence analysis with z-scoreschar_ngram_similarity(float | null): Cosine similarity between this text's character n-gram profile and the baseline's (see Custom Baselines);nullwhen the baseline has no character n-gram profile (e.g.brown_corpus)config(dict): Baseline information and analysis thresholds
Detector Benchmark
benchmarks/ is an offline evaluation surface, separate from the MCP server. It scores
the AI-detection code against committed labeled corpora and writes a report, so the
shipped thresholds can be argued about with numbers instead of intuition. It changes no
tool, default, or threshold.
uv run benchmarks/run_benchmark.pySee benchmarks/README.md for what the corpora are, what the
report contains, and how far the results reproduce. Corpus text is third-party and is
licensed separately from this repository's code.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
License
This is MIT licensed
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- CalmSEOOAuthcom.calmseo
SEO MCP server for keyword research, SERP analysis, audits, and Search Console workflows.
MCP Server for Slima - AI Writing IDE for Novel Authors with AI Beta Reader.
An MCP server that integrates with Discord to provide AI-powered features.
MCP server for Midjourney AI image generation and editing
Related MCP Servers
- FlicenseAqualityCmaintenanceMCP server for Originality.ai that provides tools for AI detection, plagiarism checking, fact verification, readability analysis, grammar/spelling, and SEO optimization.52-
- FlicenseNot gradedqualityDmaintenanceMCP server providing semantic text analysis and compression tools via Hypernym AI's API.6-
- FlicenseNot gradedqualityDmaintenanceA professional MCP server for analyzing content against the official Microsoft Writing Style Guide, enabling style, grammar, terminology, and accessibility checks via AI tools like VS Code and GitHub Copilot.1-

winston-ai-mcpofficial
AlicenseAqualityAmaintenanceMCP server for Winston AI's detection tools, enabling AI content detection, plagiarism checking, image analysis, and text comparison.4608MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wdm0006/writing-tools-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server