Skip to main content
Glama
9kubczas4

MCP Hello World Server

by 9kubczas4
README.md
# MCP Hello World App

A minimal **MCP App** boilerplate: a single Node/TypeScript MCP server that
exposes one tool (`say_hello`) and serves a tiny Angular UI as an
[MCP App](https://modelcontextprotocol.io) resource.

It mirrors the architecture of the parent `invoice-preview-mcp-app` project,
stripped down to a "Hello World".

## Architecture

```
MCP Host (e.g. Cursor)
  │  calls tool  say_hello
  ▼
Express server (:8080)
  ├─ POST/GET/DELETE /mcp   → MCP Streamable HTTP transport
  ├─ MCP resource           → ui://hello-world/app   (inlined Angular HTML)
  ├─ GET /ui/*              → HTTP fallback for assets
  └─ GET /healthz
        ▲
        │ build pipeline
  ng build → scripts/inline-bundle.mjs  (CSS + JS inlined into one HTML)
```

When the agent calls `say_hello`, the tool result carries
`_meta.ui.resourceUri = "ui://hello-world/app"`, which tells the host to open
the Angular UI in an iframe. Inside the iframe the UI calls `say_hello` again
through the MCP bridge (postMessage, with an HTTP fallback to `/mcp`).

## Project layout

```

├── package.json              # npm workspaces: server + ui
├── tsconfig.base.json
├── scripts/inline-bundle.mjs # inlines the Angular build for MCP iframes
├── .cursor/mcp.json          # points Cursor at http://127.0.0.1:8080/mcp
├── server/                   # MCP + Express server (TypeScript)
│   └── src/
│       ├── index.ts                      # entry point
│       ├── core/
│       │   ├── config/server-env.ts      # env parsing
│       │   ├── http/                     # Express app + CORS
│       │   ├── infrastructure/           # base-url / CSP helpers
│       │   └── mcp/                       # server factory, transport, tool registry
│       ├── tools/                        # one folder per MCP tool
│       │   └── say-hello/                 #   register-say-hello.ts + schemas
│       └── ui/                            # MCP App resource + HTTP fallback
└── ui/                       # Angular Hello World UI
```

### Adding a new tool

1. Create `server/src/tools/<your-tool>/register-<your-tool>.ts` (plus a
   `*.schemas.ts` if it takes input).
2. Add its registrar to the array in `server/src/core/mcp/tool-registry.ts`.

## Getting started

```bash
npm install
npm run build      # builds the server (tsc) and the UI (ng build + inline)
npm start          # node server/dist/index.js  → http://localhost:8080
```

Then add `.cursor/mcp.json` to your Cursor MCP config (or copy the
`hello-world-local` entry), and ask the agent to run the `say_hello` tool.

## Key conventions

| Convention | Why |
|------------|-----|
| MIME `text/html;profile=mcp-app` | Required by the MCP Apps spec |
| `outputHashing: "none"` (Angular) | Stable asset filenames for resource serving |
| `baseHref: "./"` | Relative paths inside the iframe |
| inline-bundle script | MCP iframes often block external script fetches |
| `_meta.ui.resourceUri` on the tool | Tells the host which UI to open |
| CORS on `/mcp` | The iframe has a null/opaque origin |
| `<meta name="mcp-server-url">` injection | Enables the HTTP tool-call fallback |