compresh-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.
Files changed (41) hide show
  1. compresh_mcp-0.1.0/LICENSE +34 -0
  2. compresh_mcp-0.1.0/NOTICES.md +38 -0
  3. compresh_mcp-0.1.0/PKG-INFO +153 -0
  4. compresh_mcp-0.1.0/README.md +105 -0
  5. compresh_mcp-0.1.0/pyproject.toml +99 -0
  6. compresh_mcp-0.1.0/setup.cfg +4 -0
  7. compresh_mcp-0.1.0/src/compresh_mcp/__init__.py +26 -0
  8. compresh_mcp-0.1.0/src/compresh_mcp/auth.py +176 -0
  9. compresh_mcp-0.1.0/src/compresh_mcp/onboarding.py +95 -0
  10. compresh_mcp-0.1.0/src/compresh_mcp/server.py +653 -0
  11. compresh_mcp-0.1.0/src/compresh_mcp/tul1/__init__.py +29 -0
  12. compresh_mcp-0.1.0/src/compresh_mcp/tul1/epistemic.py +182 -0
  13. compresh_mcp-0.1.0/src/compresh_mcp/tul1/q_matrix.py +500 -0
  14. compresh_mcp-0.1.0/src/compresh_mcp/tul1/semantic_store.py +436 -0
  15. compresh_mcp-0.1.0/src/compresh_mcp/tul1/summarizer.py +407 -0
  16. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/__init__.py +72 -0
  17. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/backfill.py +325 -0
  18. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/cli.py +80 -0
  19. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/cold_storage.py +241 -0
  20. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/compose.py +208 -0
  21. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/compression_log.py +376 -0
  22. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/config.py +73 -0
  23. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/counter.py +63 -0
  24. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/injection.py +525 -0
  25. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/main.py +59 -0
  26. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/modality.py +172 -0
  27. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/pipeline.py +403 -0
  28. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/provenance.py +255 -0
  29. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/retrieval.py +196 -0
  30. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/router.py +172 -0
  31. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/summarizer.py +244 -0
  32. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/system_prompts.py +96 -0
  33. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/tools.py +133 -0
  34. compresh_mcp-0.1.0/src/compresh_mcp/tulbase/turn_box.py +262 -0
  35. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/PKG-INFO +153 -0
  36. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/SOURCES.txt +39 -0
  37. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/dependency_links.txt +1 -0
  38. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/entry_points.txt +2 -0
  39. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/requires.txt +30 -0
  40. compresh_mcp-0.1.0/src/compresh_mcp.egg-info/top_level.txt +1 -0
  41. compresh_mcp-0.1.0/tests/test_smoke.py +90 -0
@@ -0,0 +1,34 @@
1
+ Business Source License 1.1
2
+
3
+ License text Copyright (c) 2026 Compresh Ltd.
4
+
5
+ Parameters
6
+
7
+ Licensor: Compresh Ltd
8
+ Licensed Work: compresh-mcp (this distribution)
9
+ Additional Use Grant: You may use the Licensed Work in non-production
10
+ environments. Production use requires a valid
11
+ Compresh subscription — see https://compre.sh/pricing
12
+ Change Date: 2030-05-16
13
+ Change License: MIT License
14
+
15
+ For information about alternative licensing arrangements, contact
16
+ hello@compre.sh.
17
+
18
+ ---
19
+
20
+ Notice
21
+
22
+ The Business Source License (this document, or the "License") is not an
23
+ Open Source license. However, the Licensed Work will eventually be made
24
+ available under an Open Source License, as stated in this License.
25
+
26
+ Full BSL 1.1 text: https://mariadb.com/bsl11/
27
+
28
+ ---
29
+
30
+ Patent notice
31
+
32
+ Q-protective ranking + Protection Zone are covered by TR-TPMK patent
33
+ application 2026/007305 (Compresh Ltd, May 2026). A valid Compresh
34
+ subscription includes implementation license for the covered claims.
@@ -0,0 +1,38 @@
1
+ # Third-Party Notices
2
+
3
+ This package, `compresh-mcp` (BUSL-1.1), bundles third-party code.
4
+
5
+ ---
6
+
7
+ ## tulbase (MIT)
8
+
9
+ The `compresh_mcp.tulbase` subpackage is a vendored copy of
10
+ [tulbase](https://github.com/compresh/tulbase), a depth-aware context
11
+ compression library for LLM proxies.
12
+
13
+ - **License**: MIT
14
+ - **Copyright**: © 2026 Compresh Ltd
15
+ - **Upstream**: https://github.com/compresh/tulbase
16
+ - **Vendored version**: 0.2.0
17
+ - **License text**: see `src/compresh_mcp/tulbase/LICENSE`
18
+
19
+ The vendored copy is the canonical reference implementation. The standalone
20
+ `tulbase` PyPI package (when published) will contain identical code. Vendoring
21
+ exists to keep `compresh-mcp` self-contained on PyPI without forcing a
22
+ separate dependency.
23
+
24
+ If you only need the MIT open-core compression layer (turn-box, protection zone,
25
+ compose, retrieval) without the Compresh paid-tier TUL 1.0 classifiers, prefer
26
+ installing the standalone package once it ships:
27
+
28
+ ```bash
29
+ pip install tulbase
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Acknowledgements
35
+
36
+ - [Model Context Protocol](https://modelcontextprotocol.io/) — Anthropic
37
+ - [sentence-transformers](https://www.sbert.net/) — UKPLab (MIT)
38
+ - [DuckDB](https://duckdb.org/) — DuckDB Foundation (MIT)
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: compresh-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for Compresh — production-grade context compression with Q-protective ranking, epistemic markers, and depth-aware adaptation
5
+ Author-email: Compresh Ltd <hello@compre.sh>
6
+ License: BUSL-1.1
7
+ Project-URL: Homepage, https://compre.sh
8
+ Project-URL: Documentation, https://compre.sh/docs
9
+ Project-URL: Issues, https://github.com/compresh/compresh-mcp/issues
10
+ Keywords: mcp,model-context-protocol,llm,agent,context-compression,compresh,q-protective,epistemic,tulving
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: Other/Proprietary License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ License-File: NOTICES.md
23
+ Requires-Dist: mcp>=1.0.0
24
+ Requires-Dist: duckdb>=0.10.0
25
+ Requires-Dist: httpx>=0.24.0
26
+ Requires-Dist: sentence-transformers>=2.2.0
27
+ Requires-Dist: scikit-learn>=1.3.0
28
+ Provides-Extra: tokenizer
29
+ Requires-Dist: tiktoken>=0.5.0; extra == "tokenizer"
30
+ Provides-Extra: summarizer
31
+ Requires-Dist: sumy>=0.11.0; extra == "summarizer"
32
+ Requires-Dist: nltk>=3.8.0; extra == "summarizer"
33
+ Provides-Extra: injection
34
+ Requires-Dist: torch>=2.0.0; extra == "injection"
35
+ Requires-Dist: transformers>=4.30.0; extra == "injection"
36
+ Provides-Extra: proxy
37
+ Requires-Dist: fastapi>=0.100.0; extra == "proxy"
38
+ Requires-Dist: uvicorn>=0.23.0; extra == "proxy"
39
+ Provides-Extra: verify
40
+ Requires-Dist: tiktoken>=0.7.0; extra == "verify"
41
+ Requires-Dist: transformers>=4.40.0; extra == "verify"
42
+ Provides-Extra: dev
43
+ Requires-Dist: pytest>=8.0; extra == "dev"
44
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
45
+ Requires-Dist: ruff>=0.4; extra == "dev"
46
+ Requires-Dist: mypy>=1.10; extra == "dev"
47
+ Dynamic: license-file
48
+
49
+ # compresh-mcp
50
+
51
+ **MCP server for Compresh** — production-grade context compression for LLM agent conversations.
52
+
53
+ > Compresh adds Q-protective ranking, epistemic marker classification, and
54
+ > depth-aware adaptation on top of the open-source [`tulbase`](https://github.com/compresh/tulbase)
55
+ > compression core. This is the **paid tier** distribution.
56
+
57
+ ## What's the difference vs `tulbase-mcp`?
58
+
59
+ | Feature | `tulbase-mcp` (free, open-source) | `compresh-mcp` (paid) |
60
+ |---|---|---|
61
+ | Base LexRank summarization | ✅ | ✅ |
62
+ | Modality elision (code, terminal, JSON, stack traces) | ✅ | ✅ |
63
+ | Cold storage + fetch_compressed | ✅ | ✅ |
64
+ | Protection Zone (Claim 1e) | ✅ | ✅ |
65
+ | **Q-protective sentence ranking** (Q1–Q4 categorization) | ❌ | ✅ |
66
+ | **Epistemic markers** (VR/HR/CR/UC) | ❌ | ✅ |
67
+ | **Semantic store** (cross-turn Q3 dedup) | ❌ | ✅ |
68
+ | Saving telemetry to Compresh dashboard | ❌ | ✅ |
69
+ | Multi-device sync (planned) | ❌ | ✅ |
70
+
71
+ In Compresh's bench (Compresh-bench v1, 600-turn multi-model), Q-protective
72
+ ranking adds **5–12 percentage points** of equivalence preservation vs
73
+ base LexRank at the same token savings — Pareto improvement.
74
+
75
+ ## Pricing
76
+
77
+ See [https://compre.sh/pricing](https://compre.sh/pricing). Three tiers:
78
+
79
+ - **Tier-A** (integrated MCP/OAuth metadata, e.g. Cowork, Claude Code, Cursor):
80
+ saving-share **%25** on actual model cost
81
+ - **Tier-B** (family-level provider declaration):
82
+ saving-share **%25** on the family's cheapest model price
83
+ - **Tier-C** (anonymous / local LLM / free models):
84
+ flat **$0.20 per 1M saved input tokens**
85
+
86
+ Every new user: **$30 free credit** (90-day expiry), **$10 minimum budget**
87
+ (charged $7.5 after standard %25 discount).
88
+
89
+ ## Installation
90
+
91
+ ```bash
92
+ pip install compresh-mcp
93
+ ```
94
+
95
+ On first run, you'll be prompted for your Compresh API key. If you don't
96
+ have an account, your browser opens to [compre.sh/signup](https://compre.sh/signup)
97
+ automatically.
98
+
99
+ ## MCP client configuration
100
+
101
+ ### Claude Code (`~/.claude/mcp.json`)
102
+
103
+ ```json
104
+ {
105
+ "mcpServers": {
106
+ "compresh": {
107
+ "command": "compresh-mcp",
108
+ "env": {
109
+ "COMPRESH_API_KEY": "sk-comp_...",
110
+ "COMPRESH_API_BASE": "https://api.compre.sh"
111
+ }
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### Cursor (`~/.cursor/mcp.json`)
118
+
119
+ Same structure as Claude Code.
120
+
121
+ ### Cowork
122
+
123
+ Cowork → Settings → Tools → MCP servers → Add:
124
+ - Command: `compresh-mcp`
125
+ - Environment: `COMPRESH_API_KEY=sk-comp_...`
126
+
127
+ ## Tools exposed
128
+
129
+ Same four tools as `tulbase-mcp`, with enhanced behavior:
130
+
131
+ - `compress` — Q-protective compression by default (`protection_mode="balanced"`)
132
+ - `fetch_compressed`, `list_compressed`, `stats` — same interface
133
+
134
+ Plus paid-tier extras:
135
+
136
+ - `usage` — current cycle budget, free credit balance, savings metrics
137
+
138
+ ## License
139
+
140
+ Business Source License 1.1 — see [LICENSE](./LICENSE). Production use
141
+ permitted with valid Compresh API key. License automatically converts
142
+ to MIT after 4 years (Year 2030).
143
+
144
+ ## Patents
145
+
146
+ Q-protective sentence ranking + Protection Zone are covered by
147
+ **TR-TPMK patent application 2026/007305** (Compresh Ltd, May 2026).
148
+ A valid Compresh subscription grants implementation license.
149
+
150
+ ## Status
151
+
152
+ This repo is **private** during dogfood phase (May 2026). Public release
153
+ scheduled for Q3 2026 alongside the Compresh dashboard MVP.
@@ -0,0 +1,105 @@
1
+ # compresh-mcp
2
+
3
+ **MCP server for Compresh** — production-grade context compression for LLM agent conversations.
4
+
5
+ > Compresh adds Q-protective ranking, epistemic marker classification, and
6
+ > depth-aware adaptation on top of the open-source [`tulbase`](https://github.com/compresh/tulbase)
7
+ > compression core. This is the **paid tier** distribution.
8
+
9
+ ## What's the difference vs `tulbase-mcp`?
10
+
11
+ | Feature | `tulbase-mcp` (free, open-source) | `compresh-mcp` (paid) |
12
+ |---|---|---|
13
+ | Base LexRank summarization | ✅ | ✅ |
14
+ | Modality elision (code, terminal, JSON, stack traces) | ✅ | ✅ |
15
+ | Cold storage + fetch_compressed | ✅ | ✅ |
16
+ | Protection Zone (Claim 1e) | ✅ | ✅ |
17
+ | **Q-protective sentence ranking** (Q1–Q4 categorization) | ❌ | ✅ |
18
+ | **Epistemic markers** (VR/HR/CR/UC) | ❌ | ✅ |
19
+ | **Semantic store** (cross-turn Q3 dedup) | ❌ | ✅ |
20
+ | Saving telemetry to Compresh dashboard | ❌ | ✅ |
21
+ | Multi-device sync (planned) | ❌ | ✅ |
22
+
23
+ In Compresh's bench (Compresh-bench v1, 600-turn multi-model), Q-protective
24
+ ranking adds **5–12 percentage points** of equivalence preservation vs
25
+ base LexRank at the same token savings — Pareto improvement.
26
+
27
+ ## Pricing
28
+
29
+ See [https://compre.sh/pricing](https://compre.sh/pricing). Three tiers:
30
+
31
+ - **Tier-A** (integrated MCP/OAuth metadata, e.g. Cowork, Claude Code, Cursor):
32
+ saving-share **%25** on actual model cost
33
+ - **Tier-B** (family-level provider declaration):
34
+ saving-share **%25** on the family's cheapest model price
35
+ - **Tier-C** (anonymous / local LLM / free models):
36
+ flat **$0.20 per 1M saved input tokens**
37
+
38
+ Every new user: **$30 free credit** (90-day expiry), **$10 minimum budget**
39
+ (charged $7.5 after standard %25 discount).
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install compresh-mcp
45
+ ```
46
+
47
+ On first run, you'll be prompted for your Compresh API key. If you don't
48
+ have an account, your browser opens to [compre.sh/signup](https://compre.sh/signup)
49
+ automatically.
50
+
51
+ ## MCP client configuration
52
+
53
+ ### Claude Code (`~/.claude/mcp.json`)
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "compresh": {
59
+ "command": "compresh-mcp",
60
+ "env": {
61
+ "COMPRESH_API_KEY": "sk-comp_...",
62
+ "COMPRESH_API_BASE": "https://api.compre.sh"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### Cursor (`~/.cursor/mcp.json`)
70
+
71
+ Same structure as Claude Code.
72
+
73
+ ### Cowork
74
+
75
+ Cowork → Settings → Tools → MCP servers → Add:
76
+ - Command: `compresh-mcp`
77
+ - Environment: `COMPRESH_API_KEY=sk-comp_...`
78
+
79
+ ## Tools exposed
80
+
81
+ Same four tools as `tulbase-mcp`, with enhanced behavior:
82
+
83
+ - `compress` — Q-protective compression by default (`protection_mode="balanced"`)
84
+ - `fetch_compressed`, `list_compressed`, `stats` — same interface
85
+
86
+ Plus paid-tier extras:
87
+
88
+ - `usage` — current cycle budget, free credit balance, savings metrics
89
+
90
+ ## License
91
+
92
+ Business Source License 1.1 — see [LICENSE](./LICENSE). Production use
93
+ permitted with valid Compresh API key. License automatically converts
94
+ to MIT after 4 years (Year 2030).
95
+
96
+ ## Patents
97
+
98
+ Q-protective sentence ranking + Protection Zone are covered by
99
+ **TR-TPMK patent application 2026/007305** (Compresh Ltd, May 2026).
100
+ A valid Compresh subscription grants implementation license.
101
+
102
+ ## Status
103
+
104
+ This repo is **private** during dogfood phase (May 2026). Public release
105
+ scheduled for Q3 2026 alongside the Compresh dashboard MVP.
@@ -0,0 +1,99 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "compresh-mcp"
7
+ version = "0.1.0"
8
+ description = "MCP server for Compresh — production-grade context compression with Q-protective ranking, epistemic markers, and depth-aware adaptation"
9
+ readme = "README.md"
10
+ license = { text = "BUSL-1.1" }
11
+ authors = [
12
+ { name = "Compresh Ltd", email = "hello@compre.sh" },
13
+ ]
14
+ keywords = [
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "llm",
18
+ "agent",
19
+ "context-compression",
20
+ "compresh",
21
+ "q-protective",
22
+ "epistemic",
23
+ "tulving",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 3 - Alpha",
27
+ "License :: Other/Proprietary License",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.10",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Topic :: Software Development :: Libraries :: Python Modules",
33
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
34
+ ]
35
+ requires-python = ">=3.10"
36
+ dependencies = [
37
+ "mcp >= 1.0.0",
38
+ "duckdb >= 0.10.0",
39
+ "httpx >= 0.24.0",
40
+ "sentence-transformers >= 2.2.0",
41
+ "scikit-learn >= 1.3.0",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ # tulbase tokenizer (cost counter)
46
+ tokenizer = [
47
+ "tiktoken >= 0.5.0",
48
+ ]
49
+ # tulbase summarizer (LexRank — recommended for production)
50
+ summarizer = [
51
+ "sumy >= 0.11.0",
52
+ "nltk >= 3.8.0",
53
+ ]
54
+ # tulbase injection detector (heavy ML deps)
55
+ injection = [
56
+ "torch >= 2.0.0",
57
+ "transformers >= 4.30.0",
58
+ ]
59
+ # tulbase FastAPI proxy mode (not needed for MCP stdio usage)
60
+ proxy = [
61
+ "fastapi >= 0.100.0",
62
+ "uvicorn >= 0.23.0",
63
+ ]
64
+ verify = [
65
+ "tiktoken >= 0.7.0",
66
+ "transformers >= 4.40.0",
67
+ ]
68
+ dev = [
69
+ "pytest >= 8.0",
70
+ "pytest-asyncio >= 0.23",
71
+ "ruff >= 0.4",
72
+ "mypy >= 1.10",
73
+ ]
74
+
75
+ [project.urls]
76
+ Homepage = "https://compre.sh"
77
+ Documentation = "https://compre.sh/docs"
78
+ Issues = "https://github.com/compresh/compresh-mcp/issues"
79
+
80
+ [project.scripts]
81
+ compresh-mcp = "compresh_mcp.server:main"
82
+
83
+ [tool.setuptools.packages.find]
84
+ where = ["src"]
85
+
86
+ [tool.setuptools.package-data]
87
+ compresh_mcp = ["py.typed"]
88
+
89
+ [tool.ruff]
90
+ line-length = 100
91
+ target-version = "py310"
92
+
93
+ [tool.ruff.lint]
94
+ select = ["E", "F", "I", "N", "UP", "B", "C4", "SIM", "RUF"]
95
+ ignore = ["E501"]
96
+
97
+ [tool.pytest.ini_options]
98
+ asyncio_mode = "auto"
99
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,26 @@
1
+ """compresh-mcp — MCP server for Compresh paid tier.
2
+
3
+ Bundles the open-source tulbase compression core (MIT, vendored as
4
+ ``compresh_mcp.tulbase``) and adds the proprietary TUL 1.0 layer:
5
+
6
+ - Q-protective sentence ranking (Q1-Q4 categorization)
7
+ - Epistemic marker classification (VR/HR/CR/UC)
8
+ - Semantic store (cross-turn Q3 dedup)
9
+ - Auth + saving telemetry to Compresh dashboard
10
+
11
+ The vendored tulbase code is the canonical reference (MIT, © Compresh Ltd 2026,
12
+ see ``tulbase/LICENSE``). For the standalone tulbase distribution, see
13
+ https://github.com/compresh/tulbase.
14
+
15
+ For pricing and account management, see https://compre.sh.
16
+ """
17
+
18
+ from . import tulbase
19
+
20
+ __version__ = "0.1.0"
21
+ __author__ = "Compresh Ltd"
22
+ __license__ = "BUSL-1.1"
23
+
24
+ from .server import main as run_server
25
+
26
+ __all__ = ["__version__", "run_server", "tulbase"]
@@ -0,0 +1,176 @@
1
+ """Compresh API key validation + usage telemetry.
2
+
3
+ The MCP server validates the user's COMPRESH_API_KEY against the
4
+ Compresh production API at startup, then reports per-session savings
5
+ back so the dashboard reflects local usage.
6
+
7
+ The Compresh API base URL is configurable via COMPRESH_API_BASE
8
+ (default: https://api.compre.sh) — useful for staging/dev environments.
9
+
10
+ Validation flow:
11
+
12
+ 1. Read COMPRESH_API_KEY from environment.
13
+ 2. If missing/empty -> raise NoApiKey (caller triggers onboarding flow).
14
+ 3. POST to /v1/auth/verify with Bearer token.
15
+ 4. If 200 -> cache validated key + user info for session lifetime.
16
+ 5. If 401/403 -> raise InvalidApiKey (caller may re-prompt).
17
+ 6. If network failure -> raise AuthNetworkError (caller may proceed
18
+ in offline mode with a warning).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ import os
25
+ from dataclasses import dataclass
26
+ from typing import Optional
27
+
28
+ import httpx
29
+
30
+ logger = logging.getLogger("compresh-mcp.auth")
31
+
32
+ DEFAULT_API_BASE = os.environ.get("COMPRESH_API_BASE", "https://api.compre.sh")
33
+ DEFAULT_TIMEOUT = float(os.environ.get("COMPRESH_AUTH_TIMEOUT", "10"))
34
+
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # Exceptions
38
+ # ---------------------------------------------------------------------------
39
+
40
+
41
+ class AuthError(Exception):
42
+ """Base class for auth failures."""
43
+
44
+
45
+ class NoApiKey(AuthError):
46
+ """COMPRESH_API_KEY environment variable missing or empty."""
47
+
48
+
49
+ class InvalidApiKey(AuthError):
50
+ """API key was rejected by the Compresh server (401/403)."""
51
+
52
+
53
+ class AuthNetworkError(AuthError):
54
+ """Network or unexpected error while contacting Compresh server."""
55
+
56
+
57
+ # ---------------------------------------------------------------------------
58
+ # Result dataclass
59
+ # ---------------------------------------------------------------------------
60
+
61
+
62
+ @dataclass(slots=True)
63
+ class AuthResult:
64
+ """Outcome of a successful key validation."""
65
+
66
+ ok: bool
67
+ api_key: str
68
+ email: Optional[str] = None
69
+ tier: Optional[str] = None # "free" | "pro"
70
+ free_credit_remaining: Optional[float] = None
71
+ budget_remaining: Optional[float] = None
72
+ error: Optional[str] = None
73
+
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Public API
77
+ # ---------------------------------------------------------------------------
78
+
79
+
80
+ def get_api_key() -> Optional[str]:
81
+ """Read COMPRESH_API_KEY from environment, return None if missing/empty."""
82
+ key = (os.environ.get("COMPRESH_API_KEY") or "").strip()
83
+ return key or None
84
+
85
+
86
+ def verify_api_key(
87
+ api_key: Optional[str] = None,
88
+ *,
89
+ api_base: str = DEFAULT_API_BASE,
90
+ timeout: float = DEFAULT_TIMEOUT,
91
+ ) -> AuthResult:
92
+ """Validate an API key against the Compresh server.
93
+
94
+ Raises:
95
+ NoApiKey: key is missing/empty.
96
+ InvalidApiKey: key was rejected (401/403).
97
+ AuthNetworkError: transport-level failure (caller decides whether
98
+ to proceed in offline mode).
99
+ """
100
+ key = api_key or get_api_key()
101
+ if not key:
102
+ raise NoApiKey("COMPRESH_API_KEY environment variable is not set")
103
+
104
+ url = f"{api_base.rstrip('/')}/v1/auth/verify"
105
+ headers = {"Authorization": f"Bearer {key}", "Accept": "application/json"}
106
+
107
+ try:
108
+ with httpx.Client(timeout=timeout) as client:
109
+ resp = client.get(url, headers=headers)
110
+ except httpx.HTTPError as e:
111
+ logger.warning("auth network error: %s", e)
112
+ raise AuthNetworkError(f"network error: {type(e).__name__}: {e}") from e
113
+
114
+ if resp.status_code in (401, 403):
115
+ logger.info("auth rejected: %d", resp.status_code)
116
+ raise InvalidApiKey(f"server rejected key (HTTP {resp.status_code})")
117
+
118
+ if resp.status_code != 200:
119
+ logger.warning("auth unexpected status: %d", resp.status_code)
120
+ raise AuthNetworkError(f"unexpected HTTP {resp.status_code}")
121
+
122
+ data = resp.json() if resp.content else {}
123
+ return AuthResult(
124
+ ok=True,
125
+ api_key=key,
126
+ email=data.get("email"),
127
+ tier=data.get("tier"),
128
+ free_credit_remaining=data.get("free_credit_remaining"),
129
+ budget_remaining=data.get("budget_remaining"),
130
+ )
131
+
132
+
133
+ def report_usage(
134
+ api_key: str,
135
+ *,
136
+ session_id: str,
137
+ saved_input_tokens: int,
138
+ saved_chars: int,
139
+ n_turns: int,
140
+ n_compressed_entries: int,
141
+ provider_hint: Optional[str] = None,
142
+ model_hint: Optional[str] = None,
143
+ api_base: str = DEFAULT_API_BASE,
144
+ timeout: float = DEFAULT_TIMEOUT,
145
+ ) -> bool:
146
+ """Send a per-session usage report to Compresh for billing/telemetry.
147
+
148
+ Returns True on 2xx, False otherwise. Failures are non-fatal — local
149
+ compression continues, telemetry catches up at the next successful
150
+ report.
151
+ """
152
+ url = f"{api_base.rstrip('/')}/v1/usage/report"
153
+ headers = {
154
+ "Authorization": f"Bearer {api_key}",
155
+ "Content-Type": "application/json",
156
+ }
157
+ payload = {
158
+ "session_id": session_id,
159
+ "saved_input_tokens": saved_input_tokens,
160
+ "saved_chars": saved_chars,
161
+ "n_turns": n_turns,
162
+ "n_compressed_entries": n_compressed_entries,
163
+ "provider_hint": provider_hint,
164
+ "model_hint": model_hint,
165
+ "source": "compresh-mcp",
166
+ }
167
+
168
+ try:
169
+ with httpx.Client(timeout=timeout) as client:
170
+ resp = client.post(url, headers=headers, json=payload)
171
+ if 200 <= resp.status_code < 300:
172
+ return True
173
+ logger.warning("usage report rejected: %d", resp.status_code)
174
+ except httpx.HTTPError as e:
175
+ logger.warning("usage report network error: %s", e)
176
+ return False