Skip to main content
Glama
README.md
<div align="center">
  <img src="./assets/brand/ctxrelay-banner.svg" alt="CtxRelay — System-agnostic MCP context relay" width="820"/>
  <br/><br/>

  ![Node 22+](https://img.shields.io/badge/Node-22%2B-3ddc84?style=flat-square&logo=node.js&logoColor=white)
  ![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6?style=flat-square&logo=typescript&logoColor=white)
  ![MCP](https://img.shields.io/badge/protocol-MCP-e0475c?style=flat-square)
  ![Monorepo](https://img.shields.io/badge/npm_workspaces-2_servers-555555?style=flat-square)
  ![License](https://img.shields.io/badge/license-Apache--2.0-555555?style=flat-square)

  <br/>

  **A system-agnostic MCP relay for continuous context.** Wraps [OmniEngineering](https://github.com/M4K4TT4CK/OmniEngineering)'s file-based engineering workspace as an MCP server, and orchestrates any MCP compactor — Headroom or otherwise — into it. Swapping compactors is a config edit, not a rewrite.

</div>

---

### Contents

[What is this?](#what-is-this-in-plain-english) ·
[What's in here](#whats-in-here) ·
[Architecture](#architecture) ·
[Quick start](#quick-start) ·
[Tools](#ctxrelay-tools) ·
[Status](#status) ·
[Contributing](#contributing) ·
[License](#license)

---

## What is this, in plain English?

If you're not steeped in AI tooling, here's the short version.

An **MCP server** is a small program that gives an AI assistant (like Claude)
a new skill — a set of "tools" it can call, the same way a phone app gets new
abilities from a plugin. The **MCP** (Model Context Protocol) is just the
common wiring standard that lets any assistant talk to any such plugin
without custom integration work for each one.

Two skills, two servers, one problem they solve together:

- **AI assistants forget things between sessions**, and long conversations
  eat up their limited "attention span" (context window). A **compactor**
  is a tool that squeezes a big pile of text down to the important parts —
  think of it like a good executive summary of a long meeting.
- Separately, a project can have its own rulebook of engineering standards,
  conventions, and history (that's what
  [OmniEngineering](https://github.com/M4K4TT4CK/OmniEngineering) provides).
  **omni-engineering-mcp** exposes that rulebook to an assistant as tools,
  and adds a running notebook (`.ai/context-log.md`) the assistant can keep
  writing to over time.
- **CtxRelay** is the piece that connects the two: it takes the executive
  summary from whichever compactor you use, and files it into the project's
  notebook automatically. You can swap in a different summarizer later
  without touching any code — just point a config file at it.

The net effect: an assistant working on your project keeps a running,
space-efficient memory of what's happened, instead of starting from zero
(or drowning in old transcript) every session.

---

## What's in here

Two MCP servers, one monorepo:

| Package | Role |
|---|---|
| **[CtxRelay](packages/ctxrelay-mcp)** (`ctxrelay-mcp`) | System-agnostic orchestrator. Spawns a configured compactor MCP server and an omni-engineering-mcp instance, and relays compacted output from one into the other. |
| **[omni-engineering-mcp](packages/omni-engineering-mcp)** | Turns [OmniEngineering](https://github.com/M4K4TT4CK/OmniEngineering)'s rules/playbooks/checklists workspace into MCP tools, bound to one project per instance. Adds an append-only context log OmniEngineering didn't have on its own. |

---

## Architecture

```
 caller (Claude Desktop/Code, etc.)
        │  relay_compact_and_store(text)
        ▼
 CtxRelay  ──calls "compactTool"──▶  <any compactor MCP server>
        │  context_log_append(summary)
        ▼
 omni-engineering-mcp  ──writes──▶  .ai/context-log.md  (per project)
```

**Why two servers instead of one merged one:** compaction is a per-turn
token-reduction concern; context governance is a durable per-project
ruleset. Headroom is a third-party project — folding its code into this
repo would mean vendoring and tracking someone else's releases inside
ours. Keeping them separate, wired together by CtxRelay's thin MCP
`list_tools`/`call_tool` bridge, means either side can be swapped or
upgraded independently, and CtxRelay works with any compactor that
exposes a text-in/text-out tool, not just Headroom.

---

## Quick start

```bash
npm install
npm run build
```

Then, per project you want this managing:

1. Run `omni-engineering-mcp` with `OMNI_PROJECT_ROOT` set to that project.
2. Write a `ctxrelay.config.json` for that project (see
   [`packages/ctxrelay-mcp/ctxrelay.config.example.json`](packages/ctxrelay-mcp/ctxrelay.config.example.json))
   pointing `omniServer` at step 1's server and `compactor` at whatever MCP
   compactor you're using.
3. Run CtxRelay with `CTXRELAY_CONFIG` set to that file.

Point your MCP host (Claude Desktop, Claude Code, etc.) at whichever server
it needs directly — most setups will only need to add CtxRelay, since it
manages the omni-engineering-mcp child process itself.

```json
{
  "mcpServers": {
    "ctxrelay": {
      "command": "node",
      "args": ["/absolute/path/to/context-relay-mcp/packages/ctxrelay-mcp/dist/index.js"],
      "env": {
        "CTXRELAY_CONFIG": "/absolute/path/to/your-project/ctxrelay.config.json"
      }
    }
  }
}
```

---

## CtxRelay tools

| Tool | What it does |
|---|---|
| `relay_compact_and_store` | Calls the configured compactor on `text`, then appends the result to the Omni context log. |
| `relay_recent_context` | Reads back recent context-log entries (proxies `context_log_recent`). |
| `relay_status` | Confirms both child servers are reachable and lists their tools; does not compact or store anything. |

## omni-engineering-mcp tools

| Tool | What it does |
|---|---|
| `omni_doctor` | Workspace health check. |
| `omni_sync` | Refresh entrypoints/shims/ignore files. |
| `omni_map` | Regenerate `.ai/project-map.md`. |
| `omni_graph_build` | Parse the bound project with tree-sitter into a deterministic code graph -- no embeddings, no vector store. Edges tagged `EXTRACTED`/`INFERRED`. |
| `omni_graph_trace` | Shortest tagged path between two symbols in that graph. |
| `omni_graph_show` | A symbol's direct outgoing/incoming edges, tagged `EXTRACTED`/`INFERRED`. |
| `omni_graph_render` | Renders the graph as a force-directed SVG node-link diagram (`.ai/project-graph.svg`) -- pure Python, no extra dependency. |
| `omni_context` | Print a context-loading profile's file list as JSON. |
| `omni_context_bundle` | Same, but inlines every listed file's contents in one call. |
| `omni_adopt` | Copy the vendored workspace into the bound project. |
| `omni_update` | 3-way merge upstream template improvements into an adopted project. |
| `omni_requirement_add` | Add a `REQ-###` entry to the requirement registry. |
| `omni_rule_add` | Add a rule to a structured rulepack. |
| `context_log_append` | Append a compacted context entry to `.ai/context-log.md`. |
| `context_log_recent` | Read back recent context-log entries. |

Full details, config shape, and the compactor adapter contract are in each
package's own README.

---

## Status

This is a working first cut, not a finished 1.0. Both servers build, and
CtxRelay has been exercised end-to-end against a stand-in compactor (spawn
both servers, `relay_compact_and_store`, confirm the compacted text lands
in `.ai/context-log.md`). It has **not** been exercised against a real
Headroom instance — see the compactor config note in
[`packages/ctxrelay-mcp/README.md`](packages/ctxrelay-mcp/README.md)
before pointing it at one. If you try it against Headroom (or any other
compactor) and hit a mismatch, that's exactly the kind of thing worth
opening an issue or PR for.

---

## Contributing

Contributions, bug reports, and "this didn't work with X compactor" reports
are all welcome — this is early enough that real-world use is the fastest
way to find the rough edges.

**Getting set up:**

```bash
git clone https://github.com/M4K4TT4CK/context-relay-mcp.git
cd context-relay-mcp
npm install
npm run build       # builds both packages via npm workspaces
```

Requires Node.js 22+ and, for `omni-engineering-mcp` specifically, Python
3.10+ on `PATH` (as `python3` or `python`).

**Project shape, if you're orienting for the first time:**

- `packages/omni-engineering-mcp/` — the OmniEngineering MCP server. Source
  in `src/`, a vendored snapshot of OmniEngineering under `vendor/`.
- `packages/ctxrelay-mcp/` — the orchestrator. Source in `src/`.
- Each package builds independently with `npm run build` (plain `tsc`, no
  bundler) and has its own README with the tool/config details.

**Before opening a PR:**

- Run `npm run build` at the repo root and make sure both packages compile
  clean (`tsc` is configured in strict mode).
- If you change the config schema in `ctxrelay-mcp/src/config.ts` or the
  tool set in either server's `src/index.ts`, update that package's README
  to match — the tables in these docs are meant to stay accurate, not
  aspirational.
- Keep changes scoped: this repo intentionally keeps the two servers
  decoupled (see [Architecture](#architecture) above for why), so a PR
  that starts merging their responsibilities back together needs a good
  reason in the description.

No formal issue templates or CI yet — just open an issue or PR and describe
what you were trying to do and what happened instead.

---

## Brand Assets

<div align="center">
  <img src="./assets/brand/ctxrelay-wordmark.svg" alt="CtxRelay wordmark" height="52"/>
</div>

<br/>

Vector assets are in [`assets/brand/`](./assets/brand/):

| File | Use |
|---|---|
| `ctxrelay-banner.svg` | README / repository header |
| `ctxrelay-wordmark.svg` | Horizontal lockup — docs, presentations |
| `ctxrelay-mark.svg` | Square icon — favicons, app icons, avatars |

**Brand colors**

| Token | Hex | Use |
|---|---|---|
| Crimson | `#e0475c` | Primary accent, hub, nodes |
| Background | `#0f0f12` | Dark surface |
| Text | `#e8e8e8` | Primary text |
| Muted | `#606060` | Secondary / label text |

---

## License

<div align="center">
  <img src="./assets/brand/ctxrelay-mark.svg" alt="CtxRelay" width="40"/>
</div>

<br/>

Apache-2.0 — see [LICENSE](LICENSE). Vendors a snapshot of OmniEngineering
(also Apache-2.0) under `packages/omni-engineering-mcp/vendor/` — see
[NOTICE](NOTICE) and
[`packages/omni-engineering-mcp/vendor/VENDOR.md`](packages/omni-engineering-mcp/vendor/VENDOR.md).