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

# Your first HTTP server

> Serve the same typed tool through a managed Node HTTP listener.

Keep the tool from the [stdio tutorial](https://toolgrain.mintlify.site/getting-started/stdio.md). Replace the transport to own a Node HTTP listener:

```ts src/server.ts theme={null}
import { createServer } from "@toolgrain/mcp";
import { http } from "@toolgrain/node";
import { greet } from "./tools/greet.js";

const server = createServer({
  name: "hello-http",
  version: "1.0.0",
  tools: { greet },
});
const transport = http({ port: 3333 });
await server.listen(transport);
console.error("MCP endpoint: http://127.0.0.1:3333/mcp");

for (const signal of ["SIGINT", "SIGTERM"] as const) {
  process.once(signal, () => { void server.close(); });
}
```

The listener binds to `127.0.0.1` by default. The route is `/mcp`. A managed listener's default allowed hosts match loopback authorities on its actual bound port; binding and host validation are separate settings.

## Call it

Compile and start the server from your project directory:

```bash theme={null}
npx tsc -p tsconfig.json
node dist/server.js
```

In a second terminal, use Inspector as described in [client setup](https://toolgrain.mintlify.site/getting-started/clients.md),
or send a direct modern protocol call:

```bash theme={null}
curl http://127.0.0.1:3333/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2026-07-28' \
  -H 'Mcp-Method: tools/call' \
  -H 'Mcp-Name: greet' \
  --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"greet","arguments":{"name":"Ada"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
```

The response contains the greeting as a tool result. Modern requests include protocol metadata and capabilities on each call; this example declares an empty capability set. Tools with additional required parameter headers need those headers too.

## Existing applications

If your framework owns the listener, use `createHttpHandler()` from `@toolgrain/http` for Web Request/Response, or `createNodeHttpHandler()` from `@toolgrain/node` for Node middleware. The combined handlers own MCP and auth metadata routing; mount them at the application root before body parsing.

See [HTTP behavior](https://toolgrain.mintlify.site/transports/http.md) and [framework recipes](https://toolgrain.mintlify.site/transports/frameworks.md).

## Before exposing the endpoint

Configure exact public `allowedHosts`, handle trusted proxy normalization in the application, and add authorization when the tools require it. `allowedOrigins` is a separate browser-origin check and does not emit CORS response headers. Applications own CORS, TLS, listener limits, and public URL normalization. The current HTTP implementation uses independent POST requests and JSON responses; it does not provide sessions, SSE streams, or resumability.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.