one-ctx 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,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ *.egg
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Database
16
+ *.db
17
+
18
+ # IDE
19
+ .idea/
20
+ .vscode/
21
+ *.swp
22
+ *.swo
23
+
24
+ # OS
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # Test artifacts
29
+ test_mcp.py
30
+
31
+ # Debug files
32
+ mcp_debug.log
33
+ claude_debug.log
34
+ run_ctx_debug.bat
35
+ run_claude_debug.bat
one_ctx-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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.
one_ctx-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: one-ctx
3
+ Version: 0.1.0
4
+ Summary: Combined Context — One MCP server. Every AI tool. No re-explaining.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: click>=8.1.0
9
+ Requires-Dist: mcp[cli]>=1.0.0
10
+ Requires-Dist: sse-starlette>=2.0.0
11
+ Requires-Dist: uvicorn[standard]>=0.29.0
12
+ Provides-Extra: llm
13
+ Requires-Dist: anthropic>=0.40.0; extra == 'llm'
14
+ Description-Content-Type: text/markdown
15
+
16
+ # one-context — Combined Context
17
+
18
+ > One MCP server. Every AI tool. No re-explaining.
19
+
20
+ ![Architecture Diagram](assets/architecture.png)
21
+
22
+ Claude Code, Cline, Antigravity, Codex, Ollama — they all point to the same place.
23
+ You explain your project once. Every tool knows it forever.
24
+
25
+ **No API keys needed. No cloud. No accounts. 100% local.**
26
+
27
+ ## The Architecture
28
+
29
+ Every AI tool keeps its own internal memory. That doesn't change. But they all **read and write to one shared root**:
30
+
31
+ ```mermaid
32
+ graph TD
33
+ %% Define styles
34
+ classDef rootNode fill:#0d1117,stroke:#58a6ff,stroke-width:3px,color:#c9d1d9,font-size:16px,font-weight:bold;
35
+ classDef aiNode fill:#161b22,stroke:#3fb950,stroke-width:2px,color:#c9d1d9,font-size:14px;
36
+ classDef bucketNode fill:#21262d,stroke:#8b949e,stroke-dasharray: 5 5,color:#c9d1d9;
37
+
38
+ %% Nodes
39
+ A([one-context MCP]):::rootNode
40
+
41
+ C1[Claude Code]:::aiNode
42
+ C2[Cline]:::aiNode
43
+ C3[Antigravity]:::aiNode
44
+ C4[Codex]:::aiNode
45
+
46
+ B1[(WHAT\nProject Scope)]:::bucketNode
47
+ B2[(DONE\nHistory)]:::bucketNode
48
+ B3[(NOW\nCurrent Task)]:::bucketNode
49
+ B4[(MAP\nKey Files)]:::bucketNode
50
+
51
+ %% Connections
52
+ C1 <-->|reads/writes| A
53
+ C2 <-->|reads/writes| A
54
+ C3 <-->|reads/writes| A
55
+ C4 <-->|reads/writes| A
56
+
57
+ A --- B1
58
+ A --- B2
59
+ A --- B3
60
+ A --- B4
61
+ ```
62
+
63
+ ## Install
64
+
65
+ With `uv` installed, you don't even need to download this repository. Your AI tools will fetch it automatically from PyPI!
66
+
67
+ ## Connect Your AI Tools
68
+
69
+ ### Option A: Command/stdio (recommended)
70
+
71
+ Works with Claude Desktop, Cline, Codex, and any MCP client. Just add this to your MCP settings file:
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "one-context": {
77
+ "command": "uvx",
78
+ "args": ["one-context", "stdio"]
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ No server to start. The AI tool launches it automatically.
85
+
86
+ ### Option B: HTTP/SSE (for network setups)
87
+
88
+ ```bash
89
+ uvx one-context serve
90
+ ```
91
+
92
+ Then point any MCP client to `http://localhost:7337/sse`.
93
+
94
+ ## The Four Buckets
95
+
96
+ | Bucket | Contains | Updated when... |
97
+ |--------|----------|----------------|
98
+ | **WHAT** | Project description, stack, architecture, constraints | Project-level info changes |
99
+ | **DONE** | Decisions made, files changed, problems solved | Any tool finishes a task |
100
+ | **NOW** | Current task, current state, what's in progress | A new task starts |
101
+ | **MAP** | Important file paths and what they do | AI discovers key files |
102
+
103
+ ## Usage in any tool
104
+
105
+ Start a session:
106
+ ```
107
+ "Load context from one-context for my-project"
108
+ ```
109
+
110
+ Finish a session:
111
+ ```
112
+ "Update one-context with what we just did"
113
+ ```
114
+
115
+ Register important files:
116
+ ```
117
+ "Use ctx_map to register src/main.py as the entry point"
118
+ ```
119
+
120
+ Search across all your projects:
121
+ ```
122
+ "Search one-context for 'SQLite lock error'"
123
+ ```
124
+
125
+ ## MCP Tools (6 total)
126
+
127
+ | Tool | Description |
128
+ |------|-------------|
129
+ | `ctx_get(project)` | Get the full WHAT/DONE/NOW/MAP snapshot + git info |
130
+ | `ctx_update(project, session_summary, tool_name)` | Merge a session update into context |
131
+ | `ctx_map(project, files)` | Register important files manually |
132
+ | `ctx_search(query)` | Search across ALL projects' context and history |
133
+ | `ctx_reset(project)` | Wipe project context to empty |
134
+ | `ctx_list()` | List all tracked projects |
135
+
136
+ Projects are auto-created on first `ctx_update` — you don't need `ctx init`.
137
+
138
+ ## Advanced Features
139
+
140
+ ### MAP — Important Files
141
+ When an AI tool discovers that `src/main.py` is the entry point, it saves those paths to the MAP bucket. The next AI tool instantly knows which files matter without scanning the entire codebase.
142
+
143
+ ### Git Branch Awareness
144
+ Link a project to its git repo:
145
+ ```bash
146
+ ctx init my-project --path /path/to/repo
147
+ ```
148
+ Now `ctx_get` automatically includes the current branch name, last 5 commits, and uncommitted changes.
149
+
150
+ ### Cross-Project Search
151
+ ```bash
152
+ ctx search "SQLite"
153
+ ```
154
+ Searches across ALL projects' context (what/done/now/map) and update history. Find how you solved a problem before.
155
+
156
+ ## Summarization Modes
157
+
158
+ | Mode | Setup | API Key? |
159
+ |------|-------|----------|
160
+ | **Local** (default) | Nothing | No |
161
+ | **Ollama** | `CTX_OLLAMA_MODEL=llama3.2` | No |
162
+ | **Claude** | `ANTHROPIC_API_KEY=...` | Yes |
163
+ | **OpenAI / Groq / Together** | `OPENAI_API_KEY=...` | Yes |
164
+
165
+ Priority: Ollama > Claude > OpenAI > Local fallback. If any provider fails, it silently falls back. **Local always works.**
166
+
167
+ ## CLI Commands
168
+
169
+ | Command | Description |
170
+ |---------|-------------|
171
+ | `ctx stdio` | Run via stdio (for MCP clients) |
172
+ | `ctx serve` | Start HTTP/SSE server |
173
+ | `ctx init <project> [--path /repo]` | Initialize with optional git repo |
174
+ | `ctx status [project]` | Show context + git info |
175
+ | `ctx search <query>` | Search across all projects |
176
+ | `ctx reset <project>` | Reset project context |
177
+ | `ctx list` | List all projects |
178
+ | `ctx delete <project>` | Delete a project |
179
+
180
+ ## License
181
+
182
+ MIT
@@ -0,0 +1,167 @@
1
+ # one-context — Combined Context
2
+
3
+ > One MCP server. Every AI tool. No re-explaining.
4
+
5
+ ![Architecture Diagram](assets/architecture.png)
6
+
7
+ Claude Code, Cline, Antigravity, Codex, Ollama — they all point to the same place.
8
+ You explain your project once. Every tool knows it forever.
9
+
10
+ **No API keys needed. No cloud. No accounts. 100% local.**
11
+
12
+ ## The Architecture
13
+
14
+ Every AI tool keeps its own internal memory. That doesn't change. But they all **read and write to one shared root**:
15
+
16
+ ```mermaid
17
+ graph TD
18
+ %% Define styles
19
+ classDef rootNode fill:#0d1117,stroke:#58a6ff,stroke-width:3px,color:#c9d1d9,font-size:16px,font-weight:bold;
20
+ classDef aiNode fill:#161b22,stroke:#3fb950,stroke-width:2px,color:#c9d1d9,font-size:14px;
21
+ classDef bucketNode fill:#21262d,stroke:#8b949e,stroke-dasharray: 5 5,color:#c9d1d9;
22
+
23
+ %% Nodes
24
+ A([one-context MCP]):::rootNode
25
+
26
+ C1[Claude Code]:::aiNode
27
+ C2[Cline]:::aiNode
28
+ C3[Antigravity]:::aiNode
29
+ C4[Codex]:::aiNode
30
+
31
+ B1[(WHAT\nProject Scope)]:::bucketNode
32
+ B2[(DONE\nHistory)]:::bucketNode
33
+ B3[(NOW\nCurrent Task)]:::bucketNode
34
+ B4[(MAP\nKey Files)]:::bucketNode
35
+
36
+ %% Connections
37
+ C1 <-->|reads/writes| A
38
+ C2 <-->|reads/writes| A
39
+ C3 <-->|reads/writes| A
40
+ C4 <-->|reads/writes| A
41
+
42
+ A --- B1
43
+ A --- B2
44
+ A --- B3
45
+ A --- B4
46
+ ```
47
+
48
+ ## Install
49
+
50
+ With `uv` installed, you don't even need to download this repository. Your AI tools will fetch it automatically from PyPI!
51
+
52
+ ## Connect Your AI Tools
53
+
54
+ ### Option A: Command/stdio (recommended)
55
+
56
+ Works with Claude Desktop, Cline, Codex, and any MCP client. Just add this to your MCP settings file:
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "one-context": {
62
+ "command": "uvx",
63
+ "args": ["one-context", "stdio"]
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ No server to start. The AI tool launches it automatically.
70
+
71
+ ### Option B: HTTP/SSE (for network setups)
72
+
73
+ ```bash
74
+ uvx one-context serve
75
+ ```
76
+
77
+ Then point any MCP client to `http://localhost:7337/sse`.
78
+
79
+ ## The Four Buckets
80
+
81
+ | Bucket | Contains | Updated when... |
82
+ |--------|----------|----------------|
83
+ | **WHAT** | Project description, stack, architecture, constraints | Project-level info changes |
84
+ | **DONE** | Decisions made, files changed, problems solved | Any tool finishes a task |
85
+ | **NOW** | Current task, current state, what's in progress | A new task starts |
86
+ | **MAP** | Important file paths and what they do | AI discovers key files |
87
+
88
+ ## Usage in any tool
89
+
90
+ Start a session:
91
+ ```
92
+ "Load context from one-context for my-project"
93
+ ```
94
+
95
+ Finish a session:
96
+ ```
97
+ "Update one-context with what we just did"
98
+ ```
99
+
100
+ Register important files:
101
+ ```
102
+ "Use ctx_map to register src/main.py as the entry point"
103
+ ```
104
+
105
+ Search across all your projects:
106
+ ```
107
+ "Search one-context for 'SQLite lock error'"
108
+ ```
109
+
110
+ ## MCP Tools (6 total)
111
+
112
+ | Tool | Description |
113
+ |------|-------------|
114
+ | `ctx_get(project)` | Get the full WHAT/DONE/NOW/MAP snapshot + git info |
115
+ | `ctx_update(project, session_summary, tool_name)` | Merge a session update into context |
116
+ | `ctx_map(project, files)` | Register important files manually |
117
+ | `ctx_search(query)` | Search across ALL projects' context and history |
118
+ | `ctx_reset(project)` | Wipe project context to empty |
119
+ | `ctx_list()` | List all tracked projects |
120
+
121
+ Projects are auto-created on first `ctx_update` — you don't need `ctx init`.
122
+
123
+ ## Advanced Features
124
+
125
+ ### MAP — Important Files
126
+ When an AI tool discovers that `src/main.py` is the entry point, it saves those paths to the MAP bucket. The next AI tool instantly knows which files matter without scanning the entire codebase.
127
+
128
+ ### Git Branch Awareness
129
+ Link a project to its git repo:
130
+ ```bash
131
+ ctx init my-project --path /path/to/repo
132
+ ```
133
+ Now `ctx_get` automatically includes the current branch name, last 5 commits, and uncommitted changes.
134
+
135
+ ### Cross-Project Search
136
+ ```bash
137
+ ctx search "SQLite"
138
+ ```
139
+ Searches across ALL projects' context (what/done/now/map) and update history. Find how you solved a problem before.
140
+
141
+ ## Summarization Modes
142
+
143
+ | Mode | Setup | API Key? |
144
+ |------|-------|----------|
145
+ | **Local** (default) | Nothing | No |
146
+ | **Ollama** | `CTX_OLLAMA_MODEL=llama3.2` | No |
147
+ | **Claude** | `ANTHROPIC_API_KEY=...` | Yes |
148
+ | **OpenAI / Groq / Together** | `OPENAI_API_KEY=...` | Yes |
149
+
150
+ Priority: Ollama > Claude > OpenAI > Local fallback. If any provider fails, it silently falls back. **Local always works.**
151
+
152
+ ## CLI Commands
153
+
154
+ | Command | Description |
155
+ |---------|-------------|
156
+ | `ctx stdio` | Run via stdio (for MCP clients) |
157
+ | `ctx serve` | Start HTTP/SSE server |
158
+ | `ctx init <project> [--path /repo]` | Initialize with optional git repo |
159
+ | `ctx status [project]` | Show context + git info |
160
+ | `ctx search <query>` | Search across all projects |
161
+ | `ctx reset <project>` | Reset project context |
162
+ | `ctx list` | List all projects |
163
+ | `ctx delete <project>` | Delete a project |
164
+
165
+ ## License
166
+
167
+ MIT
@@ -0,0 +1,10 @@
1
+ import urllib.request
2
+ from urllib.error import HTTPError
3
+
4
+ names = ['one-ctx', 'octx-mcp', 'ctx-mcp', 'onectx', 'mcp-ctx']
5
+ for n in names:
6
+ try:
7
+ urllib.request.urlopen(f'https://pypi.org/pypi/{n}/json')
8
+ print(f'{n}: TAKEN')
9
+ except HTTPError:
10
+ print(f'{n}: AVAILABLE')
@@ -0,0 +1 @@
1
+ """ctx — Combined Context MCP Server."""
@@ -0,0 +1,159 @@
1
+ import sys
2
+ if sys.platform == 'win32':
3
+ import asyncio
4
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
5
+ import sys
6
+ import anyio
7
+ import click
8
+ from ctx.database import (
9
+ init_project, get_project, reset_project, list_projects,
10
+ search_projects, search_logs,
11
+ )
12
+ from ctx.server import mcp_server
13
+ from ctx.git import get_git_summary
14
+ import mcp.server.stdio
15
+
16
+ @click.group()
17
+ def cli():
18
+ """ctx -- Combined Context MCP Server."""
19
+ pass
20
+
21
+ @cli.command()
22
+ @click.option("--port", default=7337, help="Port to run the server on")
23
+ @click.option("--host", default="0.0.0.0", help="Host to bind to")
24
+ def serve(port, host):
25
+ """Start the HTTP/SSE server."""
26
+ import uvicorn
27
+ print(f"[ctx] server starting on http://{host}:{port}")
28
+ print(f" SSE endpoint: http://localhost:{port}/sse")
29
+ print(f" Messages endpoint: http://localhost:{port}/messages/")
30
+ print(f" Health check: http://localhost:{port}/health\n")
31
+ print("Add to your MCP config:")
32
+ print(f' {{"mcpServers": {{"ctx": {{"url": "http://localhost:{port}/sse"}}}}}}\n')
33
+
34
+ uvicorn.run("ctx.server:app", host=host, port=port, log_level="info")
35
+
36
+ @cli.command()
37
+ def stdio():
38
+ """Start the stdio server (for direct VS Code / Cline / Codex integration)."""
39
+ async def run():
40
+ async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
41
+ await mcp_server.run(
42
+ read_stream,
43
+ write_stream,
44
+ mcp_server.create_initialization_options()
45
+ )
46
+ anyio.run(run)
47
+
48
+ @cli.command()
49
+ @click.argument("project")
50
+ @click.option("--path", default="", help="Path to the project's git repo on disk")
51
+ def init(project, path):
52
+ """Initialize a new project context."""
53
+ result = init_project(project, repo_path=path)
54
+ if "error" in result:
55
+ print(f"[!] {result['error']}")
56
+ return
57
+ print(f"[OK] Project '{project}' initialized.")
58
+ if path:
59
+ print(f" Git repo linked: {path}")
60
+ print(" Start any AI tool and call ctx_get to load context.")
61
+
62
+ @cli.command()
63
+ @click.argument("project", required=False)
64
+ def status(project):
65
+ """View the context for a project, or list all projects."""
66
+ if not project:
67
+ projects = list_projects()
68
+ if not projects:
69
+ print("No projects found.")
70
+ return
71
+ print("=== Tracked Projects ===")
72
+ for p in projects:
73
+ print(f"- {p['project']} (last updated: {p['updated_at']})")
74
+ return
75
+
76
+ data = get_project(project)
77
+ if "error" in data:
78
+ print(f"Error: {data['error']}")
79
+ return
80
+
81
+ print(f"=== {project} ===")
82
+ print(f"\n[WHAT]\n{data.get('what', '(empty)') or '(empty)'}")
83
+ print(f"\n[DONE]\n{data.get('done', '(empty)') or '(empty)'}")
84
+ print(f"\n[NOW]\n{data.get('now', '(empty)') or '(empty)'}")
85
+ print(f"\n[MAP]\n{data.get('map', '(empty)') or '(no files mapped)'}")
86
+
87
+ # Show git info if repo_path is set
88
+ repo_path = data.get("repo_path", "")
89
+ if repo_path:
90
+ print(f"\n[GIT] repo: {repo_path}")
91
+ git_info = get_git_summary(repo_path)
92
+ if git_info:
93
+ print(f" Branch: {git_info['branch']}")
94
+ if git_info.get("recent_commits"):
95
+ print(f" Recent commits:")
96
+ for c in git_info["recent_commits"][:3]:
97
+ print(f" {c['hash']} {c['message']}")
98
+ changed = git_info.get("changed_files", {})
99
+ total_changes = len(changed.get("staged", [])) + len(changed.get("unstaged", [])) + len(changed.get("untracked", []))
100
+ if total_changes:
101
+ print(f" Changed files: {total_changes}")
102
+ else:
103
+ print(" (git not available or not a repo)")
104
+
105
+ @cli.command()
106
+ @click.argument("project")
107
+ def reset(project):
108
+ """Reset a project's context back to empty."""
109
+ reset_project(project)
110
+ print(f"[OK] Project '{project}' has been reset to empty.")
111
+
112
+ @cli.command(name="list")
113
+ def list_cmd():
114
+ """List all tracked projects."""
115
+ projects = list_projects()
116
+ if not projects:
117
+ print("No projects found.")
118
+ return
119
+ print("=== Tracked Projects ===")
120
+ for p in projects:
121
+ print(f"- {p['project']} (last updated: {p['updated_at']})")
122
+
123
+ @cli.command()
124
+ @click.argument("project")
125
+ def delete(project):
126
+ """Permanently delete a project."""
127
+ from ctx.database import delete_project
128
+ result = delete_project(project)
129
+ if "error" in result:
130
+ print(f"[!] {result['error']}")
131
+ else:
132
+ print(f"[OK] Project '{project}' deleted.")
133
+
134
+ @cli.command()
135
+ @click.argument("query")
136
+ def search(query):
137
+ """Search across all projects' context and history."""
138
+ project_matches = search_projects(query)
139
+ log_matches = search_logs(query)
140
+
141
+ if not project_matches and not log_matches:
142
+ print(f"No results found for '{query}'.")
143
+ return
144
+
145
+ if project_matches:
146
+ print(f"=== Projects matching '{query}' ===")
147
+ for m in project_matches:
148
+ buckets = ", ".join(m["matched_buckets"])
149
+ print(f"- {m['project']} (found in: {buckets})")
150
+
151
+ if log_matches:
152
+ print(f"\n=== History matching '{query}' ===")
153
+ for m in log_matches:
154
+ print(f"- [{m['project']}] [{m['tool_name']} @ {m['timestamp'][:16]}] {m['summary'][:100]}")
155
+
156
+ print(f"\nTotal: {len(project_matches)} projects, {len(log_matches)} history entries")
157
+
158
+ if __name__ == "__main__":
159
+ cli()