weaver-kernel 0.3.0__tar.gz → 0.5.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.
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/.github/workflows/ci.yml +29 -0
- weaver_kernel-0.5.0/.github/workflows/publish.yml +74 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/AGENTS.md +4 -1
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/CHANGELOG.md +21 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/PKG-INFO +16 -2
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/README.md +13 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/RELEASE.md +6 -5
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/agent-context/invariants.md +4 -1
- weaver_kernel-0.5.0/docs/integrations.md +130 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/security.md +5 -1
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/pyproject.toml +3 -2
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/__init__.py +3 -1
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/drivers/__init__.py +2 -1
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/drivers/http.py +1 -1
- weaver_kernel-0.5.0/src/agent_kernel/drivers/mcp.py +236 -0
- weaver_kernel-0.5.0/src/agent_kernel/drivers/mcp_support.py +154 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/firewall/transform.py +0 -6
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/policy.py +113 -1
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_drivers.py +134 -2
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_firewall.py +131 -0
- weaver_kernel-0.5.0/tests/test_mcp_driver.py +298 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_policy.py +205 -29
- weaver_kernel-0.3.0/.github/workflows/publish.yml +0 -35
- weaver_kernel-0.3.0/docs/integrations.md +0 -70
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/.claude/CLAUDE.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/.github/copilot-instructions.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/.gitignore +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/CONTRIBUTING.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/LICENSE +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/Makefile +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/agent-context/architecture.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/agent-context/lessons-learned.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/agent-context/review-checklist.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/agent-context/workflows.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/architecture.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/capabilities.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/docs/context_firewall.md +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/examples/basic_cli.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/examples/billing_demo.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/examples/http_driver_demo.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/drivers/base.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/drivers/memory.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/enums.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/errors.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/firewall/__init__.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/firewall/budgets.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/firewall/redaction.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/firewall/summarize.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/handles.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/kernel.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/models.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/py.typed +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/registry.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/router.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/tokens.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/src/agent_kernel/trace.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/conftest.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_handles.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_kernel.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_logging.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_models.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_redaction.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_registry.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_router.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_tokens.py +0 -0
- {weaver_kernel-0.3.0 → weaver_kernel-0.5.0}/tests/test_trace.py +0 -0
|
@@ -45,3 +45,32 @@ jobs:
|
|
|
45
45
|
python examples/basic_cli.py
|
|
46
46
|
python examples/billing_demo.py
|
|
47
47
|
python examples/http_driver_demo.py
|
|
48
|
+
|
|
49
|
+
conformance_stub:
|
|
50
|
+
name: "Weaver Spec Conformance Stub (v0.1.0)"
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
needs: test
|
|
53
|
+
permissions:
|
|
54
|
+
contents: read
|
|
55
|
+
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v4
|
|
58
|
+
|
|
59
|
+
- name: Set up Python
|
|
60
|
+
uses: actions/setup-python@v5
|
|
61
|
+
with:
|
|
62
|
+
python-version: "3.12"
|
|
63
|
+
|
|
64
|
+
- name: Install dependencies
|
|
65
|
+
run: pip install -e ".[dev]"
|
|
66
|
+
|
|
67
|
+
# Placeholder: activate once dgenio/weaver-spec#4 ships the conformance runner.
|
|
68
|
+
# weaver-spec and weaver-contracts are published on PyPI.
|
|
69
|
+
# weaver_contracts.conformance does not yet exist (dgenio/weaver-spec#4).
|
|
70
|
+
# Replace this step with:
|
|
71
|
+
# pip install weaver-contracts # PyPI dist name uses a hyphen
|
|
72
|
+
# python -m weaver_contracts.conformance --target agent_kernel
|
|
73
|
+
- name: weaver-spec conformance suite (stub)
|
|
74
|
+
run: |
|
|
75
|
+
echo "weaver-contracts 0.2.0 is on PyPI; weaver_contracts.conformance runner not yet available (dgenio/weaver-spec#4)."
|
|
76
|
+
echo "Stub passes. Activate when dgenio/weaver-spec#4 ships."
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
name: "CI gate"
|
|
10
|
+
uses: ./.github/workflows/ci.yml
|
|
11
|
+
|
|
12
|
+
build:
|
|
13
|
+
name: "Build"
|
|
14
|
+
needs: ci
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Install build tools
|
|
27
|
+
run: pip install build
|
|
28
|
+
|
|
29
|
+
- name: Build sdist and wheel
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Upload dist artifacts
|
|
33
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
release:
|
|
39
|
+
name: "GitHub Release"
|
|
40
|
+
needs: build
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
permissions:
|
|
43
|
+
contents: write # required to create releases
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download dist artifacts
|
|
46
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
47
|
+
with:
|
|
48
|
+
name: dist
|
|
49
|
+
path: dist/
|
|
50
|
+
|
|
51
|
+
- name: Create GitHub Release
|
|
52
|
+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
|
53
|
+
with:
|
|
54
|
+
generate_release_notes: true
|
|
55
|
+
fail_on_unmatched_files: true
|
|
56
|
+
files: dist/*
|
|
57
|
+
|
|
58
|
+
publish:
|
|
59
|
+
name: "Publish to PyPI"
|
|
60
|
+
needs: release
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
environment: pypi
|
|
63
|
+
permissions:
|
|
64
|
+
contents: read
|
|
65
|
+
id-token: write # required for Trusted Publisher (OIDC)
|
|
66
|
+
steps:
|
|
67
|
+
- name: Download dist artifacts
|
|
68
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
|
|
73
|
+
- name: Publish to PyPI
|
|
74
|
+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
|
|
@@ -25,9 +25,12 @@ agent-kernel is part of the **Weaver ecosystem**:
|
|
|
25
25
|
|
|
26
26
|
This repo must conform to weaver-spec invariants. Key invariants (all equally critical):
|
|
27
27
|
- **I-01**: Every tool output must pass through a context boundary before reaching the LLM.
|
|
28
|
-
- **I-02**:
|
|
28
|
+
- **I-02**: Every execution must be authorized and auditable (preceded by a policy decision, followed by a trace event).
|
|
29
29
|
- **I-06**: Tokens must bind principal + capability + constraints; no reuse across principals.
|
|
30
30
|
|
|
31
|
+
Note: Budget enforcement (size, depth, field count) is an agent-kernel implementation
|
|
32
|
+
constraint that satisfies I-01 — it is not a separate weaver-spec invariant number.
|
|
33
|
+
|
|
31
34
|
Full spec: [dgenio/weaver-spec](https://github.com/dgenio/weaver-spec)
|
|
32
35
|
|
|
33
36
|
## Domain vocabulary
|
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-04-12
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Built-in `MCPDriver` with stdio and Streamable HTTP transports, tool auto-discovery, normalized MCP result handling, and optional dependency guardrails.
|
|
14
|
+
- Declared weaver-spec v0.1.0 compatibility in README: invariants I-01 (firewall), I-02 (authorization + audit), and I-06 (scoped tokens) are satisfied.
|
|
15
|
+
- Added placeholder `conformance_stub` CI job that will activate once the weaver-spec conformance suite ships (dgenio/weaver-spec#4).
|
|
16
|
+
|
|
17
|
+
## [0.4.0] - 2026-03-14
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Sliding-window rate limiting in `DefaultPolicyEngine` per `(principal_id, capability_id)` pair (#39).
|
|
21
|
+
Default limits by safety class: 60 READ / 10 WRITE / 2 DESTRUCTIVE per 60s window.
|
|
22
|
+
Service-role principals get 10× limits. Configurable via constructor.
|
|
23
|
+
- GitHub Release step in publish workflow — creates a release with auto-generated notes and artifacts before publishing to PyPI.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- `HTTPDriver`: DELETE requests now forward args as query params instead of silently dropping them.
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
- Dead `_truncate_str` helper in `firewall/transform.py` (defined but never called).
|
|
30
|
+
|
|
10
31
|
## [0.3.0] - 2026-03-09
|
|
11
32
|
|
|
12
33
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: weaver-kernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Capability-based security kernel for AI agents operating in large tool ecosystems
|
|
5
5
|
Project-URL: Homepage, https://github.com/dgenio/agent-kernel
|
|
6
6
|
Project-URL: Repository, https://github.com/dgenio/agent-kernel
|
|
@@ -223,13 +223,14 @@ Requires-Python: >=3.10
|
|
|
223
223
|
Requires-Dist: httpx>=0.27
|
|
224
224
|
Provides-Extra: dev
|
|
225
225
|
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
226
|
+
Requires-Dist: mcp>=1.6; extra == 'dev'
|
|
226
227
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
227
228
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
228
229
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
229
230
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
230
231
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
231
232
|
Provides-Extra: mcp
|
|
232
|
-
Requires-Dist: mcp>=1.
|
|
233
|
+
Requires-Dist: mcp>=1.6; extra == 'mcp'
|
|
233
234
|
Provides-Extra: otel
|
|
234
235
|
Requires-Dist: opentelemetry-api>=1.20; extra == 'otel'
|
|
235
236
|
Description-Content-Type: text/markdown
|
|
@@ -346,6 +347,19 @@ asyncio.run(main())
|
|
|
346
347
|
|
|
347
348
|
`agent-kernel` sits **above** `contextweaver` (context compilation) and **above** raw tool execution. It provides the authorization, execution, and audit layer.
|
|
348
349
|
|
|
350
|
+
## Weaver Spec Compatibility: v0.1.0
|
|
351
|
+
|
|
352
|
+
agent-kernel is a compliant implementation of [weaver-spec v0.1.0](https://github.com/dgenio/weaver-spec).
|
|
353
|
+
The following invariants are satisfied:
|
|
354
|
+
|
|
355
|
+
| Invariant | Description | How agent-kernel satisfies it |
|
|
356
|
+
|-----------|-------------|-------------------------------|
|
|
357
|
+
| **I-01** | LLM never sees raw tool output by default | `Context Firewall` always transforms `RawResult → Frame`; raw driver output is not returned by default, and non-admin principals cannot obtain `raw` response mode |
|
|
358
|
+
| **I-02** | Every execution is authorized and auditable | `PolicyEngine` authorizes at grant time; a valid `CapabilityToken` (HMAC-verified on every `invoke()`) carries the authorization decision; `TraceStore` records every `ActionTrace` |
|
|
359
|
+
| **I-06** | CapabilityTokens are scoped | Tokens bind `principal_id + capability_id + constraints` with an explicit TTL; `revoke(token_id)` / `revoke_all(principal_id)` are supported |
|
|
360
|
+
|
|
361
|
+
See [docs/agent-context/invariants.md](docs/agent-context/invariants.md) for the full internal invariant list and [weaver-spec INVARIANTS.md](https://github.com/dgenio/weaver-spec/blob/main/docs/INVARIANTS.md) for the specification.
|
|
362
|
+
|
|
349
363
|
## Security disclaimers
|
|
350
364
|
|
|
351
365
|
> **v0.1 is not production-hardened for real authentication.**
|
|
@@ -110,6 +110,19 @@ asyncio.run(main())
|
|
|
110
110
|
|
|
111
111
|
`agent-kernel` sits **above** `contextweaver` (context compilation) and **above** raw tool execution. It provides the authorization, execution, and audit layer.
|
|
112
112
|
|
|
113
|
+
## Weaver Spec Compatibility: v0.1.0
|
|
114
|
+
|
|
115
|
+
agent-kernel is a compliant implementation of [weaver-spec v0.1.0](https://github.com/dgenio/weaver-spec).
|
|
116
|
+
The following invariants are satisfied:
|
|
117
|
+
|
|
118
|
+
| Invariant | Description | How agent-kernel satisfies it |
|
|
119
|
+
|-----------|-------------|-------------------------------|
|
|
120
|
+
| **I-01** | LLM never sees raw tool output by default | `Context Firewall` always transforms `RawResult → Frame`; raw driver output is not returned by default, and non-admin principals cannot obtain `raw` response mode |
|
|
121
|
+
| **I-02** | Every execution is authorized and auditable | `PolicyEngine` authorizes at grant time; a valid `CapabilityToken` (HMAC-verified on every `invoke()`) carries the authorization decision; `TraceStore` records every `ActionTrace` |
|
|
122
|
+
| **I-06** | CapabilityTokens are scoped | Tokens bind `principal_id + capability_id + constraints` with an explicit TTL; `revoke(token_id)` / `revoke_all(principal_id)` are supported |
|
|
123
|
+
|
|
124
|
+
See [docs/agent-context/invariants.md](docs/agent-context/invariants.md) for the full internal invariant list and [weaver-spec INVARIANTS.md](https://github.com/dgenio/weaver-spec/blob/main/docs/INVARIANTS.md) for the specification.
|
|
125
|
+
|
|
113
126
|
## Security disclaimers
|
|
114
127
|
|
|
115
128
|
> **v0.1 is not production-hardened for real authentication.**
|
|
@@ -16,7 +16,7 @@ Update the `version` field in `pyproject.toml`:
|
|
|
16
16
|
|
|
17
17
|
```toml
|
|
18
18
|
[project]
|
|
19
|
-
version = "0.
|
|
19
|
+
version = "0.4.0"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
### 2. Update the changelog
|
|
@@ -25,7 +25,7 @@ Add a new section to `CHANGELOG.md` under `## [Unreleased]`, then rename it
|
|
|
25
25
|
to the new version with today's date:
|
|
26
26
|
|
|
27
27
|
```markdown
|
|
28
|
-
## [0.
|
|
28
|
+
## [0.4.0] - 2026-03-14
|
|
29
29
|
|
|
30
30
|
### Added
|
|
31
31
|
- ...
|
|
@@ -42,8 +42,8 @@ to the new version with today's date:
|
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
git add pyproject.toml CHANGELOG.md
|
|
45
|
-
git commit -m "release: v0.
|
|
46
|
-
git tag v0.
|
|
45
|
+
git commit -m "release: v0.4.0"
|
|
46
|
+
git tag v0.4.0
|
|
47
47
|
git push origin main --tags
|
|
48
48
|
```
|
|
49
49
|
|
|
@@ -53,7 +53,8 @@ Pushing the `v*` tag triggers `.github/workflows/publish.yml`, which:
|
|
|
53
53
|
|
|
54
54
|
1. Runs the full CI suite (`make ci` equivalent) as a gate.
|
|
55
55
|
2. Builds the sdist and wheel with `python -m build`.
|
|
56
|
-
3.
|
|
56
|
+
3. Creates a GitHub Release with auto-generated notes and the built artifacts attached.
|
|
57
|
+
4. Publishes to PyPI using Trusted Publisher (OIDC — no API tokens stored).
|
|
57
58
|
|
|
58
59
|
Monitor the workflow run at:
|
|
59
60
|
<https://github.com/dgenio/agent-kernel/actions/workflows/publish.yml>
|
|
@@ -11,9 +11,12 @@ All three are equally critical — there is no priority ordering.
|
|
|
11
11
|
| Invariant | Requirement | Where enforced |
|
|
12
12
|
|-----------|-------------|----------------|
|
|
13
13
|
| **I-01** | Every tool output must pass through a context boundary before reaching the LLM | `Firewall.transform()` in `firewall/transform.py` |
|
|
14
|
-
| **I-02** |
|
|
14
|
+
| **I-02** | Every execution must be authorized and auditable (CapabilityToken validated before execution; TraceEvent recorded after) | `HMACTokenProvider.verify()` + `TraceStore.record()` in `kernel.py`; `PolicyEngine.evaluate()` at grant time in `grant_capability()` |
|
|
15
15
|
| **I-06** | Tokens must bind principal + capability + constraints; no reuse across principals | `HMACTokenProvider.verify()` in `tokens.py` |
|
|
16
16
|
|
|
17
|
+
> **Budget enforcement** (size, depth, field count via `Budgets` in `firewall/budgets.py`) is an
|
|
18
|
+
> implementation constraint that strengthens I-01. It has no separate invariant number in weaver-spec.
|
|
19
|
+
|
|
17
20
|
## Forbidden shortcuts — "never do" list
|
|
18
21
|
|
|
19
22
|
These constraints are non-negotiable. Violating any one silently degrades security.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Integrations
|
|
2
|
+
|
|
3
|
+
## MCP (Model Context Protocol)
|
|
4
|
+
|
|
5
|
+
The built-in `MCPDriver` supports both local stdio servers and remote Streamable HTTP servers.
|
|
6
|
+
|
|
7
|
+
Install the optional dependency first:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install "weaver-kernel[mcp]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Stdio transport
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import asyncio
|
|
17
|
+
|
|
18
|
+
from agent_kernel import CapabilityRegistry, Kernel, StaticRouter
|
|
19
|
+
from agent_kernel.drivers.mcp import MCPDriver
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def main() -> None:
|
|
23
|
+
registry = CapabilityRegistry()
|
|
24
|
+
router = StaticRouter(fallback=[])
|
|
25
|
+
kernel = Kernel(registry=registry, router=router)
|
|
26
|
+
|
|
27
|
+
# Connect to a local MCP server process.
|
|
28
|
+
driver = MCPDriver.from_stdio(
|
|
29
|
+
command="python",
|
|
30
|
+
args=["-m", "my_mcp_server"],
|
|
31
|
+
server_name="local-tools",
|
|
32
|
+
)
|
|
33
|
+
kernel.register_driver(driver)
|
|
34
|
+
|
|
35
|
+
# Discover tools and register them as capabilities.
|
|
36
|
+
capabilities = await driver.discover(namespace="local")
|
|
37
|
+
registry.register_many(capabilities)
|
|
38
|
+
|
|
39
|
+
# Route each discovered capability to this MCP driver.
|
|
40
|
+
for capability in capabilities:
|
|
41
|
+
router.add_route(capability.capability_id, [driver.driver_id])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
asyncio.run(main())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Streamable HTTP transport
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import asyncio
|
|
51
|
+
|
|
52
|
+
from agent_kernel import CapabilityRegistry, Kernel, StaticRouter
|
|
53
|
+
from agent_kernel.drivers.mcp import MCPDriver
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def main() -> None:
|
|
57
|
+
registry = CapabilityRegistry()
|
|
58
|
+
router = StaticRouter(fallback=[])
|
|
59
|
+
kernel = Kernel(registry=registry, router=router)
|
|
60
|
+
|
|
61
|
+
# Connect to a remote Streamable HTTP MCP server.
|
|
62
|
+
# Note: max_retries > 0 creates at-least-once delivery semantics for
|
|
63
|
+
# tools/call — if a connection drops after the server processes the
|
|
64
|
+
# request but before the response arrives, the call will be repeated.
|
|
65
|
+
# Ensure target tools are idempotent, or set max_retries=0 for
|
|
66
|
+
# WRITE/DESTRUCTIVE capabilities.
|
|
67
|
+
driver = MCPDriver.from_http(
|
|
68
|
+
url="https://example.com/mcp",
|
|
69
|
+
server_name="remote-tools",
|
|
70
|
+
max_retries=1,
|
|
71
|
+
)
|
|
72
|
+
kernel.register_driver(driver)
|
|
73
|
+
|
|
74
|
+
# Discover tools and register them as capabilities.
|
|
75
|
+
capabilities = await driver.discover(namespace="remote")
|
|
76
|
+
registry.register_many(capabilities)
|
|
77
|
+
|
|
78
|
+
# Route each discovered capability to this MCP driver.
|
|
79
|
+
for capability in capabilities:
|
|
80
|
+
router.add_route(capability.capability_id, [driver.driver_id])
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
asyncio.run(main())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Notes
|
|
87
|
+
|
|
88
|
+
- `discover()` converts `tools/list` results into `Capability` objects.
|
|
89
|
+
- `execute()` calls `tools/call` and normalizes MCP content blocks for the firewall.
|
|
90
|
+
- MCP `isError` responses raise `DriverError` with the server-provided detail.
|
|
91
|
+
- If `mcp` is not installed, factory methods raise a helpful `ImportError`.
|
|
92
|
+
|
|
93
|
+
## HTTPDriver
|
|
94
|
+
|
|
95
|
+
The built-in `HTTPDriver` supports GET, POST, PUT, DELETE:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from agent_kernel.drivers.http import HTTPDriver, HTTPEndpoint
|
|
99
|
+
|
|
100
|
+
driver = HTTPDriver(driver_id="my_api")
|
|
101
|
+
driver.register_endpoint("users.list", HTTPEndpoint(
|
|
102
|
+
url="https://api.example.com/users",
|
|
103
|
+
method="GET",
|
|
104
|
+
headers={"Authorization": "Bearer ..."},
|
|
105
|
+
))
|
|
106
|
+
kernel.register_driver(driver)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Custom drivers
|
|
110
|
+
|
|
111
|
+
Any object implementing the `Driver` protocol can be registered:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
class Driver(Protocol):
|
|
115
|
+
@property
|
|
116
|
+
def driver_id(self) -> str: ...
|
|
117
|
+
async def execute(self, ctx: ExecutionContext) -> RawResult: ...
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Capability mapping
|
|
121
|
+
|
|
122
|
+
When mapping MCP tools to capabilities, prefer task-shaped names:
|
|
123
|
+
|
|
124
|
+
| MCP tool | Capability ID | Safety class |
|
|
125
|
+
|----------|--------------|--------------|
|
|
126
|
+
| `list_files` | `fs.list_files` | READ |
|
|
127
|
+
| `read_file` | `fs.read_file` | READ |
|
|
128
|
+
| `write_file` | `fs.write_file` | WRITE |
|
|
129
|
+
| `delete_file` | `fs.delete_file` | DESTRUCTIVE |
|
|
130
|
+
| `execute_code` | `sandbox.run_code` | DESTRUCTIVE |
|
|
@@ -35,4 +35,8 @@ Consider an agent that obtains a token for `billing.list_invoices` then passes i
|
|
|
35
35
|
- The `AGENT_KERNEL_SECRET` must be kept secret. Rotate it if compromised.
|
|
36
36
|
- The default `InMemoryDriver` has no persistence — suitable for testing only.
|
|
37
37
|
- PII redaction is heuristic (regex-based). It is not a substitute for proper data governance.
|
|
38
|
-
-
|
|
38
|
+
- Rate limiting is enforced per `(principal_id, capability_id)` pair using a sliding window.
|
|
39
|
+
Default limits: 60 READ / 10 WRITE / 2 DESTRUCTIVE invocations per 60-second window.
|
|
40
|
+
Principals with the `"service"` role receive 10× the default limits. Limits are
|
|
41
|
+
configurable via `DefaultPolicyEngine(rate_limits=...)`. There is no distributed or
|
|
42
|
+
persistent rate-limit state — limits reset on process restart.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "weaver-kernel"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Capability-based security kernel for AI agents operating in large tool ecosystems"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -38,8 +38,9 @@ dev = [
|
|
|
38
38
|
"ruff>=0.4",
|
|
39
39
|
"mypy>=1.10",
|
|
40
40
|
"httpx>=0.27",
|
|
41
|
+
"mcp>=1.6",
|
|
41
42
|
]
|
|
42
|
-
mcp = ["mcp>=1.
|
|
43
|
+
mcp = ["mcp>=1.6"]
|
|
43
44
|
otel = ["opentelemetry-api>=1.20"]
|
|
44
45
|
|
|
45
46
|
[tool.hatch.build.targets.wheel]
|
|
@@ -37,6 +37,7 @@ Errors::
|
|
|
37
37
|
|
|
38
38
|
from .drivers.base import Driver, ExecutionContext
|
|
39
39
|
from .drivers.http import HTTPDriver
|
|
40
|
+
from .drivers.mcp import MCPDriver
|
|
40
41
|
from .drivers.memory import InMemoryDriver, make_billing_driver
|
|
41
42
|
from .enums import SafetyClass, SensitivityTag
|
|
42
43
|
from .errors import (
|
|
@@ -78,7 +79,7 @@ from .router import StaticRouter
|
|
|
78
79
|
from .tokens import CapabilityToken, HMACTokenProvider
|
|
79
80
|
from .trace import TraceStore
|
|
80
81
|
|
|
81
|
-
__version__ = "0.
|
|
82
|
+
__version__ = "0.4.0"
|
|
82
83
|
|
|
83
84
|
__all__ = [
|
|
84
85
|
# version
|
|
@@ -129,6 +130,7 @@ __all__ = [
|
|
|
129
130
|
"ExecutionContext",
|
|
130
131
|
"InMemoryDriver",
|
|
131
132
|
"HTTPDriver",
|
|
133
|
+
"MCPDriver",
|
|
132
134
|
"make_billing_driver",
|
|
133
135
|
# firewall
|
|
134
136
|
"Firewall",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from .base import Driver, ExecutionContext
|
|
4
4
|
from .http import HTTPDriver
|
|
5
|
+
from .mcp import MCPDriver
|
|
5
6
|
from .memory import InMemoryDriver
|
|
6
7
|
|
|
7
|
-
__all__ = ["Driver", "ExecutionContext", "HTTPDriver", "InMemoryDriver"]
|
|
8
|
+
__all__ = ["Driver", "ExecutionContext", "HTTPDriver", "MCPDriver", "InMemoryDriver"]
|
|
@@ -83,7 +83,7 @@ class HTTPDriver:
|
|
|
83
83
|
params: dict[str, Any] = {}
|
|
84
84
|
json_body: dict[str, Any] | None = None
|
|
85
85
|
|
|
86
|
-
if endpoint.method.upper()
|
|
86
|
+
if endpoint.method.upper() in ("GET", "DELETE"):
|
|
87
87
|
params = {k: v for k, v in ctx.args.items() if k != "operation"}
|
|
88
88
|
else:
|
|
89
89
|
json_body = {k: v for k, v in ctx.args.items() if k != "operation"}
|