> Source: https://wexa.ai/docs/sdks-and-apis/discovery

# Discovery

`GET /v1/connection-info` says where everything else is: the MCP URL, the REST base, the SDK packages, the OAuth issuer and every tool the deployment registers. It needs no credential and returns no secret; both SDKs call it before their first tool call. `GET /healthz` is the liveness route.

**Read the connection contract**

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/connection-info
```

```json
{
  "mcp": {
    "url_template": "https://fabric.wexa.ai/mcp/{projectId}",
    "auth": "OAuth 2.1 (PKCE) or Bearer API key (fab_sk_…)"
  },
  "api": { "base_url": "https://fabric.wexa.ai/v1" },
  "workspace_header": "X-Wexa-Workspace",
  "issuer": "https://fabric.wexa.ai"
}
```

## Parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| none | | | Both routes take no parameters and no credential. |

**Errors**

| Status | Code | Raised when |
| --- | --- | --- |
| 404 | `not_found` | The path names no route, such as `POST /v1/<tool>` for a tool that does not exist. The body is JSON: `{"error":"not_found","error_description":"no route for POST /v1/<tool>"}`. |

**More details**

**The full connection information**

The example is trimmed. The full response also carries `mcp.sse_url`, the `sdk` entries and the `tools` array:

```json
{
  "mcp": {
    "url_template": "https://fabric.wexa.ai/mcp/{projectId}",
    "sse_url": "https://fabric.wexa.ai/sse",
    "auth": "OAuth 2.1 (PKCE) or Bearer API key (fab_sk_…)"
  },
  "api": { "base_url": "https://fabric.wexa.ai/v1" },
  "sdk": {
    "python": { "package": "wexa", "install": "pip install wexa" },
    "node": { "package": "@wexa-fabric/sdk", "install": "npm install @wexa-fabric/sdk" }
  },
  "workspace_header": "X-Wexa-Workspace",
  "issuer": "https://fabric.wexa.ai",
  "tools": ["query-context", "create-ontology", "save-context", "docs", "search-code", "fetch-code",
            "... every tool this deployment registers, one entry each"]
}
```

**Liveness and fields**

### `GET /healthz`

Liveness. No parameters, no authentication, and no dependency on any downstream service — it answers
`200` whether or not anything it depends on is reachable.

```bash
curl -sS https://fabric.wexa.ai/healthz
```

```json
{ "status": "ok" }
```

### `GET /v1/connection-info`

The public connection contract. Unauthenticated by design: it is what a client reads *in order to*
authenticate, so requiring a credential would be circular.

`tools` is the whole list, not a sample: it names every tool the deployment registers. The excerpt above is shortened for the page. `sdk` carries an entry per SDK — both
`python` and `node` — so a client can report the package a reader should install without hard-coding
its name.

### Field by field

| Field | What it is |
|---|---|
| `mcp.url_template` | The per-project connect URL for the Wexa MCP server. Substitute the project id for `{projectId}`. This is the value to configure a client with. |
| `mcp.sse_url` | The legacy SSE transport's address. **The default value is wrong: it is the retired bare `/sse` path, which answers `410 Gone`. Build the SSE address from `mcp.url_template` instead, substituting `/sse/` for `/mcp/`.** |
| `mcp.auth` | A human-readable note on which credentials that surface accepts. Not machine-readable; do not parse it. |
| `api.base_url` | The REST base. Every tool is `POST <base_url>/<tool-name>`. |
| `sdk.python` / `sdk.node` | Package name and install command for each published SDK. `node` is omitted entirely when the deployment has not configured one, so treat its absence as "not advertised here" rather than "not published". |
| `workspace_header` | The header name this deployment uses to carry the workspace. |
| `issuer` | The OAuth issuer. Both `.well-known` documents hang off it. |
| `tools` | The tools **this** deployment registered, by wire name. |

### `tools` is the only honest tool list

Every gateway registers every tool, whichever services the deployment is configured with. A tool
whose backing service is missing is still in this array, and a call to it fails with an error naming
what is missing — `<tool> is not configured (no data-service URL)`, `(no harness URL)` or
`(needs the harness and data-service URLs)`.
A path that names no tool is not a special error — the route simply is not there, and you get an
ordinary JSON 404, `{"error":"not_found","error_description":"no route for POST /v1/<tool>"}`, with
`content-type: application/json` like every other response.

So read this array rather than hard-coding a list. Per-tool arguments and returns are on each tool's page; what every call shares is in
[how every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).

**Discovery before configuration**

### Discovery before configuration

The pattern these routes support is worth stating plainly, because it is what keeps a client
working when the platform moves.

Hard-code one value — the workspace URL. Derive everything else:

```bash
export WEXA_WORKSPACE=https://fabric.wexa.ai
BASE=$(curl -sS "$WEXA_WORKSPACE/v1/connection-info" | python3 -c 'import sys,json;print(json.load(sys.stdin)["api"]["base_url"])')
curl -sS "$BASE/whoami" -H "Authorization: Bearer $WEXA_API_KEY"
```

Both SDKs do exactly this on your behalf before their first call. The gateway then decides its own
address, and moving it — to a different host, a different port, a different path prefix — needs no
client change and no coordinated release.

The same reasoning applies to the OAuth documents, which the `issuer` field locates and
[OAuth 2.1](/docs/sdks-and-apis/oauth) documents field by field. Between the three of them, a client that
starts with a URL and no configuration can reach a credential without anyone telling it anything.

### What these routes will not tell you

Discovery is deliberately thin. It carries no secrets, no per-caller state and no organization
detail, because anyone who can reach the gateway can read it. In particular it does not report your
grants, your project's mode, or your quota headroom — those depend on who is asking, so they need a
credential and live on [identity](/docs/sdks-and-apis/identity) and the documentation tool instead.

**Related**

- [Identity](/docs/sdks-and-apis/identity): The credentialed counterpart: who you are and what you may do.
- [OAuth 2.1](/docs/sdks-and-apis/oauth): The two `.well-known` documents the `issuer` field locates.
- [REST API overview](/docs/sdks-and-apis/rest): What to do with `api.base_url` once you have it.
- [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works): What each tool is called on each surface; the `tools` array lists the tools themselves.

Every tool call works the same way: [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).
