PyStreamMCP 3.3.1__py3-none-any.whl → 3.3.2__py3-none-any.whl
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.
- pystreammcp/__init__.py +1 -1
- pystreammcp/cli_daemon.py +14 -2
- pystreammcp-3.3.2.dist-info/METADATA +266 -0
- {pystreammcp-3.3.1.dist-info → pystreammcp-3.3.2.dist-info}/RECORD +8 -8
- pystreammcp-3.3.1.dist-info/METADATA +0 -404
- {pystreammcp-3.3.1.dist-info → pystreammcp-3.3.2.dist-info}/WHEEL +0 -0
- {pystreammcp-3.3.1.dist-info → pystreammcp-3.3.2.dist-info}/entry_points.txt +0 -0
- {pystreammcp-3.3.1.dist-info → pystreammcp-3.3.2.dist-info}/licenses/LICENSE +0 -0
- {pystreammcp-3.3.1.dist-info → pystreammcp-3.3.2.dist-info}/top_level.txt +0 -0
pystreammcp/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ Reduces token usage by 60-75% while maintaining quality.
|
|
|
7
7
|
Includes StatGuardian integration for data quality validation.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
__version__ = "3.3.
|
|
10
|
+
__version__ = "3.3.2"
|
|
11
11
|
|
|
12
12
|
from .agent import Agent, QueryResult
|
|
13
13
|
from .query import Query, QueryIntent, QueryConstraints
|
pystreammcp/cli_daemon.py
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
"""Dashboard daemon - runs in background, restarts on close"""
|
|
2
2
|
|
|
3
|
+
import re
|
|
4
|
+
import shlex
|
|
3
5
|
import subprocess
|
|
4
6
|
import time
|
|
5
7
|
import signal
|
|
6
8
|
import sys
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
11
|
+
_PACKAGE_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$")
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
class DashboardDaemon:
|
|
11
15
|
def __init__(self, package_name: str, dashboard_cmd: str):
|
|
16
|
+
if not isinstance(package_name, str) or not _PACKAGE_NAME_RE.match(
|
|
17
|
+
package_name
|
|
18
|
+
):
|
|
19
|
+
raise ValueError(f"Invalid package name: {package_name!r}")
|
|
12
20
|
self.package_name = package_name
|
|
13
|
-
|
|
21
|
+
# Split into argv and run without a shell so that a caller-supplied
|
|
22
|
+
# command cannot inject shell metacharacters.
|
|
23
|
+
self.dashboard_cmd = shlex.split(dashboard_cmd)
|
|
24
|
+
if not self.dashboard_cmd:
|
|
25
|
+
raise ValueError("dashboard_cmd must not be empty")
|
|
14
26
|
self.process = None
|
|
15
27
|
self.running = True
|
|
16
28
|
|
|
@@ -27,7 +39,7 @@ class DashboardDaemon:
|
|
|
27
39
|
|
|
28
40
|
self.process = subprocess.Popen(
|
|
29
41
|
self.dashboard_cmd,
|
|
30
|
-
shell=
|
|
42
|
+
shell=False,
|
|
31
43
|
stdout=subprocess.PIPE,
|
|
32
44
|
stderr=subprocess.PIPE,
|
|
33
45
|
)
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PyStreamMCP
|
|
3
|
+
Version: 3.3.2
|
|
4
|
+
Summary: Intelligent MCP orchestration hub - Intent understanding, capability matching, tool ranking with cohesive foundation
|
|
5
|
+
Author-email: Georgi Mammen Mullassery <mullassery@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Repository, https://github.com/Mullassery/PyStreamMCP
|
|
8
|
+
Project-URL: Issues, https://github.com/Mullassery/PyStreamMCP/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: pydantic>=2.0
|
|
21
|
+
Requires-Dist: python-frontmatter>=1.0.0
|
|
22
|
+
Requires-Dist: click>=8.0
|
|
23
|
+
Requires-Dist: rich>=13.0
|
|
24
|
+
Requires-Dist: httpx>=0.24.0
|
|
25
|
+
Requires-Dist: toml>=0.10; python_version < "3.11"
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
30
|
+
Provides-Extra: api
|
|
31
|
+
Requires-Dist: fastapi>=0.104.0; extra == "api"
|
|
32
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "api"
|
|
33
|
+
Requires-Dist: pydantic-settings>=2.0; extra == "api"
|
|
34
|
+
Requires-Dist: flask>=2.3.0; extra == "api"
|
|
35
|
+
Provides-Extra: mcp
|
|
36
|
+
Requires-Dist: mcp>=0.1.0; extra == "mcp"
|
|
37
|
+
Provides-Extra: langchain
|
|
38
|
+
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
39
|
+
Provides-Extra: llamaindex
|
|
40
|
+
Requires-Dist: llama-index>=0.9.0; extra == "llamaindex"
|
|
41
|
+
Provides-Extra: semantic-kernel
|
|
42
|
+
Requires-Dist: semantic-kernel>=0.4.0; extra == "semantic-kernel"
|
|
43
|
+
Provides-Extra: crewai
|
|
44
|
+
Requires-Dist: crewai>=0.1.0; extra == "crewai"
|
|
45
|
+
Provides-Extra: pydantic-ai
|
|
46
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == "pydantic-ai"
|
|
47
|
+
Provides-Extra: haystack
|
|
48
|
+
Requires-Dist: haystack-ai>=2.0.0; extra == "haystack"
|
|
49
|
+
Provides-Extra: temporal
|
|
50
|
+
Requires-Dist: temporalio>=1.0.0; extra == "temporal"
|
|
51
|
+
Provides-Extra: airflow
|
|
52
|
+
Requires-Dist: apache-airflow>=2.7.0; extra == "airflow"
|
|
53
|
+
Provides-Extra: all-integrations
|
|
54
|
+
Requires-Dist: langchain>=0.1.0; extra == "all-integrations"
|
|
55
|
+
Requires-Dist: llama-index>=0.9.0; extra == "all-integrations"
|
|
56
|
+
Requires-Dist: semantic-kernel>=0.4.0; extra == "all-integrations"
|
|
57
|
+
Requires-Dist: crewai>=0.1.0; extra == "all-integrations"
|
|
58
|
+
Requires-Dist: pydantic-ai>=0.1.0; extra == "all-integrations"
|
|
59
|
+
Requires-Dist: haystack-ai>=2.0.0; extra == "all-integrations"
|
|
60
|
+
Requires-Dist: temporalio>=1.0.0; extra == "all-integrations"
|
|
61
|
+
Requires-Dist: apache-airflow>=2.7.0; extra == "all-integrations"
|
|
62
|
+
Dynamic: license-file
|
|
63
|
+
|
|
64
|
+
# PyStreamMCP
|
|
65
|
+
|
|
66
|
+
[](https://pypi.org/project/pystreammcp/)
|
|
67
|
+
[](https://github.com/Mullassery/PyStreamMCP/actions/workflows/ci.yml)
|
|
68
|
+
[](https://www.python.org)
|
|
69
|
+
[](./LICENSE)
|
|
70
|
+
|
|
71
|
+
Context and token optimization for AI agents — query planning, source discovery, and MCP orchestration.
|
|
72
|
+
|
|
73
|
+
## What it is
|
|
74
|
+
|
|
75
|
+
PyStreamMCP is an AI-agent intelligence layer: query planning, context discovery, and
|
|
76
|
+
token-cost optimization, exposed both as a Python SDK and as an MCP (Model Context
|
|
77
|
+
Protocol) tool server. It also includes a small event-driven orchestration/federation
|
|
78
|
+
layer for coordinating multiple MCP endpoints. The published package is **pure Python** —
|
|
79
|
+
`pip install` works with no Rust toolchain or compiler.
|
|
80
|
+
|
|
81
|
+
## Features / Highlights
|
|
82
|
+
|
|
83
|
+
- **Agent query planning** — `pystreammcp.Agent` with selectable optimization strategies
|
|
84
|
+
(`token_efficient`, `balanced`, `quality_first`) and token accounting.
|
|
85
|
+
- **Source discovery** — `SourceRegistry` ranks registered data sources by real
|
|
86
|
+
word-overlap relevance (Jaccard) to a query; backs REST `/discover`, the
|
|
87
|
+
`pystreammcp_discover` MCP tool, and `LangchainAdapter.discover()`.
|
|
88
|
+
- **MCP tool server** — `PyStreamMCPHandler` wires the MCP tool-call surface directly to a
|
|
89
|
+
live `Orchestrator`/`EventRouter`; MCP tool args are validated with Pydantic and the
|
|
90
|
+
advertised schema is generated from the same models.
|
|
91
|
+
- **MCP orchestration & federation** — `Orchestrator` probes each configured endpoint's
|
|
92
|
+
real `tools/list` MCP method, with lexical tool-relevance ranking and capability
|
|
93
|
+
matching.
|
|
94
|
+
- **Webhook event server** — `pystreammcp.server.create_flask_app()` exposes an
|
|
95
|
+
HMAC-SHA256-signed event endpoint; unsigned or invalid events are rejected, and the
|
|
96
|
+
endpoint fails closed (`503`) if no secret is configured.
|
|
97
|
+
- **Framework adapters** — LangChain, LlamaIndex, CrewAI, Semantic Kernel, PydanticAI,
|
|
98
|
+
and Haystack under `pystreammcp.integrations`.
|
|
99
|
+
- **CLI** — `pystreammcp` with `query` / `server` / `version` / `dashboard`.
|
|
100
|
+
- **OKF integration** — an Open Knowledge Format catalog/discovery/query-planner feature
|
|
101
|
+
(see [`OKF_INTEGRATION.md`](OKF_INTEGRATION.md)).
|
|
102
|
+
|
|
103
|
+
## Who it's for / Use cases
|
|
104
|
+
|
|
105
|
+
- **Giving an AI agent a query-planning layer over multiple data sources**, exposed as
|
|
106
|
+
real MCP tools rather than hand-rolled per-agent glue code.
|
|
107
|
+
- **Coordinating multiple MCP endpoints** through the event-driven
|
|
108
|
+
orchestration/federation layer instead of wiring each one separately.
|
|
109
|
+
- **Tracking token-cost optimization** across agent queries.
|
|
110
|
+
- **Adding MCP support to an existing agent framework** through the shipped adapters.
|
|
111
|
+
|
|
112
|
+
## What it is not
|
|
113
|
+
|
|
114
|
+
- **The Rust backend is not shipped.** `core/` and `python/src/lib.rs` are an in-progress
|
|
115
|
+
Rust workspace intended as a future performance backend; the wheel built from
|
|
116
|
+
`pyproject.toml` is pure Python. The workspace compiles and its tests pass, but it is
|
|
117
|
+
tracked separately and not part of the published package.
|
|
118
|
+
- **Some orchestration capabilities are not fully implemented.** Cross-project federated
|
|
119
|
+
query *execution* and cross-database joins currently report
|
|
120
|
+
`"status": "not_implemented"` with an explanation, rather than fabricated result rows.
|
|
121
|
+
- **Source discovery is a word-overlap heuristic, not semantic search.**
|
|
122
|
+
`SourceRegistry` uses Jaccard token overlap; wrap it with your own similarity scoring if
|
|
123
|
+
you need embeddings.
|
|
124
|
+
- **Optional concurrency/framework packages have Python constraints.** The core SDK
|
|
125
|
+
(`Agent`, `SourceRegistry`, `Orchestrator`) supports Python 3.9+, but the `mcp` and
|
|
126
|
+
`semantic-kernel` extras require Python 3.10+ (their upstream packages don't publish
|
|
127
|
+
3.9-compatible releases). CI tests 3.10, 3.11, and 3.12 only.
|
|
128
|
+
- **Known dependency CVEs.** `pip-audit` (run 2026-09-20) found 7 known CVEs in
|
|
129
|
+
transitive dependencies (`werkzeug` via `flask`, `nltk` via `llama-index`). See
|
|
130
|
+
[`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) §4.
|
|
131
|
+
- **The HTTP servers have no auth layer of their own.** They bind to `127.0.0.1`
|
|
132
|
+
(localhost-only) by default; pass `host="0.0.0.0"` explicitly only inside a network
|
|
133
|
+
boundary you control. The event endpoint requires HMAC-SHA256 signatures. See
|
|
134
|
+
[SECURITY.md](SECURITY.md).
|
|
135
|
+
|
|
136
|
+
## Project status
|
|
137
|
+
|
|
138
|
+
**Beta.** Current version **3.3.1** (`Development Status :: 4 - Beta`). The pure-Python
|
|
139
|
+
package is the shipped artifact and is under active hardening; the Rust workspace compiles
|
|
140
|
+
and passes its tests but is not shipped. The most recent pass fixed the Rust build,
|
|
141
|
+
Python `ruff` findings, and a stale integration test — see
|
|
142
|
+
[`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) for the unhedged status.
|
|
143
|
+
|
|
144
|
+
## Installation
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install PyStreamMCP
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Optional extras — install only what you need:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install "PyStreamMCP[api]" # FastAPI + Flask HTTP servers
|
|
154
|
+
pip install "PyStreamMCP[mcp]" # MCP protocol client library
|
|
155
|
+
pip install "PyStreamMCP[langchain]" # LangChain adapter
|
|
156
|
+
pip install "PyStreamMCP[llamaindex]" # LlamaIndex adapter
|
|
157
|
+
pip install "PyStreamMCP[semantic-kernel]" # Semantic Kernel adapter
|
|
158
|
+
pip install "PyStreamMCP[all-integrations]" # every framework adapter
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Requires Python 3.9+ for the core SDK; the `mcp` and `semantic-kernel` extras require
|
|
162
|
+
Python 3.10+.
|
|
163
|
+
|
|
164
|
+
## Quick start
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from pystreammcp import Agent
|
|
168
|
+
|
|
169
|
+
agent = Agent(
|
|
170
|
+
agent_id="recommendation_engine",
|
|
171
|
+
name="Product Recommendation Engine",
|
|
172
|
+
optimization_strategy="token_efficient", # or "balanced" / "quality_first"
|
|
173
|
+
max_tokens=1000,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
result = agent.query("What are the top 10 customers by lifetime value?")
|
|
177
|
+
|
|
178
|
+
print(f"Baseline tokens: {result.baseline_tokens}")
|
|
179
|
+
print(f"Optimized tokens: {result.optimized_tokens}")
|
|
180
|
+
print(f"Reduction: {result.cost_reduction_percent:.1f}%")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Token counts are estimated from the actual query text (a ~4-characters-per-token
|
|
184
|
+
heuristic) and the reduction is computed from the selected strategy — not a fixed number.
|
|
185
|
+
See [`examples/basic_usage.py`](examples/basic_usage.py) for a full walkthrough.
|
|
186
|
+
|
|
187
|
+
## Usage
|
|
188
|
+
|
|
189
|
+
**Data source discovery:**
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from pystreammcp import SourceRegistry
|
|
193
|
+
|
|
194
|
+
registry = SourceRegistry()
|
|
195
|
+
registry.register(
|
|
196
|
+
"orders_db",
|
|
197
|
+
description="customer order history and revenue by quarter",
|
|
198
|
+
type="database",
|
|
199
|
+
tags=["orders", "revenue"],
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
results = registry.discover("customer revenue by quarter")
|
|
203
|
+
# [{"name": "orders_db", "type": "database", "relevance": 0.4444, "matched_terms": [...]}]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**MCP orchestration & federation** (`pystreammcp.toml`):
|
|
207
|
+
|
|
208
|
+
```toml
|
|
209
|
+
[federation]
|
|
210
|
+
endpoints = [
|
|
211
|
+
"http://localhost:8765/mcp",
|
|
212
|
+
"http://localhost:8766/mcp",
|
|
213
|
+
]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from pystreammcp import Orchestrator
|
|
218
|
+
|
|
219
|
+
orch = Orchestrator() # reads ./pystreammcp.toml
|
|
220
|
+
result = orch.discover_mcp_projects()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Webhook event server (HMAC-SHA256):**
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
export PYSTREAMMCP_WEBHOOK_SECRET="a long random shared secret"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Senders compute `HMAC-SHA256(secret, raw_request_body)` and send it as
|
|
230
|
+
`X-PyStreamMCP-Signature: sha256=<hex digest>`. Requests with a missing or invalid
|
|
231
|
+
signature are rejected with `401`; with no secret configured, the endpoint rejects every
|
|
232
|
+
request with `503`.
|
|
233
|
+
|
|
234
|
+
**Testing:**
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
pip install -e ".[dev,api,mcp,langchain,llamaindex,semantic-kernel]"
|
|
238
|
+
pytest tests/ -v
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Documentation
|
|
242
|
+
|
|
243
|
+
- [`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) — full, unhedged status: what's tested, what's fabricated/broken, technical debt, what's explicitly not built
|
|
244
|
+
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — how the shipped package is structured, with a diagram
|
|
245
|
+
- [`OKF_INTEGRATION.md`](OKF_INTEGRATION.md) — the OKF catalog/discovery/query-planner feature
|
|
246
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — release history
|
|
247
|
+
- [`examples/`](examples/) — runnable examples, including framework integrations and the MCP orchestrator
|
|
248
|
+
|
|
249
|
+
## Contributing
|
|
250
|
+
|
|
251
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) and
|
|
252
|
+
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Report security issues per
|
|
253
|
+
[SECURITY.md](SECURITY.md).
|
|
254
|
+
|
|
255
|
+
## Related projects
|
|
256
|
+
|
|
257
|
+
- [PyStreamXL](https://github.com/Mullassery/PyStreamXL) — stream large Excel workbooks with constant memory
|
|
258
|
+
- [PyStreamPDF](https://github.com/Mullassery/PyStreamPDF) — token-efficient PDF extraction for RAG
|
|
259
|
+
- [PyStreamMCP](https://github.com/Mullassery/PyStreamMCP) — context and token optimization for AI agents
|
|
260
|
+
- [PyStreamAI](https://github.com/Mullassery/PyStreamAI) — ML deployment toolkit (canary/A-B, cost tracking, ONNX)
|
|
261
|
+
- [PyTokenCalc](https://github.com/Mullassery/PyTokenCalc) — LLM token counting and cost estimation
|
|
262
|
+
- [Browse all projects](https://github.com/Mullassery?tab=repositories)
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
This project is licensed under the [Apache License 2.0](LICENSE).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
pystreammcp/__init__.py,sha256=
|
|
1
|
+
pystreammcp/__init__.py,sha256=QWzbxF2R1ASWxvVz8z4rW_8VJNRUrXH5b3hR5D_ft6I,2881
|
|
2
2
|
pystreammcp/_mcp_connector.py,sha256=CTPdQHT64aVxmolwG0l0irCj2uQshwJvhbdbGgyBEu0,31208
|
|
3
3
|
pystreammcp/_mcp_tools.py,sha256=7s3DtzIbJxHVFMmISdd9EcFbmtKrSMIDXH27j0onhMY,32540
|
|
4
4
|
pystreammcp/adapters.py,sha256=uB0zGKJU6jcTyRsUDIiiOgGg6K-8dbJw1YLt0ZiAiao,6801
|
|
5
5
|
pystreammcp/agent.py,sha256=LJUPxnvcrT01rG8l3pqVXQ58OZyeqBn41GYM-hyHIWo,6385
|
|
6
6
|
pystreammcp/api.py,sha256=4_9i86lQFKxzHdPB1TXzYVBJS6jna9Q2_s7Ea3-v6vg,12860
|
|
7
7
|
pystreammcp/cli.py,sha256=nkVGnaqjdxeALoBwv0klaSHfjdrRg_fwYY9h_1afiiU,4145
|
|
8
|
-
pystreammcp/cli_daemon.py,sha256=
|
|
8
|
+
pystreammcp/cli_daemon.py,sha256=Ck9ICofTWwV-jE3jxBfud9BSAElWMBiJA4asoUCGAh0,2513
|
|
9
9
|
pystreammcp/cli_dashboard.py,sha256=J5pnUUpkvQGjltUOFN6SPbNF1yyXsjHQR0VCI14ty6M,10562
|
|
10
10
|
pystreammcp/context.py,sha256=WIgwbb0MAZTnPfQiZW0PLunEtxJatsHmwTnCRsvSqLU,2213
|
|
11
11
|
pystreammcp/decomposition.py,sha256=peRR1MZbH29DCWMSvtL4Btzp1QhpXsFuVo5LOXPnoIs,6532
|
|
@@ -48,9 +48,9 @@ pystreammcp/qa/__init__.py,sha256=NvUUjyWNIyMfckW4J34Cn1xKYX5CnDlM22mXZF3pfnY,17
|
|
|
48
48
|
pystreammcp/qa/validator.py,sha256=qTpdkFE7Z7l16fE1emwqfbr8W2_zh1m4Zvzz3hjnGt8,10694
|
|
49
49
|
pystreammcp/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
pystreammcp/scripts/post_install.py,sha256=lnxiXH8Owq_F4M4KFHNL-GJ5JMYVevUcVo3M5JXOpRo,2719
|
|
51
|
-
pystreammcp-3.3.
|
|
52
|
-
pystreammcp-3.3.
|
|
53
|
-
pystreammcp-3.3.
|
|
54
|
-
pystreammcp-3.3.
|
|
55
|
-
pystreammcp-3.3.
|
|
56
|
-
pystreammcp-3.3.
|
|
51
|
+
pystreammcp-3.3.2.dist-info/licenses/LICENSE,sha256=9Z5Dr-U7th_6-121oVLdN8Bdtlotgo_7E71IzjHQQL4,11348
|
|
52
|
+
pystreammcp-3.3.2.dist-info/METADATA,sha256=vPNE3pbLPO5VmqO3MGSAlQzsKcr6UVESn5tysLaauPU,11665
|
|
53
|
+
pystreammcp-3.3.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
54
|
+
pystreammcp-3.3.2.dist-info/entry_points.txt,sha256=EEyR2OxJzCyf353Yipp7-g844uj4y81nTrN06k5786k,52
|
|
55
|
+
pystreammcp-3.3.2.dist-info/top_level.txt,sha256=SHNryMw9AAzKhuqpS2tCkxIfTpx4z623tlW8BazwTNM,12
|
|
56
|
+
pystreammcp-3.3.2.dist-info/RECORD,,
|
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: PyStreamMCP
|
|
3
|
-
Version: 3.3.1
|
|
4
|
-
Summary: Intelligent MCP orchestration hub - Intent understanding, capability matching, tool ranking with cohesive foundation
|
|
5
|
-
Author-email: Georgi Mammen Mullassery <mullassery@gmail.com>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Repository, https://github.com/Mullassery/PyStreamMCP
|
|
8
|
-
Project-URL: Issues, https://github.com/Mullassery/PyStreamMCP/issues
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
-
Requires-Python: >=3.9
|
|
18
|
-
Description-Content-Type: text/markdown
|
|
19
|
-
License-File: LICENSE
|
|
20
|
-
Requires-Dist: pydantic>=2.0
|
|
21
|
-
Requires-Dist: python-frontmatter>=1.0.0
|
|
22
|
-
Requires-Dist: click>=8.0
|
|
23
|
-
Requires-Dist: rich>=13.0
|
|
24
|
-
Requires-Dist: httpx>=0.24.0
|
|
25
|
-
Requires-Dist: toml>=0.10; python_version < "3.11"
|
|
26
|
-
Provides-Extra: dev
|
|
27
|
-
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
28
|
-
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
29
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
30
|
-
Provides-Extra: api
|
|
31
|
-
Requires-Dist: fastapi>=0.104.0; extra == "api"
|
|
32
|
-
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "api"
|
|
33
|
-
Requires-Dist: pydantic-settings>=2.0; extra == "api"
|
|
34
|
-
Requires-Dist: flask>=2.3.0; extra == "api"
|
|
35
|
-
Provides-Extra: mcp
|
|
36
|
-
Requires-Dist: mcp>=0.1.0; extra == "mcp"
|
|
37
|
-
Provides-Extra: langchain
|
|
38
|
-
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
39
|
-
Provides-Extra: llamaindex
|
|
40
|
-
Requires-Dist: llama-index>=0.9.0; extra == "llamaindex"
|
|
41
|
-
Provides-Extra: semantic-kernel
|
|
42
|
-
Requires-Dist: semantic-kernel>=0.4.0; extra == "semantic-kernel"
|
|
43
|
-
Provides-Extra: crewai
|
|
44
|
-
Requires-Dist: crewai>=0.1.0; extra == "crewai"
|
|
45
|
-
Provides-Extra: pydantic-ai
|
|
46
|
-
Requires-Dist: pydantic-ai>=0.1.0; extra == "pydantic-ai"
|
|
47
|
-
Provides-Extra: haystack
|
|
48
|
-
Requires-Dist: haystack-ai>=2.0.0; extra == "haystack"
|
|
49
|
-
Provides-Extra: temporal
|
|
50
|
-
Requires-Dist: temporalio>=1.0.0; extra == "temporal"
|
|
51
|
-
Provides-Extra: airflow
|
|
52
|
-
Requires-Dist: apache-airflow>=2.7.0; extra == "airflow"
|
|
53
|
-
Provides-Extra: all-integrations
|
|
54
|
-
Requires-Dist: langchain>=0.1.0; extra == "all-integrations"
|
|
55
|
-
Requires-Dist: llama-index>=0.9.0; extra == "all-integrations"
|
|
56
|
-
Requires-Dist: semantic-kernel>=0.4.0; extra == "all-integrations"
|
|
57
|
-
Requires-Dist: crewai>=0.1.0; extra == "all-integrations"
|
|
58
|
-
Requires-Dist: pydantic-ai>=0.1.0; extra == "all-integrations"
|
|
59
|
-
Requires-Dist: haystack-ai>=2.0.0; extra == "all-integrations"
|
|
60
|
-
Requires-Dist: temporalio>=1.0.0; extra == "all-integrations"
|
|
61
|
-
Requires-Dist: apache-airflow>=2.7.0; extra == "all-integrations"
|
|
62
|
-
Dynamic: license-file
|
|
63
|
-
|
|
64
|
-
# PyStreamMCP
|
|
65
|
-
|
|
66
|
-
[](https://github.com/Mullassery/PyStreamMCP/actions/workflows/ci.yml)
|
|
67
|
-
|
|
68
|
-
An AI-agent intelligence layer: query planning, context discovery, and
|
|
69
|
-
token-cost optimization, exposed both as a Python SDK and as an MCP
|
|
70
|
-
(Model Context Protocol) tool server, plus a small event-driven
|
|
71
|
-
orchestration/federation layer for coordinating multiple MCP endpoints.
|
|
72
|
-
|
|
73
|
-
Pure Python — `pip install` just works, no Rust toolchain or compiler
|
|
74
|
-
required.
|
|
75
|
-
|
|
76
|
-
## Use cases
|
|
77
|
-
|
|
78
|
-
- **Giving an AI agent a query-planning layer over multiple data
|
|
79
|
-
sources**, exposed as real MCP tools rather than hand-rolled per-agent
|
|
80
|
-
glue code.
|
|
81
|
-
- **Coordinating multiple MCP endpoints** through the event-driven
|
|
82
|
-
orchestration/federation layer instead of wiring each one separately.
|
|
83
|
-
- **Tracking token-cost optimization** across agent queries.
|
|
84
|
-
- **Not yet a good fit for:** anything depending on the Rust workspace —
|
|
85
|
-
see [Rust workspace (not shipped)](#rust-workspace-not-shipped) below;
|
|
86
|
-
the published package is pure Python only.
|
|
87
|
-
|
|
88
|
-
## Install
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
pip install PyStreamMCP
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Optional extras, install what you actually need:
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
pip install "PyStreamMCP[api]" # FastAPI + Flask HTTP servers
|
|
98
|
-
pip install "PyStreamMCP[mcp]" # MCP protocol client library
|
|
99
|
-
pip install "PyStreamMCP[langchain]" # LangChain adapter
|
|
100
|
-
pip install "PyStreamMCP[llamaindex]" # LlamaIndex adapter
|
|
101
|
-
pip install "PyStreamMCP[semantic-kernel]" # Semantic Kernel adapter
|
|
102
|
-
pip install "PyStreamMCP[all-integrations]" # every framework adapter
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Requires Python 3.9+ for the core SDK (`Agent`, `SourceRegistry`,
|
|
106
|
-
`Orchestrator`). The `mcp` and `semantic-kernel` extras require Python
|
|
107
|
-
3.10+ — their upstream packages don't publish Python 3.9-compatible
|
|
108
|
-
releases, so `pip install` for those extras will fail on 3.9. CI tests
|
|
109
|
-
3.10, 3.11, and 3.12 only; 3.9 is not covered by CI.
|
|
110
|
-
|
|
111
|
-
## Quick start
|
|
112
|
-
|
|
113
|
-
```python
|
|
114
|
-
from pystreammcp import Agent
|
|
115
|
-
|
|
116
|
-
agent = Agent(
|
|
117
|
-
agent_id="recommendation_engine",
|
|
118
|
-
name="Product Recommendation Engine",
|
|
119
|
-
optimization_strategy="token_efficient", # or "balanced" / "quality_first"
|
|
120
|
-
max_tokens=1000,
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
result = agent.query("What are the top 10 customers by lifetime value?")
|
|
124
|
-
|
|
125
|
-
print(f"Baseline tokens: {result.baseline_tokens}")
|
|
126
|
-
print(f"Optimized tokens: {result.optimized_tokens}")
|
|
127
|
-
print(f"Reduction: {result.cost_reduction_percent:.1f}%")
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Token counts are estimated from the actual query text (a standard
|
|
131
|
-
~4-characters-per-token heuristic) and the reduction percentage is
|
|
132
|
-
computed from the selected `optimization_strategy` — not a fixed number
|
|
133
|
-
returned regardless of input. See [`examples/basic_usage.py`](examples/basic_usage.py)
|
|
134
|
-
for a full runnable walkthrough, including framework adapters for
|
|
135
|
-
LangChain, LlamaIndex, CrewAI, Semantic Kernel, PydanticAI, and Haystack
|
|
136
|
-
under [`pystreammcp.integrations`](python/pystreammcp/integrations/).
|
|
137
|
-
|
|
138
|
-
## Data source discovery
|
|
139
|
-
|
|
140
|
-
`SourceRegistry` (`pystreammcp.SourceRegistry`) ranks *registered* data
|
|
141
|
-
sources by real word-overlap relevance to a query — not a fabricated or
|
|
142
|
-
hardcoded result:
|
|
143
|
-
|
|
144
|
-
```python
|
|
145
|
-
from pystreammcp import SourceRegistry
|
|
146
|
-
|
|
147
|
-
registry = SourceRegistry()
|
|
148
|
-
registry.register(
|
|
149
|
-
"orders_db",
|
|
150
|
-
description="customer order history and revenue by quarter",
|
|
151
|
-
type="database",
|
|
152
|
-
tags=["orders", "revenue"],
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
results = registry.discover("customer revenue by quarter")
|
|
156
|
-
# [{"name": "orders_db", "type": "database", "relevance": 0.4444, "matched_terms": [...]}]
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
The same registry backs `POST /discover` (REST), the `pystreammcp_discover`
|
|
160
|
-
MCP tool, and `LangchainAdapter.discover()` — register sources once via
|
|
161
|
-
`POST /sources` / `pystreammcp_register_source` / `registry.register()`,
|
|
162
|
-
then discover against them from any of the three surfaces. This is a
|
|
163
|
-
simple Jaccard token-overlap heuristic, not semantic/embedding search.
|
|
164
|
-
|
|
165
|
-
## MCP orchestration & federation
|
|
166
|
-
|
|
167
|
-
`Orchestrator` (`pystreammcp.Orchestrator`) discovers and routes across
|
|
168
|
-
other MCP-enabled projects you configure in `pystreammcp.toml`:
|
|
169
|
-
|
|
170
|
-
```toml
|
|
171
|
-
[federation]
|
|
172
|
-
endpoints = [
|
|
173
|
-
"http://localhost:8765/mcp",
|
|
174
|
-
"http://localhost:8766/mcp",
|
|
175
|
-
]
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
from pystreammcp import Orchestrator
|
|
180
|
-
|
|
181
|
-
orch = Orchestrator() # reads ./pystreammcp.toml
|
|
182
|
-
result = orch.discover_mcp_projects()
|
|
183
|
-
# {"projects": [{"project_name": ..., "endpoint": ..., "status": "healthy"|"unavailable", ...}], "total": N}
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
This actually probes each configured endpoint's real `tools/list` MCP
|
|
187
|
-
method — with nothing configured, or nothing reachable, it honestly
|
|
188
|
-
reports zero/unavailable projects rather than a fixed fixture list.
|
|
189
|
-
`Orchestrator` also does lexical tool-relevance ranking
|
|
190
|
-
(`rank_tools_by_relevance`) and capability matching
|
|
191
|
-
(`detect_compatible_projects`) against whatever it actually discovers.
|
|
192
|
-
|
|
193
|
-
To expose these (plus tool-routing and webhook-event handling) as MCP
|
|
194
|
-
tools, `PyStreamMCPHandler` (`pystreammcp._mcp_tools`) wires the MCP
|
|
195
|
-
tool-call surface directly to a live `Orchestrator`/`EventRouter`
|
|
196
|
-
instance — every handler call is backed by real, inspectable state, not
|
|
197
|
-
a hardcoded response.
|
|
198
|
-
|
|
199
|
-
**Honest limitations**: a few orchestration capabilities are accepted at
|
|
200
|
-
the API level but not fully implemented yet — cross-project federated
|
|
201
|
-
query *execution* and cross-database joins currently report
|
|
202
|
-
`"status": "not_implemented"` with an explanation, rather than fabricated
|
|
203
|
-
result rows, because there's no real query engine behind them yet.
|
|
204
|
-
|
|
205
|
-
## Webhook event server
|
|
206
|
-
|
|
207
|
-
`pystreammcp.server.create_flask_app()` exposes a small REST/webhook
|
|
208
|
-
surface for orchestration events (agent MCPs reporting `mcp.available`,
|
|
209
|
-
`tool.invoked`, health updates, etc. to `POST /orchestration/webhooks/events`).
|
|
210
|
-
|
|
211
|
-
### Webhook security (HMAC-SHA256)
|
|
212
|
-
|
|
213
|
-
Inbound events to `/orchestration/webhooks/events` must be signed:
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
export PYSTREAMMCP_WEBHOOK_SECRET="a long random shared secret"
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
Senders compute `HMAC-SHA256(secret, raw_request_body)` and send it as:
|
|
220
|
-
|
|
221
|
-
```
|
|
222
|
-
X-PyStreamMCP-Signature: sha256=<hex digest>
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
```python
|
|
226
|
-
from pystreammcp.server import compute_webhook_signature
|
|
227
|
-
import json, requests
|
|
228
|
-
|
|
229
|
-
body = json.dumps({"event_type": "mcp.available", "data": {...}}).encode()
|
|
230
|
-
signature = compute_webhook_signature(secret, body)
|
|
231
|
-
|
|
232
|
-
requests.post(
|
|
233
|
-
"http://localhost:8000/orchestration/webhooks/events",
|
|
234
|
-
data=body,
|
|
235
|
-
headers={
|
|
236
|
-
"Content-Type": "application/json",
|
|
237
|
-
"X-PyStreamMCP-Signature": signature,
|
|
238
|
-
},
|
|
239
|
-
)
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
Requests with a missing or invalid signature are rejected with `401`. If
|
|
243
|
-
`PYSTREAMMCP_WEBHOOK_SECRET` isn't set at all, the endpoint fails closed
|
|
244
|
-
and rejects every request with `503` — there is no "accept unsigned
|
|
245
|
-
events" fallback.
|
|
246
|
-
|
|
247
|
-
### Network defaults
|
|
248
|
-
|
|
249
|
-
The HTTP servers (`PyStreamMCPServer` / `create_flask_app()`,
|
|
250
|
-
`PyStreamMCPAPI.run`) bind to `127.0.0.1` (localhost-only) by default.
|
|
251
|
-
Pass `host="0.0.0.0"` explicitly if you need the server reachable from
|
|
252
|
-
other hosts — e.g. inside a container that already has its own network
|
|
253
|
-
boundary.
|
|
254
|
-
|
|
255
|
-
**The `pystreammcp` CLI**: `pip install PyStreamMCP` now installs a real
|
|
256
|
-
`pystreammcp` command (`[project.scripts]` in `pyproject.toml`) backed by
|
|
257
|
-
the Click group in `python/pystreammcp/cli.py`:
|
|
258
|
-
`query`/`server`/`version`/`dashboard`. `python -m pystreammcp.cli` reaches
|
|
259
|
-
the same Click group (the file's old, separate, smaller hand-rolled
|
|
260
|
-
command set has been removed). `server` lazy-imports `pystreammcp.api`, so
|
|
261
|
-
`pystreammcp version`/`query`/`dashboard` work without installing the
|
|
262
|
-
`api` extra; running `pystreammcp server` without it prints a clear
|
|
263
|
-
"install `pystreammcp[api]`" error instead of crashing with
|
|
264
|
-
`ModuleNotFoundError`. See [`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) §2.2
|
|
265
|
-
(now marked fixed) for how this was previously broken.
|
|
266
|
-
|
|
267
|
-
## Testing
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
pip install -e ".[dev,api,mcp,langchain,llamaindex,semantic-kernel]"
|
|
271
|
-
pytest tests/ -v
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Note: this exact command needs Python 3.10+ (see [Install](#install)); on
|
|
275
|
-
3.9 the `mcp` and `semantic-kernel` extras fail to resolve, so drop them
|
|
276
|
-
from the extras list if you're on 3.9.
|
|
277
|
-
|
|
278
|
-
## Known Issues
|
|
279
|
-
|
|
280
|
-
**2026-10-11 pass — workspace-wide error sweep; the Rust backend now
|
|
281
|
-
compiles and its tests pass, Python `ruff` is clean, and a stale
|
|
282
|
-
integration test was rewritten against the real schema:**
|
|
283
|
-
|
|
284
|
-
- **The `core/` Rust workspace compiles again.** It had accumulated 43
|
|
285
|
-
`cargo check` errors: `orchestration/` (reranking/orchestrator referenced
|
|
286
|
-
a stale `stage2_decision` field, `RankingStrategy`/`FusionMethod` were
|
|
287
|
-
missing `Serialize`/`Deserialize`, `ContentSegment` was missing
|
|
288
|
-
`PartialEq`, `TokenBudget` was re-exported from the wrong module);
|
|
289
|
-
`metadata/` (cache eviction borrow-checker error, missing
|
|
290
|
-
`CacheStats.evictions`, `clear_cache`/`cache_stats` were not `async`);
|
|
291
|
-
`selective_retrieval/` (`QueryIntent` missing `PartialEq`,
|
|
292
|
-
struct-variant `BudgetTier` match patterns, a duplicated
|
|
293
|
-
`RerankerConfig`); `quality_gates/` (duplicated `ConfidenceConfig`/
|
|
294
|
-
`SLACheckResult`); and `observability/` (per-subsystem `*Config`
|
|
295
|
-
constructors resolved to a non-existent path). All fixed; `cargo test`
|
|
296
|
-
is green — **138 library + 29 integration tests, 0 failures**.
|
|
297
|
-
- Build note: `rust-toolchain.toml` still pins `channel = "1.81"`, which
|
|
298
|
-
cannot even parse the committed lockfile — transitive deps such as
|
|
299
|
-
`idna_adapter 1.2.2` require `edition2024`, i.e. Cargo ≥ 1.85. The pin
|
|
300
|
-
was intentionally **left unchanged**; build with
|
|
301
|
-
`RUSTUP_TOOLCHAIN=1.97 cargo ...` until the pin is revisited.
|
|
302
|
-
- **5 Python `F821` undefined-name errors fixed** in
|
|
303
|
-
`python/pystreammcp/integrations/{langchain,llamaindex,semantic_kernel}.py`
|
|
304
|
-
— the retriever/tool/plugin classes were referenced in annotations but
|
|
305
|
-
never imported. Added `TYPE_CHECKING`-guarded imports so the optional
|
|
306
|
-
dependency types are visible to type-checkers without forcing a hard
|
|
307
|
-
runtime import. `ruff check python/ --select E9,F63,F7,F82` is clean.
|
|
308
|
-
- **`core/tests/phase_v05_metadata_tests.rs` was dead code** — it had never
|
|
309
|
-
compiled (it referenced an aspirational `MetadataEntry`/profile schema
|
|
310
|
-
that exists nowhere in the tree) and so was never run. Rewritten against
|
|
311
|
-
the real metadata API (`DatabaseMetadata`/`MCPToolMetadata`,
|
|
312
|
-
`Metadata::Web/Database/Mcp`, profile keys `public_postgres`,
|
|
313
|
-
`bigquery_analytics`, `ml_inference`, …); all 29 tests pass.
|
|
314
|
-
- **3 pre-existing heuristic test failures fixed.**
|
|
315
|
-
`orchestration/complexity.rs`: a "very complex" query scored *lower* than
|
|
316
|
-
a merely "complex" one because reasoning terms (`analysis`, `correlation`,
|
|
317
|
-
`anomalies`, `pattern`, …) weren't recognised — added an
|
|
318
|
-
`analytical_terms()` signal and widened the `Complex` band.
|
|
319
|
-
`selective_retrieval/intent.rs`: added an enumeration (comma-list) signal
|
|
320
|
-
and raised the multi-entity weight so list-heavy and design-style queries
|
|
321
|
-
classify correctly. No production behaviour change (these tiers only feed
|
|
322
|
-
`budgets::assign_tier`, and the detectors are otherwise unused).
|
|
323
|
-
|
|
324
|
-
- ~~No end-to-end tests for LLM failure states~~ **Fixed.** PyStreamMCP's
|
|
325
|
-
own code never calls a model provider directly (no code path here to add
|
|
326
|
-
`except RateLimitError`/`APIError` handling *to* — see `AgentFrameworkAdapter`
|
|
327
|
-
below), so what's now tested is the part this repo actually owns: that the
|
|
328
|
-
MCP tool-call path doesn't crash when whatever it's orchestrating fails.
|
|
329
|
-
`pystreammcp.testing` exports `RateLimitError`, `ContextWindowExceededError`,
|
|
330
|
-
`MalformedModelResponseError`, and `FailingAgent`/`FailingAdapter` stand-ins
|
|
331
|
-
that raise them; `mcp_server.py`'s `call_tool`/`process_message` now catch
|
|
332
|
-
exceptions raised during tool execution and return a structured
|
|
333
|
-
`{"status": "error", "error_type": ..., "message": ...}` response instead
|
|
334
|
-
of propagating uncaught. See `tests/test_mcp_server_resilience.py`.
|
|
335
|
-
- ~~No Pydantic validation for the MCP tool protocol itself~~ **Fixed.**
|
|
336
|
-
Each of the four MCP tools now has a Pydantic arg model
|
|
337
|
-
(`QueryToolArgs`/`DiscoverToolArgs`/`RegisterSourceToolArgs`/`OptimizeToolArgs`
|
|
338
|
-
in `mcp_server.py`) validated in `call_tool` before dispatch (wrong types,
|
|
339
|
-
invalid enum values, and missing required fields all now return a
|
|
340
|
-
structured `validation_errors` response instead of reaching the handler
|
|
341
|
-
unchecked), and `MCPTool.input_schema` is generated from those same models
|
|
342
|
-
via `model_json_schema()` — the advertised schema and the schema actually
|
|
343
|
-
enforced can no longer drift apart the way a hand-duplicated dict could.
|
|
344
|
-
- ~~No shipped mock MCP server / mock LLM fixture~~ **Fixed.** Added
|
|
345
|
-
`tests/conftest.py` (centralizing the `sys.path` setup 5 test files were
|
|
346
|
-
duplicating, plus `mock_adapter`/`failing_agent`/`failing_adapter`/
|
|
347
|
-
`llm_failure` pytest fixtures) and `pystreammcp/testing.py`, exporting
|
|
348
|
-
`MockAdapter` (promoted from the old test-local copy) and the
|
|
349
|
-
failure-injection stand-ins above for downstream projects' own test
|
|
350
|
-
suites to import directly.
|
|
351
|
-
- **Per-query context discovery** now has a real implementation
|
|
352
|
-
(`pystreammcp.discovery.SourceRegistry`): register data sources (name,
|
|
353
|
-
description, type, tags), and `/discover` (REST), `pystreammcp_discover`
|
|
354
|
-
(MCP), and `LangchainAdapter.discover()` all rank *registered* sources
|
|
355
|
-
by real Jaccard token-overlap against the query — an empty registry or
|
|
356
|
-
a non-matching context returns an empty list, not fabricated data. This
|
|
357
|
-
is a simple word-overlap heuristic, not semantic/embedding search — if
|
|
358
|
-
you need that, wrap `SourceRegistry` with your own similarity scoring.
|
|
359
|
-
- ~~The `pystreammcp` CLI is dead code~~ **Fixed.** `pyproject.toml` now
|
|
360
|
-
has a `[project.scripts]` entry, and the module's `__main__` guard
|
|
361
|
-
invokes the real Click group. See [Network defaults](#network-defaults)
|
|
362
|
-
above and [`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) §2.2.
|
|
363
|
-
- ~~Three orchestration-tool discovery adapters return fabricated
|
|
364
|
-
results~~ **Fixed.** `orchestration/temporal.py`'s
|
|
365
|
-
`TemporalDiscoveryActivity`/`TemporalWorkflow`, `airflow.py`'s
|
|
366
|
-
`PyStreamMCPDiscoveryOperator`, and `nocode_rpa.py`'s
|
|
367
|
-
`N8nWebhookTrigger` now take an optional shared `SourceRegistry` and
|
|
368
|
-
call its real `discover()` instead of synthesizing `source_0..
|
|
369
|
-
source_4`. With nothing registered they honestly return zero sources
|
|
370
|
-
(see [`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) §2.1).
|
|
371
|
-
- `pip-audit` (run 2026-09-20 against the `dev,api,mcp,langchain,
|
|
372
|
-
llamaindex,semantic-kernel` extras) found 7 known CVEs in transitive
|
|
373
|
-
dependencies (`werkzeug` via `flask`, `nltk` via `llama-index`) — see
|
|
374
|
-
[`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) §4. Not fixed this pass.
|
|
375
|
-
- No open GitHub issues as of this pass.
|
|
376
|
-
|
|
377
|
-
## Documentation
|
|
378
|
-
|
|
379
|
-
- [`ROADMAP_HONEST.md`](ROADMAP_HONEST.md) — full, unhedged status:
|
|
380
|
-
what's tested, what's fabricated/broken, technical debt, what's
|
|
381
|
-
explicitly not built.
|
|
382
|
-
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — how the shipped
|
|
383
|
-
package is structured, with a diagram.
|
|
384
|
-
- [`OKF_INTEGRATION.md`](OKF_INTEGRATION.md) — the OKF (Open Knowledge
|
|
385
|
-
Format) catalog/discovery/query-planner feature (real, tested, not
|
|
386
|
-
mentioned elsewhere in this README).
|
|
387
|
-
- [`CONTRIBUTING.md`](CONTRIBUTING.md), [`SECURITY.md`](SECURITY.md),
|
|
388
|
-
[`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md),
|
|
389
|
-
[`CHANGELOG.md`](CHANGELOG.md).
|
|
390
|
-
|
|
391
|
-
## Rust workspace (not shipped)
|
|
392
|
-
|
|
393
|
-
`core/` and `python/src/lib.rs` are an in-progress Rust workspace intended
|
|
394
|
-
as a future performance backend. **It is not part of the published PyPI
|
|
395
|
-
package** — the wheel built from `pyproject.toml` is pure Python. It now
|
|
396
|
-
compiles and its unit/integration tests pass (see the 2026-10-11 entry in
|
|
397
|
-
[Known Issues](#known-issues)), but note the `1.81` toolchain pin: build it
|
|
398
|
-
with `RUSTUP_TOOLCHAIN=1.97 cargo ...`. Don't rely on it as a shipped
|
|
399
|
-
artifact; it's tracked separately from the Python package described in this
|
|
400
|
-
README.
|
|
401
|
-
|
|
402
|
-
## License
|
|
403
|
-
|
|
404
|
-
This project is licensed under the [Apache License 2.0](LICENSE).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|