contextforge-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Tests (Python ${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - uses: astral-sh/setup-uv@v3
22
+ - run: |
23
+ uv venv
24
+ uv pip install -e ".[dev]"
25
+ uv run pytest tests/ -v
@@ -0,0 +1,38 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build distribution
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - uses: astral-sh/setup-uv@v3
17
+ - name: Build wheel and sdist
18
+ run: uv build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish-pypi:
25
+ name: Publish to PyPI
26
+ needs: build
27
+ runs-on: ubuntu-latest
28
+ environment:
29
+ name: pypi
30
+ url: https://pypi.org/project/contextforge-mcp/
31
+ permissions:
32
+ id-token: write
33
+ steps:
34
+ - uses: actions/download-artifact@v4
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ .env
8
+ .cbm_store/
9
+ node_modules/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Camilo Patiño
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: contextforge-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP orchestrator: codebase-memory-mcp + headroom + Spec Kit
5
+ Project-URL: Repository, https://github.com/capatinore/contextforge-mcp
6
+ Author-email: Camilo Patiño <capatinore@github.com>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Keywords: ai-agents,code-intelligence,compression,context,llm,mcp,spec-kit
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: anyio>=4.0.0
12
+ Requires-Dist: headroom-ai>=0.9.0
13
+ Requires-Dist: httpx>=0.27.0
14
+ Requires-Dist: mcp>=1.0.0
15
+ Requires-Dist: pydantic>=2.0.0
16
+ Requires-Dist: rich>=13.0.0
17
+ Requires-Dist: typer>=0.12.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
20
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # contextforge-mcp
24
+
25
+ **MCP orchestrator combining [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) + [headroom](https://github.com/headroomlabs-ai/headroom) + [Spec Kit](https://github.com/github/spec-kit) into a single pipeline.**
26
+
27
+ ```
28
+ Agent (Claude Code / Cursor / Codex)
29
+
30
+
31
+ contextforge-mcp ←── single MCP server
32
+
33
+ ├── codebase-memory-mcp (knowledge graph: 99% fewer retrieval tokens)
34
+ ├── headroom (compression: 60–95% fewer prompt tokens)
35
+ └── Spec Kit (SDD workflow: spec → plan → tasks → implement)
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ # Prerequisites
44
+ npm install -g codebase-memory-mcp
45
+ pip install "headroom-ai[all]"
46
+ pip install spec-kit
47
+
48
+ # Install contextforge-mcp
49
+ pip install contextforge-mcp
50
+ ```
51
+
52
+ ## Setup
53
+
54
+ ```bash
55
+ # Health check
56
+ contextforge-mcp doctor
57
+
58
+ # Configure Claude Code (writes .mcp.json)
59
+ contextforge-mcp install --target claude
60
+
61
+ # Configure Spec Kit extension
62
+ contextforge-mcp install --target speckit
63
+
64
+ # Both at once
65
+ contextforge-mcp install --target all
66
+ ```
67
+
68
+ ## Usage in Claude Code
69
+
70
+ ```
71
+ # 1. Index the codebase (once per session)
72
+ cbm_index_repository(repo_path=".")
73
+
74
+ # 2. Query the graph (instead of grep/read)
75
+ cbm_search_graph(name_pattern=".*Payment.*")
76
+ cbm_trace_path(function_name="processPayment")
77
+ cbm_get_architecture()
78
+
79
+ # 3. Check token savings
80
+ cf_stats()
81
+ ```
82
+
83
+ ## Spec Kit workflow
84
+
85
+ ```
86
+ /speckit.constitution
87
+ /speckit.specify
88
+ /speckit.cf-analyze ← analyze codebase before planning
89
+ /speckit.plan
90
+ /speckit.tasks
91
+ /speckit.cf-index ← index before implementing
92
+ /speckit.cf-implement ← graph-aware implementation
93
+ /speckit.cf-stats ← token savings report
94
+ ```
95
+
96
+ ## Tools (23 total)
97
+
98
+ | Prefix | Count | Description |
99
+ |--------|-------|-------------|
100
+ | `cbm_*` | 14 | codebase-memory-mcp graph tools |
101
+ | `cf_*` | 9 | ContextForge meta + Spec Kit tools |
102
+
103
+ ## Environment variables
104
+
105
+ | Variable | Default | Description |
106
+ |----------|---------|-------------|
107
+ | `CBM_BINARY_PATH` | auto | Path to codebase-memory-mcp binary |
108
+ | `CF_MODEL` | `claude-sonnet-4-6` | Model hint for headroom |
109
+ | `CF_LOG_LEVEL` | `WARNING` | Log level |
110
+
111
+ ## Credits
112
+
113
+ - [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) — MIT
114
+ - [headroom](https://github.com/headroomlabs-ai/headroom) — Apache 2.0
115
+ - [spec-kit](https://github.com/github/spec-kit) — MIT
116
+
117
+ ## License
118
+
119
+ MIT
@@ -0,0 +1,97 @@
1
+ # contextforge-mcp
2
+
3
+ **MCP orchestrator combining [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) + [headroom](https://github.com/headroomlabs-ai/headroom) + [Spec Kit](https://github.com/github/spec-kit) into a single pipeline.**
4
+
5
+ ```
6
+ Agent (Claude Code / Cursor / Codex)
7
+
8
+
9
+ contextforge-mcp ←── single MCP server
10
+
11
+ ├── codebase-memory-mcp (knowledge graph: 99% fewer retrieval tokens)
12
+ ├── headroom (compression: 60–95% fewer prompt tokens)
13
+ └── Spec Kit (SDD workflow: spec → plan → tasks → implement)
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ # Prerequisites
22
+ npm install -g codebase-memory-mcp
23
+ pip install "headroom-ai[all]"
24
+ pip install spec-kit
25
+
26
+ # Install contextforge-mcp
27
+ pip install contextforge-mcp
28
+ ```
29
+
30
+ ## Setup
31
+
32
+ ```bash
33
+ # Health check
34
+ contextforge-mcp doctor
35
+
36
+ # Configure Claude Code (writes .mcp.json)
37
+ contextforge-mcp install --target claude
38
+
39
+ # Configure Spec Kit extension
40
+ contextforge-mcp install --target speckit
41
+
42
+ # Both at once
43
+ contextforge-mcp install --target all
44
+ ```
45
+
46
+ ## Usage in Claude Code
47
+
48
+ ```
49
+ # 1. Index the codebase (once per session)
50
+ cbm_index_repository(repo_path=".")
51
+
52
+ # 2. Query the graph (instead of grep/read)
53
+ cbm_search_graph(name_pattern=".*Payment.*")
54
+ cbm_trace_path(function_name="processPayment")
55
+ cbm_get_architecture()
56
+
57
+ # 3. Check token savings
58
+ cf_stats()
59
+ ```
60
+
61
+ ## Spec Kit workflow
62
+
63
+ ```
64
+ /speckit.constitution
65
+ /speckit.specify
66
+ /speckit.cf-analyze ← analyze codebase before planning
67
+ /speckit.plan
68
+ /speckit.tasks
69
+ /speckit.cf-index ← index before implementing
70
+ /speckit.cf-implement ← graph-aware implementation
71
+ /speckit.cf-stats ← token savings report
72
+ ```
73
+
74
+ ## Tools (23 total)
75
+
76
+ | Prefix | Count | Description |
77
+ |--------|-------|-------------|
78
+ | `cbm_*` | 14 | codebase-memory-mcp graph tools |
79
+ | `cf_*` | 9 | ContextForge meta + Spec Kit tools |
80
+
81
+ ## Environment variables
82
+
83
+ | Variable | Default | Description |
84
+ |----------|---------|-------------|
85
+ | `CBM_BINARY_PATH` | auto | Path to codebase-memory-mcp binary |
86
+ | `CF_MODEL` | `claude-sonnet-4-6` | Model hint for headroom |
87
+ | `CF_LOG_LEVEL` | `WARNING` | Log level |
88
+
89
+ ## Credits
90
+
91
+ - [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) — MIT
92
+ - [headroom](https://github.com/headroomlabs-ai/headroom) — Apache 2.0
93
+ - [spec-kit](https://github.com/github/spec-kit) — MIT
94
+
95
+ ## License
96
+
97
+ MIT
@@ -0,0 +1,14 @@
1
+ # /speckit.cf-analyze
2
+
3
+ Analyze the existing codebase and compress the current spec before planning.
4
+ Run after `/speckit.specify`, before `/speckit.plan`.
5
+
6
+ ## Steps
7
+
8
+ 1. `cf_read_spec()` — load and compress the current spec
9
+ 2. `cbm_search_graph(name_pattern="<pattern from spec>")` — find related code
10
+ 3. `cbm_get_architecture()` — understand where the feature fits
11
+ 4. `cbm_find_similar_code(node_id="<key node>")` — avoid duplicating existing code
12
+ 5. `cbm_get_impact(node_id="<key node>")` — identify risk areas
13
+ 6. Write `specs/$FEATURE_ID/context.md` with findings
14
+ 7. `cf_stats()` — report token savings
@@ -0,0 +1,41 @@
1
+ # /speckit.cf-implement
2
+
3
+ Graph-aware implementation. Uses ContextForge instead of file reads.
4
+
5
+ ## Arguments
6
+ - `$FEATURE_ID` — feature directory under `specs/`
7
+ - `$TASK_ID` — (optional) specific task number
8
+
9
+ ## Steps
10
+
11
+ ### Phase 0 — Load context
12
+ ```
13
+ cf_implement_context(feature_id="$FEATURE_ID")
14
+ ```
15
+
16
+ ### Phase 1 — Understand the task
17
+ For each task, query the graph:
18
+ ```
19
+ cbm_search_graph(name_pattern="<function from task>")
20
+ cbm_trace_path(function_name="<target>", direction="inbound")
21
+ cbm_get_impact(node_id="<node>")
22
+ ```
23
+ Only read the actual file when you need to edit it.
24
+
25
+ ### Phase 2 — Implement
26
+ - Make minimum change that satisfies the task
27
+ - Mark task complete in `tasks.md`
28
+ - Check `cbm_find_similar_code` before writing new functions
29
+
30
+ ### Phase 3 — Validate
31
+ ```
32
+ cbm_trace_path(function_name="<modified>", direction="both")
33
+ cbm_find_dead_code(confidence="high")
34
+ ```
35
+
36
+ ### Phase 4 — Report
37
+ - Mark task complete
38
+ - `cf_stats()` — show token savings
39
+ - State next task
40
+
41
+ ## Rule: never grep. Always use `cbm_*` for discovery.
@@ -0,0 +1,15 @@
1
+ # /speckit.cf-index
2
+
3
+ Index the codebase into the ContextForge knowledge graph before implementing.
4
+
5
+ ## Steps
6
+
7
+ 1. Call `cf_stats()` — confirm ContextForge is connected
8
+ 2. Call `cbm_index_repository(repo_path=".")` — build the knowledge graph
9
+ 3. Call `cbm_get_indexing_status()` — confirm completion
10
+ 4. Call `cbm_get_architecture()` — show compressed architecture overview
11
+ 5. Report: files indexed, modules detected, token savings, ready for `/speckit.cf-implement`
12
+
13
+ ## Notes
14
+ - Re-run after significant refactoring
15
+ - Use `cbm_*` tools instead of grep/Read for ALL structural queries after indexing
@@ -0,0 +1,18 @@
1
+ # /speckit.cf-stats
2
+
3
+ Show ContextForge token savings for this session.
4
+
5
+ ## Steps
6
+
7
+ Call `cf_stats()` and present as a table:
8
+
9
+ | Metric | Value |
10
+ |--------|-------|
11
+ | Total calls | X |
12
+ | Original tokens | X |
13
+ | Compressed tokens | X |
14
+ | Tokens saved | X |
15
+ | Compression ratio | X% |
16
+
17
+ Estimate cost savings at $3/M tokens (Claude Sonnet).
18
+ To reset: `cf_reset_stats()`
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "contextforge-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Integrates contextforge-mcp (codebase-memory-mcp + headroom) into Spec Kit — adds code intelligence and context compression to the SDD workflow.",
5
+ "author": "Camilo Patiño",
6
+ "license": "MIT",
7
+ "repository": "https://github.com/capatinore/contextforge-mcp",
8
+ "tags": ["code-intelligence", "context-compression", "mcp", "tokens"],
9
+ "effect": "Read+Write",
10
+ "commands": [
11
+ { "name": "cf-index", "description": "Index codebase before implementing" },
12
+ { "name": "cf-analyze", "description": "Analyze codebase and compress spec before planning" },
13
+ { "name": "cf-implement", "description": "Graph-aware implement command" },
14
+ { "name": "cf-stats", "description": "Show token savings for this session" }
15
+ ]
16
+ }
@@ -0,0 +1,14 @@
1
+ # ContextForge MCP — Reference
2
+
3
+ Use `cbm_*` tools for ALL structural queries. Never grep.
4
+
5
+ | Instead of... | Use... |
6
+ |----------------------------|-----------------------------------------|
7
+ | Grep for function name | `cbm_search_graph(name_pattern="...")` |
8
+ | Read files for callers | `cbm_trace_path(direction="inbound")` |
9
+ | Explore architecture | `cbm_get_architecture()` |
10
+ | Text search across files | `cbm_search_code(query="...")` |
11
+ | Read spec/plan/tasks | `cf_read_spec/plan/tasks()` |
12
+ | Full implement context | `cf_implement_context(feature_id="...")`|
13
+
14
+ Run `cf_stats()` at end of session to see token savings.
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "contextforge-mcp"
7
+ version = "0.1.0"
8
+ description = "MCP orchestrator: codebase-memory-mcp + headroom + Spec Kit"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ keywords = ["mcp", "llm", "context", "compression", "code-intelligence", "spec-kit", "ai-agents"]
13
+ authors = [{ name = "Camilo Patiño", email = "capatinore@github.com" }]
14
+
15
+ dependencies = [
16
+ "mcp>=1.0.0",
17
+ "headroom-ai>=0.9.0",
18
+ "httpx>=0.27.0",
19
+ "anyio>=4.0.0",
20
+ "typer>=0.12.0",
21
+ "rich>=13.0.0",
22
+ "pydantic>=2.0.0",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ dev = [
27
+ "pytest>=8.0.0",
28
+ "pytest-asyncio>=0.23.0",
29
+ ]
30
+
31
+ [project.scripts]
32
+ contextforge-mcp = "contextforge_mcp.cli:app"
33
+
34
+ [project.urls]
35
+ Repository = "https://github.com/capatinore/contextforge-mcp"
36
+
37
+ [tool.hatch.build.targets.wheel]
38
+ packages = ["src/contextforge_mcp"]
39
+
40
+ [tool.pytest.ini_options]
41
+ asyncio_mode = "auto"
42
+ testpaths = ["tests"]
@@ -0,0 +1,3 @@
1
+ """contextforge-mcp — MCP orchestrator for codebase-memory-mcp + headroom + Spec Kit."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,132 @@
1
+ """Client for codebase-memory-mcp binary over stdio JSON-RPC 2.0."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import logging
8
+ import shutil
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ CBM_TOOLS: list[str] = [
15
+ "index_repository", "search_graph", "search_code", "trace_path",
16
+ "trace_call_path", "get_architecture", "get_node_details", "find_dead_code",
17
+ "find_similar_code", "get_impact", "cypher_query", "manage_adr",
18
+ "get_cross_service_links", "get_indexing_status",
19
+ ]
20
+
21
+ HIGH_TOKEN_TOOLS: set[str] = {
22
+ "search_graph", "search_code", "get_architecture",
23
+ "find_dead_code", "find_similar_code", "cypher_query",
24
+ }
25
+
26
+
27
+ class CBMClient:
28
+ def __init__(self, binary_path: str | None = None):
29
+ self.binary_path = binary_path or self._find_binary()
30
+ self._process: asyncio.subprocess.Process | None = None
31
+ self._request_id = 0
32
+ self._lock = asyncio.Lock()
33
+
34
+ async def start(self) -> None:
35
+ if not self.binary_path:
36
+ raise RuntimeError(
37
+ "codebase-memory-mcp binary not found. "
38
+ "Install with: npm install -g codebase-memory-mcp"
39
+ )
40
+ self._process = await asyncio.create_subprocess_exec(
41
+ self.binary_path,
42
+ stdin=asyncio.subprocess.PIPE,
43
+ stdout=asyncio.subprocess.PIPE,
44
+ stderr=asyncio.subprocess.PIPE,
45
+ )
46
+ await self._initialize()
47
+
48
+ async def stop(self) -> None:
49
+ if self._process and self._process.returncode is None:
50
+ self._process.terminate()
51
+ try:
52
+ await asyncio.wait_for(self._process.wait(), timeout=5.0)
53
+ except asyncio.TimeoutError:
54
+ self._process.kill()
55
+
56
+ async def __aenter__(self) -> "CBMClient":
57
+ await self.start()
58
+ return self
59
+
60
+ async def __aexit__(self, *_: Any) -> None:
61
+ await self.stop()
62
+
63
+ async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> Any:
64
+ if tool_name not in CBM_TOOLS:
65
+ raise ValueError(f"Unknown CBM tool: {tool_name!r}")
66
+ async with self._lock:
67
+ return await self._send({
68
+ "jsonrpc": "2.0",
69
+ "id": self._next_id(),
70
+ "method": "tools/call",
71
+ "params": {"name": tool_name, "arguments": arguments},
72
+ })
73
+
74
+ def is_high_token_tool(self, tool_name: str) -> bool:
75
+ return tool_name in HIGH_TOKEN_TOOLS
76
+
77
+ @property
78
+ def available(self) -> bool:
79
+ return self.binary_path is not None
80
+
81
+ async def _initialize(self) -> None:
82
+ await self._send({
83
+ "jsonrpc": "2.0", "id": self._next_id(), "method": "initialize",
84
+ "params": {
85
+ "protocolVersion": "2024-11-05", "capabilities": {},
86
+ "clientInfo": {"name": "contextforge-mcp", "version": "0.1.0"},
87
+ },
88
+ })
89
+ await self._write({"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}})
90
+
91
+ async def _send(self, payload: dict[str, Any]) -> Any:
92
+ assert self._process and self._process.stdin and self._process.stdout
93
+ await self._write(payload)
94
+ target_id = payload.get("id")
95
+ while True:
96
+ line = await asyncio.wait_for(self._process.stdout.readline(), timeout=30.0)
97
+ if not line:
98
+ raise ConnectionError("codebase-memory-mcp subprocess closed")
99
+ line = line.decode().strip()
100
+ if not line:
101
+ continue
102
+ try:
103
+ response = json.loads(line)
104
+ except json.JSONDecodeError:
105
+ continue
106
+ if response.get("id") == target_id:
107
+ if "error" in response:
108
+ raise RuntimeError(f"CBM error: {response['error']}")
109
+ return response.get("result")
110
+
111
+ async def _write(self, payload: dict[str, Any]) -> None:
112
+ assert self._process and self._process.stdin
113
+ self._process.stdin.write((json.dumps(payload) + "\n").encode())
114
+ await self._process.stdin.drain()
115
+
116
+ def _next_id(self) -> int:
117
+ self._request_id += 1
118
+ return self._request_id
119
+
120
+ @staticmethod
121
+ def _find_binary() -> str | None:
122
+ for name in ["codebase-memory-mcp", "codebase-memory-mcp.exe"]:
123
+ found = shutil.which(name)
124
+ if found:
125
+ return found
126
+ for p in [
127
+ Path.home() / ".local" / "bin" / "codebase-memory-mcp",
128
+ Path("/usr/local/bin/codebase-memory-mcp"),
129
+ ]:
130
+ if p.exists():
131
+ return str(p)
132
+ return None