---
doc: MCP Agent Guide
version: 1.1.0
last_updated: 2026-10-22
applies_to: [admin, client, provider, delivery]
decisions: [TD-31, TD-56, TD-57]
---

# Connect Your Coding Agent to the Joshen Docs (MCP)

For the Flutter (customer, provider, driver) and React (admin) developers who
use an AI coding agent: Claude Code, Cursor, Codex, VS Code Copilot, Gemini CLI
or any other agent that supports MCP.

The backend publishes its documentation as a read-only **MCP server** called
`joshen-docs`. Once your agent is connected, it reads the same files you see in
the browser at `{HOST}/docs`: the BRD, the project registry, the conventions,
the decisions, and the feature docs of every app. It is the same source, so the
agent and you always see the same version.

## Version history

| Version | Date | Summary |
|---------|------|---------|
| 1.1.0 | 2026-10-22 | `get-endpoint` now returns field docs (type, meaning, referenced record), real captured response examples for success and every error, and `variables` (what a call saves, which earlier calls fill what it needs); `list-endpoints` adds `saves`. New §6.1 on using them; rules block items 3–4 and 9 updated (TD-56, TD-57). |
| 1.0.0 | 2026-10-21 | First version: connection per agent, the mandatory reading order, the rules block for your app repo, the `get-integration-brief` tool and the `integrate-feature` prompt (TD-31). |

---

## 1. What your agent can read

| Source | Path in `docs/` | Why the agent needs it |
|--------|-----------------|------------------------|
| Project brain | `PROJECT_BRAIN.md` | Map of every feature: app, doc file, BRD IDs, phase, **status**, version. |
| API conventions | `API_CONVENTIONS.md` | Envelope `{status, message, data}`, `error_code`, pagination, headers, uuid ids, dates, money, Dio/axios setup. |
| BRD | `brd/BRD-Khadami-Project-Guide-en.md` | The business requirements: features `CUST/PROV/DRIV/ADMIN-xxx`, workflows `WF-xx`, rules `BR-xx`, acceptance `AC-xx`. Original and Arabic versions: `brd/BRD-Khadami-en.md`, `brd/*-ar.md`. |
| Decisions | `DECISIONS.md` | Client decisions D1–D4, answers to BRD gaps (DEC-xx), technical choices (TD-xx). **They override the BRD.** |
| Admin docs | `admin/` | React dashboard: one file per feature + `README.md`. |
| Customer app docs | `client/` | Flutter customer app. |
| Provider app docs | `provider/` | Flutter provider app. |
| Driver app docs | `delivery/` | Flutter driver app. |
| Data model | `database/` | Target schema (`db-schema.sql`) and its mapping notes. |
| Endpoint catalog | `postman-collection.json` | Generated from the live routes; the agent reads it through `list-endpoints` / `get-endpoint`: every request field with its type, meaning and referenced record, **real responses** captured by backend tests (success and each error), and the **call flow** (which call produces the token / uuid the next call needs). |

The BRD PDF (`brd/BRD - apps and dashboard.pdf`) is not readable over MCP; the
markdown versions above carry the same content.

**When sources disagree**, follow them in this order: `DECISIONS.md` →
the feature doc → `database/db-schema.sql` → the BRD project guide → the
original BRD. The feature doc is your contract: it already applies the
decisions. Example: the BRD describes a provider password, but DEC-15 removed
passwords, so `provider/auth.md` has phone + OTP only.

---

## 2. Before you connect

Ask the backend team for two values:

| Value | Local backend | Shared dev/staging server |
|-------|---------------|---------------------------|
| MCP URL | `http://localhost:8000/mcp/docs` | `https://{HOST}/mcp/docs` |
| Docs token | not needed | `DOCS_TOKEN`, sent as `Authorization: Bearer <token>` |

Keep the token out of git: put it in an environment variable and reference
the variable in your agent config, as shown below.

```bash
# ~/.zshrc or ~/.bashrc
export JOSHEN_DOCS_TOKEN="paste-the-token-here"
```

The browser viewer uses the same token: open `{HOST}/docs?token=<token>` once.
The `/docs` dashboard also shows ready-to-copy snippets with the right URL.

---

## 3. Connect your agent

Every agent needs the same three things: **HTTP transport** (also called
"streamable HTTP"), the **URL**, and the **Authorization header**. Leave the
header out when you connect to a local backend.

### Claude Code

```bash
claude mcp add --transport http joshen-docs https://{HOST}/mcp/docs \
  --header "Authorization: Bearer $JOSHEN_DOCS_TOKEN"
```

Or share it with your team in the app repo's `.mcp.json` (the token stays in
each developer's environment):

```json
{
  "mcpServers": {
    "joshen-docs": {
      "type": "http",
      "url": "https://{HOST}/mcp/docs",
      "headers": { "Authorization": "Bearer ${JOSHEN_DOCS_TOKEN}" }
    }
  }
}
```

### Cursor — `.cursor/mcp.json`

```json
{
  "mcpServers": {
    "joshen-docs": {
      "url": "https://{HOST}/mcp/docs",
      "headers": { "Authorization": "Bearer ${env:JOSHEN_DOCS_TOKEN}" }
    }
  }
}
```

### VS Code (Copilot agent mode) — `.vscode/mcp.json`

```json
{
  "inputs": [
    { "id": "joshen-docs-token", "type": "promptString", "description": "Joshen docs token", "password": true }
  ],
  "servers": {
    "joshen-docs": {
      "type": "http",
      "url": "https://{HOST}/mcp/docs",
      "headers": { "Authorization": "Bearer ${input:joshen-docs-token}" }
    }
  }
}
```

### Codex — `~/.codex/config.toml`

```toml
[mcp_servers.joshen-docs]
url = "https://{HOST}/mcp/docs"
bearer_token_env_var = "JOSHEN_DOCS_TOKEN"
```

### Gemini CLI — `.gemini/settings.json`

```json
{
  "mcpServers": {
    "joshen-docs": {
      "httpUrl": "https://{HOST}/mcp/docs",
      "headers": { "Authorization": "Bearer $JOSHEN_DOCS_TOKEN" }
    }
  }
}
```

### Other agents

Add an MCP server named `joshen-docs` with HTTP (streamable HTTP) transport,
the URL, and the header `Authorization: Bearer <token>`.

### Agent on the backend machine (stdio)

If your agent runs on the same machine as a checkout of this backend, it can
start the server itself, with no URL or token:

```json
{
  "mcpServers": {
    "joshen-docs": {
      "command": "php",
      "args": ["artisan", "mcp:start", "joshen-docs"],
      "cwd": "/path/to/joshen-backend"
    }
  }
}
```

---

## 4. Check the connection

1. Restart the agent (or reload its MCP servers). In Claude Code, `claude mcp list`
   must show `joshen-docs` as connected; in Cursor and VS Code the server shows a
   green status and **7 tools**.
2. Ask the agent:

   > Call `get-integration-brief` for surface `client` and show me the result.

   You should get a "Mandatory reading" checklist, the `client/README.md`
   overview, and the table of client features with their status.
3. Still failing? Test the server without the agent:

   ```bash
   curl -s https://{HOST}/mcp/docs \
     -H "Authorization: Bearer $JOSHEN_DOCS_TOKEN" \
     -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
     -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
   ```

   A JSON list of tools means the server and the token are fine; the problem is
   the agent config. See [§8 Troubleshooting](#8-troubleshooting).

---

## 5. Make sure the agent always checks the docs

An agent only reads what it is told to read. The setup has four layers; use
all of them.

### 5.1 The server tells every agent (automatic)

When an agent connects, `joshen-docs` sends instructions that say: call
`get-integration-brief` first, and read `PROJECT_BRAIN.md`,
`API_CONVENTIONS.md`, the BRD, `DECISIONS.md`, the app's README and the feature
doc before writing integration code. You do not have to do anything for this.

### 5.2 One tool returns the required context

`get-integration-brief` (surface + feature) returns, in one call:

- the mandatory reading checklist;
- the app's `README.md` (`admin/`, `client/`, `provider/` or `delivery/`);
- the feature's row from `PROJECT_BRAIN.md`, with its status: a feature that is
  not `ready` is flagged so the agent stops instead of guessing;
- the BRD sections for each of the feature's IDs, with their acceptance
  scenarios (AC-xx), business rules (BR-xx) and screen notes (SCR-xx);
- the `DECISIONS.md` rows the feature depends on.

So even an agent that reads nothing else has seen the BRD, the registry,
the decisions and the app docs for that feature.

### 5.3 Add the rules to your app repo (do this once)

Paste this block into your app repo's agent instructions file, so every task
starts with the docs. Use the file your agent reads:

| Agent | File in the app repo |
|-------|----------------------|
| Claude Code | `CLAUDE.md` |
| Codex, Antigravity, OpenCode | `AGENTS.md` |
| Cursor | `.cursor/rules/joshen-backend.mdc` (set `alwaysApply: true`) |
| VS Code Copilot | `.github/copilot-instructions.md` |
| Gemini CLI | `GEMINI.md` |

Set `SURFACE` to your app: `client` (customer app), `provider`, `delivery`
(driver app) or `admin` (dashboard).

```markdown
## Backend integration (Joshen API) — mandatory

The backend docs are served by the `joshen-docs` MCP server. This app's surface is `SURFACE`.

Before writing or changing any code that calls the Joshen API:
1. Call `get-integration-brief` with surface `SURFACE` and the feature you are working on.
2. With `read-doc`, read: `PROJECT_BRAIN.md`, `API_CONVENTIONS.md`, `DECISIONS.md`,
   `SURFACE/README.md`, the feature doc in `SURFACE/`, and the BRD sections the brief
   points to in `brd/BRD-Khadami-Project-Guide-en.md`.
3. Use `get-endpoint` for every endpoint the code calls. Build request models from its
   field docs, response models from its `examples` (real captured responses), and
   error handling from every non-2xx example's `error_code`. Ignore examples whose
   name ends "(illustrative, not captured)" for parsing decisions.
4. Order the calls of a flow from `get-endpoint` → `variables`: each `uses` entry names
   the routes (`set_by`) whose response provides that value (token, verification_token,
   media_hash, a record uuid). Keep those values in app state; never hard-code a uuid
   or token from an example.
5. Only integrate features whose status is `ready` in `PROJECT_BRAIN.md`.
6. Never invent endpoints, fields, enum values or error codes. If the docs do not
   answer something, stop and list it as a question for the backend team.
7. If the BRD and the feature doc disagree, follow the feature doc and `DECISIONS.md`.
8. Before a feature is done, compare the code with the feature doc's
   "Integration checklist" and acceptance scenarios.
9. In your final summary, list the docs you read and their versions, and the
   endpoints (route names) the code calls.
```

### 5.4 Start feature work with the `integrate-feature` prompt

The server also provides a prompt that walks the agent through the whole
order: brief → registry → conventions → BRD → decisions → README and feature
doc → endpoints → code.

- **Claude Code:** `/mcp__joshen-docs__integrate-feature` then the surface and
  feature, e.g. `client auth`.
- **Other agents:** pick `integrate-feature` from the `joshen-docs` prompts list,
  or simply write: *"Use the joshen-docs integrate-feature workflow for the
  client auth feature."*

### 5.5 Review what the agent read

Rule 9 above makes the agent list the docs it read. If the list is missing
`PROJECT_BRAIN.md`, the BRD, `DECISIONS.md` or the feature doc, send it back.

---

## 6. Tool reference

| Tool | Arguments | Returns |
|------|-----------|---------|
| `get-integration-brief` | `surface` (required), `feature` (doc path, slug or BRD ID) | Reading checklist, app README, registry row and status, BRD sections + AC/BR/SCR rows, decision rows. Without `feature`: the app's feature list. |
| `list-features` | `surface`, `status` | `PROJECT_BRAIN.md` registry rows as JSON. |
| `list-docs` | `folder` (`brd`, `admin`, `client`, `provider`, `delivery`, `database`, …) | Files with title, size, last update. |
| `read-doc` | `path`, `offset` | A document. Long files come in parts; pass the returned offset to continue. |
| `search-docs` | `query`, `folder`, `limit` | Matching lines with file and line number, e.g. `INVALID_OTP`, `awaiting_payment`, `BR-13`. |
| `list-endpoints` | `surface` (`client`, `guest`, `provider`, `delivery`, `admin`, `shared`), `query` | Method, path, route name, whether a Bearer token is needed, `saves` (values its response provides for later calls). |
| `get-endpoint` | `method`, `path` (path or route name) | Headers, query/path parameters, example body, field docs (type, meaning, allowed values, referenced record, validation rules), `examples` (real responses), `variables` (`saves` / `uses` with `set_by`). See §6.1. |

### 6.1 Reading `get-endpoint`

`get-endpoint` for `POST admin.providers.reject` returns (shortened):

```json
{
  "method": "POST",
  "path": "/api/v1/admin/providers/:id/reject",
  "route": "admin.providers.reject",
  "headers": { "Authorization": "Bearer {{admin_token}}", "Accept-Language": "{{locale}}" },
  "path_params": [{ "key": "id", "value": "{{provider_id}}", "description": "Record uuid. Saved by GET /api/v1/admin/providers, GET /api/v1/admin/providers/{id}." }],
  "body": { "mode": "raw", "raw": "{ \"reason\": \"Please upload a clear photo of your national ID\" }" },
  "variables": {
    "saves": [],
    "uses": [
      { "name": "provider_id", "set_by": ["admin.providers.index", "admin.providers.show"], "how": "Saved by GET /api/v1/admin/providers, …" },
      { "name": "admin_token", "set_by": ["admin.auth.login", "admin.auth.refresh"], "how": "Saved by POST /api/v1/admin/auth/login, …" }
    ]
  },
  "examples": [
    { "name": "200 Provider Reject", "code": 200, "body": "{ \"status\": \"success\", … }" },
    { "name": "409 Provider Invalid Transition", "code": 409, "body": "{ … \"error_code\": \"INVALID_STATE_TRANSITION\" … }" }
  ],
  "description": "… **Field documentation:** `reason` — type, required, meaning … **Variables:** … **Responses:** …"
}
```

How to use each part:

| Part | Use it to |
|------|-----------|
| `{{name}}` in path, headers, body | Know which value comes from state, not from the user. `{{admin_token}}` / `{{client_token}}` / `{{provider_token}}` / `{{delivery_token}}` = the JWT of that app; `{{token}}` = whichever app is signed in (shared routes). |
| `variables.uses[].set_by` | Find the call that must run first, then `get-endpoint` it to see where the value sits in its response. |
| `variables.saves[].path` | Where the value sits in this response: dot keys; `*` = first row of a list (`data.*.id` = `data.providers[0].id` in a paginated list). |
| `examples` | Exact response shapes, messages and `error_code`s. One example per success shape and per error. Uuids, dates and tokens in them are sample values (`[redacted JWT]`). |
| Field docs | Request model types, required flags, enum values, and which record a uuid field refers to. |

Typical flows the variables describe:

- **App sign-in:** `{app}.auth.register` or `{app}.auth.login` saves `verification_token` → `{app}.auth.verify` (with the SMS code) saves the app token → every authenticated call.
- **Upload then save:** `shared.media.upload` saves `media_hash` → send it in the form's image/file field.
- **List → details → action (admin):** `admin.providers.index` saves `provider_id` → `admin.providers.show` / `approve` / `reject` use it.

| Prompt | Arguments | Use |
|--------|-----------|-----|
| `integrate-feature` | `surface`, `feature` | Full integration workflow for one feature. |

Everything is read-only: the server never changes data and never calls the API
on your behalf. To try requests, use the API console at `{HOST}/tester`.

---

## 7. Example session

> **You:** Integrate provider login.
>
> **Agent:** calls `get-integration-brief` (`provider`, `auth`) → status `ready`,
> doc `provider/auth.md` 2.1.0, BRD PROV-001 and PROV-005, DEC-15 says phone + OTP,
> no password → reads `API_CONVENTIONS.md`, `provider/README.md`,
> `provider/auth.md` → `get-endpoint` for `provider.auth.login` and
> `provider.auth.verify` → sees from `variables` that login saves
> `verification_token` and verify needs it, then saves `provider_token` → models the
> 200, 422 and 429 responses from `examples` → writes the Dio calls, models and
> error handling → lists the docs it read and the checklist items it covered.

If you ask for a feature that is still `planned` (for example `client/booking.md`),
the brief says it is not ready and the agent should stop and tell you.

---

## 8. Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| `401` / "Docs access token required" | Token missing or wrong | Check the env variable is set **in the shell that starts the agent**, and the header is `Authorization: Bearer <token>`. |
| `404` on `/mcp/docs` | Docs are not enabled on that server | Ask the backend team; the server needs `DOCS_ENABLED=true` and `DOCS_TOKEN`. |
| Server connected but no tools | Agent cached an old tool list | Restart the agent or reload MCP servers. |
| Agent answers without calling tools | Rules block not loaded | Add §5.3 to the agent's instructions file; start with the `integrate-feature` prompt. |
| A doc looks out of date | The server shows the docs of the backend version deployed there | Compare the doc's `version` with `CHANGELOG.md`; ask which server has the latest backend. |
| `read-doc` text ends with "Call read-doc again with offset …" | Long file | Normal; the agent reads the next part with that offset. |

Questions about a feature or a missing answer in the docs go to the backend
team; the decision is then recorded in `DECISIONS.md` and the feature doc.
