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.
- contextforge_mcp-0.1.0/.github/workflows/ci.yml +25 -0
- contextforge_mcp-0.1.0/.github/workflows/publish.yml +38 -0
- contextforge_mcp-0.1.0/.gitignore +9 -0
- contextforge_mcp-0.1.0/LICENSE +21 -0
- contextforge_mcp-0.1.0/PKG-INFO +119 -0
- contextforge_mcp-0.1.0/README.md +97 -0
- contextforge_mcp-0.1.0/extensions/speckit/commands/cf-analyze.md +14 -0
- contextforge_mcp-0.1.0/extensions/speckit/commands/cf-implement.md +41 -0
- contextforge_mcp-0.1.0/extensions/speckit/commands/cf-index.md +15 -0
- contextforge_mcp-0.1.0/extensions/speckit/commands/cf-stats.md +18 -0
- contextforge_mcp-0.1.0/extensions/speckit/extension.json +16 -0
- contextforge_mcp-0.1.0/extensions/speckit/templates/CONTEXTFORGE.md +14 -0
- contextforge_mcp-0.1.0/pyproject.toml +42 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/__init__.py +3 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/cbm_client.py +132 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/cli.py +127 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/compressor.py +138 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/server.py +203 -0
- contextforge_mcp-0.1.0/src/contextforge_mcp/speckit.py +125 -0
- contextforge_mcp-0.1.0/tests/__init__.py +0 -0
- contextforge_mcp-0.1.0/tests/test_cbm_client.py +52 -0
- contextforge_mcp-0.1.0/tests/test_compressor.py +100 -0
- contextforge_mcp-0.1.0/tests/test_speckit.py +133 -0
|
@@ -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,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,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
|