> ## Documentation Index
> Fetch the complete documentation index at: https://developers.investorlift.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connecting a client

> curl, Claude Code, Cursor, VS Code, the MCP Inspector, the Claude Agent SDK and the Messages API connector against the one route.

Every client here points at the one route, `https://api.investorlift.com/mcp`, and sends the same `zpka_` key as a
bearer header. The clients differ only in where the entry lives and in the name of the entry. Put the key in the
environment first (`export GM_API_KEY="zpka_..."`), so no tracked file carries it.

## curl

Two legs answer on the same route. An `initialize`-era client sends the plain handshake. It gets one
`text/event-stream` frame, and the frame closes as soon as the server writes it:

```
curl -s -D - "https://api.investorlift.com/mcp" -H "Authorization: Bearer $GM_API_KEY" \
  -H 'Accept: application/json, text/event-stream' -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
```

```
HTTP/1.1 200 OK
x-request-id: ef81aef9-...   zp-rid: ef81aef9-...
cache-control: no-cache, no-transform   vary: Authorization   x-accel-buffering: no
x-dataset-version: hou=1789052706,phx=1789053358   x-data-end: hou=2026-08-11,phx=2026-08-12
content-type: text/event-stream

event: message
data: {"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{"listChanged":false},"resources":{"listChanged":false,"subscribe":false},"prompts":{"listChanged":false},"completions":{}},"serverInfo":{"name":"god-mode","version":"0.9.0"},"instructions":"Read-only county deed, MLS listing and Investorlift marketplace data ..."},"jsonrpc":"2.0","id":1}
```

The modern 2026-07-28 leg adds three headers and the two `_meta` protocol keys inside `params`. The answer is
`application/json` with `cache-control: private, no-cache` and no `x-accel-buffering`. `Mcp-Protocol-Version` and
`Mcp-Method` go on every message. `Mcp-Name` carries the name or the uri the body names, on a `tools/call`, a
`resources/read` and a `prompts/get` alike:

```
curl -s "https://api.investorlift.com/mcp" -H "Authorization: Bearer $GM_API_KEY" \
  -H 'Accept: application/json, text/event-stream' -H 'Content-Type: application/json' \
  -H 'Mcp-Protocol-Version: 2026-07-28' -H 'Mcp-Method: tools/call' -H 'Mcp-Name: godmode_coverage' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"godmode_coverage","arguments":{},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
```

Swap `tools/call` for `server/discover` or `tools/list`, and drop `Mcp-Name`: those two methods name nothing.
`resources/read` and `prompts/get` still need it, with `godmode://concepts` or `who_owns_this_house` as the value.
Without it the route answers `400` with JSON-RPC `-32020`. The message says that the request headers and the body
disagree, because the body carries `params.uri` or `params.name` and the required header is absent.

## Claude Code

The key comes out of the environment, so no tracked script carries it on a command line:

```
claude mcp add --transport http godmode https://api.investorlift.com/mcp \
  --header "Authorization: Bearer ${GM_API_KEY}"
claude mcp get godmode          # prints whether the server is connected
```

`--transport http`, `--header` (repeatable) and `--scope local|user|project` are the flags `claude mcp add --help`
lists. The equivalent JSON, in `.mcp.json` at the project root or in the user scope, expands `${VAR}` in both `url` and
`headers`:

```json theme={null}
{ "mcpServers": { "godmode": { "type": "http", "url": "https://api.investorlift.com/mcp",
  "headers": { "Authorization": "Bearer ${GM_API_KEY}" } } } }
```

The entry must carry `"type": "http"`. Claude Code skips an entry that has a `url` and no `type`. Then
`claude mcp list` prints a configuration warning that names the entry and the type it wants. A refused key shows as a
failed connection, not a login prompt, because the server publishes no OAuth metadata. Fix the key and reconnect. In a
session the tools appear as `godmode_*`, the resources as `@godmode:godmode://concepts`, the prompts as
`/godmode:find_buyers`.

## Cursor and VS Code

Same URL, same static headers map. Cursor reads `.cursor/mcp.json` in the project or `~/.cursor/mcp.json`. VS Code
reads `.vscode/mcp.json` and wraps the entries in `servers` instead of `mcpServers`:

```json theme={null}
{ "mcpServers": { "godmode": { "url": "https://api.investorlift.com/mcp", "headers": { "Authorization": "Bearer ${env:GM_API_KEY}" } } } }
{ "servers": { "godmode": { "type": "http", "url": "https://api.investorlift.com/mcp", "headers": { "Authorization": "Bearer ${env:GM_API_KEY}" } } } }
```

Each shape belongs to its client, not to this server. If a client later moves a key in its shape, the
client's own documentation decides.

## MCP Inspector

The smoke test. Pin an exact version, give the key as a header, and read the exit code:

```
npx --yes @modelcontextprotocol/inspector@2.6.0 --cli "https://api.investorlift.com/mcp" --transport http --stored-auth-only \
  --header "Authorization: Bearer ${GM_API_KEY}" --method tools/list
```

That runs the `initialize`-era leg, the Inspector's default. To run the modern leg, pass a config entry that sets
`protocolEra` and select it with `--config <file> --server godmode`:

```json theme={null}
{ "mcpServers": { "godmode": { "type": "http", "url": "https://api.investorlift.com/mcp",
  "headers": { "Authorization": "Bearer zpka_..." }, "protocolEra": "modern" } } }
```

`--stored-auth-only` is about OAuth, not about the key. It forbids an interactive login and fails with `auth_required`
instead, which is what an unattended run wants. Against this server it does nothing, because the route publishes no
OAuth metadata.

The Inspector does not write a key given with `--header` anywhere. `--catalog` is the writable file. The Inspector
only reads the `--config` file and never seeds or rewrites it. But that file holds the key in clear text. Keep it out
of every repository, and delete it when the run is over.

## Claude Agent SDK

An Agent SDK session takes the same server entry as Claude Code, under the SDK's `mcpServers` option. The SDK can also
replace the list in the middle of a session. The entry shape is Claude Code's, so `type`, `url` and `headers` are as
in [Claude Code](#claude-code) above. Check the Agent SDK's own documentation for the option surface. An unattended
run takes the same key as an interactive one. The key, not the client, decides what the server serves.

## Messages API connector

Available with a `zpka_` key. The connector runs from Anthropic's network and reaches `https://api.investorlift.com/mcp`
like any other client. It sees tools only, no resources and no prompts. It needs the beta header
`anthropic-beta: mcp-client-2025-11-20` with both halves of the declaration: one `mcp_servers` entry of `type: "url"`
and one `mcp_toolset` that names it. The server entry alone is a validation error.

The key goes in the server entry's `authorization_token` field. This page assumes the field travels as
`Authorization: Bearer`. No live call confirmed that yet. The gateway attributes every call to your account itself, so
the connector sends nothing else.


## Related topics

- [The MCP endpoint](/mcp/overview.md)
- [Plans and limits](/guides/plans-and-limits.md)
- [Quickstart](/guides/quickstart.md)
- [Keys and headers](/mcp/keys.md)
- [The twenty-six tools](/mcp/tools.md)
