mcp-server-appwrite 2.3.1__tar.gz → 2.4.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.
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/PKG-INFO +1 -1
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/documentation-search.md +12 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/constants.py +2 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/data/docs_index.npz +1 -1
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_search.py +8 -1
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/http_app.py +51 -1
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/operator.py +4 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_tools.py +59 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.dockerignore +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.env.example +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/ci.yml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/production.yml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/publish.yml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/staging.yml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/update-docs-index.yml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.gitignore +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.python-version +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/AGENTS.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/CLAUDE.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/Dockerfile +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/LICENSE +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/README.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/compose.yaml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/apps.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/appwrite-mcp-flow.png +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/appwrite-mcp-flow.svg +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/authentication.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/development.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/events.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/flags.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/images/claude-desktop-local-mcp-servers.png +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/images/codex-mcp.png +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/images/cursor-mcp.png +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/self-hosted.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/docs/tool-surface.md +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/glama.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/pyproject.toml +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/scripts/build_docs_index.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/scripts/docs_release_notes.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/scripts/render_server_json.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/server.template.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/__init__.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/__main__.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/__init__.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/executions.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/files.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/protocol.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/resource.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/usage.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/users.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/views.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/__init__.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/favicon.svg +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/instructions.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/view.html +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/auth.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/catalog_policy.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/context.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_index.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_source.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/error_classification.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/error_monitoring.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/__init__.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/bus.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/catalog.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/delivery.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/egress.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/envelope.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/errors.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/ingress.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/projection.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/protocol.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/streams.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/subscriptions.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/webhooks.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/flags.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/headers.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/instructions.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/legacy.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/server.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/service.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/telemetry.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/tool_manager.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/deployment_function_duplicate.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/deployment_function_failed.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/deployment_function_ready.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/deployment_site_ready.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/execution_async_failed.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/execution_async_waiting.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/execution_sync_failed.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/file_created.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/function_activation.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/row_created.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/user_created.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/support.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_apps.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_events_ingress.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_events_protocol.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_events_stream.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_events_subscribe.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/test_stdio.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/support.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_avatars.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_console_sdk_oauth.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_docs_index.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_docs_source.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_functions.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_locale.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_messaging.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_oauth_discovery.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_operator.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_sites.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_storage.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_tables_db.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_teams.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_users.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/test_all.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/fixtures/jwe-v1.json +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_auth.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_context.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_docs.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_docs_search.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_error_classification.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_error_monitoring.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_events_delivery.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_events_egress.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_events_envelope.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_events_protocol.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_http_app.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_instructions.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_operator.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_release_metadata.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_server.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_service.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_telemetry.py +0 -0
- {mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mcp-server-appwrite
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Build and deploy application backends. Add authentication, PostgreSQL/MySQL databases, vector databases, storage, serverless functions, realtime, messaging, hosting, domains, CDN and firewall.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -20,6 +20,18 @@ otherwise the server boots without it.
|
|
|
20
20
|
| `DOCS_SEARCH_MIN_SCORE` | No | `0.25` | Minimum cosine score for a match. |
|
|
21
21
|
| `DOCS_SEARCH_LIMIT` | No | `5` (max `10`) | Default max pages returned. |
|
|
22
22
|
|
|
23
|
+
## Search route
|
|
24
|
+
|
|
25
|
+
The deprecated docs MCP server at `mcp-for-docs.appwrite.io` has no OAuth session to use, so it searches through this public route instead of the MCP endpoint:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
curl -X POST https://mcp.appwrite.io/docs/search \
|
|
29
|
+
-H 'content-type: application/json' \
|
|
30
|
+
-d '{"query": "create a row"}'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
It answers `{"results": [{"path", "title", "description", "score", "content"}]}` with up to 5 pages, `400` for an invalid query or one over 500 characters, `413` for a body over 16 KiB, and `502` when the embedding request fails. The route exists only when documentation search is available.
|
|
34
|
+
|
|
23
35
|
## Rebuilding the index
|
|
24
36
|
|
|
25
37
|
Re-run when the docs change, then commit the refreshed artifact:
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/constants.py
RENAMED
|
@@ -114,6 +114,8 @@ DOCS_DEFAULT_LIMIT = 5
|
|
|
114
114
|
DOCS_MAX_LIMIT = 10
|
|
115
115
|
DOCS_DEFAULT_MIN_SCORE = 0.25
|
|
116
116
|
DOCS_MIN_QUERY_LENGTH = 3
|
|
117
|
+
DOCS_MAX_QUERY_LENGTH = 500
|
|
118
|
+
DOCS_MAX_BODY_BYTES = 16 * 1024
|
|
117
119
|
|
|
118
120
|
DATA_DIR = Path(__file__).parent / "data"
|
|
119
121
|
INDEX_FILE = "docs_index.npz"
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/data/docs_index.npz
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
|
-
name: mcp_server_appwrite-2.
|
|
2
|
+
name: mcp_server_appwrite-2.4.0/src/mcp_server_appwrite/data/docs_index.npz
|
|
3
3
|
size: 35820220 bytes
|
|
4
4
|
sha256: 1d70caae9062ecf77513f23cee05e5c9c0c0213d0db8258316cd94b73ae20f38
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_search.py
RENAMED
|
@@ -178,7 +178,10 @@ class DocsSearch:
|
|
|
178
178
|
},
|
|
179
179
|
)
|
|
180
180
|
|
|
181
|
-
def
|
|
181
|
+
def find(
|
|
182
|
+
self, arguments: dict[str, Any] | None
|
|
183
|
+
) -> tuple[str, list[dict[str, Any]]]:
|
|
184
|
+
"""Return the normalized query and its ranked pages."""
|
|
182
185
|
arguments = arguments or {}
|
|
183
186
|
query = str(arguments.get("query", "")).strip()
|
|
184
187
|
if len(query) < DOCS_MIN_QUERY_LENGTH:
|
|
@@ -198,6 +201,10 @@ class DocsSearch:
|
|
|
198
201
|
"Documentation search embedding request failed. "
|
|
199
202
|
"Check OPENAI_API_KEY and outbound connectivity to OpenAI."
|
|
200
203
|
) from exc
|
|
204
|
+
return query, results
|
|
205
|
+
|
|
206
|
+
def search(self, arguments: dict[str, Any] | None) -> list[ToolContent]:
|
|
207
|
+
query, results = self.find(arguments)
|
|
201
208
|
|
|
202
209
|
if not results:
|
|
203
210
|
return [
|
|
@@ -13,6 +13,9 @@ Builds a single-tenant Starlette ASGI app for the served Appwrite project:
|
|
|
13
13
|
following ``resource_metadata`` from the 401 challenge. Mirrors the Appwrite
|
|
14
14
|
authorization server's discovery document verbatim.
|
|
15
15
|
* ``/healthz`` — liveness probe.
|
|
16
|
+
* ``/docs/search`` — public documentation search for the deprecated docs MCP
|
|
17
|
+
server, whose clients have no user to sign in. Results and limits are fixed, so
|
|
18
|
+
a call costs one small embedding.
|
|
16
19
|
* ``/.well-known/openai-apps-challenge`` — public domain verification token.
|
|
17
20
|
* ``/appwrite/webhooks/{id}`` — MCP Events ingress for Appwrite webhooks, only
|
|
18
21
|
with the events flag on. Unauthenticated by bearer token: the Appwrite
|
|
@@ -39,6 +42,7 @@ from importlib.resources import files
|
|
|
39
42
|
from types import FrameType
|
|
40
43
|
from urllib.parse import urlsplit
|
|
41
44
|
|
|
45
|
+
import anyio.to_thread
|
|
42
46
|
import httpx
|
|
43
47
|
import uvicorn
|
|
44
48
|
from mcp.server.auth.middleware.auth_context import AuthContextMiddleware
|
|
@@ -71,7 +75,14 @@ from .auth import (
|
|
|
71
75
|
public_base_url,
|
|
72
76
|
resource_metadata_url,
|
|
73
77
|
)
|
|
74
|
-
from .constants import
|
|
78
|
+
from .constants import (
|
|
79
|
+
CORS_HEADERS,
|
|
80
|
+
DOCS_DEFAULT_LIMIT,
|
|
81
|
+
DOCS_MAX_BODY_BYTES,
|
|
82
|
+
DOCS_MAX_QUERY_LENGTH,
|
|
83
|
+
SERVER_VERSION,
|
|
84
|
+
)
|
|
85
|
+
from .docs_search import DocsSearch
|
|
75
86
|
from .events import protocol as events_protocol
|
|
76
87
|
from .events.ingress import Ingress
|
|
77
88
|
from .events.streams import Settings, Streams
|
|
@@ -449,6 +460,34 @@ async def oauth_authorize_proxy_endpoint(request: Request) -> Response:
|
|
|
449
460
|
)
|
|
450
461
|
|
|
451
462
|
|
|
463
|
+
def docs_search_endpoint(docs_search: DocsSearch):
|
|
464
|
+
async def endpoint(request: Request) -> JSONResponse:
|
|
465
|
+
try:
|
|
466
|
+
raw = b""
|
|
467
|
+
async for chunk in request.stream():
|
|
468
|
+
raw += chunk
|
|
469
|
+
if len(raw) > DOCS_MAX_BODY_BYTES:
|
|
470
|
+
return JSONResponse({"error": "body_too_large"}, status_code=413)
|
|
471
|
+
body = json.loads(raw)
|
|
472
|
+
query = body.get("query") if isinstance(body, dict) else None
|
|
473
|
+
if not isinstance(query, str) or len(query) > DOCS_MAX_QUERY_LENGTH:
|
|
474
|
+
raise ValueError(
|
|
475
|
+
f"query must be a string of at most {DOCS_MAX_QUERY_LENGTH} characters."
|
|
476
|
+
)
|
|
477
|
+
_query, results = await anyio.to_thread.run_sync(
|
|
478
|
+
docs_search.find,
|
|
479
|
+
{"query": query, "limit": DOCS_DEFAULT_LIMIT},
|
|
480
|
+
abandon_on_cancel=True,
|
|
481
|
+
)
|
|
482
|
+
except ValueError as error:
|
|
483
|
+
return JSONResponse({"error": str(error)}, status_code=400)
|
|
484
|
+
except RuntimeError as error:
|
|
485
|
+
return JSONResponse({"error": str(error)}, status_code=502)
|
|
486
|
+
return JSONResponse({"results": results})
|
|
487
|
+
|
|
488
|
+
return endpoint
|
|
489
|
+
|
|
490
|
+
|
|
452
491
|
async def health_endpoint(request: Request) -> PlainTextResponse:
|
|
453
492
|
return PlainTextResponse(f"appwrite-mcp {SERVER_VERSION} ok")
|
|
454
493
|
|
|
@@ -560,6 +599,17 @@ def build_app(
|
|
|
560
599
|
Route("/favicon.ico", endpoint=favicon_ico_endpoint, methods=["GET"]),
|
|
561
600
|
Route("/healthz", endpoint=health_endpoint, methods=["GET"]),
|
|
562
601
|
*([ingress.route] if ingress is not None else []),
|
|
602
|
+
*(
|
|
603
|
+
[
|
|
604
|
+
Route(
|
|
605
|
+
"/docs/search",
|
|
606
|
+
endpoint=docs_search_endpoint(operator.docs_search),
|
|
607
|
+
methods=["POST"],
|
|
608
|
+
)
|
|
609
|
+
]
|
|
610
|
+
if operator.docs_search is not None
|
|
611
|
+
else []
|
|
612
|
+
),
|
|
563
613
|
Route(
|
|
564
614
|
"/",
|
|
565
615
|
endpoint=mcp_endpoint,
|
|
@@ -182,6 +182,10 @@ class Operator:
|
|
|
182
182
|
def docs_enabled(self) -> bool:
|
|
183
183
|
return self._docs_search is not None
|
|
184
184
|
|
|
185
|
+
@property
|
|
186
|
+
def docs_search(self) -> DocsSearch | None:
|
|
187
|
+
return self._docs_search
|
|
188
|
+
|
|
185
189
|
def get_public_tools(self, *, apps: bool = False) -> list[types.Tool]:
|
|
186
190
|
"""The exposed tools, with the MCP Apps view tools when ``apps``."""
|
|
187
191
|
return [public.tool for public in self._tools(apps).values()]
|
|
@@ -19,10 +19,14 @@ import base64
|
|
|
19
19
|
import json
|
|
20
20
|
import unittest
|
|
21
21
|
from typing import Any
|
|
22
|
+
from unittest import mock
|
|
22
23
|
from urllib.parse import unquote
|
|
23
24
|
|
|
25
|
+
import httpx
|
|
24
26
|
from support import PNG, SCOPES, TOKEN, Client, Cloud, Project, Server, collector
|
|
25
27
|
|
|
28
|
+
from mcp_server_appwrite import docs_search
|
|
29
|
+
|
|
26
30
|
PROJECT = "6630f1a2b3c4d5e6f7a8"
|
|
27
31
|
STAGING = Project("internal-staging", buckets={"photos"}, name="Staging")
|
|
28
32
|
"""The project's ``staging`` environment, a project whose own ID is internal."""
|
|
@@ -63,6 +67,61 @@ def tearDownModule() -> None:
|
|
|
63
67
|
cloud.close()
|
|
64
68
|
|
|
65
69
|
|
|
70
|
+
class DocsSearchRoute(unittest.TestCase):
|
|
71
|
+
"""``POST /docs/search``, which the deprecated docs MCP server calls without a
|
|
72
|
+
user. Only the OpenAI query embedding is stubbed; the index is the real one."""
|
|
73
|
+
|
|
74
|
+
def setUp(self) -> None:
|
|
75
|
+
patch = mock.patch.object(
|
|
76
|
+
docs_search,
|
|
77
|
+
"_default_embedder",
|
|
78
|
+
lambda: lambda _query: [1.0] + [0.0] * 1535,
|
|
79
|
+
)
|
|
80
|
+
patch.start()
|
|
81
|
+
self.addCleanup(patch.stop)
|
|
82
|
+
|
|
83
|
+
def server(self) -> Server:
|
|
84
|
+
return Server(
|
|
85
|
+
{
|
|
86
|
+
"APPWRITE_ENDPOINT": cloud.endpoint,
|
|
87
|
+
"DOCS_SEARCH_MIN_SCORE": "-1",
|
|
88
|
+
"OPENAI_API_KEY": "stubbed",
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def test_returns_a_fixed_number_of_pages_without_auth(self):
|
|
93
|
+
with self.server() as server:
|
|
94
|
+
found = httpx.post(
|
|
95
|
+
f"{server.url}/docs/search",
|
|
96
|
+
json={"query": "create a row", "limit": 10},
|
|
97
|
+
)
|
|
98
|
+
self.assertEqual(found.status_code, 200)
|
|
99
|
+
results = found.json()["results"]
|
|
100
|
+
self.assertTrue(1 <= len(results) <= 5)
|
|
101
|
+
self.assertEqual(
|
|
102
|
+
set(results[0]), {"path", "title", "description", "score", "content"}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def test_rejects_invalid_queries_before_embedding_them(self):
|
|
106
|
+
with self.server() as server:
|
|
107
|
+
for invalid in (
|
|
108
|
+
{"query": "x"},
|
|
109
|
+
{"query": None},
|
|
110
|
+
{"query": "x" * 501},
|
|
111
|
+
["create a row"],
|
|
112
|
+
):
|
|
113
|
+
refused = httpx.post(f"{server.url}/docs/search", json=invalid)
|
|
114
|
+
self.assertEqual(refused.status_code, 400, invalid)
|
|
115
|
+
|
|
116
|
+
malformed = httpx.post(f"{server.url}/docs/search", content="nope")
|
|
117
|
+
self.assertEqual(malformed.status_code, 400)
|
|
118
|
+
|
|
119
|
+
oversized = httpx.post(
|
|
120
|
+
f"{server.url}/docs/search", content=b"x" * (16 * 1024 + 1)
|
|
121
|
+
)
|
|
122
|
+
self.assertEqual(oversized.status_code, 413)
|
|
123
|
+
|
|
124
|
+
|
|
66
125
|
class ToolsFlow(unittest.TestCase):
|
|
67
126
|
server: Server
|
|
68
127
|
client: Client
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/.github/workflows/update-docs-index.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/__init__.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/executions.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/files.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/protocol.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/resource.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/usage.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/users.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/apps/views.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/__init__.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/favicon.svg
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/assets/view.html
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/catalog_policy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_index.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/docs_source.py
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/error_monitoring.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/__init__.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/bus.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/catalog.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/delivery.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/egress.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/envelope.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/errors.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/ingress.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/projection.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/protocol.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/streams.py
RENAMED
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/events/webhooks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/instructions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/telemetry.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/src/mcp_server_appwrite/tool_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/e2e/fixtures/appwrite/row_created.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_console_sdk_oauth.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_docs_index.py
RENAMED
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_docs_source.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/integration/test_oauth_discovery.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mcp_server_appwrite-2.3.1 → mcp_server_appwrite-2.4.0}/tests/unit/test_error_classification.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|