Connect a client

Add the gateway to the app you already use. Every client below supports a remote HTTP MCP server with OAuth, so none of them needs a bridge, a pre-registered client ID, or a key pasted into a config file.

The URL is the same everywhere. https://port.harborgovcon.com/mcp reaches all 147 tools. Once you know which dataset you need, a single source at https://port.harborgovcon.com/servers/<slug>/mcp costs less context and selects tools more reliably. Both work with the same credential.

ChatGPT desktop and Codex

Supported. The desktop app lists Streamable HTTP servers with OAuth, including dynamic client registration, which is what this gateway serves.

  1. Open Settings, then MCP servers.
  2. Select Add server.
  3. Enter a name, choose Streamable HTTP, and paste https://port.harborgovcon.com/mcp.
  4. Save the server, then select Restart. A restart is required.
  5. The server list shows which servers need OAuth. Select Authenticate and approve in the browser. In the composer, /mcp lists what connected.

The Codex app reads ~/.codex/config.toml instead, and the minimal entry is two lines. OAuth is the default, so there is no key to add:

[mcp_servers.harbor]
url = "https://port.harborgovcon.com/mcp"

Source: learn.chatgpt.com/docs/extend/mcp, read 2026-09-28.

Claude Desktop

Supported through a custom connector, on Free, Pro, Max, Team and Enterprise plans.

  1. Select Customize in the sidebar, then Connectors.
  2. Select Add custom connector and paste https://port.harborgovcon.com/mcp.
  3. For authentication choose Sign in now, so each person signs in through the gateway's own OAuth flow.
  4. For the OAuth client choose Register automatically, and not "Use Claude's published identity". This gateway registers clients dynamically and does not advertise client ID metadata documents, so the published-identity option cannot complete. This is the one client setting that matters.

The browser consent opens on your desktop. No restart is needed for a connector.

claude_desktop_config.json cannot do this. That file is documented only for local stdio servers started with command and args, and it has no way to express a remote URL. If you have seen an mcpServers block for Claude Desktop, it was for a server running on your own machine. Use Connectors for this gateway.

Source: claude.com/docs/connectors/custom/add-unlisted, read 2026-09-28. Team and Enterprise accounts add the connector under Organization settings instead, then members connect it from Customize.

Cursor

Supported. Cursor's transport table lists Streamable HTTP with OAuth for both local and remote servers.

  1. Open Customize in the sidebar, then MCPs.
  2. Add a server with the URL https://port.harborgovcon.com/mcp.
  3. Save, then restart Cursor. A restart is required.

Or edit ~/.cursor/mcp.json globally, or .cursor/mcp.json in a project. The two are merged and the project wins on a name clash:

{
  "mcpServers": {
    "harbor": {
      "url": "https://port.harborgovcon.com/mcp"
    }
  }
}
Do not add an auth block. That block exists for servers that cannot do dynamic client registration, and it replaces the OAuth flow with static credentials. This gateway does register clients dynamically, so adding it breaks a path that already works.

Source: cursor.com/docs/mcp, read 2026-09-28.

OpenCode

Supported, and the flow is the best documented of the four: OpenCode detects the 401, discovers the authorization server, uses PKCE, refreshes tokens, and registers a client dynamically.

The config shape changed between versions, so check which one you are on. On V2 servers live under mcp.servers; on V1 they sit directly under mcp. A file using the wrong shape is ignored silently, which produces a connection that never appears rather than an error message.

// V2, current:
{
  "mcp": {
    "servers": {
      "harbor": { "type": "remote", "url": "https://port.harborgovcon.com/mcp" }
    }
  }
}

// V1, up to and including 1.18.x:
{
  "mcp": {
    "harbor": { "type": "remote", "url": "https://port.harborgovcon.com/mcp" }
  }
}

The global file is ~/.config/opencode/opencode.json; a project file is opencode.json. On V1, run opencode mcp auth harbor to start the browser authorization. On V2, run opencode mcp add harbor --url https://port.harborgovcon.com/mcp and sign in from the server list. Tokens are stored by the client, not by us.

Sources: opencode.ai/v2/docs/mcp-servers and opencode.ai/docs/mcp-servers, read 2026-09-28.

Claude Code and raw config

Command line clients take one command. This registers the aggregate endpoint with a key rather than OAuth, which is the right choice in CI where no browser exists:

claude mcp add --transport http harbor-port https://port.harborgovcon.com/mcp \
  --header "Authorization: Bearer $HARBOR_KEY"

Most clients also accept the same server as JSON:

{
  "mcpServers": {
    "harbor-port": {
      "type": "http",
      "url": "https://port.harborgovcon.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

Replace YOUR_API_KEY with a key from API keys. Create a test key if you would rather not spend plan quota while you wire the client up; test calls never count against your plan.

If discovery fails

MCP clients find the authorization server from the 401 response. Send a request with no credentials and you get:

POST https://port.harborgovcon.com/mcp          # no credentials
401 WWW-Authenticate: Bearer error="invalid_token", error_description="…",
  scope="read server:harbor-meta server:usaspending … server:gao-bid-protests",
  resource_metadata="https://port.harborgovcon.com/.well-known/oauth-protected-resource/mcp"

resource_metadata is the URL to fetch, and it is deliberately the last parameter in the header, so a client that reads everything after it still gets a clean URL. scope names the scopes this endpoint accepts, which is the same list every discovery document publishes.

That URL resolves, and so does the bare form, https://port.harborgovcon.com/.well-known/oauth-protected-resource with no /mcp suffix, along with the shape some clients try with /.well-known/ after the resource path. All of them answer with the same document.

They used to be different answers, and this page used to say so: the bare form returned 404, and a client that tried it first reported that it could not discover an authorization server. If you are reading a cached copy of this page that still says that, the gateway has moved on and the page has not. The 404 was our defect rather than your configuration, and it is fixed.

Two other causes worth ruling out first, because they are more common:

If none of that applies, tell us which client and version you are on. A discovery failure we cannot reproduce from the server side is information we want.