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

# Connect ChatGPT

> ChatGPT connects from OpenAI's cloud, so Postern needs a public HTTPS address on port 443 before you start.

<Info>
  **Before you start**

  * **A paid ChatGPT plan that offers Developer mode.** It is what lets ChatGPT call a server of your
    own. Step 3 turns it on.
  * **A public HTTPS address on port 443, already set up.** ChatGPT connects from OpenAI's cloud on
    port 443 only. It cannot reach `localhost` or your private Tailscale network. Nothing on the
    internet can reach Postern until you set this up, and it is off by default: [Set up remote
    access](/start/remote-access) — Tailscale plus Funnel, about 20 minutes, once.
  * **Postern running, and the Console at [http://localhost:8787](http://localhost:8787).**
    Everything on this side happens at **Agents & keys**.
  * **Your password manager open.** Postern shows the key once. ChatGPT asks for it at the **end** of
    the sign-in, in another window, after step 2 has replaced it on your clipboard.
</Info>

About 10 minutes, once the address is up. Every ChatGPT label below comes from a real run on
1 August 2026. Where that run recorded no label, this page names none. OpenAI renames these screens,
so trust your screen over this page.

If you already saved an agent key that expires, start at [step 2](#copy-the-endpoint).

<Steps>
  <Step title="Create a key that expires, and save it" titleSize="h2" id="mint-a-key">
    Open the Console at [http://localhost:8787](http://localhost:8787). Go to **Agents & keys** and press
    **Mint a key**.

    In **Name**, type `chatgpt`. That name is what the record prints under **Who**.

    Under **Grant which sectors**, tick each sector ChatGPT may reach. The six toggles read **Finance**,
    **Mail**, **Calendar**, **Contacts**, **Health** and **Home**. A grant covers read and act across
    every provider in the sector, and only **Home** has anything to act on today —
    [what a grant covers](/reference/grants-and-sectors#what-a-grant-covers). A key with no sectors
    ticked still connects, and Postern then denies every read.

    Under **Expires**, press **30 days**, **60 days** or **90 days**. Do not press **Never**: the
    sign-in in step 5 refuses a key that never expires. Once you save an address, the form starts on
    **90 days** and prints `This gate is published. A key you paste into a hosted client should expire.`

    <Warning>
      Postern cannot show you this key again. It keeps a scrambled copy it can check against, never the
      key itself. The only remedy is a new key. Step 2 then puts your address on the clipboard, over the
      key, and ChatGPT does not ask for the key until step 5.
    </Warning>

    Press **Mint the key**. A screen opens headed `chatgpt is ready`, with the key under
    **Agent key — shown once**. Press the **Copy** beside it, then paste and save it in your password
    manager.
  </Step>

  <Step title="Copy the address ChatGPT connects to" titleSize="h2" id="copy-the-endpoint">
    On that same screen, follow **Connect a hosted client (claude.ai, ChatGPT) →**. From anywhere else:
    **Agents & keys** → **Set up the bridge →**. Both open **Connect claude.ai or ChatGPT**.

    If your address works for ChatGPT, that page prints it under **Paste this into claude.ai or
    ChatGPT**. Press **Copy** there. It ends in `/mcp`, which the Console adds itself —
    [the endpoint](/reference/mcp-primitives#the-endpoint):

    ```text theme={"system"}
    https://gateway.example-tailnet.ts.net/mcp
    ```

    <Warning>
      The **MCP endpoint** block on the previous screen prints the address on the machine Postern runs
      on, which ChatGPT can never reach. It still reads that way after you save a public address. Copy
      only from **Paste this into claude.ai or ChatGPT**.
    </Warning>

    <Note>
      No **Copy** button, and the pattern `https://your-mac.tailnet.ts.net/mcp` in place of your address?
      One sentence on that page says which of five things is true.

      | What the page says                                                                                           | What to do                                                                                    |
      | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
      | `Bridge is off — agents can only reach this gate with a pasted key`                                          | Nothing was ever published. [Set up remote access](/start/remote-access).                     |
      | `Bridge is off — an address is saved but not published yet`                                                  | In the folder that holds `docker-compose.yml`, run `docker compose restart app`.              |
      | `Bridge is off — this gateway couldn't read its own exposure setting`                                        | Open Settings → **Remote access**, which says why.                                            |
      | `This gateway didn’t answer with its bridge status`                                                          | About the Console's own request, not about Postern. Reload.                                   |
      | `Hosted clients egress on port 443 only; on any other port the connection is reset with nothing you'll see.` | Your address is local, plain `http`, or off port 443. Fix it in Settings → **Remote access**. |
    </Note>
  </Step>

  <Step title="Turn on Developer mode in ChatGPT" titleSize="h2" id="developer-mode">
    Open ChatGPT's settings, then **Plugins**. Scroll to the bottom of that list, past **Browse
    plugins**, and press **Developer mode**.

    ChatGPT moves you to **Security and login**, and the address ends
    `#settings/Security?section=developer-mode`. The **Developer mode** row there carries a red
    **⊘ ELEVATED RISK** badge and the line *Allows you to add unverified connectors that could modify
    or erase data permanently. Use at your own risk.*

    That badge is correct. Developer mode is what lets ChatGPT call a server you point it at, rather
    than one OpenAI reviewed. Turn **Developer mode** on.

    <Note>
      No menu in ChatGPT says **Connectors**. The settings rail says **Plugins**, ChatGPT's banner says
      **Apps**, and the addresses still say Connectors. Three names, one thing. Go by the rail.

      The run behind this page met that screen with **Developer mode** already on. Nobody wrote down
      the switch's own name, or what it reads afterwards. Go by the row's name.
    </Note>
  </Step>

  <Step title="Create the plugin and point it at your address" titleSize="h2" id="create-the-connector">
    Open `chatgpt.com/plugins`. The page carries the heading *Plugins — Work with ChatGPT across your
    favorite tools.* Press the **+** button, top right. The **New Plugin** form opens.

    * **Name** — type `Postern`. Its placeholder reads `Custom Tool`.
    * **Connection** — leave the toggle on **Server URL**, not **Tunnel**, and paste the address you
      copied in step 2. Its placeholder reads `https://example.com/sse`.
    * **Authentication** — already reads `OAuth`. Leave it.
    * **Icon** and **Description** are optional. Skip both.

    Watch **Advanced OAuth settings** as you paste. It starts at *Enter a valid MCP Server URL to review
    discovered OAuth settings*. Once your address goes in, it changes to *Review discovered OAuth
    settings, or enter them manually, then choose a client setup method and configure default scopes*.
    That change means ChatGPT reached your Postern.

    Under the red *⚠ Custom MCP servers introduce risk* warning, tick **I understand and want to
    continue**. **Create** stays greyed out until you do. Press **Create**.

    The button shows a spinner. ChatGPT then lands on **App Preferences**, where **Permissions** reads
    `Allow low-risk`. That setting decides when ChatGPT asks you before it uses a plugin, not what
    Postern allows. The run behind this page changed nothing there. The address still says `Connectors`,
    as it does everywhere in ChatGPT's settings.

    A second tab opens on your own address, served by your own Postern. Step 5 happens in that tab.

    <Note>
      If no tab opens, your browser blocked it. Allow pop-ups for `chatgpt.com`, then press **Create**
      again. You can also close that tab before you approve: press **Create** again to reopen it.

      If ChatGPT says instead that it could not reach your server, and nothing appears in your logs:
      nothing arrived, so there was nothing to log. Fix the address in step 2, then wait five minutes
      before you retry. The Console says the same thing under the address:
      `If claude.ai or ChatGPT says it can't connect, fix the address, wait five minutes, and try once: a
              hosted client remembers a failed check for a few minutes.`
    </Note>
  </Step>

  <Step title="Approve the sign-in on your own machine" titleSize="h2" id="approve-the-sign-in">
    Your own Postern serves this tab. It opens blank, then resolves to your own address. It is plain
    and unstyled, in a system font on a white background — nothing like the Console. That is normal.

    It carries the heading **Authorize agent access**, then two lines. The first is the name ChatGPT
    registered with your Postern, followed by `is asking to connect to your gateway.` The second reads
    `Approving sends a sign-in code to`, then the address that code goes to, then `. If you did not
        start this from that app, close this page.` Postern prints both from what ChatGPT registered.

    <Warning>
      Read both lines before you approve. Anyone who can reach your address can ask to connect, so those
      two lines are your only check —
      [why the bridge cannot refuse an unknown client](/reference/oauth-bridge#anyone-can-register-a-client). If the name
      is not the app you started this from, or the address does not belong to OpenAI, close the page.
    </Warning>

    Paste the key from step 1 into **Paste an agent key from the Console**, then press **Approve**.

    The tab goes black with a spinner and returns to ChatGPT. Postern shows no page of its own to say it
    worked. ChatGPT confirms instead, with a green message over your plugin's own page. That page lists
    no actions yet. That is what a new plugin shows, not a broken connection.

    <Note>
      Your browser's password manager pops over the key field. Dismiss it. It can cover the **Approve**
      button underneath, and the key is not a login.
    </Note>

    <Note>
      The page answers `This agent key never expires. Keys used with a cloud client must have an expiry —
              mint or rotate a key with a 30/90/365-day expiry in the Console, then try again.` The key is good;
      its lifetime is not. Ignore the 365: the Console offers **Never**, **30 days**, **60 days** and
      **90 days**, and nothing else.

      Rotate it. Console → **Agents & keys** → `chatgpt` → **Rotate**. The form opens headed
      `Rotate chatgpt`. Press **90 days**, then **Rotate the key**, then **Copy**. Save the new key and
      run this step again with it. A rotation keeps the name and the sectors, so you do not tick the
      sectors again.
    </Note>
  </Step>

  <Step title="Ask ChatGPT something, then read the record" titleSize="h2" id="ask-and-check">
    In a chat, attach the plugin you named `Postern`. A `[P] Postern` chip lands in the message field.
    Type your question after it.

    ChatGPT shows plain-English progress, never tool names: **Describing the Current Context** means
    ChatGPT called `describe_context`. On the `Allow low-risk` setting from step 4 it asked no
    permission per call. A **Postern** entry in the **Sources** rail is the sign that a call landed.

    <Warning>
      ChatGPT can narrate work it never did. On the 1 August 2026 run it printed a progress line about a
      weekly total, then `Worked for 50s`, then: *Postern didn't provide any transaction data in this
      chat, so I can't calculate the total without guessing.* No call for it reached the record. When an
      answer looks empty, open Console → **The ledger** before you change anything.

      That failure also offers the wrong fix: its link points at `chatgpt.com/apps`, the public
      directory, where a plugin you made yourself never appears. Yours is on the plugins page, under
      **Personal → Created by me**.
    </Warning>
  </Step>
</Steps>

## Confirm it works

* `chatgpt.com/plugins` lists **Postern** under **Personal → Created by me**.
* Console → **The ledger** holds a row with `chatgpt` under **Who**.
* That row names the tool ChatGPT called under **Tool**.
* Leave the sector filter alone. The Console says why: `One sector at a time also leaves out every
  call that belonged to no sector — an agent asking what the gate holds, or a handshake the gate
  refused. Those are still recorded; they just cannot match a sector.`
* An empty answer **with** a row means Postern has no sources yet. No row means nothing arrived.

## If something went wrong

| What you see                                                                      | What to do                                                                                                                          |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `That agent key was not accepted. Check the key in the Console and try again.`    | You pasted the address, not the key. Paste the key from your password manager into **Paste an agent key from the Console**.         |
| `This agent key never expires. Keys used with a cloud client must have an expiry` | Console → **Agents & keys** → `chatgpt` → **Rotate** → **90 days** → **Rotate the key** → **Copy**. Approve again with the new key. |
| ChatGPT could not reach your server, and your logs show nothing                   | The request never arrived. Fix the address in Settings → **Remote access**, wait five minutes, try once.                            |
| Nothing answers at `http://localhost:8787`, and Postern runs on another machine   | Open the Console over SSH first: [Set up remote access](/start/remote-access).                                                      |

## What you have now

ChatGPT holds a temporary pass issued by your own machine, never the key itself. It sees exactly the
sectors you ticked in step 1, and appears in the record under the name you gave it. Its access ends
when the key expires —
[the OAuth bridge, for hosted agents](/reference/oauth-bridge).

Revoke the key and Postern refuses ChatGPT's next call. Rotate it and its passes die at the same
moment — [revoking and rotating a key](/reference/agent-keys#revoking-rotating-and-removing).

Three standing costs come with this.

* The key now lives on OpenAI's infrastructure and dies on the date you chose. Postern then refuses
  ChatGPT's calls, and to replace the key you work this page again from step 1.
* Your address stays reachable from the internet until you turn it off in Settings → **Remote
  access**. That is also what turns the sign-in off: `Stop publishing and the sign-in disappears —
  nothing else about this gate changes.`
* ChatGPT asked no permission per call on the run behind this page, so the sectors you ticked are
  its whole boundary for as long as the key lives.

Any wait you feel comes from ChatGPT, not Postern. Postern answers reads from its cache, on your
own machine.

## Next

ChatGPT can only answer from sources Postern already holds. Pick the one you can finish now.

<Columns cols={2}>
  <Card title="Connect Google and Gmail" href="/connect/google">
    your own Google Cloud app and one app password · about 20 minutes · weekly re-consent until you
    publish to production
  </Card>

  <Card title="Connect Apple Health" href="/connect/apple-health">
    Health Auto Export on your iPhone · about 10 minutes · push, not pull
  </Card>
</Columns>
