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.
Files changed (72) hide show
  1. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.claude-plugin/marketplace.json +2 -2
  2. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.claude-plugin/plugin.json +1 -1
  3. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.codex-plugin/plugin.json +1 -1
  4. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.cursor-plugin/plugin.json +1 -1
  5. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/CHANGELOG.md +20 -0
  6. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/PKG-INFO +6 -5
  7. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/README.md +5 -4
  8. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/README.ru.md +5 -4
  9. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/runtime.md +2 -2
  10. telegram_dev-0.7.0/glama.json +8 -0
  11. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/pyproject.toml +1 -1
  12. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/package_openai.py +1 -1
  13. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/server.json +2 -2
  14. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/SKILL.md +3 -3
  15. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/PKG-INFO +6 -5
  16. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_knowledge.py +72 -15
  17. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_http.py +1 -1
  18. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_knowledge.py +45 -2
  19. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/uv.lock +1 -1
  20. telegram_dev-0.6.0/glama.json +0 -4
  21. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.agents/plugins/marketplace.json +0 -0
  22. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.dockerignore +0 -0
  23. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/.mcp.json +0 -0
  24. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/AGENTS.md +0 -0
  25. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/Dockerfile +0 -0
  26. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/LICENSE +0 -0
  27. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/MANIFEST.in +0 -0
  28. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/NOTICE +0 -0
  29. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/icon-dark.svg +0 -0
  30. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/icon.svg +0 -0
  31. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/logo-dark.svg +0 -0
  32. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/assets/logo.svg +0 -0
  33. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/.env.example +0 -0
  34. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/Caddyfile +0 -0
  35. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/challenges/.gitkeep +0 -0
  36. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/deploy/compose.yml +0 -0
  37. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/catalog-submissions.md +0 -0
  38. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/deployment.md +0 -0
  39. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/maintenance.md +0 -0
  40. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/privacy.md +0 -0
  41. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/support.md +0 -0
  42. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/terms.md +0 -0
  43. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/docs/validation.md +0 -0
  44. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/check_sources.py +0 -0
  45. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/scripts/install.py +0 -0
  46. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/setup.cfg +0 -0
  47. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/agents/openai.yaml +0 -0
  48. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-libraries.md +0 -0
  49. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/bot-operations.md +0 -0
  50. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/business-and-commerce.md +0 -0
  51. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/buttons-and-custom-emoji.md +0 -0
  52. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/client-development.md +0 -0
  53. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/feature-checks.md +0 -0
  54. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/groups-and-channels.md +0 -0
  55. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/mini-apps-and-web.md +0 -0
  56. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/surface-map.md +0 -0
  57. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/skills/telegram-dev/references/ton-and-blockchain.md +0 -0
  58. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/SOURCES.txt +0 -0
  59. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/dependency_links.txt +0 -0
  60. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/entry_points.txt +0 -0
  61. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/requires.txt +0 -0
  62. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev.egg-info/top_level.txt +0 -0
  63. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/telegram_dev_install.py +0 -0
  64. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/behavioral-cases.json +0 -0
  65. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_evals.py +0 -0
  66. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_fetch.py +0 -0
  67. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_install.py +0 -0
  68. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_libraries.py +0 -0
  69. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_package.py +0 -0
  70. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_refresh.py +0 -0
  71. {telegram_dev-0.6.0 → telegram_dev-0.7.0}/tests/test_sources.py +0 -0
  72. {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.6.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.6.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.6.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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telegram-dev",
3
- "version": "0.6.0",
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.0",
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,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.6.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
- 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
 
@@ -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
+ }
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "telegram-dev"
7
- version = "0.6.0"
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.0",
11
+ "version": "0.7.0",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "pypi",
15
15
  "identifier": "telegram-dev",
16
- "version": "0.6.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. `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.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
- 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
 
@@ -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(query: str, area: str = "", limit: int = 6) -> dict:
837
- """Search public Telegram docs, preferring exact English API symbols. Areas: bot-api, mini-apps, telegram-api, tdlib, releases, product-releases, gateway, web-integrations, media-design, ton (docs.ton.org, TON Connect, Tolk, TVM, TEPs), ton-releases, aiogram, python-telegram-bot (docs and wiki), grammy. Core Telegram docs rank first unless the query names a library (aiogram, PTB/python-telegram-bot/telegram.ext, grammY). Russian feature aliases supported for common media topics."""
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(url: str, offset: int = 0, length: int = 16000, refresh: bool = False) -> dict:
845
- """Read paginated official documentation. Missing/stale pages refresh automatically; refresh=True forces a live check. Failures preserve cached content with freshness.stale and refresh_error. Includes hash and observation date, not release date. URL fragments do not change pagination."""
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 telegram_corpus_status() -> dict:
850
- """Report indexed scope, coverage gaps, source errors, and last successful check. Never equate indexed pages with all Telegram knowledge."""
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 telegram_document_history(url: str) -> dict:
855
- """List locally observed revisions of a source. Does not reconstruct versions predating this corpus."""
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 telegram_sources() -> dict:
865
- """List configured official entrypoints by API family; use the relevant index to discover current feature pages. This is source configuration, not proof of complete cached coverage."""
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), 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)
@@ -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"])
@@ -946,7 +946,7 @@ wheels = [
946
946
 
947
947
  [[package]]
948
948
  name = "telegram-dev"
949
- version = "0.6.0"
949
+ version = "0.7.0"
950
950
  source = { editable = "." }
951
951
  dependencies = [
952
952
  { name = "beautifulsoup4" },
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "https://glama.ai/mcp/schemas/server.json",
3
- "maintainers": ["Kay0k1"]
4
- }
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