mcp-hello-typescript-server

mcp-hello-typescript-server

A minimal MCP server that provides a health check (server_info) and multi-language greeting (greet) tools, built with TypeScript and the official SDK.

Category
访问服务器

README

mcp-hello-typescript-server

ci image-scan npm-audit publish

Docker Hub image size Docker pulls GHCR License: MIT

A minimal MCP server built with TypeScript and the official @modelcontextprotocol/sdk — a good starting point for a new server or a demo. It exposes just two tools:

  • server_info — a health/status check.
  • greet — a friendly greeting in one of a handful of languages, defaulting to English. Ask it to "greet in French" and it replies Bonjour!.

Built with TypeScript, the TypeScript SDK, and make. It is the TypeScript port of the sibling Python mcp-hello-server, following the official MCP Build a server (TypeScript) reference. The Docker image compiles the TypeScript and runs it on a distroless Chainguard/Wolfi Node base — no shell, no package manager, non-root.


Quick start — demo an MCP server in 2 minutes

New to MCP? This is a tiny, safe server for seeing how an MCP client discovers and calls tools. Every tool is a harmless in-memory lookup, so it's a good sandbox. All you need is Docker and an MCP client — the steps below use Claude Code and the published Docker image (nothing to build or install).

Already running one of the sibling hello servers? The Python mcp-hello-server (alias hello), Go mcp-hello-go-server (alias hello-go), and Rust mcp-hello-rust-server (alias hello-rust) expose the same server_info / greet tools, so it's easy to test the wrong one. Remove any you don't want registered so your client only talks to hello-ts:

claude mcp list                # see what's registered
claude mcp remove hello        # the Python server, if present
claude mcp remove hello-go     # the Go server, if present
claude mcp remove hello-rust   # the Rust server, if present

1. Add the server. Claude Code launches the container per session and talks to it over stdio:

claude mcp add hello-ts -- docker run -i --rm -e MCP_TRANSPORT=stdio ghcr.io/mitchallen/mcp-hello-typescript-server:latest

2. Confirm it connected:

claude mcp list        # "hello-ts" should report ✔ Connected

3. Ask in plain language — Claude discovers the tools and picks one (the tool it calls is in parentheses):

  • "Is the hello server up? What version is it?" → (server_info)
  • "Greet me in French." → (greet → Bonjour!)
  • "Say hello in Japanese to Alice." → (greet → こんにちは (Konnichiwa), Alice!)
  • "What languages can you greet in?" → (server_info, reads languages)

That round trip — the client listing tools, then calling one with arguments and getting structured JSON back — is MCP.

4. Remove it when you're done:

claude mcp remove hello-ts

Prefer HTTP? Run it as a long-lived server instead:

docker run --rm -p 8000:8000 ghcr.io/mitchallen/mcp-hello-typescript-server:latest
claude mcp add --transport http hello-ts http://localhost:8000/mcp

Tools

Tool Purpose
server_info() Health/status: app name, version, uptime, supported languages
greet(language?, name?) Greeting in language (default English); optional name

greet

greet takes two optional arguments:

  • language — a language name, an alternate spelling, or an ISO code (case-insensitive). Omit it to default to English. Supported: english, spanish, french, german, italian, portuguese, japanese, hawaiian (e.g. french, Français, or fr all work).
  • name — optional; personalizes the message (Bonjour, Alice!).

It returns { language, greeting, message }:

// greet(language="french")
{ "language": "french", "greeting": "Bonjour", "message": "Bonjour!" }

// greet(language="spanish", name="Alice")
{ "language": "spanish", "greeting": "Hola", "message": "Hola, Alice!" }

// greet()  -> { "language": "english", "greeting": "Hello", "message": "Hello!" }

An unknown language returns a tool error listing the supported set.

Add a language

Add a row to GREETINGS in src/greetings.ts (and, optionally, an alias / ISO code to ALIASES). server_info reports the supported set automatically.


Quick start (from source)

Requires Node.js 20+.

make install     # npm ci
make build       # tsc -> ./build
make test        # run the test suite
make run         # run the server over stdio

make help lists every target.


Running the server

stdio (default — for MCP clients that launch the server)

npm run dev      # runs src/index.ts via tsx
# or, after `make build`:
node build/index.js
# or
make run

Streamable HTTP (for networked clients / containers)

make run-http            # PORT defaults to 8000
PORT=9000 make run-http

The MCP endpoint is served at /mcp.


Configuration

All configuration is via environment variables:

Variable Default Purpose
APP_NAME mcp-hello-typescript-server Name reported by server_info
MCP_TRANSPORT stdio stdio or http
HOST 127.0.0.1 Bind address for http
PORT 8000 Bind port for http

Using with an MCP client — local development (from source)

Point a stdio-based client (e.g. Claude Desktop, Claude Code) at the built entry point. With Claude Code, from the project directory:

make build
claude mcp add hello-ts -- node "$PWD/build/index.js"

Confirm it's connected with claude mcp list (or /mcp inside a session).

Example prompts (Claude Code)

Once the server is added, just ask in plain language — Claude picks the right tool. The tool it invokes is shown in parentheses.

  • "Is the hello server up? What version is it?" → (server_info)
  • "Greet me." → (greet, defaults to English → "Hello!")
  • "Greet in French." → (greet with language="french" → "Bonjour!")
  • "Say hello in Japanese to Alice." → (greet with language="japanese", name="Alice")
  • "What languages can you greet in?" → (server_info, then read languages)

Using a published image

The image is published to two registries:

  • GitHub Container Registry: ghcr.io/mitchallen/mcp-hello-typescript-server
  • Docker Hub: mitchallen/mcp-hello-typescript-server

Option A — Docker image, client launches it (stdio)

This is the simplest setup: there's nothing to build or install — just the published image. Pull it up front once so the first session doesn't block on the download (which can race an MCP client's connect/startup timeout):

docker pull ghcr.io/mitchallen/mcp-hello-typescript-server:latest

The client starts a fresh container per session and talks to it over stdio. Use -i (keep stdin open) and force the stdio transport, since the image defaults to HTTP:

{
  "mcpServers": {
    "hello-ts": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "MCP_TRANSPORT=stdio",
        "ghcr.io/mitchallen/mcp-hello-typescript-server:latest",
      ],
    },
  },
}

Claude Code equivalent:

claude mcp add hello-ts -- docker run -i --rm -e MCP_TRANSPORT=stdio ghcr.io/mitchallen/mcp-hello-typescript-server:latest

(Pin a version like :0.1.0 in place of :latest for a reproducible setup.)

Option B — Long-running container over HTTP

The image serves HTTP by default. Start it once, then point an HTTP-capable client at it:

docker run -d --rm -p 8000:8000 --name mcp-hello-ts ghcr.io/mitchallen/mcp-hello-typescript-server:latest
claude mcp add --transport http hello-ts http://localhost:8000/mcp

For clients that only speak stdio, bridge to the HTTP endpoint with mcp-remote:

{
  "mcpServers": {
    "hello-ts": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://localhost:8000/mcp"],
    },
  },
}

Notes for remote use:

  • Prefer HTTPS so traffic is encrypted in transit.
  • This server ships no authentication. If you expose it beyond localhost, put it behind a reverse proxy, gateway, or network policy.
  • The endpoint path is /mcp.

Docker

Published multi-platform (linux/amd64, linux/arm64) images run the server over streamable HTTP by default (MCP_TRANSPORT=http, HOST=0.0.0.0, PORT=8000) so they're reachable on a published port.

A multi-stage build compiles the TypeScript on cgr.dev/chainguard/node:latest-dev, prunes to production dependencies, and copies build/ + node_modules onto a distroless Chainguard/Wolfi node base — no shell, no package manager, runs as the non-root node user. Unlike the Go/Rust siblings (which ship a single static binary at ~10–17 MB), this image carries the Node runtime and node_modules, so it's larger (~275 MB) — that's inherent to shipping a runtime rather than a compiled binary. Every build is gated by a Trivy scan (fails on fixable CRITICAL/HIGH); the dependency tree is separately scanned with npm audit, and the published :latest is re-scanned daily — see Security scanning.

Pull and run

docker pull ghcr.io/mitchallen/mcp-hello-typescript-server:latest
docker run --rm -p 8000:8000 --name mcp-hello-ts ghcr.io/mitchallen/mcp-hello-typescript-server:latest

Then connect an HTTP MCP client to http://localhost:8000/mcp.

Test a published release with make

make docker-test               # up + smoke + down in one shot (exits non-zero on failure)

make docker-up                 # pull + run ghcr.io/mitchallen latest, detached
make docker-smoke              # MCP `initialize` handshake — passes if the server responds
make docker-down               # stop it

make docker-up TAG=0.1.0                         # pin a version
make docker-up REGISTRY=docker.io/mitchallen     # pull from Docker Hub instead
make docker-up HTTP_PORT=9000                    # publish on a different host port

Build locally

make docker-build        # docker build -t mcp-hello-typescript-server .
make docker-run          # serves http on localhost:8000
make scan                # Trivy scan of the local image (fixable CRITICAL/HIGH fail)

Security scanning

Two complementary gates catch vulnerabilities, both reproducible locally:

  • image-scan (make scan) — Trivy scans the built container image and fails the build on fixable CRITICAL/HIGH vulnerabilities. It covers the OS layer of the runtime image and reads the JavaScript packages in node_modules.
  • npm-audit (npm audit --omit=dev --audit-level=high) — scans the production dependency tree against the npm advisory database. Dev-only tooling advisories don't wedge the build.
  • scan-scheduled re-scans the published :latest image daily and uploads results to the GitHub Security tab, catching CVEs disclosed after build time.
  • Dependabot opens weekly PRs for npm packages, the Docker base image, and GitHub Actions; low-risk updates auto-merge once CI passes.

CI / Publish

Workflows live in .github/workflows/:

  • ci — on every push/PR to main: prettier format check, tsc type-check, and node --test.
  • npm-audit / image-scan / scan-scheduled — vulnerability scanning (see above).
  • publish / publish-dockerhub — triggered by pushing a v* tag. Build a multi-platform image, Trivy-scan it, push it to GHCR and Docker Hub, then run make docker-test against the just-published image. The Docker Hub job needs DOCKERHUB_USERNAME / DOCKERHUB_TOKEN repository secrets.

To cut a release, use the release target — it bumps the version in package.json, commits, tags, pushes, and creates the GitHub Release from the CHANGELOG.md section, which triggers both publish workflows:

make release              # patch bump (default)
make release BUMP=minor   # or minor / major

The target refuses to run unless the working tree is clean, you're on main, and CHANGELOG.md already has a ## [X.Y.Z] section for the new version.

Docker Hub secrets (one-time setup)

Pushing to GHCR needs no setup — it uses the built-in GITHUB_TOKEN. The publish-dockerhub job additionally needs two repository secrets and a pre-created Docker Hub repo:

  1. Create a Docker Hub access token (not your password) with Read & Write permissions, at hub.docker.com → Account Settings → Personal access tokens.

  2. Create the Docker Hub repository mitchallen/mcp-hello-typescript-server (Public).

  3. Add the two GitHub secrets — DOCKERHUB_USERNAME and DOCKERHUB_TOKEN:

    gh secret set DOCKERHUB_USERNAME --body "mitchallen"
    gh secret set DOCKERHUB_TOKEN          # prompts for the value — paste the token
    

Without these, the GHCR publish job still succeeds; only publish-dockerhub fails at the login step.


Development

  • Source: src/
    • greetings.ts — greeting data + language resolution (greet), unit-tested
    • server.ts — createServer() + tools registered with server.registerTool
    • version.ts — reads the version from package.json at runtime
    • index.ts — the entry point; transport wiring (stdio / HTTP)
  • Tests: tests/server.test.ts drives the tools through an in-memory client (InMemoryTransport.createLinkedPair, no network/subprocess); tests/greetings.test.ts unit-tests the resolver/builder. Run everything with make test, or the full CI gate with make check (prettier + type-check + test).
  • Dependencies: package.json / package-lock.json are committed. Run npm install after changing dependencies to refresh the lockfile.

License

MIT © Mitch Allen

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选