Skip to content

brfid/oldspeak

Repository files navigation

oldspeak

This MCP implements practical checks derived from George Orwell's six rules in Politics and the English Language.

Scope

Current implementation ships one MCP tool:

  • analyze_document(path, ...)

The tool analyzes a single file, aggregates analyzer output, applies server-side filters, and returns normalized violations plus metadata (cached, errors, analyzers_run).

Requirements

  • Python 3.11+
  • POSIX shell

Cold Start

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e ".[dev]"
python -m spacy download en_core_web_sm

Run

Run as a Python module:

source .venv/bin/activate
python -m oldspeak.server

Run through FastMCP CLI:

source .venv/bin/activate
fastmcp run oldspeak/server.py --transport stdio
fastmcp run oldspeak/server.py --transport http --port 8000

Inspect server metadata:

source .venv/bin/activate
fastmcp inspect oldspeak/server.py --format fastmcp

MCP Interface

Tool: analyze_document

Required input:

  • path: str

Optional filters:

  • include_analyzers: list[str] | None
  • include_rules: list[str] | None
  • severities: list[str] | None
  • has_suggestion: bool | None
  • line_start: int | None
  • line_end: int | None
  • limit: int | None

Validation:

  • line_start and line_end must be >= 1 when provided.
  • line_start <= line_end.
  • limit >= 0.

Response fields:

  • path: str (absolute path)
  • violations: list[dict]
  • total: int
  • analyzers_run: list[str]
  • errors: list[{analyzer: str, error: str}]
  • cached: bool

Violation fields:

  • analyzer, rule, severity, message, text
  • offset, length, line, end_line
  • suggestion, context, meta

Resource: oldspeak://rules

Returns the rule summary text used by this server.

Runtime Architecture

  • oldspeak/server.py: FastMCP registration and input/output surface
  • oldspeak/analysis_cache.py: mtime/size cache-aside for file analyses
  • oldspeak/workflow/collector.py: parallel analyzer execution, failure isolation, line normalization, dedupe, stable sort
  • oldspeak/filters.py: post-collection filtering
  • oldspeak/analyzers/*.py: analyzer implementations
  • oldspeak/wordlists/*: phrase and substitution data

Example Fixtures

  • examples/noisy_policy_memo.txt
  • examples/manifesto_draft.txt
  • examples/clean_control.txt

Testing

Run all tests:

source .venv/bin/activate
pytest

Test coverage includes:

  • analyzer unit tests
  • collector behavior tests
  • cache hit/miss/mtime tests
  • server filter semantics tests
  • example prose integration tests
  • MCP runtime tests via fastmcp.Client (stdio path + filter/failure paths)
  • HTTP transport smoke test using StreamableHttpTransport

Quality Gates

Local quality/security commands used before publishing:

source .venv/bin/activate
ruff check .
mypy oldspeak
bandit -r oldspeak -q
vulture oldspeak tests --min-confidence 80
pip-audit --ignore-vuln CVE-2025-69872
pytest -q

Notes:

  • CVE-2025-69872 (via diskcache) currently has no published fix version. CI is configured to ignore this one CVE until an upstream patch is available.

MCP Smoke Check (Manual)

source .venv/bin/activate
python - <<'PY'
import asyncio
import json
from fastmcp import Client

async def main():
    async with Client("oldspeak/server.py") as client:
        result = await client.call_tool("analyze_document", {"path": "examples/noisy_policy_memo.txt", "limit": 5})
        payload = json.loads(result.content[0].text)
        print(payload["total"], payload["cached"])

asyncio.run(main())
PY

Extension Point

To add an analyzer:

  1. Add a callable in oldspeak/analyzers/ and decorate with @analyzer(name=..., description=...).
  2. Add module name to _BUILTIN_MODULES in oldspeak/analyzers/__init__.py.
  3. Add tests under tests/.

About

MCP implementation of George Orwell's essay "Politics and the English Language"

Resources

License

Stars

Watchers

Forks

Contributors

Languages