Skip to main content
Glama
Rajendertyagi

MCPEvent

EventHub — MCP Event Server

Generic self-hosted MCP event server foundation (python -m app.server).

Layout

app/      application composition: Starlette+Uvicorn host, entrypoint,
          lifespan presentation helpers, canonical config + paths
core/     generic services: events, alerts, runtime/background tasks,
          SSE broker, persistence (core/persistence/store.py + modules/)
mcp_server/  MCP surface: contract identifiers, tools/, resources,
          services bundle, metrics   (named mcp_server so it can never
          shadow the installed `mcp` SDK distribution)
sources/  external source subsystem (registry, HTTP poller, test source)
test/     feature-focused regression suite (see below)

Layout

test/
  run_all.py            # regression driver: isolated subprocess per file, hard 300s/file timeout
  helpers/              # lifecycle, mcp, wait, mock_http, runner — shared test support
  mcp_result.py         # SDK result normalization + safe teardown
  test_*.py             # one feature per file (the units of the suite)
  config.json           # base server config (overwritten per-test, restored after)
TEST_RUNTIME_MAP.md     # per-file server usage, harness behavior, run guidance

Production source under test/ is frozen — do not edit server.py, events.py, store.py, runtime.py, errors.py, client.py, config.json, requirements.txt, or sources/* as part of test work.

Run

# Focused (preferred while debugging one feature):
python test/test_acknowledgement.py
python test/run_all.py --group fast

# Full regression (CI / release only — slow path):
python test/run_all.py
python test/run_all.py --timeout 300

See TEST_RUNTIME_MAP.md for the server-usage matrix, the bounded-wait strategy, and why you should run focused, not full, during development.

Principles

  • No server unless the test needs the MCP/HTTP boundary. Application logic (store, events, routing, checkpoint/ack, background tasks, source lifecycle, dedup) is tested directly against the real objects with an in-memory stub bus.

  • One server per D-level file (exceptions: restart tests in test_errors.py / test_reconnect.py, and test_subscriptions.py whose tests need different source configs).

  • Bounded waits, no long fixed sleeps. Readiness/counts are polled with timeouts.

  • Hard timeout (300 s/file) + parent-owned cleanup — the runner terminates the child's process group, so a hung file fails fast (reported as TIMEOUT) and any server.py it spawned is killed with it. No reliance on the child's atexit (which can't run after a hard kill).

Deleted (do not recreate)

test/test_phase8.py, test/integrate_test.py — replaced by the per-feature files above.