# Other Clients



No client-specific code lives in Surface's MCP server. If your tool speaks
[Streamable HTTP MCP](https://modelcontextprotocol.io/docs/concepts/transports#streamable-http),
it connects with a URL and a header.

```json
{
  "mcpServers": {
    "surface-forms": {
      "url": "https://app.withsurface.com/mcp",
      "headers": { "Authorization": "Bearer <your-api-key>" }
    }
  }
}
```

## Clients with a Written-up Config [#clients-with-a-written-up-config]

| Client             | Notes                                                                                          |
| ------------------ | ---------------------------------------------------------------------------------------------- |
| **Cursor**         | Settings UI or `.cursor/mcp.json`. [Config →](/mcp-server/setup#cursor)                        |
| **Windsurf**       | `~/.codeium/windsurf/mcp_config.json`, `serverUrl` key. [Config →](/mcp-server/setup#windsurf) |
| **Your own agent** | Any MCP client library. Nothing here is Surface-specific                                       |

Any other editor that supports Streamable HTTP takes the generic block above.
These are the two clients with a written-up config in
[API setup](/mcp-server/setup).

## Clients That Configure Headers but Not URLs [#clients-that-configure-headers-but-not-urls]

For hosts that set headers but not query strings:

```json
{
  "headers": {
    "Authorization": "Bearer <your-api-key>",
    "X-Surface-Tool-Families": "content"
  }
}
```

`?tools=` wins if both are present. Full rules in
[Tool bundles](/mcp-server/tool-bundles).

## Writing Your Own Client [#writing-your-own-client]

Three behaviours worth coding against:

**Schemas are discoverable.** `list_component_types`,
`describe_component_type` and `get_tool_schema` return the real shapes at
runtime, so you never hard-code a payload that a release can change.

**Unknown selections fail open.** A `?tools=` list with a typo falls back to
everything rather than producing a zero-tool server. A *known* tool your
credential excludes is silently skipped, so fewer tools than you expected is a
permissions problem, not a spelling one.

**Form writes are drafts.** `publish_form` is the only call that changes what a
visitor sees.

## When Something Does Not Work [#when-something-does-not-work]

<Steps>
  <Step title="Check the tool count">
    A default connection loads 45 tools. Fewer usually means `?readonly=1` or a
    restricted credential; 128 means `?tools=all`.
  </Step>

  <Step title="Check the transport">
    Streamable HTTP. There is no local process and no Docker container, so a
    client that can only launch a stdio server needs a bridge.
  </Step>

  <Step title="Check the header">
    `Authorization: Bearer <key>`, with the word `Bearer`. This is the single
    most common failure.
  </Step>

  <Step title="Check the environment">
    Every call is scoped to the credential's environment. A tool returning an
    empty list is often a correct answer about the wrong environment.
  </Step>
</Steps>

More in [MCP troubleshooting](/mcp-server/setup#troubleshooting).
