Skip to main content
Glama
glatinone

MCP Local-to-Hosted Deployment Fix

by glatinone
README.md
# MCP Local-to-Hosted Deployment Fix

![tests](https://github.com/glatinone/mcp-local-to-hosted-deployment-fix/actions/workflows/tests.yml/badge.svg)

## Business story

A local MCP server can work on its author's laptop while a hosted-like client fails because transport, endpoint, authentication, version, and discovery are implicit. This MVP makes one supported path explicit and testable.

## Before and after

Before: manual local process, unclear endpoint, unpinned dependencies, vague errors. After: Node 22 server version `demo-1`, streamable HTTP at `/mcp`, sandbox bearer token, stable two-tool registry, tenant fixtures, request IDs, deterministic failures, smoke client, reset script, and runbook.

## Quick start

No package installation is required or permitted for this demo.

```sh
./scripts/reset-demo.sh
./scripts/start-demo.sh
# in another terminal
node runtime/client.mjs
node runtime/run-tests.mjs

On Node 22.22+ use `node --experimental-strip-types runtime/run-tests.mjs` (the suite imports src/*.ts directly).
```

## Normal walkthrough

Health, token issuance, initialize, discovery, tenant-a read, and approval-denied archive are covered by `smoke/client.ts`. The read returns only tenant-a titles. The write never mutates data and is denied without a request-bound approval string.

## Failure walkthrough

Use `MCP_FAILURE=timeout ./scripts/start-demo.sh` or `MCP_FAILURE=unavailable ./scripts/start-demo.sh`. The failure matrix is represented by deterministic unit and integration checks in `tests/run-tests.mjs`.

## Test evidence

The dependency-free runner verifies token rejection and expiry, protocol mismatch, discovery, schemas, tenant isolation, approval policy, read, write, and registry behavior (13 checks). `runtime/run-rest-tests.mjs` covers the REST surface (10 checks). Run it after reset. Logs are JSON lines in `logs/events.jsonl` and never contain the raw bearer token.

## AWS deployment layer

The same dependency-free code runs unchanged on managed containers. `Dockerfile` and `apprunner.yaml` target App Runner or ECS Fargate on port 8080, health checked on `/health`. A REST surface (`runtime/rest-server.mjs`, `./scripts/start-rest.sh`) exposes the same two operations with the identical bearer, tenant, and approval policy, packaged with a Bedrock Agent action group schema in `integrations/bedrock/`. Full instructions in `docs/aws-deployment.md`.

## REST quick check

```sh
./scripts/start-rest.sh &          # listens on 8081, honors PORT
curl -s http://localhost:8081/health
node runtime/run-rest-tests.mjs    # 10 checks
```

Writes on the REST surface need `approval` equal to `approve:<x-request-id>` of that exact call, so agent-initiated writes stay replay safe and human gated. See `integrations/bedrock/README.md` for the managed agent flow.

## Repository

See `docs/architecture.md`, `docs/compatibility.md`, and `docs/runbook.md`. Intended dependency versions are pinned in `package.json`; no `node_modules` is required for the constrained fallback.

## Visual demo

![MCP deployment demo](assets/demo-screenshot.png)

[Open the short GIF demo](assets/demo.gif)

---

Maintained by Kiell Tampubolon. More selected work at [kielltampubolon.id](https://www.kielltampubolon.id/).