ruts-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ target/
7
+
8
+ # Environments
9
+ .venv/
10
+ venv/
11
+ .env
12
+
13
+ # Tools
14
+ .coverage
15
+ coverage.xml
16
+ .mypy_cache
17
+ .pytest_cache
18
+ .ruff_cache
19
+
20
+ # Documentation
21
+ site/
22
+
23
+ # Editors and OS
24
+ .vscode
25
+ .idea
26
+ .DS_Store
@@ -0,0 +1,17 @@
1
+ MIT License
2
+ Copyright (c) 2026 Sergey Shkarin
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+ The above copyright notice and this permission notice shall be included in all
10
+ copies or substantial portions of the Software.
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17
+ SOFTWARE.
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.5
2
+ Name: ruts-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for ruTS: statistics of Russian texts as tools for LLM agents
5
+ Project-URL: Homepage, https://github.com/SergeyShk/ruTS-mcp
6
+ Project-URL: Repository, https://github.com/SergeyShk/ruTS-mcp
7
+ Project-URL: Documentation, https://sergeyshk.github.io/ruTS-mcp/
8
+ Project-URL: Issues, https://github.com/SergeyShk/ruTS-mcp/issues
9
+ Author-email: Sergey Shkarin <kouki.sergey@gmail.com>
10
+ Maintainer-email: Sergey Shkarin <kouki.sergey@gmail.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE.txt
13
+ Keywords: LLM,MCP,NLP,agents,model context protocol,readability,russian,statistics,text
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Education
17
+ Classifier: Intended Audience :: Information Technology
18
+ Classifier: Intended Audience :: Science/Research
19
+ Classifier: Natural Language :: Russian
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3 :: Only
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
27
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
28
+ Classifier: Topic :: Text Processing
29
+ Classifier: Topic :: Text Processing :: Linguistic
30
+ Classifier: Typing :: Typed
31
+ Requires-Python: >=3.11
32
+ Requires-Dist: fastmcp<5,>=4
33
+ Requires-Dist: platformdirs>=4
34
+ Requires-Dist: ruts<0.17,>=0.16
35
+ Description-Content-Type: text/markdown
36
+
37
+ <p align="center">
38
+ <img src="https://raw.githubusercontent.com/SergeyShk/ruTS-mcp/master/docs/img/ruts-mcp.png" alt="ruTS-mcp" width="480">
39
+ </p>
40
+
41
+ <h1 align="center">ruTS-mcp</h1>
42
+
43
+ <p align="center">
44
+ <b>MCP-сервер для <a href="https://github.com/SergeyShk/ruTS">ruTS</a></b> - статистики русского текста как инструменты для LLM-агентов
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://sergeyshk.github.io/ruTS-mcp/">Документация</a> ·
49
+ <a href="https://pypi.org/project/ruts-mcp/">PyPI</a> ·
50
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/README.en.md">English</a>
51
+ </p>
52
+
53
+ <p align="center">
54
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/v/ruts-mcp?logo=pypi&logoColor=FFE873" alt="Версия"></a>
55
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/pyversions/ruts-mcp.svg?logo=python&logoColor=FFE873" alt="Поддерживаемые версии Python"></a>
56
+ <a href="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml"><img src="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml/badge.svg" alt="Сборка"></a>
57
+ <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
58
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="Лицензия"></a>
59
+ </p>
60
+
61
+ ---
62
+
63
+ **ruTS-mcp** дает LLM-агенту инструменты библиотеки [ruTS](https://github.com/SergeyShk/ruTS), чтобы измерить русский текст, а не оценивать его на глаз. Каждое значение приходит вместе с описанием, прочтением по шкале, если она есть, и предупреждениями, когда значение неустойчиво или не имеет смысла для текста.
64
+
65
+ * **[`analyze_text`](https://sergeyshk.github.io/ruTS-mcp/tools/#analyze_text)** - статистики текста по группам: базовые, удобочитаемость с классом и возрастом читателя, лексическое разнообразие, морфология, фоностатистики, связность, стиль и канцелярит, лексическая сложность, стих, синтаксис
66
+ * **[`kwic`](https://sergeyshk.github.io/ruTS-mcp/tools/#kwic)** - вхождения слова или словосочетания с контекстом
67
+ * **[`collocations`](https://sergeyshk.github.io/ruTS-mcp/tools/#collocations)** - устойчивые сочетания и сочетаемость слова
68
+ * **[`dispersion`](https://sergeyshk.github.io/ruTS-mcp/tools/#dispersion)** - насколько равномерно слова распределены по тексту
69
+ * **[`keyness`](https://sergeyshk.github.io/ruTS-mcp/tools/#keyness)** - ключевые слова относительно русского языка или другого текста
70
+ * **[`compare_texts`](https://sergeyshk.github.io/ruTS-mcp/tools/#compare_texts)** - чем различаются два корпуса текстов по признакам стиля
71
+ * **[Ресурсы и промпты](https://sergeyshk.github.io/ruTS-mcp/resources/)** - шкалы удобочитаемости и нормы стиля, готовые разборы: удобочитаемость, канцелярит, стихотворение, SEO-проверка, сравнение двух текстов
72
+
73
+ ## Установка
74
+
75
+ Сервер запускается через `uvx` из [uv](https://docs.astral.sh/uv/getting-started/installation/), который сам скачает пакет и Python. Подключение к Claude Code:
76
+
77
+ ```bash
78
+ claude mcp add ruts -- uvx ruts-mcp
79
+ ```
80
+
81
+ Для групп `lexical`, `verse` и `syntax` нужны словари и модель spaCy, их скачивает одна команда:
82
+
83
+ ```bash
84
+ uvx ruts-mcp download
85
+ ```
86
+
87
+ Подключение к Claude Desktop, Cursor и другим клиентам и настройки - в [документации](https://sergeyshk.github.io/ruTS-mcp/installation/).
88
+
89
+ ## Лицензия
90
+
91
+ [MIT](https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt). Словари, которые скачивает `ruts-mcp download`, распространяются на условиях их авторов: [частотный словарь](http://dict.ruslang.ru/freq.php) Ляшевской и Шарова, [словарь ударений](https://github.com/Koziev/NLP_Datasets) Козиева (CC0), [модель spaCy](https://github.com/explosion/spacy-models) (MIT).
@@ -0,0 +1,55 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/SergeyShk/ruTS-mcp/master/docs/img/ruts-mcp.png" alt="ruTS-mcp" width="480">
3
+ </p>
4
+
5
+ <h1 align="center">ruTS-mcp</h1>
6
+
7
+ <p align="center">
8
+ <b>MCP server for <a href="https://github.com/SergeyShk/ruTS">ruTS</a></b> - statistics of Russian texts as tools for LLM agents
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://sergeyshk.github.io/ruTS-mcp/en/">Documentation</a> ·
13
+ <a href="https://pypi.org/project/ruts-mcp/">PyPI</a> ·
14
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/README.md">Русский</a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/v/ruts-mcp?logo=pypi&logoColor=FFE873" alt="Version"></a>
19
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/pyversions/ruts-mcp.svg?logo=python&logoColor=FFE873" alt="Supported Python versions"></a>
20
+ <a href="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml"><img src="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml/badge.svg" alt="Build"></a>
21
+ <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
22
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ **ruTS-mcp** gives an LLM agent the tools of the [ruTS](https://github.com/SergeyShk/ruTS) library to measure a Russian text instead of judging it by eye. Every value comes with a description, a reading by a scale where there is one, and warnings when the value is unstable or meaningless for the text. The server answers in Russian.
28
+
29
+ * **[`analyze_text`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#analyze_text)** - statistics of a text by groups: basic, readability with the grade and age of the reader, lexical diversity, morphology, phonetics, cohesion, style and officialese, lexical sophistication, verse, syntax
30
+ * **[`kwic`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#kwic)** - occurrences of a word or a phrase with their context
31
+ * **[`collocations`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#collocations)** - set phrases and the collocates of a word
32
+ * **[`dispersion`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#dispersion)** - how evenly words are spread over the text
33
+ * **[`keyness`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#keyness)** - keywords against the Russian language or another text
34
+ * **[`compare_texts`](https://sergeyshk.github.io/ruTS-mcp/en/tools/#compare_texts)** - how two corpora of texts differ by style features
35
+ * **[Resources and prompts](https://sergeyshk.github.io/ruTS-mcp/en/resources/)** - readability scales and style norms, ready reviews: readability, officialese, a poem, an SEO check, a comparison of two texts
36
+
37
+ ## Installation
38
+
39
+ The server runs with `uvx` from [uv](https://docs.astral.sh/uv/getting-started/installation/), which downloads the package and Python itself. Connecting to Claude Code:
40
+
41
+ ```bash
42
+ claude mcp add ruts -- uvx ruts-mcp
43
+ ```
44
+
45
+ The `lexical`, `verse` and `syntax` groups need dictionaries and a spaCy model; one command downloads them:
46
+
47
+ ```bash
48
+ uvx ruts-mcp download
49
+ ```
50
+
51
+ Connecting to Claude Desktop, Cursor and other clients and the settings are in the [documentation](https://sergeyshk.github.io/ruTS-mcp/en/installation/).
52
+
53
+ ## License
54
+
55
+ [MIT](https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt). The dictionaries that `ruts-mcp download` fetches are distributed on the terms of their authors: the [frequency dictionary](http://dict.ruslang.ru/freq.php) of Lyashevskaya and Sharoff, the [stress dictionary](https://github.com/Koziev/NLP_Datasets) of Koziev (CC0), the [spaCy model](https://github.com/explosion/spacy-models) (MIT).
@@ -0,0 +1,55 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/SergeyShk/ruTS-mcp/master/docs/img/ruts-mcp.png" alt="ruTS-mcp" width="480">
3
+ </p>
4
+
5
+ <h1 align="center">ruTS-mcp</h1>
6
+
7
+ <p align="center">
8
+ <b>MCP-сервер для <a href="https://github.com/SergeyShk/ruTS">ruTS</a></b> - статистики русского текста как инструменты для LLM-агентов
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://sergeyshk.github.io/ruTS-mcp/">Документация</a> ·
13
+ <a href="https://pypi.org/project/ruts-mcp/">PyPI</a> ·
14
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/README.en.md">English</a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/v/ruts-mcp?logo=pypi&logoColor=FFE873" alt="Версия"></a>
19
+ <a href="https://pypi.org/project/ruts-mcp/"><img src="https://img.shields.io/pypi/pyversions/ruts-mcp.svg?logo=python&logoColor=FFE873" alt="Поддерживаемые версии Python"></a>
20
+ <a href="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml"><img src="https://github.com/SergeyShk/ruTS-mcp/actions/workflows/ci.yml/badge.svg" alt="Сборка"></a>
21
+ <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff"></a>
22
+ <a href="https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="Лицензия"></a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ **ruTS-mcp** дает LLM-агенту инструменты библиотеки [ruTS](https://github.com/SergeyShk/ruTS), чтобы измерить русский текст, а не оценивать его на глаз. Каждое значение приходит вместе с описанием, прочтением по шкале, если она есть, и предупреждениями, когда значение неустойчиво или не имеет смысла для текста.
28
+
29
+ * **[`analyze_text`](https://sergeyshk.github.io/ruTS-mcp/tools/#analyze_text)** - статистики текста по группам: базовые, удобочитаемость с классом и возрастом читателя, лексическое разнообразие, морфология, фоностатистики, связность, стиль и канцелярит, лексическая сложность, стих, синтаксис
30
+ * **[`kwic`](https://sergeyshk.github.io/ruTS-mcp/tools/#kwic)** - вхождения слова или словосочетания с контекстом
31
+ * **[`collocations`](https://sergeyshk.github.io/ruTS-mcp/tools/#collocations)** - устойчивые сочетания и сочетаемость слова
32
+ * **[`dispersion`](https://sergeyshk.github.io/ruTS-mcp/tools/#dispersion)** - насколько равномерно слова распределены по тексту
33
+ * **[`keyness`](https://sergeyshk.github.io/ruTS-mcp/tools/#keyness)** - ключевые слова относительно русского языка или другого текста
34
+ * **[`compare_texts`](https://sergeyshk.github.io/ruTS-mcp/tools/#compare_texts)** - чем различаются два корпуса текстов по признакам стиля
35
+ * **[Ресурсы и промпты](https://sergeyshk.github.io/ruTS-mcp/resources/)** - шкалы удобочитаемости и нормы стиля, готовые разборы: удобочитаемость, канцелярит, стихотворение, SEO-проверка, сравнение двух текстов
36
+
37
+ ## Установка
38
+
39
+ Сервер запускается через `uvx` из [uv](https://docs.astral.sh/uv/getting-started/installation/), который сам скачает пакет и Python. Подключение к Claude Code:
40
+
41
+ ```bash
42
+ claude mcp add ruts -- uvx ruts-mcp
43
+ ```
44
+
45
+ Для групп `lexical`, `verse` и `syntax` нужны словари и модель spaCy, их скачивает одна команда:
46
+
47
+ ```bash
48
+ uvx ruts-mcp download
49
+ ```
50
+
51
+ Подключение к Claude Desktop, Cursor и другим клиентам и настройки - в [документации](https://sergeyshk.github.io/ruTS-mcp/installation/).
52
+
53
+ ## Лицензия
54
+
55
+ [MIT](https://github.com/SergeyShk/ruTS-mcp/blob/master/LICENSE.txt). Словари, которые скачивает `ruts-mcp download`, распространяются на условиях их авторов: [частотный словарь](http://dict.ruslang.ru/freq.php) Ляшевской и Шарова, [словарь ударений](https://github.com/Koziev/NLP_Datasets) Козиева (CC0), [модель spaCy](https://github.com/explosion/spacy-models) (MIT).
@@ -0,0 +1,168 @@
1
+ [project]
2
+ name = "ruts-mcp"
3
+ version = "0.1.0"
4
+ description = "MCP server for ruTS: statistics of Russian texts as tools for LLM agents"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = "MIT"
8
+ license-files = ["LICENSE.txt"]
9
+ authors = [{ name = "Sergey Shkarin", email = "kouki.sergey@gmail.com" }]
10
+ maintainers = [{ name = "Sergey Shkarin", email = "kouki.sergey@gmail.com" }]
11
+ keywords = [
12
+ "MCP",
13
+ "model context protocol",
14
+ "LLM",
15
+ "agents",
16
+ "NLP",
17
+ "text",
18
+ "statistics",
19
+ "readability",
20
+ "russian",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 2 - Pre-Alpha",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3 :: Only",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Programming Language :: Python :: 3.14",
31
+ "Intended Audience :: Developers",
32
+ "Intended Audience :: Education",
33
+ "Intended Audience :: Information Technology",
34
+ "Intended Audience :: Science/Research",
35
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
36
+ "Topic :: Text Processing",
37
+ "Topic :: Text Processing :: Linguistic",
38
+ "Typing :: Typed",
39
+ "Natural Language :: Russian",
40
+ ]
41
+ dependencies = [
42
+ "fastmcp>=4,<5",
43
+ "platformdirs>=4",
44
+ "ruts>=0.16,<0.17",
45
+ ]
46
+
47
+ [project.scripts]
48
+ ruts-mcp = "ruts_mcp.cli:main"
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/SergeyShk/ruTS-mcp"
52
+ Repository = "https://github.com/SergeyShk/ruTS-mcp"
53
+ Documentation = "https://sergeyshk.github.io/ruTS-mcp/"
54
+ Issues = "https://github.com/SergeyShk/ruTS-mcp/issues"
55
+
56
+ [build-system]
57
+ requires = ["hatchling>=1.27"]
58
+ build-backend = "hatchling.build"
59
+
60
+ [tool.hatch.build.targets.wheel]
61
+ packages = ["ruts_mcp"]
62
+
63
+ [tool.hatch.build.targets.sdist]
64
+ include = ["/ruts_mcp", "/README.md", "/README.en.md", "/LICENSE.txt"]
65
+
66
+ [[tool.uv.index]]
67
+ name = "testpypi"
68
+ url = "https://test.pypi.org/simple/"
69
+ publish-url = "https://test.pypi.org/legacy/"
70
+ explicit = true
71
+
72
+ [dependency-groups]
73
+ test = ["pytest>=8.3", "pytest-cov>=6.0", "ru-core-news-sm"]
74
+ lint = ["mypy>=1.14", "pre-commit>=4.0", "ruff>=0.9"]
75
+ docs = [
76
+ "mkdocs>=1.6",
77
+ "mkdocs-material>=9.5",
78
+ "mkdocs-static-i18n>=1.2",
79
+ "pymdown-extensions>=10.0",
80
+ ]
81
+ dev = [
82
+ { include-group = "test" },
83
+ { include-group = "lint" },
84
+ { include-group = "docs" },
85
+ ]
86
+
87
+ [tool.uv.sources]
88
+ ru-core-news-sm = { url = "https://github.com/explosion/spacy-models/releases/download/ru_core_news_sm-3.8.0/ru_core_news_sm-3.8.0-py3-none-any.whl" }
89
+
90
+ [tool.ruff]
91
+ target-version = "py311"
92
+ line-length = 99
93
+ src = ["ruts_mcp", "tests"]
94
+
95
+ [tool.ruff.lint]
96
+ select = [
97
+ "A", # flake8-builtins
98
+ "B", # flake8-bugbear
99
+ "C4", # flake8-comprehensions
100
+ "C90", # mccabe
101
+ "E", # pycodestyle errors
102
+ "F", # pyflakes
103
+ "I", # isort
104
+ "N", # pep8-naming
105
+ "PERF", # perflint
106
+ "PTH", # flake8-use-pathlib
107
+ "Q", # flake8-quotes
108
+ "RET", # flake8-return
109
+ "RUF", # ruff-specific
110
+ "SIM", # flake8-simplify
111
+ "UP", # pyupgrade
112
+ "W", # pycodestyle warnings
113
+ ]
114
+ ignore = [
115
+ "E501",
116
+ "RUF001",
117
+ "RUF002",
118
+ "RUF003",
119
+ ]
120
+
121
+ [tool.ruff.lint.mccabe]
122
+ max-complexity = 18
123
+
124
+ [tool.ruff.lint.isort]
125
+ known-first-party = ["ruts_mcp"]
126
+ combine-as-imports = true
127
+
128
+ [tool.ruff.lint.per-file-ignores]
129
+ "tests/**" = ["N801", "N802"]
130
+
131
+ [tool.mypy]
132
+ python_version = "3.11"
133
+ files = ["ruts_mcp"]
134
+ pretty = true
135
+ show_traceback = true
136
+ color_output = true
137
+ allow_redefinition = false
138
+ check_untyped_defs = true
139
+ disallow_any_generics = true
140
+ disallow_incomplete_defs = true
141
+ ignore_missing_imports = true
142
+ implicit_reexport = false
143
+ no_implicit_optional = true
144
+ show_column_numbers = true
145
+ show_error_codes = true
146
+ show_error_context = true
147
+ strict_equality = true
148
+ strict_optional = true
149
+ warn_no_return = true
150
+ warn_redundant_casts = true
151
+ warn_return_any = true
152
+ warn_unreachable = true
153
+ warn_unused_configs = true
154
+ warn_unused_ignores = true
155
+
156
+ [tool.pytest.ini_options]
157
+ addopts = "-v --strict-markers --strict-config --doctest-modules"
158
+ testpaths = ["tests", "ruts_mcp"]
159
+ doctest_optionflags = ["NORMALIZE_WHITESPACE", "ELLIPSIS"]
160
+
161
+ [tool.coverage.run]
162
+ source = ["ruts_mcp"]
163
+ branch = true
164
+
165
+ [tool.coverage.report]
166
+ fail_under = 100
167
+ show_missing = true
168
+ exclude_also = ["if TYPE_CHECKING:", "raise NotImplementedError"]
@@ -0,0 +1,18 @@
1
+ # MCP-сервер Russian Texts Statistics (ruTS-mcp)
2
+ #
3
+ # Copyright (C) 2026
4
+ # Автор: Шкарин Сергей <kouki.sergey@gmail.com>
5
+ # URL: <https://github.com/SergeyShk/ruTS-mcp>
6
+
7
+ from importlib.metadata import PackageNotFoundError, version
8
+
9
+ try:
10
+ __version__ = version("ruts-mcp")
11
+ except PackageNotFoundError:
12
+ __version__ = "0.0.0"
13
+ __description__ = """MCP-сервер для ruTS: статистики русского текста как инструменты для LLM-агентов.
14
+ Требует версию Python 3.11 и выше"""
15
+ __author__ = "Шкарин Сергей"
16
+ __author_email__ = "kouki.sergey@gmail.com"
17
+
18
+ __all__ = ["__version__"]
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,137 @@
1
+ import math
2
+ from dataclasses import dataclass
3
+ from functools import cached_property
4
+ from typing import TYPE_CHECKING, Any, Literal
5
+
6
+ if TYPE_CHECKING:
7
+ from ruts import BasicStats
8
+
9
+ Preset = Literal["plainrussian", "fiction", "academic"]
10
+ GroupResult = tuple[dict[str, Any], list[str]]
11
+
12
+ SIGNIFICANT_DIGITS = 4
13
+ # Группы lexical и verse не считают числа словами, остальные считают
14
+ NO_WORDS_WARNING = "Группа {group} не посчитана: в тексте нет слов, а числа словами не считаются"
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class Options:
19
+ """
20
+ Настройки групп статистик
21
+
22
+ Атрибуты:
23
+ distributions (bool): Добавить распределения в группу basic
24
+ preset (str): Пресет коэффициентов формул удобочитаемости ruTS
25
+ """
26
+
27
+ distributions: bool = False
28
+ preset: Preset = "plainrussian"
29
+
30
+
31
+ class Analysis:
32
+ """
33
+ Текст с настройками и объектами ruTS, общими для групп статистик
34
+
35
+ Описание:
36
+ Базовые статистики нужны группам basic и readability, поэтому они
37
+ считаются один раз за вызов инструмента, при первом обращении
38
+
39
+ Аргументы:
40
+ text (str): Текст на русском языке
41
+ options (Options): Настройки групп; None - по умолчанию
42
+
43
+ Атрибуты:
44
+ text (str): Текст на русском языке
45
+ options (Options): Настройки групп
46
+ """
47
+
48
+ def __init__(self, text: str, options: Options | None = None) -> None:
49
+ self.text = text
50
+ self.options = Options() if options is None else options
51
+
52
+ @cached_property
53
+ def basic(self) -> "BasicStats":
54
+ """Базовые статистики текста с нормированными долями"""
55
+ from ruts import BasicStats
56
+
57
+ return BasicStats(self.text, normalize=True)
58
+
59
+
60
+ def clean(value: Any) -> Any:
61
+ """
62
+ Значение статистики, готовое для JSON
63
+
64
+ Описание:
65
+ Дробное число округляется до четырех значащих цифр; nan и бесконечность,
66
+ которых нет в JSON, становятся None. Остальные значения не меняются
67
+
68
+ Аргументы:
69
+ value (Any): Значение статистики ruTS
70
+
71
+ Вывод:
72
+ Any: Значение для ответа инструмента
73
+
74
+ Пример использования:
75
+ >>> clean(0.0061549), clean(1771.13), clean(float("nan")), clean(7)
76
+ (0.006155, 1771.0, None, 7)
77
+ """
78
+ if isinstance(value, float):
79
+ if not math.isfinite(value):
80
+ return None
81
+ return float(f"{value:.{SIGNIFICANT_DIGITS}g}")
82
+ return value
83
+
84
+
85
+ def stat(
86
+ value: Any,
87
+ description: str,
88
+ share: float | None = None,
89
+ interpretation: str | None = None,
90
+ details: dict[str, Any] | None = None,
91
+ ) -> dict[str, Any]:
92
+ """
93
+ Статистика в ответе инструмента
94
+
95
+ Аргументы:
96
+ value (Any): Значение статистики
97
+ description (str): Что считает статистика
98
+ share (float): Доля от всех слов или символов; None - без доли
99
+ interpretation (str): Прочтение значения по шкале; None - без шкалы
100
+ details (dict[str, Any]): Другие ключи статистики перед описанием
101
+
102
+ Вывод:
103
+ dict[str, Any]: Значение, доля, прочтение, другие ключи и описание
104
+
105
+ Пример использования:
106
+ >>> stat(0.85714, "Доля", interpretation="высокая")
107
+ {'value': 0.8571, 'interpretation': 'высокая', 'description': 'Доля'}
108
+ """
109
+ item: dict[str, Any] = {"value": clean(value)}
110
+ if share is not None:
111
+ item["share"] = clean(share)
112
+ if interpretation is not None:
113
+ item["interpretation"] = interpretation
114
+ item |= details or {}
115
+ item["description"] = description
116
+ return item
117
+
118
+
119
+ def undefined_warnings(stats: dict[str, dict[str, Any]], reason: str) -> list[str]:
120
+ """
121
+ Предупреждение о статистиках, не определенных на тексте
122
+
123
+ Аргументы:
124
+ stats (dict[str, dict[str, Any]]): Статистики группы
125
+ reason (str): Почему значения не определены
126
+
127
+ Вывод:
128
+ list[str]: Предупреждение со списком статистик со значением None или пустой список
129
+
130
+ Пример использования:
131
+ >>> undefined_warnings({"hdd": {"value": None}, "ttr": {"value": 1.0}}, "текст короткий")
132
+ ['Не определены на этом тексте: hdd - текст короткий']
133
+ """
134
+ names = [name for name, item in stats.items() if item["value"] is None]
135
+ if not names:
136
+ return []
137
+ return [f"Не определены на этом тексте: {', '.join(names)} - {reason}"]