# ai.etincel/etincel-nonfiction (npm · etincel)

Trainable non-fiction writing voice, presets, and an anti-AI-tells audit for Claude, via MCP.

- Trust score: 65/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-20

## Components

- remote · `etincel.ai`: 38/100, [markdown](https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/api-mcp.md), [page](https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/api-mcp)
- npm · `etincel`: 65/100 (this document), [markdown](https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel.md), [page](https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel)

## Channel facts

- Registry: `npm`
- Package: `etincel`
- Version: `0.10.1`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-20.

- **Supply Chain Security**: 86/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Install-script check failed: the install command fetches or executes arbitrary code (inline_eval). An install hook runs on every machine, in CI, and on transitive installs, whether or not you ever run the server.
  - 30 of 95 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 48/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 4 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 73/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 3308 tokens (~165/item across 20 items; 20 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 0/100
  - Stability not yet verified: not enough scan history yet (needs a 30-day window).
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### Claude

```bash
claude mcp add ai-etincel-etincel-nonfiction -- npx -y etincel
```

### Codex

```bash
codex mcp add ai-etincel-etincel-nonfiction -- npx -y etincel
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ai-etincel-etincel-nonfiction": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "etincel"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ai-etincel-etincel-nonfiction --command npx --arg -y --arg etincel
```

### Hermes

```yaml
mcp_servers:
  ai-etincel-etincel-nonfiction:
    command: "npx"
    args: ["-y", "etincel"]
```

### Other

```json
{
  "mcpServers": {
    "ai-etincel-etincel-nonfiction": {
      "command": "npx",
      "args": [
        "-y",
        "etincel"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-16 (score 65, +40)

- [security improvement] Known CVEs: unverified → pass
- [security] Stability: Stability not yet verified: not enough scan history yet (needs a 30-day window).
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Dependency health: unverified → 0.85
- [functional] First check of Schema quality: fail
- [functional] First check of Tool coverage: 100
- [functional] First check of Schema quality: fail
- [functional] First check of Schema quality: excellent

### 2026-08-15 (score 25)

First indexed and scored.

## MCP tools (20)

### `list_styles` (~85 tokens)

List writing styles

List every available style: premade emotional-tone presets, any voices the user has trained from their own samples, and (if a .etincelrc in the current repo defines one) the shared team style, id 'team'. Call this before drafting or revising non-fiction prose if the caller hasn't been told which style to use, or if the user asks what styles exist.

### `get_style_guide` (~167 tokens)

Get a style guide

Fetch the full drafting guide for one style (a preset id like 'direct-warm', the id of a trained voice, or 'team' for the shared style a .etincelrc in the current repo defines, if any). Returns prose instructions to follow while drafting or revising: sentence rhythm, tone dials, and (for trained voices) the writer's own measured habits. If a .etincelrc in the current repo sets team-wide instructions, those are folded into every style's instructions, not just 'team''s. Read this before drafting; it is context for you, the drafting model, not a tool that writes prose itself.

Input parameters:

- `styleId` (string, required): Preset id, trained voice id, or 'team', from list_styles.

### `train_style` (~304 tokens)

Train a voice from writing samples

Analyze one or more of the user's own writing samples (emails, posts, essays, memos: real finished text they wrote or approved) and persist a trained voice profile under that name. Measures sentence length and variance, paragraph rhythm, contraction rate, em-dash and semicolon habits, fragment use, structural entropy (sentence-opener variety and punctuation-mark variety), and recurring phrasing. Call again with the same name and new samples to add more training data to that voice; the new samples blend into its existing measurements rather than replacing them. If the voice may have been renamed since it was created, pass its id (from list_styles) instead so the right voice is targeted regardless of its current name. This never fabricates a voice from a description; it only learns from real text the user supplies.

Input parameters:

- `id` (string): Deprecated alias for styleId.
- `name` (string, required): Name for this voice, e.g. the user's name or a project name.
- `samples` (array, required): One or more raw text samples of the user's own writing, at least a few paragraphs each for a reliable read.
- `styleId` (string): Id of an existing trained voice to train further, from list_styles. Use this to precisely target a voice you want to add more samples to, especially if it's been renamed. Omitted: falls back to match…

### `create_style_from_dials` (~161 tokens)

Create a style from dials

Build a style profile from explicit dial values instead of writing samples: for when the user wants to hand-tune a voice (or doesn't have samples handy). 3 persona dials (formality, warmth, directness, 0-10) plus 8 mechanical dials (0-100, including entropy: how much AI-typical structural regularity to break) that map onto the same measurements train_style extracts from real text, so a dial-built style and a trained voice are the same shape. Call again with the same name to overwrite.

Input parameters:

- `dials` (object, required): The 11 dial values (3 persona + 8 mechanical) that define this style's voice.
- `name` (string, required): Name for this voice.

### `update_style` (~159 tokens)

Edit an existing custom style

Rename a trained voice or adjust its dials in place, keeping its id (and default-style pointer) stable. Persona dials (formality, warmth, directness) always apply; the mechanical dials only take effect if the voice has no writing samples (was built from dials, not trained). A sample-trained voice keeps its measured mechanical stats regardless of what's passed here.

Input parameters:

- `dials` (object, required): The 11 dial values (3 persona + 8 mechanical) that define this style's voice.
- `id` (string): Deprecated alias for styleId.
- `name` (string, required): New (or unchanged) name for this voice.
- `styleId` (string): Id of the trained voice to edit, from list_styles.

### `fork_style` (~296 tokens)

Fork a preset or published community style into a trained voice

Copy a style into a new trained voice under the given name, seeded with its persona dials and drafting guide. Two kinds of source: a premade preset (e.g. 'pr-review', 'linkedin-post'), or another installer's style published publicly on the hosted gallery, addressed as "handle/slug" (e.g. "jpleblanc/blunt-memo", the same address shown on its public page at etincel.ai/v/handle/slug). A public-style fork also carries over its 8 mechanical dials (rhythm, sentence length, em-dash use, etc.) and any banned words, custom words, or drafting instructions the source installer set specifically for that style, never their private account-wide dictionary or instructions; a preset fork only ever has persona dials and entropy to carry, since a preset has no measured mechanics. A public-style fork makes one network call to etincel.ai to fetch it; a preset fork never leaves this install. The fork is then a normal trained voice: retrain it with train_style from real samples, or hand-tune it with update_style, without touching the original.

Input parameters:

- `name` (string, required): Name for the new trained voice.
- `presetId` (string): Deprecated alias for styleId.
- `styleId` (string): Id of the preset to fork (from list_styles), or a published style's "handle/slug" address.

### `delete_style` (~56 tokens)

Delete a trained voice

Permanently delete a trained voice profile by id. Does not affect premade presets.

Input parameters:

- `id` (string): Deprecated alias for styleId.
- `styleId` (string): Id of the trained voice to delete, from list_styles.

### `set_default_style` (~79 tokens)

Set the default style

Set which style (preset or trained voice) should be used by default for this user going forward, so it doesn't need to be re-specified every time.

Input parameters:

- `id` (string): Deprecated alias for styleId.
- `styleId` (string): Id of the style (preset or trained voice) to set as default, from list_styles.

### `check_voice_match` (~312 tokens)

Check a draft's rhythm against a trained voice

Compare a piece of drafted text's measured sentence/paragraph rhythm and mechanics against a trained or custom voice's baseline (sentence length, rhythm variance, paragraph variance, contraction rate, em-dash use, fragment use, question use, structural entropy). Use this after drafting in a voice to check whether the draft's rhythm actually landed close to it, instead of just eyeballing it. Returns a verdict ('on rhythm' / 'some drift' / 'off rhythm'), a match score, specific dials that drifted with a plain-language note for each, and a caveat you should relay alongside the verdict: this is a rhythm/mechanics measurement, not an authorship or AI-detection check, so text merely shaped like the voice (by anyone, or any tool) can come back 'on rhythm', and a genuine off-voice draft by the target writer can still come back drifted. Confidence comes back "low" on short input, since a handful of sentences isn't enough to read rhythm reliably; treat a low-confidence verdict as provisional. Only works against trained or custom voices (from train_style, create_style_from_dials, or fork_style), not bare presets, which have no measured baseline; fork_style a preset first if you want to check a draft against one.

Input parameters:

- `id` (string): Deprecated alias for styleId.
- `styleId` (string): Id of the trained or custom voice to compare against, from list_styles.
- `text` (string, required): The drafted text to check.

### `check_self_repetition` (~225 tokens)

Check a draft for habits repeated across a voice's past pieces

Compare a piece of drafted text against a trained voice's own recent training samples for two kinds of self-repetition: opening the same way ("you've opened this way in 4 of your last 6 pieces"), and reusing a characteristic phrase across several of them. This is about the writer's own recurring habits, not AI-writing tells; use audit_text for those. Only meaningful for a voice trained from real samples (train_style) with at least 3 recorded samples; dial-tuned or preset-forked voices, or ones with too little history yet, come back with an empty findings list rather than an error. Only the local install tracks sample history today, so a hosted/remote connection may always report zero history. A signal to weigh, same trust-mode spirit as audit_text: never rewrite the draft on the strength of this alone.

Input parameters:

- `id` (string): Deprecated alias for styleId.
- `styleId` (string): Id of the trained voice to compare against, from list_styles.
- `text` (string, required): The drafted text to check.

### `audit_text` (~395 tokens)

Audit text for AI writing tells

Deterministically scan a piece of non-fiction text for common AI-writing tells: banned hype vocabulary, chatbot fingerprints, and structural patterns (uniform paragraph length, stacked transitions, em-dash overuse, rule-of-three compulsion, and more), plus this installer's own banned/custom word lists from add_banned_word/add_custom_word (the 'global' list, merged with a style's own list if styleId is given), plus a repo-local .etincelrc/.etincelrc.json/etincel.config.json if one exists at or above the current directory (dictionary as code, reviewable and versioned). Returns a tier (green/yellow/orange/red), a numeric score, specific findings with severity and location, and a strengths signal (specificity density, concrete-vs-abstract ratio, sentence-rhythm variation). Read strengths too, not just findings: it's the counter-signal against fixing every flagged word into flat, sterile prose. Never a silent rewrite. Use this to show the user what's flagged and why, so they stay in control of any change; only rewrite what they ask you to rewrite.

Input parameters:

- `register` (string): Register to calibrate strictness against. Defaults to 'general'.
- `sourceFacts` (array): Elicited answers from the skill's Step 0.5 (details only the user could supply, never generated): specific spans the draft was supposed to draw on. When given, checks how many actually made it into t…
- `styleId` (string): Style id (from list_styles) whose own banned/custom word list should merge with the installer's global list. Omit to use only the global list.
- `text` (string, required): The text to audit.

### `second_read` (~140 tokens)

Get a second read on a draft (hosted only)

A single model call that reads a draft and reports what a careful human editor would notice: unscored, untiered, and never a rewrite. Distinct from audit_text, which is deterministic and reproducible; this is neither, so weigh it as one more opinion, not a verdict, and never gate a decision on it alone. Requires the hosted server (https://etincel.ai/api/mcp): the local (stdio) install has no account to bill a model call against, so this always fails there with a clear explanation. audit_text remains fully available locally, no account needed.

Input parameters:

- `text` (string, required): The text to read.

### `add_banned_word` (~147 tokens)

Add a word to a banned-words list

Add a term to this installer's own banned-words list, checked by audit_text alongside the built-in AI-tell corpus. Without styleId, this adds to the global list, which applies to every style. With styleId, it only applies when auditing against that specific style, merged on top of the global list. Use this when the user says something like 'add [word] to my banned words list' or 'never let me use [word] again'.

Input parameters:

- `styleId` (string): Style id to scope this ban to, from list_styles. Omit to add to the global list.
- `word` (string, required): The term or short phrase to ban.

### `remove_banned_word` (~69 tokens)

Remove a word from a banned-words list

Remove a term from this installer's banned-words list (global, or a specific style's list).

Input parameters:

- `styleId` (string): Style id the ban was scoped to, from list_styles. Omit for the global list.
- `word` (string, required): The term to unban.

### `add_custom_word` (~167 tokens)

Add a word to a custom (allowed) words list

Add a term to this installer's own allowed-words list, so audit_text never flags it even if it matches the built-in corpus or a banned word: the 'corporate dictionary' case, e.g. an org's own acronyms or house terms. Without styleId, this adds to the global list. With styleId, it only applies to that specific style, merged on top of the global list. Use this when the user says something like 'add [word] to my custom words list' or 'stop flagging [word], it's one of ours'.

Input parameters:

- `styleId` (string): Style id to scope this to, from list_styles. Omit to add to the global list.
- `word` (string, required): The term or short phrase to always allow.

### `remove_custom_word` (~71 tokens)

Remove a word from a custom (allowed) words list

Remove a term from this installer's allowed-words list (global, or a specific style's list).

Input parameters:

- `styleId` (string): Style id the allowance was scoped to, from list_styles. Omit for the global list.
- `word` (string, required): The term to remove from the allowed list.

### `list_dictionary` (~92 tokens)

List a dictionary's banned and custom words

Show the banned-words and custom (allowed) words lists for a scope: the global list (default), or a specific style's list. For a style, also returns the effective merged list (that style's words plus the global ones): what audit_text actually applies when that style is selected.

Input parameters:

- `styleId` (string): Style id to look up, from list_styles. Omit for the global list.

### `set_style_instructions` (~177 tokens)

Set custom instructions for a style

Save free-text drafting rules layered on top of a style's voice: required elements ('always include a CTA'), audience notes, forbidden topics, format constraints, anything that isn't about sentence rhythm or tone. Overwrites whatever was saved for this scope. Without styleId, this sets the global instructions, which apply to every style. With styleId, it only applies to that specific style, merged after the global instructions (get_style_guide returns the merged result automatically). Use this when the user says something like 'for this style, always end with a CTA' or 'remember: never mention pricing in emails'.

Input parameters:

- `instructions` (string, required): The full instructions text for this scope, replacing whatever was there.
- `styleId` (string): Style id to scope this to, from list_styles. Omit to set the global instructions.

### `clear_style_instructions` (~53 tokens)

Clear custom instructions for a style

Remove the saved instructions for a scope (global, or a specific style), leaving it empty.

Input parameters:

- `styleId` (string): Style id to clear, from list_styles. Omit to clear the global instructions.

### `get_style_instructions` (~83 tokens)

Get custom instructions for a style

Show the saved instructions for a scope: the global instructions (default), or a specific style's own. For a style, also returns the effective merged text (global plus that style's own) that get_style_guide already folds in automatically.

Input parameters:

- `styleId` (string): Style id to look up, from list_styles. Omit for the global instructions.

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel#diagnostics

## Score history

- 2026-08-20: 65
- 2026-08-19: 65
- 2026-08-18: 65
- 2026-08-17: 65
- 2026-08-16: 65
- 2026-08-15: 25

## Links

- npm package: https://www.npmjs.com/package/etincel
- Socket report: https://socket.dev/npm/package/etincel
- Repository: https://github.com/AIStoryHub/etincel
- Website: https://etincel.ai/connect
- Changelog RSS feed: https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel.xml
- Changelog JSON feed: https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel.json
- HTML version of this page: https://verifymcp.io/servers/ai-etincel-etincel-nonfiction/etincel
