Skip to main content
Glama
mgreenspan17

mcp-home-server

by mgreenspan17
README.md
# mcp-home-server

Single, stable Model Context Protocol (MCP) "door" server that runs on your
home machine and exposes a **dynamic set of tools** to every connected AI
client (desktop, phone, future agents). Tools can be added, edited, or removed
at runtime — no restart needed.

Behind the door:

- **Dynamic tool loader** watches `src/tools/` and hot-reloads each module via
  chokidar + the MCP SDK's `list_changed` notification.
- **JSON manifest** is regenerated automatically and served at `GET /manifest`.
- **URLTracker** ingests "AI usage" events, hashes them, and emits a
  `url_tracker:new_ai` event the first time a URL is seen.
- **Onboarding agent** listens to those events and writes per-AI onboarding
  payloads (`manifests/onboarding/<hash>.json`) so new clients can instantly
  configure themselves to use this MCP host.
- **Scouting worker** periodically scans configured roots (`SCOUT_ROOTS`) for
  scripts/modules that look like MCP tool candidates; proposals are written to
  `manifests/pending/` for human review (no auto-promotion).
- **Dedupe worker** compares registered tools and writes overlap reports to
  `docs/dedupe/` to surface merges/refactors.

## Quick start

```bash
git clone https://github.com/manniegreenspan/mcp-home-server.git
cd mcp-home-server
npm install
npm run dev
# Server binds 127.0.0.1 on the first free port in 7000-7999.
# Check console for the actual URL, e.g.: http://127.0.0.1:7432/mcp
```

Test it with the MCP Inspector:

```bash
npx @modelcontextprotocol/inspector@latest
# Paste the MCP endpoint URL into the inspector.
```

## Endpoints

| Path                | Method | Purpose                                          |
| ------------------- | ------ | ------------------------------------------------ |
| `/mcp`              | POST/GET | MCP Streamable HTTP endpoint (JSON-RPC)        |
| `/manifest`         | GET    | JSON manifest of currently registered tools      |
| `/url-track`        | POST   | URLTracker ingestion: `{ "url": "...", "source": "..." }` |
| `/health`           | GET    | Liveness + last chokidar refresh                 |

## Adding a tool

Drop a file in `src/tools/`:

```ts
// src/tools/hello-world.ts
import { z } from "zod";
import type { ToolModule } from "../lib/types";

export default {
  name: "hello_world",
  description: "Says hello to a name",
  inputSchema: { name: z.string().describe("Name to greet") },
  handler: async ({ name }) => ({
    content: [{ type: "text", text: `Hello, ${name}!` }]
  })
} satisfies ToolModule;
```

The loader picks it up immediately, registers it with the MCP server, and
sends the `notifications/tools/list_changed` notification. Connected clients
(Inspector, Claude Desktop, etc.) refresh their tool list automatically.

Delete the file → tool unregistered. Edit the file → tool re-registered.

## Cloudflare deployment

See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md). v1 recommends **Cloudflare
Tunnel** fronting the local Express server. A pure-Cloudflare-Worker rewrite
is in the ROADMAP (Workers can't do dynamic `import()` of `src/tools/*.ts`).

## Project layout

```
mcp-home-server/
├── src/
│   ├── server.ts               # main entry: Express + McpServer + transports
│   ├── ports.ts                # port scan 7000-7999
│   ├── manifest.ts             # generate/serve JSON manifest
│   ├── logger.ts               # pino instance
│   ├── event-bus.ts            # shared EventEmitter
│   ├── tools/                  # dynamic tool modules (one file per tool)
│   ├── workers/                # onboarding-agent, scouting-worker, dedupe-worker
│   ├── url-tracker/            # ingestion + detector + hash store
│   └── lib/                    # types, hashing
├── manifests/
│   ├── current.json            # auto-regenerated manifest
│   ├── pending/                # scout proposals (manual review)
│   └── onboarding/             # onboarding payloads written by agent
├── docs/
│   ├── DEPLOYMENT.md
│   ├── ARCHITECTURE.md
│   └── dedupe/                 # dedupe-worker reports
├── tests/
└── logs/
```

## License

MIT — see [LICENSE](LICENSE).