telegram-dev 0.6.1__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.
Files changed (71) hide show
  1. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.claude-plugin/marketplace.json +2 -2
  2. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.claude-plugin/plugin.json +1 -1
  3. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.codex-plugin/plugin.json +1 -1
  4. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.cursor-plugin/plugin.json +1 -1
  5. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/CHANGELOG.md +12 -0
  6. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/PKG-INFO +6 -5
  7. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/README.md +5 -4
  8. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/README.ru.md +5 -4
  9. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/runtime.md +2 -2
  10. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/pyproject.toml +1 -1
  11. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/scripts/package_openai.py +1 -1
  12. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/server.json +2 -2
  13. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/SKILL.md +3 -3
  14. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/PKG-INFO +6 -5
  15. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_knowledge.py +33 -10
  16. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_http.py +1 -1
  17. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_knowledge.py +28 -3
  18. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/uv.lock +1 -1
  19. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.agents/plugins/marketplace.json +0 -0
  20. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.dockerignore +0 -0
  21. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/.mcp.json +0 -0
  22. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/AGENTS.md +0 -0
  23. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/Dockerfile +0 -0
  24. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/LICENSE +0 -0
  25. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/MANIFEST.in +0 -0
  26. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/NOTICE +0 -0
  27. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/assets/icon-dark.svg +0 -0
  28. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/assets/icon.svg +0 -0
  29. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/assets/logo-dark.svg +0 -0
  30. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/assets/logo.svg +0 -0
  31. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/deploy/.env.example +0 -0
  32. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/deploy/Caddyfile +0 -0
  33. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/deploy/challenges/.gitkeep +0 -0
  34. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/deploy/compose.yml +0 -0
  35. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/catalog-submissions.md +0 -0
  36. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/deployment.md +0 -0
  37. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/maintenance.md +0 -0
  38. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/privacy.md +0 -0
  39. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/support.md +0 -0
  40. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/terms.md +0 -0
  41. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/docs/validation.md +0 -0
  42. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/glama.json +0 -0
  43. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/scripts/check_sources.py +0 -0
  44. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/scripts/install.py +0 -0
  45. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/setup.cfg +0 -0
  46. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/agents/openai.yaml +0 -0
  47. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-libraries.md +0 -0
  48. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-operations.md +0 -0
  49. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/business-and-commerce.md +0 -0
  50. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/buttons-and-custom-emoji.md +0 -0
  51. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/client-development.md +0 -0
  52. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/feature-checks.md +0 -0
  53. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/groups-and-channels.md +0 -0
  54. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/mini-apps-and-web.md +0 -0
  55. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/surface-map.md +0 -0
  56. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/skills/telegram-dev/references/ton-and-blockchain.md +0 -0
  57. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/SOURCES.txt +0 -0
  58. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/dependency_links.txt +0 -0
  59. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/entry_points.txt +0 -0
  60. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/requires.txt +0 -0
  61. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev.egg-info/top_level.txt +0 -0
  62. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/telegram_dev_install.py +0 -0
  63. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/behavioral-cases.json +0 -0
  64. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_evals.py +0 -0
  65. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_fetch.py +0 -0
  66. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_install.py +0 -0
  67. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_libraries.py +0 -0
  68. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_package.py +0 -0
  69. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_refresh.py +0 -0
  70. {telegram_dev-0.6.1 → telegram_dev-0.7.0}/tests/test_sources.py +0 -0
  71. {telegram_dev-0.6.1 → 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.6.1"},
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.6.1",
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.6.1",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegram-dev",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Source-verified Telegram and TON development across Bot API, Mini Apps, MTProto, TDLib, TON Connect, Tolk and public release history",
5
5
  "author": {
6
6
  "name": "Kay0k1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegram-dev",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Source-verified Telegram and TON development: Bot API, Mini Apps, MTProto, TDLib, TON Connect, Tolk and public releases",
5
5
  "author": {"name": "Kay0k1"},
6
6
  "license": "MIT",
@@ -2,6 +2,17 @@
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
+
5
16
  ## [0.6.1] - 2026-11-10
6
17
 
7
18
  ### Changed
@@ -69,6 +80,7 @@ All notable changes to this project. Versions follow [Semantic Versioning](https
69
80
 
70
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.
71
82
 
83
+ [0.7.0]: https://github.com/Kay0k1/telegram-dev/compare/v0.6.1...v0.7.0
72
84
  [0.6.1]: https://github.com/Kay0k1/telegram-dev/compare/v0.6.0...v0.6.1
73
85
  [0.6.0]: https://github.com/Kay0k1/telegram-dev/compare/v0.5.1...v0.6.0
74
86
  [0.5.1]: https://github.com/Kay0k1/telegram-dev/compare/v0.5.0...v0.5.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: telegram-dev
3
- Version: 0.6.1
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
- telegram_corpus_status {}
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
- | `telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
151
- | `telegram_document_history` | Revisions of a page captured by this installation |
152
- | `telegram_sources` | The 61 official entry points, grouped by API area |
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
- telegram_corpus_status {}
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
- | `telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
134
- | `telegram_document_history` | Revisions of a page captured by this installation |
135
- | `telegram_sources` | The 61 official entry points, grouped by API area |
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
- telegram_corpus_status {}
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: [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](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
- | `telegram_corpus_status` | Что проиндексировано, насколько свежее и какие источники не загрузились |
128
- | `telegram_document_history` | Версии страницы, которые видела эта установка |
129
- | `telegram_sources` | 61 официальная точка входа по областям API |
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. `telegram_sources` перечисляет настроенные точки входа; живые API indexes и schema позволяют находить дополнительные функции.
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. `telegram_sources` lists configured entrypoints; follow the live API indexes and schema for further features.
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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "telegram-dev"
7
- version = "0.6.1"
7
+ version = "0.7.0"
8
8
  description = "Source-grounded Telegram development skills and documentation MCP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10,<3.15"
@@ -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, telegram_corpus_status",
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.6.1",
11
+ "version": "0.7.0",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "pypi",
15
15
  "identifier": "telegram-dev",
16
- "version": "0.6.1",
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. `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 `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.
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. `telegram_document_history` only for observed local revisions. Release history is in official changelog documents, not inferred from local capture timestamps.
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.6.1
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
- telegram_corpus_status {}
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
- | `telegram_corpus_status` | What is indexed, how fresh it is and which sources failed |
151
- | `telegram_document_history` | Revisions of a page captured by this installation |
152
- | `telegram_sources` | The 61 official entry points, grouped by API area |
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
 
@@ -671,6 +671,18 @@ def _maintain(stop):
671
671
  stop.wait(30)
672
672
 
673
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
+
674
686
  def coverage():
675
687
  with connect() as conn:
676
688
  states = dict(conn.execute("SELECT state,count(*) FROM frontier GROUP BY state"))
@@ -860,7 +872,7 @@ def create_server(transport="stdio", host="127.0.0.1", port=8000):
860
872
  @server.tool(title="Read an official documentation page", annotations=annotations)
861
873
  def get_telegram_document(
862
874
  url: Annotated[str, Field(description=(
863
- "Official page URL from search results or telegram_sources, e.g. https://core.telegram.org/bots/api "
875
+ "Official page URL from search results or list_telegram_sources, e.g. https://core.telegram.org/bots/api "
864
876
  "or https://docs.ton.org/applications/ton-connect/overview. Pages outside the official sources are rejected."))],
865
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,
866
878
  length: Annotated[int, Field(ge=100, le=40000, description="Number of characters to return.")] = 16000,
@@ -868,23 +880,23 @@ def create_server(transport="stdio", host="127.0.0.1", port=8000):
868
880
  ) -> dict:
869
881
  """Read the text of an official Telegram, TON or bot-library documentation page, one window at a time.
870
882
 
871
- Use it to read requirements, parameters and limits in full after search, or to load an entry page into an empty cache. 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."""
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."""
872
884
  return document(url, offset, length, refresh)
873
885
 
874
886
  @server.tool(title="Cache coverage and freshness", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
875
- def telegram_corpus_status() -> dict:
876
- """Report what the local documentation cache contains and how current it is.
887
+ def get_telegram_corpus_status() -> dict:
888
+ """Report how complete and how current the local documentation cache is, as totals.
877
889
 
878
- Use it at the start of a task or when results look incomplete. 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."""
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."""
879
891
  return coverage()
880
892
 
881
893
  @server.tool(title="Observed revisions of a page", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
882
- def telegram_document_history(
894
+ def list_telegram_document_revisions(
883
895
  url: Annotated[str, Field(description="Official page URL, the same form accepted by get_telegram_document.")],
884
896
  ) -> dict:
885
- """List the versions of a documentation page that this installation has observed, newest first.
897
+ """List the revisions of one documentation page that this installation has observed, newest first.
886
898
 
887
- Use it to see whether a page changed since an earlier read. 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`)."""
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`)."""
888
900
  with connect() as conn:
889
901
  base = canonical(url)
890
902
  if base is None:
@@ -893,13 +905,24 @@ def create_server(transport="stdio", host="127.0.0.1", port=8000):
893
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,))]}
894
906
 
895
907
  @server.tool(title="Official documentation entry points", annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
896
- def telegram_sources() -> dict:
908
+ def list_telegram_sources() -> dict:
897
909
  """List the official entry points this server crawls, each with its documentation area.
898
910
 
899
- 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. This is the source configuration, not proof that every page below it is already cached."""
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."""
900
912
  return {"sources": [{"url": url, "area": family(url)} for url in SEEDS],
901
913
  "scope": "Entry points for discovery. Follow each official API index and schema for additional features."}
902
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
+
903
926
  return server
904
927
 
905
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), 5)
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), 5)
99
- result = await session.call_tool("telegram_corpus_status", {})
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)
@@ -129,13 +129,38 @@ class ToolDefinitionTests(unittest.TestCase):
129
129
  return await k.create_server().list_tools()
130
130
  with patch.dict(os.environ, {"TELEGRAM_DOC_AUTO_SYNC": "0"}):
131
131
  listing = asyncio.run(tools())
132
- self.assertEqual(len(listing), 5)
132
+ self.assertEqual(len(listing), 6)
133
+ verbs = ("search_", "get_", "list_")
133
134
  for tool in listing:
134
135
  with self.subTest(tool=tool.name):
135
136
  self.assertTrue(tool.title)
137
+ self.assertTrue(tool.name.startswith(verbs))
136
138
  self.assertGreater(len(tool.description), 150)
137
139
  for name, schema in tool.inputSchema.get("properties", {}).items():
138
140
  self.assertTrue(schema.get("description"), name)
139
141
  search = next(tool for tool in listing if tool.name == "search_telegram_docs")
140
142
  areas = set(search.inputSchema["properties"]["area"]["enum"])
141
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"])
@@ -946,7 +946,7 @@ wheels = [
946
946
 
947
947
  [[package]]
948
948
  name = "telegram-dev"
949
- version = "0.6.1"
949
+ version = "0.7.0"
950
950
  source = { editable = "." }
951
951
  dependencies = [
952
952
  { name = "beautifulsoup4" },
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