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.
- ruts_mcp-0.1.0/.gitignore +26 -0
- ruts_mcp-0.1.0/LICENSE.txt +17 -0
- ruts_mcp-0.1.0/PKG-INFO +91 -0
- ruts_mcp-0.1.0/README.en.md +55 -0
- ruts_mcp-0.1.0/README.md +55 -0
- ruts_mcp-0.1.0/pyproject.toml +168 -0
- ruts_mcp-0.1.0/ruts_mcp/__init__.py +18 -0
- ruts_mcp-0.1.0/ruts_mcp/__main__.py +4 -0
- ruts_mcp-0.1.0/ruts_mcp/analysis.py +137 -0
- ruts_mcp-0.1.0/ruts_mcp/cli.py +167 -0
- ruts_mcp-0.1.0/ruts_mcp/compare.py +396 -0
- ruts_mcp-0.1.0/ruts_mcp/corpus.py +278 -0
- ruts_mcp-0.1.0/ruts_mcp/data.py +251 -0
- ruts_mcp-0.1.0/ruts_mcp/errors.py +28 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/__init__.py +41 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/basic.py +72 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/cohesion.py +82 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/diversity.py +123 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/lexical.py +121 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/morph.py +67 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/phon.py +61 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/readability.py +81 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/style.py +103 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/syntax.py +174 -0
- ruts_mcp-0.1.0/ruts_mcp/groups/verse.py +110 -0
- ruts_mcp-0.1.0/ruts_mcp/inputs.py +174 -0
- ruts_mcp-0.1.0/ruts_mcp/language.py +66 -0
- ruts_mcp-0.1.0/ruts_mcp/prompts.py +149 -0
- ruts_mcp-0.1.0/ruts_mcp/py.typed +0 -0
- ruts_mcp-0.1.0/ruts_mcp/resources.py +189 -0
- ruts_mcp-0.1.0/ruts_mcp/server.py +65 -0
- ruts_mcp-0.1.0/ruts_mcp/settings.py +85 -0
- ruts_mcp-0.1.0/ruts_mcp/tools.py +76 -0
|
@@ -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.
|
ruts_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -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).
|
ruts_mcp-0.1.0/README.md
ADDED
|
@@ -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,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}"]
|