# or - if you have Bun installed globally
bun --watch src/http-server.ts
```

This will start the server and listen for incoming requests on port `3000`.
Trying to connect to this server with the MCP Inspector will result in an
error, so let's implement the MCP transport handling logic next.

## Handling MCP Client Requests

To handle requests from an MCP client (eg: Claude, Cursor, MCP Inspector, etc),
we'll need to implement the MCP transport logic in the `POST /mcp` endpoint.
We'll accomplish this by constructing an internal MCP server instance, and
connecting it to a transport that can handle incoming HTTP requests.

```typescript
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
import { createConsoleLogger } from "./mcp-server/console-logger.js";
import { createMCPServer } from "./mcp-server/server.js";

const app = express();
app.use(express.json());

app.post("/mcp", async (req, res) => {
  // Key Component #1: Create the MCP server instance
  const mcpServer = createMCPServer({
    logger: createConsoleLogger("warning"), // or info/debug/error
  });

  // Key Component #2: Create the MCP transport instance
  const mcpTransport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // Stateless - no session tracking
  });

  // Key Component #3: Connect the MCP server to the transport
  await mcpServer.connect(mcpTransport);

  // Key Component #4: Handle the request using the MCP transport
  await mcpTransport.handleRequest(req, res, req.body);
});

app.get('/mcp', async (req, res) => {
  res.status(405).send('Method not allowed: SSE not implemented.');
})

// Start the server and listen for requests
app.listen(3000, () => {
  console.log("MCP server listening on port 3000");
});
```

Let's break down the **key components** of this code:

- **Key Component #1: Create the MCP Server Instance** - The MCP Server
  instance manages the server's capabilities and handles capability negotiation
  with clients. It processes resource discovery, tool registration, and routes
  MCP protocol messages.

- **Key Component #2: Create the MCP Transport Instance** - The Transport
  handles the communication details between HTTP requests and MCP protocol
  messages. This includes aspects such as headers, status codes, encoding, and
  streaming. Setting `sessionIdGenerator` to `undefined` makes the implementation
  stateless - each request is independent with no session tracking.

- **Key Component #3: Connect the MCP Server to the Transport** - This connects
  the MCP server to the transport, establishing the bridge between MCP protocol
  logic and HTTP communication.

- **Key Component #4: Handle the Request Using the MCP Transport** - This
  processes the incoming HTTP request through the MCP transport layer and sends
  the appropriate MCP response back to the client.

After implementing the above code, the MCP Inspector (and other clients) should
be able to connect to the server, list its capabilities (tools, prompts,
resources), and even execute *unauthenticated* tools.

![MCP Inspector with Streamable HTTP transport](/assets/docs/mcp-inspector_streamable-http-local-tool-list.png)

If your MCP server needs to be able to use tools that interact with
authenticated API endpoints, keep reading to learn how to accept an
authentication header from the client, and use it to authenticate requests to
the API.

## Adding Authentication Support

Our HTTP server can also accept headers from a client and pass them to the
underlying MCP server. This is useful for scenarios where the MCP server needs
to authenticate requests to an API.

The following example accepts an `Authorization` header from the client, and
uses it to authorize the underlying API client, which is used by the MCP server
to make requests to the API.

```typescript
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
import { MySdkCore } from "./core.js";
import { createConsoleLogger } from "./mcp-server/console-logger.js";
import { createMCPServer } from "./mcp-server/server.js";

const app = express();
app.use(express.json());

app.post("/mcp", async (req, res) => {
  const apiKey = req.headers.authorization;

  // Key Component #1: Initialize the generated API client with the optional
  // credential
  const apiClient = new MySdkCore({
    security: apiKey ? { api_key: apiKey } : undefined,
  });

  const mcpServer = createMCPServer({
    logger: createConsoleLogger("warning"),
    // Key Component #2: Pass the API client to the MCP server
    getSDK: () => apiClient,
  });

  const mcpTransport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });

  await mcpServer.connect(mcpTransport);
  await mcpTransport.handleRequest(req, res, req.body);
});

app.get('/mcp', async (req, res) => {
  res.status(405).send('Method not allowed: SSE not implemented.');
})

// Start the server and listen for requests
app.listen(3000, () => {
  console.log("MCP server listening on port 3000");
});
```

Let's review the key components again:

- **Key Component #1: Initialize the API Client with the Optional Credential** - This
  initializes the API client with the `Authorization` header from the request, if
  it exists. This allows the MCP server to authenticate requests to the API.

- **Key Component #2: Pass the API Client to the MCP Server** - This passes the
  authenticated API client to the server, so calls can be made to secured API
  operations.

Now, when the MCP Inspector (or any other client) connects to the server, it
can include an `Authorization` header with an API key or token. The MCP server
will use this header to authenticate requests to the API client, allowing it to
access secured operations and resources.

<Callout title="Note" type="info">

This pattern can be used further configure the API client. For example, an
`X-Env` header could be sent to the server from the client, which can be used
to select the `serverUrl` to use for the API client (eg: `production` or
`sandbox`):

```typescript
const serverUrl = req.headers["x-env"] === "sandbox"
  ? "https://api.sandbox.acme.io"
  : "https://api.acme.io";

const apiClient = new MySdkCore({
  security: apiKey ? { api_key: apiKey } : undefined,
  serverUrl: serverUrl,
});
```
</Callout>