diff --git a/.gitignore b/.gitignore index 61a7f1ce2..0bbb1b9c8 100644 --- a/.gitignore +++ b/.gitignore @@ -89,4 +89,7 @@ AGENTS.md .windsurfrules .aider* .copilot/ +.mcp.json +.codex/ +.gemini/ .github/copilot-instructions.md diff --git a/Makefile b/Makefile index c87bcfd46..cacc01a3a 100644 --- a/Makefile +++ b/Makefile @@ -424,7 +424,8 @@ help: @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(GREEN)%-30s$(RESET) %s\n", $$1, $$2}' .PHONY: help -# Front +# -- Frontend + frontend-development-install: ## install the frontend locally cd $(PATH_FRONT_IMPRESS) && yarn .PHONY: frontend-development-install @@ -456,6 +457,79 @@ frontend-i18n-compile: ## Format the crowin json files used deploy to the apps cd $(PATH_FRONT) && yarn i18n:deploy .PHONY: frontend-i18n-compile +# -- MCP +## Helpful targets to connect various MCP clients to docs-mcp (localhost:4455/mcp) for development. + +mcp-claude: ## Connect Claude Code to docs-mcp and launch it (authenticate with `/mcp` on first use) + @test -f .mcp.json || printf '%s\n' \ + '{' \ + ' "mcpServers": {' \ + ' "docs-mcp": {' \ + ' "type": "http",' \ + ' "url": "http://localhost:4455/mcp",' \ + ' "oauth": {' \ + ' "clientId": "docs-mcp-client",' \ + ' "callbackPort": 8090' \ + ' }' \ + ' }' \ + ' }' \ + '}' \ + > .mcp.json + claude +.PHONY: mcp-claude + +mcp-codex: ## Connect Codex CLI to docs-mcp and launch it (authenticate with `codex mcp login docs-mcp` on first use) + @mkdir -p .codex + @test -f .codex/config.toml || printf '%s\n' \ + '# docs-mcp: fixes the local OAuth callback port so it can be pre-registered as a' \ + '# Keycloak redirect URI (docker/auth/realm.json, docs-mcp-client). See' \ + '# documentation/mcp_server.md.' \ + 'mcp_oauth_callback_port = 8091' \ + > .codex/config.toml + codex mcp add docs-mcp --url http://localhost:4455/mcp --oauth-client-id docs-mcp-client 2>/dev/null || true + codex +.PHONY: mcp-codex + +mcp-cursor: ## Open this project in Cursor with docs-mcp connected (authenticate docs-mcp from Cursor's MCP settings on first use) + @mkdir -p .cursor + @test -f .cursor/mcp.json || printf '%s\n' \ + '{' \ + ' "mcpServers": {' \ + ' "docs-mcp": {' \ + ' "url": "http://localhost:4455/mcp",' \ + ' "auth": {' \ + ' "CLIENT_ID": "docs-mcp-client"' \ + ' }' \ + ' }' \ + ' }' \ + '}' \ + > .cursor/mcp.json + cursor . +.PHONY: mcp-cursor + +mcp-gemini: ## Connect Gemini CLI to docs-mcp and launch it (approve the OAuth prompt on first use) + @mkdir -p .gemini + @test -f .gemini/settings.json || printf '%s\n' \ + '{' \ + ' "mcpServers": {' \ + ' "docs-mcp": {' \ + ' "httpUrl": "http://localhost:4455/mcp",' \ + ' "oauth": {' \ + ' "enabled": true,' \ + ' "clientId": "docs-mcp-client",' \ + ' "redirectUri": "http://localhost:8092/oauth/callback"' \ + ' }' \ + ' }' \ + ' }' \ + '}' \ + > .gemini/settings.json + gemini +.PHONY: mcp-gemini + +mcp-inspector: ## Launch the MCP Inspector against docs-mcp with the client/scopes pre-filled + cd src/frontend/servers/mcp && yarn mcp-inspector +.PHONY: mcp-inspector + # -- K8S build-k8s-cluster: ## build the kubernetes cluster using kind ./bin/start-kind.sh diff --git a/documentation/mcp_server.md b/documentation/mcp_server.md index a7bc5b770..5fead8cbd 100644 --- a/documentation/mcp_server.md +++ b/documentation/mcp_server.md @@ -58,9 +58,9 @@ this server holds no credentials of its own. Validates incoming tokens against Keycloak's JWKS (`src/auth/jwtVerifier.ts`) and forwards them to Django (`src/docsApiClient.ts`). - `env.d/development/mcp`, `compose.yml` (`mcp-development` service) — how it runs locally. -- `.mcp.json`, `.codex/config.toml`, `.gemini/settings.json`, `.cursor/mcp.json` — per-client - config pinning `docs-mcp-client` for Claude Code, Codex CLI, Gemini CLI, and Cursor (see - "Connecting other MCP clients" below). +- `Makefile` (`mcp-claude`/`mcp-codex`/`mcp-gemini`/`mcp-cursor` targets) — generate each + client's local, gitignored config pinning `docs-mcp-client` on first run (see "Connecting + other MCP clients" below). ## Environment variables (`src/frontend/servers/mcp`) @@ -171,8 +171,7 @@ configured on this realm. This realm does not expose Dynamic Client Registration (DCR) — `docker/auth/realm.json` only declares `docs-mcp-client` statically. Clients that support pinning a static `client_id` (no -DCR, no client secret needed since it's a public client) can still connect. Each has a -project-level config file and a `make` target that launches it: +DCR, no client secret needed since it's a public client) can still connect. A `make` target generates each client's config on first run and launches it: | Client | Config | Makefile target | | --- | --- | --- | @@ -181,14 +180,14 @@ project-level config file and a `make` target that launches it: | Gemini CLI | `.gemini/settings.json` | `make mcp-gemini` | | Cursor | `.cursor/mcp.json` | `make mcp-cursor` | -Each config pins `docs-mcp-client` as the OAuth client and a fixed local callback port/URL, -which is why that port needs to be a registered redirect URI on `docs-mcp-client` (see -`docker/auth/realm.json`): `8090` (Claude Code), `8091` (Codex CLI), `8092` (Gemini CLI), and -Cursor's own fixed `8787` (not configurable on Cursor's side). None of these tools authenticate -automatically on launch — trigger the OAuth login once per client (Claude Code: `/mcp` inside -the session; Codex CLI: `codex mcp login docs-mcp`; Gemini CLI and Cursor: accept the OAuth -prompt on first tool call). Codex CLI additionally requires the project to be marked as trusted -before it reads `.codex/config.toml`. +Each config pins `docs-mcp-client` as the OAuth client and a fixed local callback port/URL +(`8090` for Claude Code, `8091` for Codex CLI, `8092` for Gemini CLI, Cursor's own fixed +`8787`). `docs-mcp-client`'s `redirectUris` is `["*"]` in this dev realm, so none of these need +registering individually — don't carry that wildcard into a non-dev realm. None of these tools +authenticate automatically on launch — trigger the OAuth login once per client (Claude Code: +`/mcp` inside the session; Codex CLI: `codex mcp login docs-mcp`; Gemini CLI and Cursor: accept +the OAuth prompt on first tool call). Codex CLI additionally requires the project to be marked +as trusted before it reads `.codex/config.toml`. These are external, fast-moving CLIs — if a `make mcp-*` target fails to connect, check that tool's current MCP/OAuth flag names against its own docs before assuming the Keycloak side is