telegram-dev 0.6.0__tar.gz → 0.7.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.
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.claude-plugin/marketplace.json +2 -2
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.claude-plugin/plugin.json +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.codex-plugin/plugin.json +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.cursor-plugin/plugin.json +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/CHANGELOG.md +20 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/PKG-INFO +6 -5
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/README.md +5 -4
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/README.ru.md +5 -4
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/runtime.md +2 -2
- telegram_dev-0.7.0/glama.json +8 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/pyproject.toml +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/package_openai.py +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/server.json +2 -2
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/SKILL.md +3 -3
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/PKG-INFO +6 -5
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_knowledge.py +72 -15
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_http.py +1 -1
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_knowledge.py +45 -2
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/uv.lock +1 -1
- telegram_dev-0.6.0/glama.json +0 -4
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.agents/plugins/marketplace.json +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.dockerignore +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.mcp.json +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/AGENTS.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/Dockerfile +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/LICENSE +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/MANIFEST.in +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/NOTICE +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/icon-dark.svg +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/icon.svg +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/logo-dark.svg +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/logo.svg +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/.env.example +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/Caddyfile +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/challenges/.gitkeep +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/compose.yml +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/catalog-submissions.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/deployment.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/maintenance.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/privacy.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/support.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/terms.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/validation.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/check_sources.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/install.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/setup.cfg +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/agents/openai.yaml +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-libraries.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-operations.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/business-and-commerce.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/buttons-and-custom-emoji.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/client-development.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/feature-checks.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/groups-and-channels.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/mini-apps-and-web.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/surface-map.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/ton-and-blockchain.md +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/SOURCES.txt +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/dependency_links.txt +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/entry_points.txt +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/requires.txt +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/top_level.txt +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev_install.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/behavioral-cases.json +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_evals.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_fetch.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_install.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_libraries.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_package.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_refresh.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_sources.py +0 -0
- {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_ton.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telegram-dev-tools",
|
|
3
3
|
"owner": {"name": "Kay0k1"},
|
|
4
|
-
"metadata": {"description": "Independent Telegram development tools with official documentation", "version": "0.
|
|
4
|
+
"metadata": {"description": "Independent Telegram development tools with official documentation", "version": "0.7.0"},
|
|
5
5
|
"plugins": [
|
|
6
6
|
{
|
|
7
7
|
"name": "telegram-dev",
|
|
8
8
|
"source": "./",
|
|
9
9
|
"description": "Source-verified Telegram and TON development with official documentation search",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.7.0",
|
|
11
11
|
"homepage": "https://github.com/Kay0k1/telegram-dev",
|
|
12
12
|
"repository": "https://github.com/Kay0k1/telegram-dev",
|
|
13
13
|
"license": "MIT",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telegram-dev",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"displayName": "Telegram Dev",
|
|
5
5
|
"description": "Source-verified Telegram and TON development across Bot API, Mini Apps, MTProto, TDLib, TON Connect, Tolk and public releases. Independent project by Kay0k1.",
|
|
6
6
|
"author": {
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project. Versions follow [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [0.7.0] - 2026-11-10
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- MCP tools follow one verb-noun naming scheme. Renamed: `telegram_corpus_status` → `get_telegram_corpus_status`, `telegram_document_history` → `list_telegram_document_revisions`, `telegram_sources` → `list_telegram_sources`. `search_telegram_docs` and `get_telegram_document` are unchanged. The skill uses the new names; update a project install with `uvx telegram-dev@latest install --agent <agent> --update`.
|
|
10
|
+
- Every tool description names its neighbouring tools and says when to use them instead.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `list_telegram_cached_pages`: pages already stored in the local cache, filtered by area, with freshness and paging.
|
|
15
|
+
|
|
16
|
+
## [0.6.1] - 2026-11-10
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- MCP tool definitions: every tool has a short title and a description of when to use it and what it returns; every parameter has a description, examples and limits (`limit` 1–20, `length` 100–40000, `offset` ≥ 0); `area` is a list of allowed values instead of free text.
|
|
21
|
+
- `glama.json` pins the Glama build spec (Python 3.14 until dependencies support 3.15).
|
|
22
|
+
|
|
5
23
|
## [0.6.0] - 2026-11-10
|
|
6
24
|
|
|
7
25
|
### Added
|
|
@@ -62,6 +80,8 @@ All notable changes to this project. Versions follow [Semantic Versioning](https
|
|
|
62
80
|
|
|
63
81
|
- First public release: documentation MCP server with an on-demand local cache, agent skill, project installer for Codex, Claude Code and Cursor, and a Claude Code plugin catalog.
|
|
64
82
|
|
|
83
|
+
[0.7.0]: https://github.com/Kay0k1/telegram-dev/compare/v0.6.1...v0.7.0
|
|
84
|
+
[0.6.1]: https://github.com/Kay0k1/telegram-dev/compare/v0.6.0...v0.6.1
|
|
65
85
|
[0.6.0]: https://github.com/Kay0k1/telegram-dev/compare/v0.5.1...v0.6.0
|
|
66
86
|
[0.5.1]: https://github.com/Kay0k1/telegram-dev/compare/v0.5.0...v0.5.1
|
|
67
87
|
[0.5.0]: https://github.com/Kay0k1/telegram-dev/compare/v0.4.0...v0.5.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: telegram-dev
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Source-grounded Telegram development skills and documentation MCP
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: <3.15,>=3.10
|
|
@@ -45,7 +45,7 @@ With Telegram Dev the agent reads the current page before it writes code. A real
|
|
|
45
45
|
'Delete' button to be red and show a custom emoji. Which Bot API fields do this,
|
|
46
46
|
what are the requirements, and what does the request JSON look like?
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
get_telegram_corpus_status {}
|
|
49
49
|
search_telegram_docs {"query": "style icon_custom_emoji_id", "area": "releases"}
|
|
50
50
|
search_telegram_docs {"query": "InlineKeyboardButton icon_custom_emoji_id style", "area": "bot-api"}
|
|
51
51
|
get_telegram_document {"url": "https://core.telegram.org/bots/api", "offset": 167594, "length": 10500}
|
|
@@ -147,9 +147,10 @@ The tools work without the skill, but the skill is what makes an agent use them
|
|
|
147
147
|
| --- | --- |
|
|
148
148
|
| `search_telegram_docs` | Full-text search over indexed sections, optionally limited to one area: `bot-api`, `mini-apps`, `telegram-api`, `tdlib`, `ton`, `releases`, `ton-releases`, `aiogram`, `python-telegram-bot`, `grammy` and others. Core Telegram docs rank first unless the query names a library |
|
|
149
149
|
| `get_telegram_document` | Reads an official page in pages of up to 40,000 characters; fetches it if it is missing or older than 6 hours |
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
150
|
+
| `get_telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
|
|
151
|
+
| `list_telegram_document_revisions` | Revisions of a page captured by this installation |
|
|
152
|
+
| `list_telegram_sources` | The 61 official entry points, grouped by API area |
|
|
153
|
+
| `list_telegram_cached_pages` | Pages already stored in the local cache, by area, with freshness |
|
|
153
154
|
|
|
154
155
|
The cache starts empty. Pages are fetched the first time the agent reads them and indexed right away. To pre-fetch everything reachable from the configured sources:
|
|
155
156
|
|
|
@@ -28,7 +28,7 @@ With Telegram Dev the agent reads the current page before it writes code. A real
|
|
|
28
28
|
'Delete' button to be red and show a custom emoji. Which Bot API fields do this,
|
|
29
29
|
what are the requirements, and what does the request JSON look like?
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
get_telegram_corpus_status {}
|
|
32
32
|
search_telegram_docs {"query": "style icon_custom_emoji_id", "area": "releases"}
|
|
33
33
|
search_telegram_docs {"query": "InlineKeyboardButton icon_custom_emoji_id style", "area": "bot-api"}
|
|
34
34
|
get_telegram_document {"url": "https://core.telegram.org/bots/api", "offset": 167594, "length": 10500}
|
|
@@ -130,9 +130,10 @@ The tools work without the skill, but the skill is what makes an agent use them
|
|
|
130
130
|
| --- | --- |
|
|
131
131
|
| `search_telegram_docs` | Full-text search over indexed sections, optionally limited to one area: `bot-api`, `mini-apps`, `telegram-api`, `tdlib`, `ton`, `releases`, `ton-releases`, `aiogram`, `python-telegram-bot`, `grammy` and others. Core Telegram docs rank first unless the query names a library |
|
|
132
132
|
| `get_telegram_document` | Reads an official page in pages of up to 40,000 characters; fetches it if it is missing or older than 6 hours |
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
133
|
+
| `get_telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
|
|
134
|
+
| `list_telegram_document_revisions` | Revisions of a page captured by this installation |
|
|
135
|
+
| `list_telegram_sources` | The 61 official entry points, grouped by API area |
|
|
136
|
+
| `list_telegram_cached_pages` | Pages already stored in the local cache, by area, with freshness |
|
|
136
137
|
|
|
137
138
|
The cache starts empty. Pages are fetched the first time the agent reads them and indexed right away. To pre-fetch everything reachable from the configured sources:
|
|
138
139
|
|
|
@@ -26,7 +26,7 @@ TON меняется так же быстро. В текущей докумен
|
|
|
26
26
|
'Delete' button to be red and show a custom emoji. Which Bot API fields do this,
|
|
27
27
|
what are the requirements, and what does the request JSON look like?
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
get_telegram_corpus_status {}
|
|
30
30
|
search_telegram_docs {"query": "style icon_custom_emoji_id", "area": "releases"}
|
|
31
31
|
search_telegram_docs {"query": "InlineKeyboardButton icon_custom_emoji_id style", "area": "bot-api"}
|
|
32
32
|
get_telegram_document {"url": "https://core.telegram.org/bots/api", "offset": 167594, "length": 10500}
|
|
@@ -124,9 +124,10 @@ Cursor: [](htt
|
|
|
124
124
|
| --- | --- |
|
|
125
125
|
| `search_telegram_docs` | Полнотекстовый поиск по разделам, можно ограничить областью: `bot-api`, `mini-apps`, `telegram-api`, `tdlib`, `ton`, `releases`, `ton-releases`, `aiogram`, `python-telegram-bot`, `grammy` и другими. Документация Telegram идёт первой, если в запросе не названа библиотека |
|
|
126
126
|
| `get_telegram_document` | Читает официальную страницу частями до 40 000 символов; загружает её, если страницы нет или она старше 6 часов |
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
127
|
+
| `get_telegram_corpus_status` | Что проиндексировано, насколько свежее и какие источники не загрузились |
|
|
128
|
+
| `list_telegram_document_revisions` | Версии страницы, которые видела эта установка |
|
|
129
|
+
| `list_telegram_sources` | 61 официальная точка входа по областям API |
|
|
130
|
+
| `list_telegram_cached_pages` | Страницы, которые уже лежат в локальном кэше, по областям, со свежестью |
|
|
130
131
|
|
|
131
132
|
Кэш сначала пустой. Страница загружается, когда агент впервые её читает, и сразу индексируется. Загрузить заранее всё, что достижимо из настроенных источников:
|
|
132
133
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Пока MCP запущен, фоновая задача каждые 6 часов обрабатывает до **120 страниц**. Она проверяет входные источники, расширяет обнаруженный набор документов и возвращается к старым страницам. Расписание хранится в общей SQLite-базе, поэтому несколько проектов, использующих один кеш, не начинают отдельный обход при каждом запуске. Первое подключение запускает проверку в фоне и не ждёт загрузки всей базы.
|
|
10
10
|
|
|
11
|
-
Это постепенное заполнение кеша. Для полного первоначального обхода используйте `uv run --frozen telegram-dev sync --max-pages 0`. Его завершение и недоступные источники проверяйте через `telegram-dev status`; количество страниц само по себе не доказывает полноту знаний Telegram. `
|
|
11
|
+
Это постепенное заполнение кеша. Для полного первоначального обхода используйте `uv run --frozen telegram-dev sync --max-pages 0`. Его завершение и недоступные источники проверяйте через `telegram-dev status`; количество страниц само по себе не доказывает полноту знаний Telegram. `list_telegram_sources` перечисляет настроенные точки входа; живые API indexes и schema позволяют находить дополнительные функции.
|
|
12
12
|
|
|
13
13
|
Настройки задаются в окружении MCP-сервера:
|
|
14
14
|
|
|
@@ -54,7 +54,7 @@ From 0.3.0, reading a document automatically refreshes pages older than **6 hour
|
|
|
54
54
|
|
|
55
55
|
Source failures preserve previously cached text and explicitly mark it stale; they never advance the successful check date. Automatic retries wait 15 minutes by default; forced refresh bypasses that backoff.
|
|
56
56
|
|
|
57
|
-
While the MCP process runs, a background cycle every 6 hours checks up to **120 pages**, covering entrypoints, new discovered links and older documents. Its SQLite schedule is shared between projects using the same cache. Startup does not wait for a full corpus. Coverage expands gradually; use `uv run --frozen telegram-dev sync --max-pages 0` for a complete initial crawl of the discovered scope and inspect `telegram-dev status` for gaps. `
|
|
57
|
+
While the MCP process runs, a background cycle every 6 hours checks up to **120 pages**, covering entrypoints, new discovered links and older documents. Its SQLite schedule is shared between projects using the same cache. Startup does not wait for a full corpus. Coverage expands gradually; use `uv run --frozen telegram-dev sync --max-pages 0` for a complete initial crawl of the discovered scope and inspect `telegram-dev status` for gaps. `list_telegram_sources` lists configured entrypoints; follow the live API indexes and schema for further features.
|
|
58
58
|
|
|
59
59
|
The environment settings in the table above control the database, age threshold, background enablement, interval, page budget and retry backoff. Run `uv run --frozen telegram-dev maintain --max-pages 120` for one bounded cycle. Background work requires a running server; a permanently hosted MCP continues refreshing between user sessions.
|
|
60
60
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://glama.ai/mcp/schemas/server.json",
|
|
3
|
+
"maintainers": ["Kay0k1"],
|
|
4
|
+
"transport": "stdio",
|
|
5
|
+
"buildSteps": ["uv sync --frozen --python 3.14"],
|
|
6
|
+
"cmdArguments": ["mcp-proxy", "--", "uv", "run", "--frozen", "telegram-dev", "serve"],
|
|
7
|
+
"placeholderArguments": {}
|
|
8
|
+
}
|
|
@@ -83,7 +83,7 @@ def review_cases() -> dict:
|
|
|
83
83
|
"expected_behavior": "Select the client API/TDLib surface, read the relevant public pages and cite them."},
|
|
84
84
|
{"description": "Check published release history",
|
|
85
85
|
"prompt": "Inspect the Bot API changelog and report the cache freshness before summarizing a documented change.",
|
|
86
|
-
"tools_triggered": "get_telegram_document,
|
|
86
|
+
"tools_triggered": "get_telegram_document, get_telegram_corpus_status",
|
|
87
87
|
"expected_behavior": "Read the changelog and separate source observation timestamps from Telegram release dates."},
|
|
88
88
|
],
|
|
89
89
|
"negative": [
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
10
|
"websiteUrl": "https://github.com/Kay0k1/telegram-dev",
|
|
11
|
-
"version": "0.
|
|
11
|
+
"version": "0.7.0",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "pypi",
|
|
15
15
|
"identifier": "telegram-dev",
|
|
16
|
-
"version": "0.
|
|
16
|
+
"version": "0.7.0",
|
|
17
17
|
"runtimeHint": "uvx",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|
|
@@ -42,11 +42,11 @@ Prefer the project's existing suitable library. Do not introduce a connector, ac
|
|
|
42
42
|
## Retrieve evidence
|
|
43
43
|
|
|
44
44
|
If available, use the telegram-knowledge MCP tools:
|
|
45
|
-
1. `
|
|
46
|
-
Use `
|
|
45
|
+
1. `get_telegram_corpus_status` when corpus coverage/freshness is not yet known in this task. Inspect per-document observations and reported refresh errors; a recent corpus-wide check does not prove the requested page is current.
|
|
46
|
+
Use `list_telegram_sources` to discover the configured official entrypoints for the requested area when the right source is unclear; its source count is not proof that every page has been indexed. A new public installation can start with an empty local cache. In that case, call `get_telegram_document` on the relevant entrypoint; it fetches and indexes the page. Bot API and Mini App entrypoints include their full specifications. Do not fetch every source or require a full crawl before helping the user. `list_telegram_cached_pages` shows which pages of an area are already in the cache.
|
|
47
47
|
2. `search_telegram_docs` with exact API names or English feature keywords and a suitable area. Translate Russian intent to API terms; built-in Russian aliases are only a convenience.
|
|
48
48
|
3. `get_telegram_document` to read actual requirements; start at the search result's `document_offset` and paginate beyond a truncated excerpt. Reads/searches automatically check stale matched sources, and the runtime can also synchronize sources in the background while MCP is running. Inspect each result's freshness/error metadata rather than assuming a background task finished. Use the existing `refresh=true` parameter when a current limit, permission rule, newly released method or deprecated behavior needs an immediate source check. After a refresh changes the source hash, search again because offsets may have changed. If a source check fails, distinguish usable cached evidence from verified current evidence and use direct official browsing when available.
|
|
49
|
-
4. `
|
|
49
|
+
4. `list_telegram_document_revisions` only for observed local revisions. Release history is in official changelog documents, not inferred from local capture timestamps.
|
|
50
50
|
|
|
51
51
|
Without MCP, open the official sources linked in the surface map using available browsing tools. If neither is available, explicitly identify unverified details instead of fabricating methods or restrictions.
|
|
52
52
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: telegram-dev
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Source-grounded Telegram development skills and documentation MCP
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: <3.15,>=3.10
|
|
@@ -45,7 +45,7 @@ With Telegram Dev the agent reads the current page before it writes code. A real
|
|
|
45
45
|
'Delete' button to be red and show a custom emoji. Which Bot API fields do this,
|
|
46
46
|
what are the requirements, and what does the request JSON look like?
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
get_telegram_corpus_status {}
|
|
49
49
|
search_telegram_docs {"query": "style icon_custom_emoji_id", "area": "releases"}
|
|
50
50
|
search_telegram_docs {"query": "InlineKeyboardButton icon_custom_emoji_id style", "area": "bot-api"}
|
|
51
51
|
get_telegram_document {"url": "https://core.telegram.org/bots/api", "offset": 167594, "length": 10500}
|
|
@@ -147,9 +147,10 @@ The tools work without the skill, but the skill is what makes an agent use them
|
|
|
147
147
|
| --- | --- |
|
|
148
148
|
| `search_telegram_docs` | Full-text search over indexed sections, optionally limited to one area: `bot-api`, `mini-apps`, `telegram-api`, `tdlib`, `ton`, `releases`, `ton-releases`, `aiogram`, `python-telegram-bot`, `grammy` and others. Core Telegram docs rank first unless the query names a library |
|
|
149
149
|
| `get_telegram_document` | Reads an official page in pages of up to 40,000 characters; fetches it if it is missing or older than 6 hours |
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
150
|
+
| `get_telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
|
|
151
|
+
| `list_telegram_document_revisions` | Revisions of a page captured by this installation |
|
|
152
|
+
| `list_telegram_sources` | The 61 official entry points, grouped by API area |
|
|
153
|
+
| `list_telegram_cached_pages` | Pages already stored in the local cache, by area, with freshness |
|
|
153
154
|
|
|
154
155
|
The cache starts empty. Pages are fetched the first time the agent reads them and indexed right away. To pre-fetch everything reachable from the configured sources:
|
|
155
156
|
|
|
@@ -14,12 +14,14 @@ import sys
|
|
|
14
14
|
import threading
|
|
15
15
|
import time
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
|
+
from typing import Annotated, Literal
|
|
17
18
|
from urllib.parse import urljoin, urlsplit, urlunsplit
|
|
18
19
|
|
|
19
20
|
import httpx
|
|
20
21
|
from bs4 import BeautifulSoup
|
|
21
22
|
from markdownify import markdownify
|
|
22
23
|
from platformdirs import user_cache_path
|
|
24
|
+
from pydantic import Field
|
|
23
25
|
|
|
24
26
|
ROOT = Path(__file__).resolve().parent
|
|
25
27
|
DB = Path(os.environ.get("TELEGRAM_KNOWLEDGE_DB", str(user_cache_path("telegram-dev") / "corpus.sqlite3")))
|
|
@@ -669,6 +671,18 @@ def _maintain(stop):
|
|
|
669
671
|
stop.wait(30)
|
|
670
672
|
|
|
671
673
|
|
|
674
|
+
def cached_pages(area="", offset=0, limit=50):
|
|
675
|
+
offset, limit = max(0, offset), max(1, min(limit, 200))
|
|
676
|
+
with connect() as conn:
|
|
677
|
+
total = conn.execute("SELECT count(*) FROM pages WHERE ?='' OR family=?", (area, area)).fetchone()[0]
|
|
678
|
+
rows = conn.execute("SELECT url,title,family,checked_at,error FROM pages WHERE ?='' OR family=? ORDER BY url LIMIT ? OFFSET ?",
|
|
679
|
+
(area, area, limit, offset)).fetchall()
|
|
680
|
+
pages = [{"url": r["url"], "title": r["title"], "area": r["family"], "checked_at": r["checked_at"],
|
|
681
|
+
"freshness": freshness(r)} for r in rows]
|
|
682
|
+
return {"pages": pages, "total": total, "offset": offset,
|
|
683
|
+
"next_offset": offset + len(pages) if offset + len(pages) < total else None}
|
|
684
|
+
|
|
685
|
+
|
|
672
686
|
def coverage():
|
|
673
687
|
with connect() as conn:
|
|
674
688
|
states = dict(conn.execute("SELECT state,count(*) FROM frontier GROUP BY state"))
|
|
@@ -794,6 +808,10 @@ def document(url, offset=0, length=16000, refresh=False):
|
|
|
794
808
|
return result
|
|
795
809
|
|
|
796
810
|
|
|
811
|
+
Area = Literal["", "bot-api", "mini-apps", "telegram-api", "tdlib", "releases", "product-releases", "gateway",
|
|
812
|
+
"web-integrations", "media-design", "ton", "ton-releases", "aiogram", "python-telegram-bot", "grammy"]
|
|
813
|
+
|
|
814
|
+
|
|
797
815
|
def create_server(transport="stdio", host="127.0.0.1", port=8000):
|
|
798
816
|
from mcp.server.fastmcp import FastMCP
|
|
799
817
|
from mcp.server.transport_security import TransportSecuritySettings
|
|
@@ -832,27 +850,53 @@ def create_server(transport="stdio", host="127.0.0.1", port=8000):
|
|
|
832
850
|
return JSONResponse({"status": "ok", "pages": status["pages"],
|
|
833
851
|
"stale_pages": status["stale_pages"], "source_errors": len(status["errors"])})
|
|
834
852
|
|
|
835
|
-
@server.tool(annotations=annotations)
|
|
836
|
-
def search_telegram_docs(
|
|
837
|
-
|
|
853
|
+
@server.tool(title="Search Telegram and TON docs", annotations=annotations)
|
|
854
|
+
def search_telegram_docs(
|
|
855
|
+
query: Annotated[str, Field(min_length=1, description=(
|
|
856
|
+
"Exact API names or short English keywords work best, e.g. 'InlineKeyboardButton style', "
|
|
857
|
+
"'sendVideoNote', 'ton_proof', 'jetton transfer', 'aiogram Router callback_query'. "
|
|
858
|
+
"Common Russian feature words (кнопка, кружок, кошелек) are expanded automatically."))],
|
|
859
|
+
area: Annotated[Area, Field(description=(
|
|
860
|
+
"Limit results to one documentation area; empty searches all areas. Core Telegram docs rank above "
|
|
861
|
+
"library docs unless the query names a library."))] = "",
|
|
862
|
+
limit: Annotated[int, Field(ge=1, le=20, description="Maximum number of matching sections to return.")] = 6,
|
|
863
|
+
) -> dict:
|
|
864
|
+
"""Find the official documentation sections that answer a Telegram or TON development question.
|
|
865
|
+
|
|
866
|
+
Use it before writing or reviewing code that calls the Bot API, Mini Apps JS, Telegram API/MTProto, TDLib, TON Connect, Tolk contracts or the aiogram, python-telegram-bot and grammY libraries. Returns up to `limit` sections with page URL, heading, excerpt, `document_offset` and freshness. Excerpts are partial: open the page with `get_telegram_document` at `document_offset` before relying on details. Stale matching pages are re-fetched first. An empty result is not proof that a feature does not exist; if the cache is empty, the response suggests pages to fetch."""
|
|
838
867
|
result = search(query, area, limit, refresh_results=True)
|
|
839
868
|
if not result['results'] and coverage()['pages'] == 0:
|
|
840
869
|
result['note'] = 'The cache is empty. Fetch a relevant official URL with get_telegram_document first, then search again. Suggested starts: https://core.telegram.org/bots/api ; https://core.telegram.org/api ; https://core.telegram.org/bots/webapps ; TON: https://docs.ton.org/llms.txt (index of all TON pages) ; libraries: https://docs.aiogram.dev/en/latest/ ; https://docs.python-telegram-bot.org/en/stable/ ; https://grammy.dev/sitemap.xml.'
|
|
841
870
|
return result
|
|
842
871
|
|
|
843
|
-
@server.tool(annotations=annotations)
|
|
844
|
-
def get_telegram_document(
|
|
845
|
-
|
|
872
|
+
@server.tool(title="Read an official documentation page", annotations=annotations)
|
|
873
|
+
def get_telegram_document(
|
|
874
|
+
url: Annotated[str, Field(description=(
|
|
875
|
+
"Official page URL from search results or list_telegram_sources, e.g. https://core.telegram.org/bots/api "
|
|
876
|
+
"or https://docs.ton.org/applications/ton-connect/overview. Pages outside the official sources are rejected."))],
|
|
877
|
+
offset: Annotated[int, Field(ge=0, description="Character offset to start from; use a search result's document_offset or the previous next_offset.")] = 0,
|
|
878
|
+
length: Annotated[int, Field(ge=100, le=40000, description="Number of characters to return.")] = 16000,
|
|
879
|
+
refresh: Annotated[bool, Field(description="Force a live check of the source even if the cached copy is fresh.")] = False,
|
|
880
|
+
) -> dict:
|
|
881
|
+
"""Read the text of an official Telegram, TON or bot-library documentation page, one window at a time.
|
|
882
|
+
|
|
883
|
+
Use it to read requirements, parameters and limits in full after `search_telegram_docs` found the page, or to load an entry page from `list_telegram_sources` into an empty cache. Do not use it to find which page answers a question: search first. Pages missing from the cache or older than the freshness limit (6 hours by default) are fetched first. Returns title, URL, Markdown `body` for the requested window, `next_offset` (null at the end), `total_characters`, content hash and freshness. If the live source fails, the cached text is returned with `freshness.stale` and `refresh_error` set. The observation date is when this installation read the page, not when Telegram changed it."""
|
|
846
884
|
return document(url, offset, length, refresh)
|
|
847
885
|
|
|
848
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
849
|
-
def
|
|
850
|
-
"""Report
|
|
886
|
+
@server.tool(title="Cache coverage and freshness", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
887
|
+
def get_telegram_corpus_status() -> dict:
|
|
888
|
+
"""Report how complete and how current the local documentation cache is, as totals.
|
|
889
|
+
|
|
890
|
+
Use it at the start of a task or when search results look incomplete. For the configured entry points use `list_telegram_sources`; for the individual cached pages use `list_telegram_cached_pages`; to answer a question use `search_telegram_docs`. Refreshing is automatic (on read, on search and in a background cycle), so there is no refresh command. Returns page counts per area, crawl queue state, stale page count, last and oldest successful checks, refresh policy and the latest source errors. Indexed pages are not all of Telegram's knowledge: absence from the cache is not evidence that a feature does not exist."""
|
|
851
891
|
return coverage()
|
|
852
892
|
|
|
853
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
854
|
-
def
|
|
855
|
-
|
|
893
|
+
@server.tool(title="Observed revisions of a page", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
894
|
+
def list_telegram_document_revisions(
|
|
895
|
+
url: Annotated[str, Field(description="Official page URL, the same form accepted by get_telegram_document.")],
|
|
896
|
+
) -> dict:
|
|
897
|
+
"""List the revisions of one documentation page that this installation has observed, newest first.
|
|
898
|
+
|
|
899
|
+
Use it to see whether a page changed since an earlier read. To read the current text use `get_telegram_document`. Returns content hash, capture time and length for each revision. It does not reconstruct history before the page was first fetched here; for Telegram release history read the official changelogs (area `releases` or `ton-releases`)."""
|
|
856
900
|
with connect() as conn:
|
|
857
901
|
base = canonical(url)
|
|
858
902
|
if base is None:
|
|
@@ -860,12 +904,25 @@ def create_server(transport="stdio", host="127.0.0.1", port=8000):
|
|
|
860
904
|
target = conn.execute("SELECT target FROM aliases WHERE url=?", (base,)).fetchone()
|
|
861
905
|
return {"revisions": [dict(r) for r in conn.execute("SELECT sha,captured_at,length(body) AS characters FROM revisions WHERE url=? ORDER BY captured_at DESC", (target[0] if target else base,))]}
|
|
862
906
|
|
|
863
|
-
@server.tool(annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
864
|
-
def
|
|
865
|
-
"""List
|
|
907
|
+
@server.tool(title="Official documentation entry points", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
908
|
+
def list_telegram_sources() -> dict:
|
|
909
|
+
"""List the official entry points this server crawls, each with its documentation area.
|
|
910
|
+
|
|
911
|
+
Use it to find where to start reading for an unfamiliar area (for example the Bot API index, docs.ton.org/llms.txt or a library's docs) and pass the URL to `get_telegram_document`. If you already know the feature or API name, use `search_telegram_docs` instead. This is the source configuration, not the cache: `list_telegram_cached_pages` shows what is already stored."""
|
|
866
912
|
return {"sources": [{"url": url, "area": family(url)} for url in SEEDS],
|
|
867
913
|
"scope": "Entry points for discovery. Follow each official API index and schema for additional features."}
|
|
868
914
|
|
|
915
|
+
@server.tool(title="List cached documentation pages", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
|
|
916
|
+
def list_telegram_cached_pages(
|
|
917
|
+
area: Annotated[Area, Field(description="Only pages from this documentation area; empty lists all areas.")] = "",
|
|
918
|
+
offset: Annotated[int, Field(ge=0, description="Number of pages to skip, for paging through long lists; use the previous next_offset.")] = 0,
|
|
919
|
+
limit: Annotated[int, Field(ge=1, le=200, description="Maximum number of pages to return.")] = 50,
|
|
920
|
+
) -> dict:
|
|
921
|
+
"""List the documentation pages already stored in the local cache, sorted by URL.
|
|
922
|
+
|
|
923
|
+
Use it to see which pages of an area are available offline or to pick a page to open with `get_telegram_document`. Returns URL, title, area, last check time and freshness for each page, the total count and `next_offset` (null at the end). It lists stored pages only; to find content by topic use `search_telegram_docs`, and for totals and errors use `get_telegram_corpus_status`."""
|
|
924
|
+
return cached_pages(area, offset, limit)
|
|
925
|
+
|
|
869
926
|
return server
|
|
870
927
|
|
|
871
928
|
|
|
@@ -58,7 +58,7 @@ class HttpTransportTests(unittest.TestCase):
|
|
|
58
58
|
async with ClientSession(read, write) as session:
|
|
59
59
|
await session.initialize()
|
|
60
60
|
listing = await session.list_tools()
|
|
61
|
-
self.assertEqual(len(listing.tools),
|
|
61
|
+
self.assertEqual(len(listing.tools), 6)
|
|
62
62
|
self.assertTrue(all(tool.annotations.readOnlyHint for tool in listing.tools))
|
|
63
63
|
result = await session.call_tool("search_telegram_docs", {"query": "InlineKeyboardButton", "area": "bot-api"})
|
|
64
64
|
self.assertFalse(result.isError)
|
|
@@ -95,8 +95,8 @@ class KnowledgeTests(unittest.TestCase):
|
|
|
95
95
|
async with ClientSession(read, write) as session:
|
|
96
96
|
await session.initialize()
|
|
97
97
|
listing = await session.list_tools()
|
|
98
|
-
self.assertEqual(len(listing.tools),
|
|
99
|
-
result = await session.call_tool("
|
|
98
|
+
self.assertEqual(len(listing.tools), 6)
|
|
99
|
+
result = await session.call_tool("get_telegram_corpus_status", {})
|
|
100
100
|
self.assertFalse(result.isError)
|
|
101
101
|
payload = result.structuredContent or json.loads(result.content[0].text)
|
|
102
102
|
self.assertEqual(payload["pages"], 0)
|
|
@@ -121,3 +121,46 @@ class CliTests(unittest.TestCase):
|
|
|
121
121
|
with patch("builtins.print") as printed:
|
|
122
122
|
k.main(["--version"])
|
|
123
123
|
self.assertRegex(printed.call_args.args[0], r"^\d+\.\d+\.\d+")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ToolDefinitionTests(unittest.TestCase):
|
|
127
|
+
def test_every_tool_has_a_title_and_documented_parameters(self):
|
|
128
|
+
async def tools():
|
|
129
|
+
return await k.create_server().list_tools()
|
|
130
|
+
with patch.dict(os.environ, {"TELEGRAM_DOC_AUTO_SYNC": "0"}):
|
|
131
|
+
listing = asyncio.run(tools())
|
|
132
|
+
self.assertEqual(len(listing), 6)
|
|
133
|
+
verbs = ("search_", "get_", "list_")
|
|
134
|
+
for tool in listing:
|
|
135
|
+
with self.subTest(tool=tool.name):
|
|
136
|
+
self.assertTrue(tool.title)
|
|
137
|
+
self.assertTrue(tool.name.startswith(verbs))
|
|
138
|
+
self.assertGreater(len(tool.description), 150)
|
|
139
|
+
for name, schema in tool.inputSchema.get("properties", {}).items():
|
|
140
|
+
self.assertTrue(schema.get("description"), name)
|
|
141
|
+
search = next(tool for tool in listing if tool.name == "search_telegram_docs")
|
|
142
|
+
areas = set(search.inputSchema["properties"]["area"]["enum"])
|
|
143
|
+
self.assertEqual(areas - {""}, {k.family(url) for url in k.SEEDS} | {"media-design", "gateway"})
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class CachedPagesTests(unittest.TestCase):
|
|
147
|
+
def setUp(self):
|
|
148
|
+
self.temp = tempfile.TemporaryDirectory()
|
|
149
|
+
self.old_db = k.DB
|
|
150
|
+
k.DB = Path(self.temp.name) / "pages.sqlite3"
|
|
151
|
+
|
|
152
|
+
def tearDown(self):
|
|
153
|
+
k.DB = self.old_db
|
|
154
|
+
self.temp.cleanup()
|
|
155
|
+
|
|
156
|
+
def test_lists_cached_pages_by_area_with_paging(self):
|
|
157
|
+
with k.connect() as conn:
|
|
158
|
+
for url in ("https://core.telegram.org/bots/api", "https://core.telegram.org/bots/webapps",
|
|
159
|
+
"https://docs.ton.org/applications/ton-connect/overview"):
|
|
160
|
+
k.save(conn, url, (url, url.rsplit("/", 1)[-1], "# Title\nSome documented text for the page.", []))
|
|
161
|
+
first = k.cached_pages(limit=2)
|
|
162
|
+
self.assertEqual((first["total"], len(first["pages"]), first["next_offset"]), (3, 2, 2))
|
|
163
|
+
self.assertIsNone(k.cached_pages(offset=2, limit=2)["next_offset"])
|
|
164
|
+
ton = k.cached_pages(area="ton")
|
|
165
|
+
self.assertEqual([page["url"] for page in ton["pages"]], ["https://docs.ton.org/applications/ton-connect/overview"])
|
|
166
|
+
self.assertFalse(ton["pages"][0]["freshness"]["stale"])
|
telegram_dev-0.6.0/glama.json
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/business-and-commerce.md
RENAMED
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/buttons-and-custom-emoji.md
RENAMED
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/client-development.md
RENAMED
|
File without changes
|
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/groups-and-channels.md
RENAMED
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/mini-apps-and-web.md
RENAMED
|
File without changes
|
|
File without changes
|
{telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/ton-and-blockchain.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|