~/en/articles/mcp-server-typescript-erstellen

Build your own MCP server in TypeScript: connect company data to AI

AI-generated, human-reviewed

17/07/2026 · ai-integrations

Your developers already use AI assistants. The open question is how those assistants reach internal systems — the document store, the ticketing system, the knowledge base. The convenient path is copy-paste: dumping backend content into the chat. The controlled path is a service that offers narrowly defined capabilities — with authentication, logging, and no direct access to the backend. That is exactly the role of a server that speaks the Model Context Protocol (MCP).

This article explains, conceptually, how to build an MCP server that exposes an internal system as tools for Claude and other assistants — self-hosted and auditable. The running example is a document store that an assistant may only read from.

Why run your own MCP server instead of direct access

MCP is an open standard, initiated by Anthropic, with broad client support. An MCP server offers an AI assistant three kinds of capability: tools (actions the assistant can call), resources (readable data sources), and prompts (predefined flows). The assistant discovers these capabilities at runtime — you don’t maintain a client-specific plugin.

The real gain over direct access is the control layer in between. Instead of handing the model a database connection or an API key, you define a clear permission boundary: the server exposes only the tools you explicitly release, checks every call, and writes it to the log. What the assistant doesn’t see as a tool does not exist for it.

Building an MCP server in TypeScript

There is an official SDK for TypeScript. A minimal project needs two dependencies:

npm install @modelcontextprotocol/sdk zod

The SDK provides a high-level McpServer class that handles the protocol handshake, capability negotiation, and message serialization. You only describe your tools:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({
  name: "document-store",
  version: "1.0.0",
});

name and version announce the server to the client — no further configuration is needed to get started.

Defining a read-only tool

The permission boundary is drawn at tool definition. The following tool searches the document store and returns matches — read-only, with no write path:

server.registerTool(
  "search_documents",
  {
    title: "Search documents",
    description:
      "Searches the internal document store and returns matching results. Read-only access.",
    inputSchema: {
      query: z.string().describe("Search term"),
      limit: z.number().int().min(1).max(20).default(5),
    },
  },
  async ({ query, limit }) => {
    const results = await store.search(query, limit); // your existing search function
    return {
      content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
    };
  }
);

Two things matter here. First, the inputSchema uses Zod to declare which parameters are allowed — the SDK validates every call before your code sees it. Second, the handler calls your existing search function. The MCP server does not replace your domain logic; it wraps it in a clearly bounded interface. A write tool such as delete_document is deliberately omitted here, or placed behind additional checks — the read-only default stays as narrow as possible.

Starting the server: stdio or HTTP

MCP has two common transports.

stdio fits when the server runs as a local subprocess of the client — for instance inside a desktop app on the user’s machine:

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const transport = new StdioServerTransport();
await server.connect(transport);

Streamable HTTP is what you need once the server runs as a standalone service on your infrastructure and must be reachable by several clients over the network. The SDK ships StreamableHTTPServerTransport for this, which you mount into an HTTP handler (Express, for example). For an internal company server, this is the usual case.

Securing it: token and reverse proxy

An HTTP-reachable MCP server is a network service and must be secured accordingly. Two layers are enough to start:

  • Authentication at the edge: run the server behind a reverse proxy (Traefik, Caddy, nginx) that terminates TLS and enforces a bearer token or mTLS. No unauthenticated request reaches the server at all.
  • Least privilege inside the server: the server uses a technical account with exactly the rights its tools require — no admin access “just in case”.

For stricter requirements, MCP supports OAuth 2.1; combined with your own identity provider such as Keycloak, tools can be released per role. Either way, one rule holds: log every tool call. The log is your audit trail.

Deployment on your own infrastructure

An MCP server is an ordinary Node service and deploys like any other. On a self-hosted platform such as Coolify, a Dockerfile (or a Nixpacks build), one environment variable for the token, and a domain behind the built-in reverse proxy with automatic TLS are enough. The entire data path — documents, search index, logs — stays on your infrastructure; nothing moves to a third-party cloud. For GDPR-compliant processing this is the decisive point: the AI assistant only sees the answers your tools return, never the raw data, and you can account for every access.

When a classic API integration is enough

An MCP server is not always the right answer. It pays off when several, changing AI clients should discover and use the same capabilities — with consistent auth and an audit trail. That is when the protocol’s self-description earns its keep.

If, on the other hand, you have a single, fixed integration — one service calls a known API in a fixed flow — a direct API call is usually simpler, and an MCP server would be overhead. And if your goal is to make a large body of free-text knowledge searchable, a RAG system is often the better lever than a tool server — the frame for that is described under RAG systems for enterprise knowledge. Whether an MCP server fits your case can usually be settled in a few sentences; our FAQ “What is an MCP server — and do we need one?” sums up the rule of thumb.

Takeaways

  • An MCP server opens internal systems to AI assistants in a controlled way — instead of copy-paste or direct access.
  • With the official TypeScript SDK the skeleton is small: create an McpServer, define tools with a Zod schema, connect a transport.
  • The permission boundary is drawn at tool definition: expose only what is released; read before write.
  • Security belongs at the edge (reverse proxy, token or OAuth) and in the log (audit trail).
  • Deployed self-hosted — on Coolify, for example — the whole data path stays GDPR-compliant on your infrastructure.
  • Not an end in itself: a single fixed integration is fine with a classic API; for free-text knowledge, RAG is often better.

If you’re planning an MCP server from tool definition to operation on your own infrastructure, we can support you — from the permission boundary to deployment: MCP servers for AI integrations.