trueconf-server-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. trueconf_server_mcp-0.1.0/.env.example +39 -0
  2. trueconf_server_mcp-0.1.0/.github/workflows/release-test.yml +51 -0
  3. trueconf_server_mcp-0.1.0/.github/workflows/release.yml +44 -0
  4. trueconf_server_mcp-0.1.0/.gitignore +193 -0
  5. trueconf_server_mcp-0.1.0/.python-version +1 -0
  6. trueconf_server_mcp-0.1.0/AGENTS.md +309 -0
  7. trueconf_server_mcp-0.1.0/LICENSE +32 -0
  8. trueconf_server_mcp-0.1.0/PKG-INFO +476 -0
  9. trueconf_server_mcp-0.1.0/README-ru.md +442 -0
  10. trueconf_server_mcp-0.1.0/README.md +444 -0
  11. trueconf_server_mcp-0.1.0/app/__init__.py +0 -0
  12. trueconf_server_mcp-0.1.0/app/_version.py +24 -0
  13. trueconf_server_mcp-0.1.0/app/config.py +168 -0
  14. trueconf_server_mcp-0.1.0/app/mcp/__init__.py +311 -0
  15. trueconf_server_mcp-0.1.0/app/mcp/auth.py +276 -0
  16. trueconf_server_mcp-0.1.0/app/mcp/code_mode.py +73 -0
  17. trueconf_server_mcp-0.1.0/app/mcp/errors.py +29 -0
  18. trueconf_server_mcp-0.1.0/app/mcp/i18n.py +104 -0
  19. trueconf_server_mcp-0.1.0/app/mcp/instructions.py +192 -0
  20. trueconf_server_mcp-0.1.0/app/mcp/logging_utils.py +11 -0
  21. trueconf_server_mcp-0.1.0/app/mcp/pages.py +105 -0
  22. trueconf_server_mcp-0.1.0/app/mcp/prompts.py +27 -0
  23. trueconf_server_mcp-0.1.0/app/mcp/routes.py +488 -0
  24. trueconf_server_mcp-0.1.0/app/mcp/token_store.py +323 -0
  25. trueconf_server_mcp-0.1.0/app/mcp/tools/__init__.py +0 -0
  26. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/__init__.py +45 -0
  27. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/add_invitation.py +31 -0
  28. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/calculate_conferences.py +27 -0
  29. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/create_conference.py +130 -0
  30. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/delete_conference.py +13 -0
  31. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/export_chat_messages.py +46 -0
  32. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_chat_messages.py +13 -0
  33. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference.py +13 -0
  34. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_calendars.py +13 -0
  35. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_ics.py +24 -0
  36. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_me.py +13 -0
  37. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_owner.py +13 -0
  38. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_participants.py +36 -0
  39. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_conference_translations.py +13 -0
  40. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_deeplinks.py +24 -0
  41. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_invitation.py +19 -0
  42. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_recording.py +19 -0
  43. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/get_shared_links.py +13 -0
  44. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/invite_participants.py +21 -0
  45. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/join_conference.py +13 -0
  46. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/list_conferences.py +58 -0
  47. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/list_invitations.py +13 -0
  48. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/list_recordings.py +42 -0
  49. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/notify_conference.py +25 -0
  50. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/pause_recording.py +13 -0
  51. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/register_for_conference.py +28 -0
  52. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/remove_invitation.py +19 -0
  53. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/run_conference.py +13 -0
  54. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/start_recording.py +13 -0
  55. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/stop_conference.py +13 -0
  56. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/stop_recording.py +13 -0
  57. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/update_conference.py +112 -0
  58. trueconf_server_mcp-0.1.0/app/mcp/tools/conferences/update_invitation.py +25 -0
  59. trueconf_server_mcp-0.1.0/app/tls.py +241 -0
  60. trueconf_server_mcp-0.1.0/app/trueconf_api/__init__.py +0 -0
  61. trueconf_server_mcp-0.1.0/app/trueconf_api/mode_utils.py +76 -0
  62. trueconf_server_mcp-0.1.0/app/trueconf_api/models.py +149 -0
  63. trueconf_server_mcp-0.1.0/app/web/assets/favicon.ico +0 -0
  64. trueconf_server_mcp-0.1.0/app/web/assets/logo.png +0 -0
  65. trueconf_server_mcp-0.1.0/app/web/locales/common.en.yml +10 -0
  66. trueconf_server_mcp-0.1.0/app/web/locales/common.ru.yml +10 -0
  67. trueconf_server_mcp-0.1.0/app/web/locales/error.en.yml +14 -0
  68. trueconf_server_mcp-0.1.0/app/web/locales/error.ru.yml +14 -0
  69. trueconf_server_mcp-0.1.0/app/web/locales/login.en.yml +12 -0
  70. trueconf_server_mcp-0.1.0/app/web/locales/login.ru.yml +12 -0
  71. trueconf_server_mcp-0.1.0/app/web/locales/success.en.yml +26 -0
  72. trueconf_server_mcp-0.1.0/app/web/locales/success.ru.yml +27 -0
  73. trueconf_server_mcp-0.1.0/app/web/static/app.css +196 -0
  74. trueconf_server_mcp-0.1.0/app/web/static/app.js +82 -0
  75. trueconf_server_mcp-0.1.0/app/web/templates/error.html +341 -0
  76. trueconf_server_mcp-0.1.0/app/web/templates/login.html +344 -0
  77. trueconf_server_mcp-0.1.0/app/web/templates/success.html +468 -0
  78. trueconf_server_mcp-0.1.0/assets/login_en.png +0 -0
  79. trueconf_server_mcp-0.1.0/assets/login_ru.png +0 -0
  80. trueconf_server_mcp-0.1.0/assets/poster-en.png +0 -0
  81. trueconf_server_mcp-0.1.0/assets/poster-ru.png +0 -0
  82. trueconf_server_mcp-0.1.0/assets/success_en.png +0 -0
  83. trueconf_server_mcp-0.1.0/assets/success_ru.png +0 -0
  84. trueconf_server_mcp-0.1.0/main.py +295 -0
  85. trueconf_server_mcp-0.1.0/pyproject.toml +89 -0
  86. trueconf_server_mcp-0.1.0/setup.cfg +4 -0
  87. trueconf_server_mcp-0.1.0/tests/__init__.py +6 -0
  88. trueconf_server_mcp-0.1.0/tests/conftest.py +162 -0
  89. trueconf_server_mcp-0.1.0/tests/test_auth.py +226 -0
  90. trueconf_server_mcp-0.1.0/tests/test_code_mode.py +52 -0
  91. trueconf_server_mcp-0.1.0/tests/test_config.py +189 -0
  92. trueconf_server_mcp-0.1.0/tests/test_conftest.py +39 -0
  93. trueconf_server_mcp-0.1.0/tests/test_instructions.py +34 -0
  94. trueconf_server_mcp-0.1.0/tests/test_logging.py +97 -0
  95. trueconf_server_mcp-0.1.0/tests/test_mode_utils.py +47 -0
  96. trueconf_server_mcp-0.1.0/tests/test_request.py +219 -0
  97. trueconf_server_mcp-0.1.0/tests/test_request_file.py +164 -0
  98. trueconf_server_mcp-0.1.0/tests/test_routes.py +65 -0
  99. trueconf_server_mcp-0.1.0/tests/test_routes_auth.py +540 -0
  100. trueconf_server_mcp-0.1.0/tests/test_tls.py +211 -0
  101. trueconf_server_mcp-0.1.0/tests/test_token_store.py +355 -0
  102. trueconf_server_mcp-0.1.0/tests/test_tools.py +182 -0
  103. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/PKG-INFO +476 -0
  104. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/SOURCES.txt +109 -0
  105. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/dependency_links.txt +1 -0
  106. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/entry_points.txt +2 -0
  107. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/requires.txt +7 -0
  108. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/scm_file_list.json +104 -0
  109. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/scm_version.json +8 -0
  110. trueconf_server_mcp-0.1.0/trueconf_server_mcp.egg-info/top_level.txt +2 -0
  111. trueconf_server_mcp-0.1.0/uv.lock +1494 -0
@@ -0,0 +1,39 @@
1
+ # TrueConf Server MCP — example configuration.
2
+ # Copy to .env and edit. .env is git-ignored.
3
+ #
4
+ # Priority (highest → lowest):
5
+ # 1. CLI flags: trueconf-server-mcp --server 10.0.0.1 --port 9000
6
+ # 2. Environment variables (export TRUECONF_SERVER=...)
7
+ # 3. This .env file (loaded via python-dotenv)
8
+ # 4. Built-in defaults
9
+ #
10
+ # Required:
11
+ TRUECONF_SERVER=10.140.1.255
12
+ TRUECONF_CLIENT_ID=your_client_id
13
+ TRUECONF_SECRET=your_secret
14
+ #
15
+ # Optional:
16
+ TRUECONF_VERIFY_SSL=false
17
+ MCP_BASE_URL=https://localhost
18
+ # MCP_BASE_URL must be reachable by MCP clients from outside — 127.0.0.1 does NOT work.
19
+ # Default: https://localhost (port 443 omitted); http://localhost:<port> when MCP_NO_TLS=true.
20
+ # For LAN access use https://<your-LAN-IP>, e.g. https://10.140.1.177
21
+ TRUECONF_MCP_PORT=443
22
+ # Default: 443 (HTTPS) or 80 when MCP_NO_TLS=true. Omit to use the default.
23
+ AUTH_MODE=token
24
+ # AUTH_MODE: oauth (OAuthProxy + DCR) or token (manual long-lived token)
25
+ DISCOVERY_MODE=static
26
+ # DISCOVERY_MODE: static (all 33 tools) | bm25 (search gateway) | code (CodeMode sandbox)
27
+ API_TOKEN_TTL=86400
28
+ # Legacy: CODE_MODE_EXPERIMENTAL=true forces DISCOVERY_MODE=code (overrides DISCOVERY_MODE)
29
+ HTTP_TIMEOUT=30
30
+ # HTTP_TIMEOUT: timeout (seconds) for TrueConf API HTTP requests. Default: 30.
31
+ #
32
+ # TLS:
33
+ MCP_NO_TLS=false
34
+ # MCP_NO_TLS=true — disable TLS (plain HTTP, default port 80).
35
+ MCP_TLS_CERT=
36
+ MCP_TLS_KEY=
37
+ # MCP_TLS_CERT / MCP_TLS_KEY — paths to a custom PEM cert+key. Both required if either is set.
38
+ # If omitted and TLS is enabled, a self-signed cert is generated and persisted
39
+ # in ~/Library/Application Support/fastmcp/tls/ (SAN from MCP_BASE_URL host).
@@ -0,0 +1,51 @@
1
+ name: Release to TestPyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tag:
7
+ description: "Tag to release (e.g. v1.2.3 or v1.2.3rc1)"
8
+ required: true
9
+ type: string
10
+
11
+ permissions:
12
+ contents: read
13
+ id-token: write
14
+
15
+ jobs:
16
+ publish-to-testpypi:
17
+ runs-on: ubuntu-latest
18
+ environment: testpypi
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+ fetch-tags: true
24
+ ref: ${{ github.event.inputs.tag }}
25
+
26
+ - name: Set version from tag
27
+ run: |
28
+ TAG="${{ github.event.inputs.tag }}"
29
+ VERSION="${TAG#v}"
30
+ sed -i "s/^version = .*/version = \"${VERSION}\"/" pyproject.toml
31
+
32
+ - name: Set up Python
33
+ uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.12"
36
+
37
+ - name: Build package
38
+ run: |
39
+ pip install build
40
+ python -m build
41
+
42
+ - name: Check dist metadata
43
+ run: |
44
+ pip install twine
45
+ twine check dist/*
46
+
47
+ - name: Publish package to TestPyPI
48
+ uses: pypa/gh-action-pypi-publish@release/v1
49
+ with:
50
+ repository-url: https://test.pypi.org/legacy/
51
+ verbose: true
@@ -0,0 +1,44 @@
1
+ name: Release to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write
10
+
11
+ jobs:
12
+ build-and-publish:
13
+ runs-on: ubuntu-latest
14
+ environment: pypi
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ with:
18
+ fetch-depth: 0
19
+ ref: ${{ github.event.release.tag_name }}
20
+
21
+ - name: Set version from tag
22
+ run: |
23
+ TAG="${{ github.event.release.tag_name }}"
24
+ VERSION="${TAG#v}"
25
+ sed -i "s/^version = .*/version = \"${VERSION}\"/" pyproject.toml
26
+
27
+ - name: Set up Python
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+
32
+ - name: Build package
33
+ run: |
34
+ pip install build
35
+ python -m build
36
+
37
+ - name: Upload artifacts to Actions
38
+ uses: actions/upload-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/*
42
+
43
+ - name: Publish to PyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,193 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ app/_version.py
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ #Pipfile.lock
97
+
98
+ # UV
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ #uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ #poetry.lock
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ #pdm.lock
114
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
115
+ # in version control.
116
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
117
+ .pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
122
+ __pypackages__/
123
+
124
+ # Celery stuff
125
+ celerybeat-schedule
126
+ celerybeat.pid
127
+
128
+ # SageMath parsed files
129
+ *.sage.py
130
+
131
+ # Environments
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+ # dotenv: real config (keep .env.example tracked)
139
+ .env
140
+ .env.local
141
+ .env.*.local
142
+
143
+ # Spyder project settings
144
+ .spyderproject
145
+ .spyproject
146
+
147
+ # Rope project settings
148
+ .ropeproject
149
+
150
+ # mkdocs documentation
151
+ /site
152
+
153
+ # mypy
154
+ .mypy_cache/
155
+ .dmypy.json
156
+ dmypy.json
157
+
158
+ # Pyre type checker
159
+ .pyre/
160
+
161
+ # pytype static type analyzer
162
+ .pytype/
163
+
164
+ # Cython debug symbols
165
+ cython_debug/
166
+
167
+ # PyCharm
168
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
169
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
170
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
171
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
172
+ #.idea/
173
+
174
+ # PyPI configuration file
175
+ .pypirc
176
+
177
+ #VS Code folder
178
+ .vscode
179
+
180
+ .idea
181
+
182
+ *.DS_Store
183
+
184
+ .venv*
185
+ venv*
186
+ /gitignore/
187
+
188
+ docs
189
+ graphify-out
190
+
191
+ # Local-only files (not part of the project)
192
+ openapi.yaml
193
+ skills-lock.json
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,309 @@
1
+ # TrueConf Server MCP
2
+
3
+ ## Запуск
4
+
5
+ ```bash
6
+ # Typer CLI (entry point после uv sync):
7
+ trueconf-server-mcp serve --server 10.0.0.1 --port 9000
8
+
9
+ # или через python main.py (тот же Typer app):
10
+ uv run python main.py serve --server 10.0.0.1
11
+
12
+ # без подкоманды — работает (serve — единственная команда):
13
+ uv run python main.py --server 10.0.0.1
14
+
15
+ # с .env файлом (см. ниже):
16
+ uv run python main.py
17
+ ```
18
+
19
+ Python 3.12, пакеты через `uv`. Тесты: `uv run pytest` (pytest + pytest-asyncio, `asyncio_mode = auto`, 15 файлов в `tests/`). Линтер: `uv run ruff check .`.
20
+
21
+ ### Приоритет конфигурации
22
+
23
+ **CLI flags > env vars > `.env` > дефолты кода.**
24
+
25
+ 1. **CLI flags** — `--server`, `--port`, `--discovery-mode {static|bm25|code}`, ... (см. `trueconf-server-mcp serve --help`).
26
+ 2. **Environment variables** — `TRUECONF_SERVER`, `TRUECONF_MCP_PORT`, ... (Typer `envvar=` читает их автоматически).
27
+ 3. **`.env` файл** — загружается через `python-dotenv` (`load_dotenv()` в начале `main.py`). Пример: `.env.example`. Реальный `.env` в `.gitignore`.
28
+ 4. **Дефолты** — в сигнатурах Typer-опций и `app/config.py::Config`.
29
+
30
+ `run_server(config)` (в `main.py`) принимает готовый `Config` dataclass и запускает сервер. `Config.from_env()` — fallback для программного использования без Typer.
31
+
32
+ ## Конфигурация
33
+
34
+ | Параметр CLI | Env var | По умолчанию | Описание |
35
+ |---|---|---|---|
36
+ | `--server` | `TRUECONF_SERVER` | (обязательный) | Хост TrueConf Server |
37
+ | `--client-id` | `TRUECONF_CLIENT_ID` | (обязательный) | OAuth client_id |
38
+ | `--secret` | `TRUECONF_SECRET` | (обязательный) | OAuth client_secret |
39
+ | `--verify-ssl/--no-verify-ssl` | `TRUECONF_VERIFY_SSL` | `true` | Проверка SSL-сертификата |
40
+ | `--base-url` | `MCP_BASE_URL` | `https://localhost` | Публичный URL сервера. По умолчанию `https://localhost` (порт 443 опускается); `http://localhost:<port>` при `--no-tls`. |
41
+ | `--port` | `TRUECONF_MCP_PORT` | `443` (`80` при `--no-tls`) | Порт. HTTPS по умолчанию 443, plain HTTP при `--no-tls` — 80. |
42
+ | `--no-tls` | `MCP_NO_TLS` | `false` | Отключить TLS — plain HTTP. Дефолт порта становится 80, самоподписанный сертификат не генерируется. |
43
+ | `--tls-cert` | `MCP_TLS_CERT` | (none → авто-генерация) | Путь к PEM-сертификату. Требует `--tls-key`. Если не указан и TLS включён — генерируется self-signed. |
44
+ | `--tls-key` | `MCP_TLS_KEY` | (none → авто-генерация) | Путь к PEM-ключу. Требует `--tls-cert`. |
45
+ | `--discovery-mode` | `DISCOVERY_MODE` | `static` | `static` (все 32 инструмента), `bm25` (search gateway), `code` (CodeMode sandbox) |
46
+ | — | `CODE_MODE_EXPERIMENTAL` | `false` | **Deprecated** — legacy-альяс: `true` → `discovery-mode=code` (только если `--discovery-mode`/`DISCOVERY_MODE` не заданы явно) |
47
+ | `--auth-mode` | `AUTH_MODE` | `token` | `token` = ручной токен через TokenStore (единственный активный режим). `oauth` = OAuthProxy + DCR (**отключён**: `_TrueConfTokenVerifier` принимал любой токен — auth bypass; код оставлен как dead code для будущего re-enable после реализации настоящей верификации). `--auth-mode oauth` rejected Typer. |
48
+ | `--api-token-ttl` | `API_TOKEN_TTL` | `86400` | TTL нашего токена (сек) |
49
+ | `--http-timeout` | `HTTP_TIMEOUT` | `30.0` | Timeout (сек) для HTTP-запросов к TrueConf API |
50
+
51
+ `run.sh` / `run.bat` содержат хардкод-креденшалы — не коммитьте изменения в них. Для локальной разработки скопируйте `.env.example` → `.env` и отредактируйте.
52
+
53
+ ## TLS
54
+
55
+ По умолчанию сервер запускается на `https://0.0.0.0:443` с **автоматически сгенерированным self-signed сертификатом**. SAN сертификата берётся из host-части `MCP_BASE_URL`:
56
+ - `https://localhost` (дефолт) → SAN `[localhost, 127.0.0.1]`
57
+ - `https://10.100.2.108` → SAN `[10.100.2.108]`
58
+ - `https://conf.local` → SAN `[conf.local]`
59
+
60
+ Сертификат **персистится** в `~/Library/Application Support/fastmcp/tls/{cert.pem,key.pem}` (права `0600` на ключ) и переиспользуется между рестартами. Регенерация — при отсутствии файлов, истечении срока (<30 дней), **или несовпадении SAN с текущим `MCP_BASE_URL`**.
61
+
62
+ **Кастомный сертификат**: `--tls-cert /path/cert.pem --tls-key /path/key.pem` (оба флага обязательны, если указан хотя бы один). Используется для валидных сертификатов (Let's Encrypt и т.п.).
63
+
64
+ **Plain HTTP**: `--no-tls` — отключает TLS, дефолт порта становится 80. Bearer-токены передаются в cleartext — только для случаев, когда TLS-клиент не работает (например, LM Studio с self-signed).
65
+
66
+ ### Привилегированные порты (<1024)
67
+
68
+ - **macOS** (Mojave+): бинд `0.0.0.0:443` работает **без root**. Бинд на конкретный интерфейс (`127.0.0.1:443`) требует root.
69
+ - **Linux**: требует `sudo setcap cap_net_bind_service+ep $(which python)` (один раз при установке) либо запуск под `sudo`. Без прав — exit с понятной ошибкой и подсказкой про `setcap`/`sudo`/`--port 8443`.
70
+ - **Windows**: запуск от администратора (UAC) либо `--port 8443`.
71
+
72
+ ### Перерегистрация OAuth redirect_uri
73
+
74
+ Смена дефолта `MCP_BASE_URL` с `http://localhost:8000` на `https://localhost` меняет `redirect_uri`, который регистрируется на TrueConf Server при OAuth-настройке. Существующие регистрации нужно обновить. Проект не релизнут — миграции нет.
75
+
76
+ **Переименование `/login/callback` → `/auth/callback`** также меняет `redirect_uri` (теперь `.../auth/callback`). Для **обоих** auth-режимов (`oauth` и `token`) существующие регистрации на TrueConf Server нужно обновить — старый путь `/login/callback` больше не обслуживается.
77
+
78
+ ## Архитектура
79
+
80
+ ```
81
+ main.py # Typer CLI (app + serve + DiscoveryMode), run_server(config),
82
+ # _serve() (uvicorn+cleanup_task), import-time side effects
83
+ # (load_dotenv, logging.basicConfig, init_i18n, регистрация
84
+ # tools/prompts/routes через side-effect imports)
85
+ app/
86
+ __init__.py # маркер пакета
87
+ config.py # Config dataclass + get_config()/set_config() — единый источник конфигурации
88
+ tls.py # TLS: extract_san_names, generate/ensure_self_signed_cert,
89
+ # resolve_tls_files(config), bind_error_help(port)
90
+ trueconf_api/ # слой 1: чистый домен TrueConf (без зависимостей от MCP/fastmcp)
91
+ __init__.py # маркер пакета
92
+ models.py # Pydantic-модели из OpenAPI schemas
93
+ mode_utils.py # _resolve_mode() + _MODE_MAP / _ACCESS_MAP
94
+ mcp/ # слой 2: MCP-инфра (зависит от trueconf_api + fastmcp)
95
+ __init__.py # mcp (FastMCP), _request(), init_http_client()/close_http_client()
96
+ # _token_store + get_token_store()/set_token_store() — общие утилиты
97
+ auth.py # ApiTokenAuth — наш UUID → TrueConf токен + авто-refresh,
98
+ # create_oauth_auth() — OAuthProxy с DCR,
99
+ # init_auth(config, token_store) — всегда ApiTokenAuth (OAuth path disabled)
100
+ token_store.py # TokenStore — зашифрованное файловое хранилище токенов,
101
+ # init_token_store(config) — фабрика (derive keys + FileTreeStore + Fernet),
102
+ # periodic_cleanup() — часовая фоновая задача (вызывает cleanup_expired)
103
+ instructions.py # STATIC/BM25/CODE_MODE_INSTRUCTIONS — per-mode server instructions,
104
+ # apply_discovery_mode(config) — выбор transform + mcp.instructions
105
+ code_mode.py # CodeMode: guide + create_code_mode_transform()
106
+ pages.py # HTML-страницы (login/success/error) + путь к templates/
107
+ prompts.py # MCP-prompts (conference_help) — side-effect регистрация через import
108
+ routes.py # HTTP UI-роуты (/, /success, /error, /auth/callback, /api/health,
109
+ # /static/*, /favicon.ico, /logo.png) + _cors() +
110
+ # register_login_callback() — всегда (OAuth path disabled)
111
+ tools/
112
+ __init__.py # маркер (агрегатор при масштабировании: транскрипции и т.д.)
113
+ conferences/ # 32 MCP-инструмента, один файл на инструмент
114
+ __init__.py # импорт всех 32 модулей → триггер @mcp.tool регистрации
115
+ # Core CRUD
116
+ list_conferences.py
117
+ get_conference.py
118
+ create_conference.py
119
+ update_conference.py
120
+ delete_conference.py
121
+ # Lifecycle
122
+ run_conference.py
123
+ stop_conference.py
124
+ join_conference.py
125
+ # Invitations
126
+ list_invitations.py
127
+ add_invitation.py
128
+ remove_invitation.py
129
+ get_invitation.py
130
+ update_invitation.py
131
+ invite_participants.py
132
+ # Participants & Roles
133
+ get_conference_participants.py
134
+ get_conference_owner.py
135
+ get_conference_me.py
136
+ # Recordings
137
+ list_recordings.py
138
+ get_recording.py
139
+ start_recording.py
140
+ stop_recording.py
141
+ pause_recording.py
142
+ download_recording.py
143
+ # Chat
144
+ get_chat_messages.py
145
+ export_chat_messages.py
146
+ # Links & Calendar
147
+ get_deeplinks.py
148
+ get_shared_links.py
149
+ get_conference_ics.py
150
+ get_conference_calendars.py
151
+ # Notifications & Registration
152
+ notify_conference.py
153
+ register_for_conference.py
154
+ # Translations
155
+ get_conference_translations.py
156
+ # Admin
157
+ calculate_conferences.py
158
+ # (масштабируется: tools/transcriptions/, tools/users/ и т.д.)
159
+ web/ # веб-ассеты и шаблоны (раньше были в корне как static/ + templates/)
160
+ assets/ # favicon.ico, logo.png
161
+ static/
162
+ app.css # Общий chrome (topbar, footer, lang-switch, status-badge) — login/success/error
163
+ app.js # Language switcher dropdown + TrueConf Server health check
164
+ templates/
165
+ login.html # Полная страница входа (shared topbar + two-column main + footer)
166
+ success.html # Полная страница после авторизации (токен + конфиги MCP-клиентов)
167
+ error.html # Полная страница ошибки OAuth (красный акцент, retry-карточка)
168
+ login_body.html # Legacy body-фрагмент (не используется)
169
+ success_body.html # Legacy body-фрагмент (не используется)
170
+ openapi.yaml # TrueConf Server API v4 (277 эндпоинтов)
171
+ ```
172
+
173
+ ## Критично: Токен-флоу
174
+
175
+ Цепочка авторизации — самая важная концепция в проекте:
176
+
177
+ **Режим `oauth` (отключён):** OAuthProxy + DCR путь оставлен как dead code (`create_oauth_auth` / `_TrueConfTokenVerifier` в `auth.py`). `init_auth` всегда возвращает `ApiTokenAuth`. Причина отключения: `_TrueConfTokenVerifier.verify_token` принимал ЛЮБУЮ строку как валидный токен — полный обход авторизации. Re-enable только после реализации настоящей валидации opaque-токенов против TrueConf Server.
178
+
179
+ **Режим `token` (единственный активный):**
180
+ 1. Пользователь заходит на `/` → OAuth2 редирект на TrueConf Server
181
+ 2. `/auth/callback` обменивает code на TrueConf tokens, создаёт наш длинный токен, редиректит на `/success` (токен доставляется через `mcp_token` httpOnly cookie, не через query param)
182
+ 3. Наш токен хранится зашифрованно в `~/Library/Application Support/fastmcp/oauth-proxy/<fingerprint>/mcp-api-tokens/`
183
+ 4. MCP-клиент шлёт `Authorization: Bearer <our_token>`:
184
+ - `ApiTokenAuth.verify_token()` ищет наш токен в TokenStore
185
+ - Если TrueConf токен протух — прозрачный refresh
186
+ - Возвращает `AccessToken(token=<TrueConf_token>)` — `.token` это TrueConf токен, не наш UUID
187
+ 5. Инструменты вызывают `get_access_token()` → `.token` = TrueConf токен, `.client_id` = user_id
188
+ 6. `_call_trueconf()` использует общий httpx-клиент (`init_http_client()`), добавляет `Authorization: Bearer <TrueConf_token>` в headers per-request
189
+
190
+ **Не путайте наш UUID-токен с TrueConf access_token.** `ApiTokenAuth` делает маппинг.
191
+
192
+ **CORS для cookie-флоу.** TrueConf Server выполняет `/oauth2/authorize` через `fetch()` из JS — `/auth/callback` приходит как **credentialed cross-site CORS request**. Для таких запросов браузер требует: (1) `Access-Control-Allow-Origin` = конкретный Origin (не `*`), (2) `Access-Control-Allow-Credentials: true`. Без обоих браузер блокирует ответ и **дропает `Set-Cookie`** → `/success` не видит cookie → login loop. `_cors()` в `routes.py` эхит Origin из request + ставит `Allow-Credentials: true` + `Vary: Origin`. `SameSite=None` + `Secure` на cookie необходимы, но **недостаточны** без правильных CORS headers.
193
+
194
+ **Неаутентифицированные запросы (pass-through).** `RequireAuthMiddleware` пропатчен (`_patch_auth_middleware_optional` в `auth.py`) так, что запросы без Bearer-токена проходят через middleware к MCP-обработчику. Инструменты сами проверяют `get_access_token()` через `_request` и, если токена нет, возвращают `{"error": "authorization_required", "login_url": ..., "message": ..., "how_to": ...}` dict — LLM объясняет юзеру как авторизоваться. Жёсткий 401-ответ с JSON-инструкциями **никогда не срабатывает** в обоих auth-режимах (token и oauth). Pass-through патч обязателен для code_mode/bm25 — иначе `initialize` падает на 401 и discovery недоступен.
195
+
196
+ ## Добавление новых инструментов
197
+
198
+ 1. Если нужны новые модели — добавить в `app/trueconf_api/models.py`
199
+ 2. Создать файл в соответствующем пакете (`app/mcp/tools/conferences/`, `app/mcp/tools/transcriptions/` и т.д.)
200
+ 3. Декоратор `@mcp.tool(tags={"tag1", "tag2"})` — `mcp` импортируется из `app.mcp`
201
+ 4. API-запросы через `await _request("METHOD", "path", json=..., params=...)` (`_request` — из `app.mcp`)
202
+ 5. `_request` сам обрабатывает auth, логирование, парсинг ошибок и учёт использования
203
+ 6. Импорт нового модуля в `__init__.py` пакета (например `app/mcp/tools/conferences/__init__.py`) автоматически регистрирует инструменты. Не забыть `import app.mcp.tools.<domain>` в `main.py` (или в общем `app/mcp/tools/__init__.py`)
204
+
205
+ `mcp.instructions` (server-level контекст для MCP-клиента) задаётся в `apply_discovery_mode()` (`app/mcp/instructions.py`) per-режим (`STATIC_INSTRUCTIONS` / `BM25_INSTRUCTIONS` / `CODE_MODE_INSTRUCTIONS`). Вызывается из `run_server()` в `main.py`. При изменении домена (новые типы объектов) обновлять все три константы.
206
+
207
+ ## Деплой
208
+
209
+ - По умолчанию сервер сам терминирует TLS на 443 с self-signed сертификатом (см. раздел [TLS](#tls))
210
+ - Caddy (`Caddyfile`) — опционально, для валидных сертификатов (Let's Encrypt); проксирует на `localhost:443` (или `--port 8443` при коллизии)
211
+ - Альтернатива: ngrok (`ngrok http 443`) — туннелирует HTTPS с валидным сертификатом
212
+ - Путь хранения токенов зависит от `TRUECONF_SECRET` — смена = все токены станут нечитаемыми
213
+ - Фоновая задача `periodic_cleanup()` стартует с одного sweep при запуске, затем каждые час чистит протухшие токены без refresh_token
214
+ - **⚠️ Single-worker only:** `asyncio.Lock` в `TokenStore._index_lock` сериализует только в одном процессе. Multi-worker деплой (uvicorn `--workers N`) с общим filesystem — гонки на индексе (read-modify-write → потерянные токены, двойные удаления). Запускать с одним worker.
215
+
216
+ ## Подключение MCP-клиентов (LM Studio, Cursor и т.д.)
217
+
218
+ ### MCP_BASE_URL — критически важно
219
+
220
+ `MCP_BASE_URL` определяет URL-адреса в OAuth metadata (`/.well-known/oauth-authorization-server`).
221
+ MCP-клиент получает эти URL и обращается к ним при DCR и OAuth flow.
222
+
223
+ **Правило:** `MCP_BASE_URL` должен быть тем URL, по которому клиент может достучаться до сервера извне.
224
+
225
+ | Сценарий | `MCP_BASE_URL` |
226
+ |----------|----------------|
227
+ | Локальный (только localhost) | `https://localhost` (дефолт, порт 443 опущен) |
228
+ | LAN (другие устройства в сети) | `https://<LAN-IP>` (порт 443 опущен) |
229
+ | Через Caddy | `https://<domain-or-ip>` |
230
+ | Через ngrok | `https://<ngrok-url>` |
231
+
232
+ **Частая ошибка:** `MCP_BASE_URL=https://127.0.0.1` — metadata возвращает `127.0.0.1`, клиент не может достучаться → 401 → "Plugin process exited".
233
+
234
+ ### CIMD (Client ID Metadata Document)
235
+
236
+ FastMCP OAuthProxy по умолчанию включает CIMD (`enable_cimd=True`). В metadata появляется `client_id_metadata_document_supported: true`.
237
+
238
+ **Проблема:** LM Studio интерпретирует это как "сервер поддерживает только CIMD, а не стандартный DCR" → показывает "This server does not support Dynamic Client Registration".
239
+
240
+ **Решение:** Отключить CIMD в `create_oauth_auth()` (`auth.py`):
241
+ ```python
242
+ auth = OAuthProxy(
243
+ ...,
244
+ enable_cimd=False,
245
+ )
246
+ ```
247
+
248
+ ### LM Studio + OAuth
249
+
250
+ LM Studio (начиная с 0.3.17) поддерживает MCP-серверы через `mcp.json`. Поддерживает DCR (Dynamic Client Registration) для OAuth flow. **Не поддерживает CIMD.**
251
+
252
+ Пример конфигурации в LM Studio:
253
+ ```json
254
+ {
255
+ "mcpServers": {
256
+ "trueconf": {
257
+ "url": "https://<MCP_BASE_URL>/mcp"
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### Caddy + Node.js (LM Studio)
264
+
265
+ Node.js (используется внутри LM Studio) **не доверяет самоподписанным сертификатам** — ни Caddy, ни нашему авто-сгенерированному self-signed из раздела [TLS](#tls). Не использует macOS Keychain.
266
+
267
+ Caddy пишет `root certificate is already trusted by system`, но Node.js это игнорирует. `NODE_EXTRA_CA_CERTS` не помогает — LM Studio не прокидывает эту переменную в свой Node.js процесс.
268
+
269
+ **Решения:**
270
+ - **ngrok** — туннелирует HTTPS с валидным сертификатом (free tier: URL меняется при каждом перезапуске)
271
+ - **Домен + Let's Encrypt** — Caddy автоматически получит валидный сертификат
272
+
273
+ ### NODE_TLS_REJECT_UNAUTHORIZED workaround (self-signed cert)
274
+
275
+ Если LM Studio вылетает с ошибкой:
276
+
277
+ > TypeError: fetch failed: self-signed certificate; if the root CA is installed locally, try running Node.js with --use-system-ca
278
+
279
+ Запустите LM Studio с отключённой валидацией TLS-сертификатов:
280
+
281
+ **macOS:**
282
+ ```bash
283
+ NODE_TLS_REJECT_UNAUTHORIZED=0 open "/Applications/LM Studio.app"
284
+ ```
285
+
286
+ **Windows (CMD):**
287
+ ```cmd
288
+ set NODE_TLS_REJECT_UNAUTHORIZED=0
289
+ start "" "C:\Program Files\LM Studio\LM Studio.exe"
290
+ ```
291
+
292
+ **Linux:**
293
+ ```bash
294
+ NODE_TLS_REJECT_UNAUTHORIZED=0 lm-studio
295
+ ```
296
+
297
+ **Важно:**
298
+ - Env var действует только для текущей сессии — перезапуск из Dock/Start Menu/Spotlight требует повторного запуска из терминала
299
+ - Отключает валидацию сертификатов для ВСЕХ HTTPS-запросов Node.js в процессе LM Studio — только для локальной разработки
300
+ - Проверено: работает с auth mode `token`
301
+
302
+ ## Известные проблемы
303
+
304
+ - `download_recording` удалён — грузил весь видеофайл в base64 (memory bomb), LLM не мог осмысленно использовать видео-блоб в MCP-контексте. Скачивание записей — через `download_url` из `get_recording`/`list_recordings`
305
+ - LM Studio не поддерживает CIMD — если в metadata есть `client_id_metadata_document_supported: true`, LM Studio показывает "DCR not supported". Решение: `enable_cimd=False` в OAuthProxy
306
+ - `MCP_BASE_URL` с `127.0.0.1` не работает для удалённых клиентов — metadata возвращает localhost URL
307
+ - Node.js (LM Studio) не доверяет самоподписанным сертификатам — ни Caddy, ни авто-сгенерированному из [TLS](#tls). Workaround: `NODE_TLS_REJECT_UNAUTHORIZED=0` при запуске LM Studio (см. раздел выше). Для production — ngrok или Let's Encrypt.
308
+ - ~~**CORS login loop (fixed).**~~ Исторически `_cors()` в `routes.py` возвращал `Access-Control-Allow-Origin: *` без `Access-Control-Allow-Credentials: true`. Для credentialed cross-site `fetch()` (которым является `/auth/callback` из TrueConf Server JS) браузер блокирует такой ответ и **дропает `Set-Cookie`** → `/success` не видит cookie → login loop. Фикс: `_cors()` эхит Origin из request + ставит `Allow-Credentials: true` + `Vary: Origin` (когда Origin есть); без Origin — `*` как и раньше.
309
+ - **Login CSRF (session fixation, insider-only).** TrueConf Server не поддерживает `state` и PKCE в OAuth flow, поэтому классическая OAuth state-binding недоступна. Атакующий — легитимный пользователь TrueConf Server — может прогнать `/` flow своими кредами, перехватить `code` до consumed и доставить жертве `https://<mcp>/auth/callback?code=<attacker_code>` в течение ~60с (TTL кода). В результате MCP-клиент жертвы работает в аккаунте атакующего (видит его конференции, записи, чаты). Это session fixation, не credential theft: creds жертвы не утекают, work product жертвы оседает в аккаунте атакующего. Митигации: `mcp_token` cookie `max_age=60`, single-use, `httponly`, `samesite=none` + `secure` (None обязателен: TrueConf Server выполняет `/oauth2/authorize` через `fetch()` из JS — callback приходит как cross-site cors request, и SameSite=Lax было бы drop'нуто браузером; cookie вообще не сохранялось → /success не видел токен → login loop). Re-confirmation step (страница «Вы авторизуетесь как X. Подтвердить?» + POST с CSRF-токеном) отклонён по cost/benefit — friction на каждый легитимный логин ради узкого insider-сценария. Остаточный риск принят.