2026-09-18

Six real bugs between us and a working Glama deployment

A record of a real multi-round debugging session against a third party's hosting platform, not a single clean fix — each round produced a different real error, and each is quoted here as it actually appeared.

Glama's Spomory listing showing a working green Deploy button and an active Try in Browser button

The start: no explanation, just "cannot be deployed"

Glama is an MCP directory that also offers one-click hosted deployment for any listed server. Spomory's listing showed a greyed-out "Deploy Server" button with a single line underneath: "This server cannot be deployed." No error, no log, no hint about what was missing.

First guess: add a Dockerfile

The obvious first guess was a missing Dockerfile — Glama needs to containerize the server somehow. Spomory's repo didn't have one, so one was added and verified locally: a real `docker build` succeeded, and a real `docker run` with a dummy `LLM_API_KEY` stayed up without crashing. The Dockerfile was correct.

It still made no difference on Glama's side. The button stayed grey. That was the first sign this wasn't going to be a one-line fix — Glama, it turned out, doesn't use a repository's own Dockerfile at all. It synthesizes its own build recipe from a detected language and lets you edit that recipe directly — but only once you've claimed the listing.

Claiming the listing, via glama.json

Claiming requires two things: a `glama.json` file in the repo naming the GitHub maintainer, and then signing in with that GitHub account on Glama's own site to confirm ownership. The file is simple:

{
  "$schema": "https://glama.ai/mcp/schemas/server.json",
  "maintainers": ["lyf-wxy"]
}

Real error #1: a command that doesn't exist where Glama looks for it

Claiming unlocked an editable "Docker Builds" configuration panel — the actual recipe Glama uses, not the repo's own Dockerfile:

Glama's Docker build configuration panel, showing base image, Python version, build steps, and the generated Dockerfile
The configuration that generates Glama's own Dockerfile — base image debian:trixie-slim, build steps just `uv sync`, before any of the fixes below.

The first real test run against this produced an actual crash, quoted verbatim from the instance logs:

could not start the proxy Error: spawn memory-core-mcp ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:287:19)
    at onErrorNT (node:internal/child_process:525:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn memory-core-mcp',
  path: 'memory-core-mcp',
  spawnargs: []
}

The command name itself was correct — `memory-core-mcp` is a real console script defined in `pyproject.toml`. The actual problem was in the "CMD arguments" field, the literal command Glama spawns to start the server:

Glama's CMD arguments field, set to a bare mcp-proxy -- memory-core-mcp command
The CMD arguments field before the fix — a bare command with no way to reach the virtual environment `uv sync` had just created.
["mcp-proxy", "--", "uv", "run", "memory-core-mcp"]

Real error #2, caught before it happened: missing optional dependencies

Before re-testing, a check of `pyproject.toml` showed `llm`, `embedding`, and `mcp` are all optional-dependency groups — a bare `uv sync` installs none of them, which would have failed the very next run with a missing-import error instead of the command-not-found one. The build steps needed the extras spelled out explicitly:

["uv sync --extra llm --extra embedding --extra mcp"]

Real error #3: the process starts, then Glama kills it anyway

With both fixes in place, the next run got much further — the Python process actually started, and the instance logs show a real embedding model loading to completion:

Loading weights: 100%|██████████| 391/391 [00:00<00:00, 16767.95it/s]
/root/.local/share/uv/python/.../resource_tracker.py:475: UserWarning: resource_tracker: ...
could not start the proxy SdkError: Connection closed

No traceback — the process just stopped responding right after the model finished loading. The actual error surfaced one layer up: "Container exited with code 1 before responding to ping." That phrase is the real clue: Glama pings a freshly started container to confirm it's alive, and Spomory's MCP server was loading a multi-hundred-megabyte multilingual embedding model synchronously at startup — blocking the process for several seconds before it could answer anything, including that ping. Glama's health check timed out and killed it.

class SentenceTransformerProvider(EmbeddingProvider):
    """Loads its model lazily, on the first `embed()` call, rather than in
    `__init__`: constructing this class runs at MCP server startup, and
    eagerly loading a multi-GB multilingual model there blocks the process
    for several seconds before it can respond to anything -- including a
    health-check ping, which some hosts (e.g. Glama's container deploy)
    time out and kill before the server ever comes up."""

    def __init__(self, model_name: str | None = None) -> None:
        self.model_name = model_name or os.environ.get("EMBEDDING_MODEL", DEFAULT_MODEL_NAME)
        self._model = None

    def _get_model(self):
        if self._model is None:
            from sentence_transformers import SentenceTransformer
            self._model = SentenceTransformer(self.model_name)
        return self._model

Model loading moved out of `__init__` and into a private `_get_model()`, called only from `embed()` — the first real search or write, not server startup. The next test run: status `success`, duration 1m 19.2s, and the instance logs showed real JSON-RPC traffic — `tools/list` correctly returning all six tools including `export_memory`'s full schema, `prompts/list` and `resources/list` both answering cleanly. The server was actually working now.

Real error #4: a passing test that still wouldn't turn into a deploy

A passing build test still isn't a deployable release on Glama — there's a separate "Make Release" action tied to a real GitHub Release, matching a line already sitting in the Admin panel: "Auto-Release: builds and publishes a new version on every GitHub release." The `yliuai/spomory` repo had never shipped one. A real GitHub Release, `v0.1.1`, matching the version then published on PyPI, fixed that.

One more real mistake followed almost immediately: the PyPI package was republished as 0.1.2 shortly after, and the natural question was whether the `v0.1.1` tag was now stale. Checking the actual commit SHAs showed the tag and `main`'s HEAD were identical — `pyproject.toml` at that exact commit already said `0.1.2`. The code was never behind; the release was just mislabeled. The fix was to delete `v0.1.1` and recreate the same commit as `v0.1.2` — a naming correction, not a rebuild.

What actually made this five layers deep

None of these five fixes on their own would have looked complicated in isolation. What made this a real six-round debugging session was that each fix only revealed the next failure — a missing Dockerfile hid a missing claim step, which hid a wrong start command, which hid missing extras, which hid an eager model load, which hid a release-labeling step with its own separate bug. Every log quoted above is what Glama actually printed at each stage, not a cleaned-up retelling.