Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ operator-style tools, supporting two deployments from one codebase:

- **Cloud (hosted HTTP):** a Starlette ASGI app that acts as an OAuth 2.1
Resource Server. It validates the client's bearer token and forwards it to the
Appwrite REST API. Served at `mcp.appwrite.io/mcp`.
Appwrite REST API. Served primarily at `mcp.appwrite.io/`, with `/mcp` also
available as a conventional alias.
- **Self-hosted (`stdio`):** runs locally and authenticates with a project API
key (`APPWRITE_PROJECT_ID`, `APPWRITE_API_KEY`, `APPWRITE_ENDPOINT`).

Expand All @@ -23,7 +24,7 @@ Source lives in `src/mcp_server_appwrite/`:
| File | Responsibility |
| --- | --- |
| `__main__.py` / `server.py` | Entry point, CLI args, transport selection (`--transport stdio\|http`), service registration, low-level MCP server. |
| `http_app.py` | Hosted Streamable-HTTP transport: `/mcp`, RFC 9728 protected-resource metadata, `/healthz`. |
| `http_app.py` | Hosted Streamable-HTTP transport: `/` plus the `/mcp` alias, RFC 9728 protected-resource metadata, `/healthz`. |
| `auth.py` | OAuth 2.1 resource-server layer — bearer-token validation against the project's Appwrite authorization server. |
| `service.py` | `Service` base class: introspects an Appwrite SDK service and turns its methods into MCP tool definitions. |
| `tool_manager.py` | Registry of all services and their generated tools. |
Expand Down Expand Up @@ -70,7 +71,7 @@ APPWRITE_PROJECT_ID=<id> APPWRITE_API_KEY=<key> \
uv run mcp-server-appwrite

# Or via Docker (hosted HTTP/OAuth)
docker compose up --build # compose.yaml; endpoint at http://localhost:8000/mcp
docker compose up --build # compose.yaml; endpoint at http://localhost:8000/
```

## Pre-PR checklist
Expand Down
41 changes: 21 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ A [Model Context Protocol](https://modelcontextprotocol.io) server for Appwrite.
It exposes Appwrite's API — databases, users, functions, teams, storage, and more
— as tools your MCP client can call.

Connect to the hosted server at **`https://mcp.appwrite.io/mcp`** and authenticate
Connect to the hosted server at **`https://mcp.appwrite.io/`** and authenticate
through your browser. The first time you connect, your client opens an Appwrite
consent screen; approve the scopes and you're connected. There are no keys to
copy.
copy. The conventional `https://mcp.appwrite.io/mcp` URL is also supported and
connects to the same server.

![How the Appwrite MCP server handles OAuth and scopes](docs/appwrite-mcp-flow.png)

Expand All @@ -21,7 +22,7 @@ Pick your client below. Each adds the hosted Appwrite Cloud server.
<summary><b>Claude Code</b></summary>

```bash
claude mcp add --transport http appwrite https://mcp.appwrite.io/mcp
claude mcp add --transport http appwrite https://mcp.appwrite.io/
```

Then, inside a Claude Code session, run `/mcp`, select **appwrite**, and follow
Expand All @@ -33,7 +34,7 @@ the browser prompt to authenticate.
<summary><b>Claude Desktop</b></summary>

Go to **Settings → Connectors → Add custom connector** and paste
`https://mcp.appwrite.io/mcp`. Available on Pro and Max plans; on Team and
`https://mcp.appwrite.io/`. Available on Pro and Max plans; on Team and
Enterprise plans only an organization Owner can add custom connectors.

If you don't see that option (free plan, or a Team/Enterprise member), bridge
Expand All @@ -45,7 +46,7 @@ the remote server through stdio instead (requires Node.js). Go to **Settings →
"mcpServers": {
"appwrite": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/mcp"]
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/"]
}
}
}
Expand All @@ -67,7 +68,7 @@ Edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project).
{
"mcpServers": {
"appwrite": {
"url": "https://mcp.appwrite.io/mcp"
"url": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -91,7 +92,7 @@ Palette → **MCP: Open User Configuration**.
"servers": {
"appwrite": {
"type": "http",
"url": "https://mcp.appwrite.io/mcp"
"url": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -106,7 +107,7 @@ Edit `~/.codex/config.toml`.

```toml
[mcp_servers.appwrite]
url = "https://mcp.appwrite.io/mcp"
url = "https://mcp.appwrite.io/"
```

Then authenticate from the terminal:
Expand All @@ -116,7 +117,7 @@ codex mcp login appwrite
```

In the Codex GUI, you can instead add the server from the MCP settings —
set the URL to `https://mcp.appwrite.io/mcp` and leave the token and header
set the URL to `https://mcp.appwrite.io/` and leave the token and header
fields empty (authentication happens through the browser):

![Appwrite MCP server settings in the Codex GUI](docs/images/codex-mcp.png)
Expand All @@ -134,7 +135,7 @@ Edit `opencode.json` (project) or `~/.config/opencode/opencode.json` (global).
"mcp": {
"appwrite": {
"type": "remote",
"url": "https://mcp.appwrite.io/mcp",
"url": "https://mcp.appwrite.io/",
"enabled": true
}
}
Expand All @@ -152,7 +153,7 @@ Edit `~/.codeium/windsurf/mcp_config.json`.
{
"mcpServers": {
"appwrite": {
"serverUrl": "https://mcp.appwrite.io/mcp"
"serverUrl": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -164,7 +165,7 @@ Edit `~/.codeium/windsurf/mcp_config.json`.
<summary><b>Gemini CLI</b></summary>

```bash
gemini mcp add --transport http appwrite https://mcp.appwrite.io/mcp
gemini mcp add --transport http appwrite https://mcp.appwrite.io/
```

Or edit `~/.gemini/settings.json` (note the key is `httpUrl`, not `url`):
Expand All @@ -173,7 +174,7 @@ Or edit `~/.gemini/settings.json` (note the key is `httpUrl`, not `url`):
{
"mcpServers": {
"appwrite": {
"httpUrl": "https://mcp.appwrite.io/mcp"
"httpUrl": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -193,7 +194,7 @@ Edit `~/.gemini/config/mcp_config.json` (global) or `.agents/mcp_config.json` (p
{
"mcpServers": {
"appwrite": {
"serverUrl": "https://mcp.appwrite.io/mcp"
"serverUrl": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -209,7 +210,7 @@ Antigravity opens the browser OAuth flow automatically on first connect. If you
<summary><b>GitHub Copilot CLI</b></summary>

```bash
copilot mcp add --transport http appwrite https://mcp.appwrite.io/mcp
copilot mcp add --transport http appwrite https://mcp.appwrite.io/
```

Or run `/mcp add` inside a session, or edit `~/.copilot/mcp-config.json`:
Expand All @@ -219,7 +220,7 @@ Or run `/mcp add` inside a session, or edit `~/.copilot/mcp-config.json`:
"mcpServers": {
"appwrite": {
"type": "http",
"url": "https://mcp.appwrite.io/mcp"
"url": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -240,7 +241,7 @@ to your `settings.json` (`zed: open settings`):
{
"context_servers": {
"appwrite": {
"url": "https://mcp.appwrite.io/mcp"
"url": "https://mcp.appwrite.io/"
}
}
}
Expand All @@ -254,7 +255,7 @@ Zed prompts you to authenticate through the browser on first connect.
<summary><b>Warp</b></summary>

Go to **Settings → Agents → MCP servers → + Add**, choose the URL-based
server type, and enter `https://mcp.appwrite.io/mcp`.
server type, and enter `https://mcp.appwrite.io/`.

Warp opens a browser window to authenticate on first connect.

Expand All @@ -272,7 +273,7 @@ Model Context Protocol (MCP) → Add**, switch to the JSON view, and paste:
"mcpServers": {
"appwrite": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/mcp"]
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/"]
}
}
}
Expand All @@ -294,7 +295,7 @@ stdio (requires Node.js). In the Cline panel, open the **MCP Servers** icon →
"mcpServers": {
"appwrite": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/mcp"]
"args": ["-y", "mcp-remote", "https://mcp.appwrite.io/"]
}
}
}
Expand Down
Binary file modified docs/appwrite-mcp-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/appwrite-mcp-flow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 8 additions & 4 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ MCP-aware clients run this automatically:
```mermaid
sequenceDiagram
participant C as MCP Client
participant S as MCP Server (/mcp)
participant S as MCP Server (/)
participant A as Appwrite OAuth Server
participant API as Appwrite REST API

C->>S: GET /mcp (no token)
C->>S: GET / (no token)
S-->>C: 401 + WWW-Authenticate → metadata URL
C->>S: GET /.well-known/oauth-protected-resource/mcp
C->>S: GET /.well-known/oauth-protected-resource
S-->>C: auth server + scopes (RFC 9728)
C->>A: Discover (RFC 8414 / OIDC)
C->>A: Self-register as public PKCE client (RFC 7591)
A-->>C: client_id (no secret to pre-provision)
C->>A: OAuth 2.1 + PKCE auth-code flow (RFC 8707 resource)
A-->>C: access token (audience bound to this server)
C->>S: GET /mcp + Authorization: Bearer <token>
C->>S: GET / + Authorization: Bearer <token>
S->>API: Forward bearer token
API-->>S: Response
S-->>C: Response
Expand All @@ -37,3 +37,7 @@ The key detail is that clients **self-register** — the auth server exposes an
`registration_endpoint` (RFC 7591), so there's no client ID or secret to
pre-provision. Everything else is standard OAuth 2.1 + PKCE, with the RFC 8707
resource indicator binding each token's audience to this server.

The conventional `/mcp` endpoint is a direct alias. It publishes matching
protected-resource metadata at `/.well-known/oauth-protected-resource/mcp`, and
tokens audience-bound to either URL are accepted by the shared service.
5 changes: 3 additions & 2 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
## Run the server

**Docker Compose** — hosted HTTP/OAuth transport, endpoint at
`http://localhost:8000/mcp` (default `MCP_PUBLIC_URL=http://localhost:8000`):
`http://localhost:8000/` (default `MCP_PUBLIC_URL=http://localhost:8000`;
`/mcp` is also supported):

```bash
docker compose up --build
Expand Down Expand Up @@ -71,7 +72,7 @@ Run the MCP Inspector against a server:
npx @modelcontextprotocol/inspector
```

To debug the hosted transport, point it at `https://mcp.appwrite.io/mcp` and
To debug the hosted transport, point it at `https://mcp.appwrite.io/` and
complete the OAuth flow when prompted. For self-hosted, start the Inspector in
stdio mode with `uv run mcp-server-appwrite` as the command and the `APPWRITE_*`
env vars above.
2 changes: 1 addition & 1 deletion server.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"remotes": [
{
"type": "streamable-http",
"url": "https://mcp.appwrite.io/mcp"
"url": "https://mcp.appwrite.io/"
}
],
"packages": [
Expand Down
Loading
Loading