ouncemcp 1.0.0rc1__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.
- ouncemcp-1.0.0rc1/.gitignore +16 -0
- ouncemcp-1.0.0rc1/CHANGELOG.md +39 -0
- ouncemcp-1.0.0rc1/CONTRIBUTING.md +32 -0
- ouncemcp-1.0.0rc1/LICENSE +202 -0
- ouncemcp-1.0.0rc1/PKG-INFO +232 -0
- ouncemcp-1.0.0rc1/README.md +182 -0
- ouncemcp-1.0.0rc1/SECURITY.md +15 -0
- ouncemcp-1.0.0rc1/benchmarks/README.md +14 -0
- ouncemcp-1.0.0rc1/benchmarks/bench.yaml +31 -0
- ouncemcp-1.0.0rc1/benchmarks/results/.gitkeep +0 -0
- ouncemcp-1.0.0rc1/benchmarks/results/gate6-release-check.json +5148 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m0-inventory-tokens.json +38 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m0-overhead.json +43 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m1-truncation.json +34 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m3-bench.json +4931 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m3-bench.md +66 -0
- ouncemcp-1.0.0rc1/benchmarks/results/m4-perf.json +96 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/.gitkeep +0 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/_common.py +12 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/m0_compare.py +90 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/m0_overhead.py +119 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/m1_truncation.py +118 -0
- ouncemcp-1.0.0rc1/benchmarks/scripts/m4_release_perf.py +294 -0
- ouncemcp-1.0.0rc1/benchmarks/servers/.gitkeep +0 -0
- ouncemcp-1.0.0rc1/benchmarks/tasks/.gitkeep +0 -0
- ouncemcp-1.0.0rc1/benchmarks/tasks/inventory.yaml +123 -0
- ouncemcp-1.0.0rc1/benchmarks/tasks/ticketing.yaml +133 -0
- ouncemcp-1.0.0rc1/benchmarks/tasks/ticketing_checks.py +30 -0
- ouncemcp-1.0.0rc1/conformance/expected-failures.yml +22 -0
- ouncemcp-1.0.0rc1/docs/README.md +95 -0
- ouncemcp-1.0.0rc1/docs/assets/extra.css +23 -0
- ouncemcp-1.0.0rc1/docs/assets/favicon.svg +1 -0
- ouncemcp-1.0.0rc1/docs/book/appendix-a-cli.md +22 -0
- ouncemcp-1.0.0rc1/docs/book/appendix-b-errors-lints.md +33 -0
- ouncemcp-1.0.0rc1/docs/book/appendix-c-glossary.md +45 -0
- ouncemcp-1.0.0rc1/docs/book/ch01-getting-started.md +69 -0
- ouncemcp-1.0.0rc1/docs/book/ch02-first-server.md +112 -0
- ouncemcp-1.0.0rc1/docs/book/ch03-budgets.md +100 -0
- ouncemcp-1.0.0rc1/docs/book/ch04-shaping.md +77 -0
- ouncemcp-1.0.0rc1/docs/book/ch05-errors.md +60 -0
- ouncemcp-1.0.0rc1/docs/book/ch06-writes.md +78 -0
- ouncemcp-1.0.0rc1/docs/book/ch07-security.md +66 -0
- ouncemcp-1.0.0rc1/docs/book/ch08-jobs.md +55 -0
- ouncemcp-1.0.0rc1/docs/book/ch09-resources-prompts.md +55 -0
- ouncemcp-1.0.0rc1/docs/book/ch10-testing.md +77 -0
- ouncemcp-1.0.0rc1/docs/book/ch11-measuring.md +89 -0
- ouncemcp-1.0.0rc1/docs/book/ch12-discovery.md +55 -0
- ouncemcp-1.0.0rc1/docs/book/ch13-deploying.md +63 -0
- ouncemcp-1.0.0rc1/docs/book/ch14-migrating.md +38 -0
- ouncemcp-1.0.0rc1/docs/book/ch15-clients.md +33 -0
- ouncemcp-1.0.0rc1/docs/book/index.md +35 -0
- ouncemcp-1.0.0rc1/docs/changelog.md +1 -0
- ouncemcp-1.0.0rc1/docs/compatibility.md +28 -0
- ouncemcp-1.0.0rc1/docs/concepts/budgets.md +21 -0
- ouncemcp-1.0.0rc1/docs/concepts/discovery.md +10 -0
- ouncemcp-1.0.0rc1/docs/concepts/execution.md +14 -0
- ouncemcp-1.0.0rc1/docs/concepts/resources-prompts.md +22 -0
- ouncemcp-1.0.0rc1/docs/concepts/security.md +37 -0
- ouncemcp-1.0.0rc1/docs/concepts/shaping.md +17 -0
- ouncemcp-1.0.0rc1/docs/concepts/traces.md +13 -0
- ouncemcp-1.0.0rc1/docs/errors/ambiguous_write.md +13 -0
- ouncemcp-1.0.0rc1/docs/errors/authentication.md +12 -0
- ouncemcp-1.0.0rc1/docs/errors/internal.md +11 -0
- ouncemcp-1.0.0rc1/docs/errors/not_found.md +13 -0
- ouncemcp-1.0.0rc1/docs/errors/permission.md +16 -0
- ouncemcp-1.0.0rc1/docs/errors/rate_limit.md +13 -0
- ouncemcp-1.0.0rc1/docs/errors/transient.md +14 -0
- ouncemcp-1.0.0rc1/docs/errors/validation.md +20 -0
- ouncemcp-1.0.0rc1/docs/guides/client-broker.md +23 -0
- ouncemcp-1.0.0rc1/docs/guides/deploying-http.md +52 -0
- ouncemcp-1.0.0rc1/docs/guides/evaluating.md +47 -0
- ouncemcp-1.0.0rc1/docs/guides/host-verification.md +58 -0
- ouncemcp-1.0.0rc1/docs/guides/migrating-from-fastmcp.md +64 -0
- ouncemcp-1.0.0rc1/docs/guides/safe-writes.md +19 -0
- ouncemcp-1.0.0rc1/docs/guides/securing-tools.md +15 -0
- ouncemcp-1.0.0rc1/docs/guides/testing.md +33 -0
- ouncemcp-1.0.0rc1/docs/m0-report.md +85 -0
- ouncemcp-1.0.0rc1/docs/m2-report.md +54 -0
- ouncemcp-1.0.0rc1/docs/m4-report.md +60 -0
- ouncemcp-1.0.0rc1/docs/maintainers/releasing.md +47 -0
- ouncemcp-1.0.0rc1/docs/maintainers/repository-settings.md +73 -0
- ouncemcp-1.0.0rc1/docs/maintainers/security-review.md +82 -0
- ouncemcp-1.0.0rc1/docs/mcp-token-footprint.png +0 -0
- ouncemcp-1.0.0rc1/docs/performance-research.md +171 -0
- ouncemcp-1.0.0rc1/docs/proposals/0001-m0-core-api.md +49 -0
- ouncemcp-1.0.0rc1/docs/proposals/0002-schema-safe-shaping-and-pagination.md +138 -0
- ouncemcp-1.0.0rc1/docs/proposals/0003-signed-cursors.md +112 -0
- ouncemcp-1.0.0rc1/docs/proposals/0004-pluggable-tokenizer.md +67 -0
- ouncemcp-1.0.0rc1/docs/proposals/0005-counting-scope-and-output-schema-modes.md +89 -0
- ouncemcp-1.0.0rc1/docs/proposals/0006-discovery-modes.md +126 -0
- ouncemcp-1.0.0rc1/docs/proposals/0007-errors-and-execution-limits.md +114 -0
- ouncemcp-1.0.0rc1/docs/proposals/0008-security-and-policy.md +80 -0
- ouncemcp-1.0.0rc1/docs/proposals/0009-traces.md +46 -0
- ouncemcp-1.0.0rc1/docs/proposals/0010-m2-plan.md +75 -0
- ouncemcp-1.0.0rc1/docs/proposals/0011-store-and-idempotency.md +58 -0
- ouncemcp-1.0.0rc1/docs/proposals/0012-safe-writes.md +50 -0
- ouncemcp-1.0.0rc1/docs/proposals/0013-handles-and-jobs.md +32 -0
- ouncemcp-1.0.0rc1/docs/proposals/0014-resources-and-prompts.md +39 -0
- ouncemcp-1.0.0rc1/docs/proposals/0015-migration-and-audit.md +43 -0
- ouncemcp-1.0.0rc1/docs/proposals/0016-client-broker.md +46 -0
- ouncemcp-1.0.0rc1/docs/proposals/0017-operations.md +26 -0
- ouncemcp-1.0.0rc1/docs/proposals/0018-trace-viewer.md +26 -0
- ouncemcp-1.0.0rc1/docs/proposals/0019-eval-kit.md +48 -0
- ouncemcp-1.0.0rc1/docs/proposals/0020-report-ui.md +51 -0
- ouncemcp-1.0.0rc1/docs/proposals/0021-budget-overrides.md +36 -0
- ouncemcp-1.0.0rc1/docs/proposals/0022-parallel-safe-tools.md +32 -0
- ouncemcp-1.0.0rc1/docs/proposals/0023-safe-fetch.md +40 -0
- ouncemcp-1.0.0rc1/docs/proposals/0024-context-and-audit-pages.md +33 -0
- ouncemcp-1.0.0rc1/docs/proposals/0025-oauth.md +37 -0
- ouncemcp-1.0.0rc1/docs/proposals/0026-real-model-evals.md +48 -0
- ouncemcp-1.0.0rc1/docs/proposals/0027-benchmark.md +50 -0
- ouncemcp-1.0.0rc1/docs/proposals/0028-resumable-jobs.md +47 -0
- ouncemcp-1.0.0rc1/docs/proposals/0029-api-freeze.md +86 -0
- ouncemcp-1.0.0rc1/docs/proposals/README.md +5 -0
- ouncemcp-1.0.0rc1/docs/quickstart.md +81 -0
- ouncemcp-1.0.0rc1/docs/reference/budgets.md +29 -0
- ouncemcp-1.0.0rc1/docs/reference/client.md +12 -0
- ouncemcp-1.0.0rc1/docs/reference/errors.md +26 -0
- ouncemcp-1.0.0rc1/docs/reference/eval.md +51 -0
- ouncemcp-1.0.0rc1/docs/reference/execution.md +24 -0
- ouncemcp-1.0.0rc1/docs/reference/index.md +15 -0
- ouncemcp-1.0.0rc1/docs/reference/security.md +8 -0
- ouncemcp-1.0.0rc1/docs/reference/server.md +30 -0
- ouncemcp-1.0.0rc1/docs/reference/testing.md +6 -0
- ouncemcp-1.0.0rc1/docs/reference/trace.md +24 -0
- ouncemcp-1.0.0rc1/docs/rules/budget-override-without-reason.md +25 -0
- ouncemcp-1.0.0rc1/docs/rules/description-too-short.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/destructive-without-policy.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/elicit-in-write.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/free-form-input.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/inconsistent-tool-names.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/input-after-effect.md +27 -0
- ouncemcp-1.0.0rc1/docs/rules/missing-usage-guidance.md +15 -0
- ouncemcp-1.0.0rc1/docs/rules/stdio-skips-policy.md +16 -0
- ouncemcp-1.0.0rc1/docs/rules/undocumented-parameter.md +21 -0
- ouncemcp-1.0.0rc1/docs/rules/unpaginated-list.md +23 -0
- ouncemcp-1.0.0rc1/docs/rules/write-without-side-effects.md +15 -0
- ouncemcp-1.0.0rc1/docs/spec.md +1045 -0
- ouncemcp-1.0.0rc1/examples/README.md +13 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/README.md +19 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/eval.yaml +62 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/eval_checks.py +13 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/library.py +109 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/step1_catalog.py +80 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/step2_shaped.py +128 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/step3_writes.py +192 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/step4_secure.py +217 -0
- ouncemcp-1.0.0rc1/examples/book/shelf/step5_complete.py +293 -0
- ouncemcp-1.0.0rc1/examples/inventory/README.md +50 -0
- ouncemcp-1.0.0rc1/examples/inventory/data.py +72 -0
- ouncemcp-1.0.0rc1/examples/inventory/eval.yaml +93 -0
- ouncemcp-1.0.0rc1/examples/inventory/eval_checks.py +24 -0
- ouncemcp-1.0.0rc1/examples/inventory/plain_server.py +38 -0
- ouncemcp-1.0.0rc1/examples/inventory/server.py +101 -0
- ouncemcp-1.0.0rc1/examples/inventory/workflow.py +101 -0
- ouncemcp-1.0.0rc1/examples/markitdown/README.md +28 -0
- ouncemcp-1.0.0rc1/examples/markitdown/converter.py +31 -0
- ouncemcp-1.0.0rc1/examples/markitdown/original.py +39 -0
- ouncemcp-1.0.0rc1/examples/markitdown/server.py +98 -0
- ouncemcp-1.0.0rc1/examples/markitdown/step1.py +17 -0
- ouncemcp-1.0.0rc1/examples/ouncemcp.example.toml +18 -0
- ouncemcp-1.0.0rc1/examples/report/README.md +26 -0
- ouncemcp-1.0.0rc1/examples/report/server.py +101 -0
- ouncemcp-1.0.0rc1/examples/ticketing/README.md +42 -0
- ouncemcp-1.0.0rc1/examples/ticketing/eval.yaml +96 -0
- ouncemcp-1.0.0rc1/examples/ticketing/eval_checks.py +26 -0
- ouncemcp-1.0.0rc1/examples/ticketing/plain_server.py +50 -0
- ouncemcp-1.0.0rc1/examples/ticketing/server.py +160 -0
- ouncemcp-1.0.0rc1/examples/ticketing/upstream.py +70 -0
- ouncemcp-1.0.0rc1/mkdocs.yml +209 -0
- ouncemcp-1.0.0rc1/pyproject.toml +95 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/__init__.py +99 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/__main__.py +3 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/audit/__init__.py +21 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/audit/runner.py +392 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/cli/__init__.py +662 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/cli/dev.py +248 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/cli/loader.py +52 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/cli/scaffold.py +252 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/client/__init__.py +25 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/client/broker.py +507 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/client/oauth.py +83 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/__init__.py +37 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/budget.py +88 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/config.py +112 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/costs.py +237 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/cursor.py +246 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/docs.py +20 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/effects.py +45 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/errors.py +532 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/lints.py +429 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/pagination.py +88 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/primitives.py +240 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/provider_tokens.py +97 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/schema.py +45 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/server.py +1863 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/shaping.py +811 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/tokens.py +167 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/core/wire.py +13 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/discovery/__init__.py +40 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/discovery/modes.py +103 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/discovery/recall.py +97 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/discovery/search.py +209 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/__init__.py +31 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/__init__.py +25 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/model.py +153 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/openrouter.py +273 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/report.py +282 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/runner.py +383 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/agent/suite.py +261 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/bench.py +507 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/conformance.py +291 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/eval/security.py +312 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/__init__.py +26 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/approval.py +159 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/handles.py +278 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/idempotency.py +268 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/limits.py +114 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/middleware.py +161 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/resolver.py +32 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/retry.py +53 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/runner.py +60 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/execution/store.py +175 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/py.typed +0 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/__init__.py +112 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/cache.py +117 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/fetch.py +115 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/http.py +43 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/identity.py +108 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/passthrough.py +86 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/policy.py +181 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/replay.py +34 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/state.py +184 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/stdio.py +93 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/security/urls.py +147 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/testing.py +59 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/trace/__init__.py +237 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/trace/metrics.py +113 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/trace/otel.py +77 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/trace/report.py +97 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/ui/__init__.py +5 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/ui/page.py +69 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/ui/static/THIRD_PARTY.md +88 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/ui/static/report.html +70 -0
- ouncemcp-1.0.0rc1/src/ouncemcp/ui/views.py +94 -0
- ouncemcp-1.0.0rc1/tests/api_snapshot.json +840 -0
- ouncemcp-1.0.0rc1/tests/conftest.py +23 -0
- ouncemcp-1.0.0rc1/tests/test_api_surface.py +102 -0
- ouncemcp-1.0.0rc1/tests/test_audit.py +179 -0
- ouncemcp-1.0.0rc1/tests/test_bench.py +241 -0
- ouncemcp-1.0.0rc1/tests/test_book_shelf.py +196 -0
- ouncemcp-1.0.0rc1/tests/test_bud4_overrides.py +105 -0
- ouncemcp-1.0.0rc1/tests/test_bud5_traces.py +172 -0
- ouncemcp-1.0.0rc1/tests/test_bud6_tokenizer.py +306 -0
- ouncemcp-1.0.0rc1/tests/test_bud7_9_output_schemas.py +294 -0
- ouncemcp-1.0.0rc1/tests/test_budget_tokens.py +48 -0
- ouncemcp-1.0.0rc1/tests/test_cap2_resources_prompts.py +156 -0
- ouncemcp-1.0.0rc1/tests/test_cap7_composite.py +119 -0
- ouncemcp-1.0.0rc1/tests/test_cli.py +32 -0
- ouncemcp-1.0.0rc1/tests/test_client_broker.py +212 -0
- ouncemcp-1.0.0rc1/tests/test_costs.py +35 -0
- ouncemcp-1.0.0rc1/tests/test_disc_discovery.py +785 -0
- ouncemcp-1.0.0rc1/tests/test_dx1_dx2_init_dev.py +149 -0
- ouncemcp-1.0.0rc1/tests/test_dx3_schema_lints.py +143 -0
- ouncemcp-1.0.0rc1/tests/test_dx5_trace_viewer.py +128 -0
- ouncemcp-1.0.0rc1/tests/test_dx6_doc_links.py +83 -0
- ouncemcp-1.0.0rc1/tests/test_dx7_wrap.py +81 -0
- ouncemcp-1.0.0rc1/tests/test_err_errors.py +483 -0
- ouncemcp-1.0.0rc1/tests/test_eval1_conformance_fixtures.py +127 -0
- ouncemcp-1.0.0rc1/tests/test_eval2_security_catalog.py +172 -0
- ouncemcp-1.0.0rc1/tests/test_eval_agent_suites.py +188 -0
- ouncemcp-1.0.0rc1/tests/test_eval_openrouter.py +163 -0
- ouncemcp-1.0.0rc1/tests/test_exe4_idempotency.py +311 -0
- ouncemcp-1.0.0rc1/tests/test_exe5_parallel_safe.py +76 -0
- ouncemcp-1.0.0rc1/tests/test_exe_execution.py +778 -0
- ouncemcp-1.0.0rc1/tests/test_jobs_resume.py +168 -0
- ouncemcp-1.0.0rc1/tests/test_lints.py +107 -0
- ouncemcp-1.0.0rc1/tests/test_m2_ops.py +160 -0
- ouncemcp-1.0.0rc1/tests/test_package.py +28 -0
- ouncemcp-1.0.0rc1/tests/test_pilot_markitdown.py +121 -0
- ouncemcp-1.0.0rc1/tests/test_pilot_ticketing.py +126 -0
- ouncemcp-1.0.0rc1/tests/test_provider_tokens.py +136 -0
- ouncemcp-1.0.0rc1/tests/test_res11_handler_hints.py +84 -0
- ouncemcp-1.0.0rc1/tests/test_res5_handles_jobs.py +161 -0
- ouncemcp-1.0.0rc1/tests/test_res8_conformance.py +205 -0
- ouncemcp-1.0.0rc1/tests/test_res9_pagination.py +143 -0
- ouncemcp-1.0.0rc1/tests/test_safe_writes.py +210 -0
- ouncemcp-1.0.0rc1/tests/test_schema.py +34 -0
- ouncemcp-1.0.0rc1/tests/test_sec10_oauth.py +139 -0
- ouncemcp-1.0.0rc1/tests/test_sec12_cursors.py +458 -0
- ouncemcp-1.0.0rc1/tests/test_sec9_fetch.py +173 -0
- ouncemcp-1.0.0rc1/tests/test_sec9_urls.py +53 -0
- ouncemcp-1.0.0rc1/tests/test_sec_security.py +568 -0
- ouncemcp-1.0.0rc1/tests/test_server.py +149 -0
- ouncemcp-1.0.0rc1/tests/test_shaping.py +76 -0
- ouncemcp-1.0.0rc1/tests/test_shaping_fit.py +237 -0
- ouncemcp-1.0.0rc1/tests/test_stdio_e2e.py +44 -0
- ouncemcp-1.0.0rc1/tests/test_stdio_policy.py +123 -0
- ouncemcp-1.0.0rc1/tests/test_ui_report.py +163 -0
- ouncemcp-1.0.0rc1/ui/report/.gitignore +1 -0
- ouncemcp-1.0.0rc1/ui/report/build.sh +11 -0
- ouncemcp-1.0.0rc1/ui/report/index.html +14 -0
- ouncemcp-1.0.0rc1/ui/report/licenses.mjs +33 -0
- ouncemcp-1.0.0rc1/ui/report/package-lock.json +6591 -0
- ouncemcp-1.0.0rc1/ui/report/package.json +37 -0
- ouncemcp-1.0.0rc1/ui/report/src/App.tsx +53 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/cost-bar.tsx +51 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/stat-card.tsx +40 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/theme-toggle.tsx +51 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/badge.tsx +47 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/button.tsx +63 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/card.tsx +91 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/input.tsx +20 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/progress.tsx +30 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/select.tsx +189 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/separator.tsx +27 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/table.tsx +115 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/tabs.tsx +90 -0
- ouncemcp-1.0.0rc1/ui/report/src/components/ui/tooltip.tsx +56 -0
- ouncemcp-1.0.0rc1/ui/report/src/index.css +91 -0
- ouncemcp-1.0.0rc1/ui/report/src/lib/format.ts +17 -0
- ouncemcp-1.0.0rc1/ui/report/src/lib/utils.ts +6 -0
- ouncemcp-1.0.0rc1/ui/report/src/main.tsx +31 -0
- ouncemcp-1.0.0rc1/ui/report/src/reports/audit-report.tsx +196 -0
- ouncemcp-1.0.0rc1/ui/report/src/reports/bench-report.tsx +259 -0
- ouncemcp-1.0.0rc1/ui/report/src/reports/context-report.tsx +210 -0
- ouncemcp-1.0.0rc1/ui/report/src/reports/eval-report.tsx +259 -0
- ouncemcp-1.0.0rc1/ui/report/src/reports/trace-report.tsx +444 -0
- ouncemcp-1.0.0rc1/ui/report/src/sample.ts +45 -0
- ouncemcp-1.0.0rc1/ui/report/src/types.ts +172 -0
- ouncemcp-1.0.0rc1/ui/report/tsconfig.json +17 -0
- ouncemcp-1.0.0rc1/ui/report/vite.config.ts +17 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to OunceMCP. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [semantic versioning](https://semver.org/) with the promises in [proposal 0029](https://github.com/subbusainath/ouncemcp/blob/main/docs/proposals/0029-api-freeze.md).
|
|
4
|
+
|
|
5
|
+
## 1.0.0rc1 (15 November 2026)
|
|
6
|
+
|
|
7
|
+
Release candidate for 1.0.0. Install it with `pip install --pre ouncemcp` or `pipx install "ouncemcp==1.0.0rc1"`. 1.0.0 follows the external security review; the API below will not change before it unless the review requires it.
|
|
8
|
+
|
|
9
|
+
The first stable release. The public API is frozen: names listed as stable in proposal 0029 do not change in a breaking way before 2.0.
|
|
10
|
+
|
|
11
|
+
### Stable
|
|
12
|
+
|
|
13
|
+
- **Server and tools** (`ouncemcp`): `OunceServer` with typed tools, declared effects, resources, prompts and background jobs; `ToolContext`; budgets and per-tool overrides; response shaping with `Detail`, `Paginated` and signed `Cursor`s; automatic discovery; errors in eight categories; deadlines, retries and limits; stores, idempotent writes and approvals; handles and resumable jobs; tokenizers and cost reports.
|
|
14
|
+
- **Security** (`ouncemcp.security`): verified identity, policies, partitioned caches, signed state, safe outbound fetches and token-passthrough guards.
|
|
15
|
+
- **Clients** (`ouncemcp.client`): the `Broker` over many servers and `OunceOAuth`.
|
|
16
|
+
- **Traces** (`ouncemcp.trace`): the tracer, its sinks and redaction.
|
|
17
|
+
- **Testing** (`ouncemcp.testing`) and the **security suite** (`ouncemcp.eval`).
|
|
18
|
+
- **Contracts outside Python:** error categories and codes, `_meta["ouncemcp"]` keys, the `handles.read` and `jobs.get` tools, command names, flags and exit codes, report `report_version`, and lint rule names.
|
|
19
|
+
|
|
20
|
+
### Provisional
|
|
21
|
+
|
|
22
|
+
May change in a minor release, with the change named here: `ouncemcp.eval.agent` (task suites and models), `ouncemcp.eval.bench`, `ouncemcp.ui` and `AnthropicCounter`.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `AnthropicCounter` and `--tokenizer anthropic:MODEL`: token counts from Anthropic's counting API, through the official SDK (`pip install "ouncemcp[anthropic]"`). Provisional (spec BUD-6).
|
|
27
|
+
|
|
28
|
+
### Deprecated
|
|
29
|
+
|
|
30
|
+
- `ouncemcp.security.resolve_http_options` and `ouncemcp.security.partition_key` are internal. They still work but raise a `DeprecationWarning`, and will be removed in 1.1. `OunceServer.run` and `PartitionedCache` use them for you.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- FastMCP is supported as a range, `>=4.1.6,<5`, instead of an exact pin. CI tests the lowest version (the lockfile) and the newest release in the range.
|
|
35
|
+
|
|
36
|
+
### Supported versions
|
|
37
|
+
|
|
38
|
+
- Python 3.11, 3.12 and 3.13.
|
|
39
|
+
- FastMCP 4.1.6 and later 4.x releases.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Contributing to OunceMCP
|
|
2
|
+
|
|
3
|
+
OunceMCP is pre-alpha. The best contributions right now are feedback on the [specification](docs/spec.md) through issues.
|
|
4
|
+
|
|
5
|
+
## Good first contributions
|
|
6
|
+
|
|
7
|
+
These are designed to be small and self-contained:
|
|
8
|
+
|
|
9
|
+
- New lint rules for tool definitions, each with a fixture that triggers it and a documentation page.
|
|
10
|
+
- New benchmark servers or task suites with verifiable outcomes.
|
|
11
|
+
- Documentation fixes.
|
|
12
|
+
|
|
13
|
+
## Development
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
uv venv && uv pip install -e ".[dev]"
|
|
17
|
+
uv run pytest
|
|
18
|
+
uv run ruff check .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Pull requests
|
|
22
|
+
|
|
23
|
+
- Keep changes focused and include tests.
|
|
24
|
+
- Changes to the public API or default behavior need a design proposal in `docs/proposals/`.
|
|
25
|
+
- Any change that affects token usage should state its measured effect.
|
|
26
|
+
|
|
27
|
+
By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
28
|
+
|
|
29
|
+
## Public API changes
|
|
30
|
+
|
|
31
|
+
`tests/test_api_surface.py` records every exported name and public signature of `ouncemcp`, `ouncemcp.security`, `ouncemcp.client`, `ouncemcp.eval.agent`, `ouncemcp.testing` and `ouncemcp.ui` in `tests/api_snapshot.json`. A change to the public API fails it on purpose. If the change is intended, regenerate the snapshot with `OUNCEMCP_UPDATE_API_SNAPSHOT=1 uv run pytest tests/test_api_surface.py` and explain the change in the PR. After 1.0, removing or changing a public name needs a deprecation first.
|
|
32
|
+
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
202
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ouncemcp
|
|
3
|
+
Version: 1.0.0rc1
|
|
4
|
+
Summary: Build MCP servers and clients that are fast, low-noise, and safe for agents by default.
|
|
5
|
+
Project-URL: Homepage, https://subbusainath.github.io/ouncemcp/
|
|
6
|
+
Project-URL: Documentation, https://subbusainath.github.io/ouncemcp/
|
|
7
|
+
Project-URL: Repository, https://github.com/subbusainath/ouncemcp
|
|
8
|
+
Project-URL: Changelog, https://github.com/subbusainath/ouncemcp/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/subbusainath/ouncemcp/issues
|
|
10
|
+
Author: Subbusainath Rengasamy
|
|
11
|
+
License-Expression: Apache-2.0
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: agents,fastmcp,llm,mcp,model-context-protocol
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: fastmcp<5,>=4.1.6
|
|
23
|
+
Requires-Dist: jsonschema>=4.20
|
|
24
|
+
Requires-Dist: pydantic<3,>=2.11
|
|
25
|
+
Requires-Dist: tiktoken==0.14.0
|
|
26
|
+
Provides-Extra: anthropic
|
|
27
|
+
Requires-Dist: anthropic<3,>=2.3; extra == 'anthropic'
|
|
28
|
+
Provides-Extra: client
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: anthropic<3,>=2.3; extra == 'dev'
|
|
31
|
+
Requires-Dist: anyio>=4; extra == 'dev'
|
|
32
|
+
Requires-Dist: hypothesis>=6.100; extra == 'dev'
|
|
33
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
34
|
+
Requires-Dist: opentelemetry-sdk>=1.28; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
36
|
+
Requires-Dist: pyyaml>=6; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
38
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: mkdocs-material==9.8.1; extra == 'docs'
|
|
41
|
+
Requires-Dist: mkdocs==1.6.1; extra == 'docs'
|
|
42
|
+
Requires-Dist: mkdocstrings-python==2.0.11; extra == 'docs'
|
|
43
|
+
Requires-Dist: mkdocstrings==1.0.8; extra == 'docs'
|
|
44
|
+
Provides-Extra: eval
|
|
45
|
+
Requires-Dist: pyyaml>=6; extra == 'eval'
|
|
46
|
+
Provides-Extra: otel
|
|
47
|
+
Requires-Dist: opentelemetry-api>=1.28; extra == 'otel'
|
|
48
|
+
Provides-Extra: ui
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
|
|
51
|
+
# OunceMCP
|
|
52
|
+
|
|
53
|
+
**Every token counts.** OunceMCP is a framework for building Model Context Protocol (MCP) servers and clients that are fast, low-noise, and safe for agents by default. It builds on [FastMCP](https://gofastmcp.com) and the official MCP Python SDK, and targets the MCP `2026-07-28` specification.
|
|
54
|
+
|
|
55
|
+
> **Status: pre-1.0 (M0 to M4 built).** The framework, safe writes, jobs, the client broker, the eval kit, the trace viewer and the benchmark work and are tested; the official MCP conformance suite passes in CI and the M4 performance gates are met ([M4 report](docs/m4-report.md)). The 1.0 API is frozen ([proposal 0029](docs/proposals/0029-api-freeze.md), [changelog](CHANGELOG.md)); 1.0 ships after the external security review. Release gates that need people or outside systems are listed in the [spec](docs/spec.md) (section 14.2). New here? Read [The OunceMCP Book](docs/book/index.md).
|
|
56
|
+
|
|
57
|
+
## Why
|
|
58
|
+
|
|
59
|
+
Most MCP slowdowns don't come from the protocol. They come from loading every tool definition up front, returning large raw results, and making the model chain many small calls. OunceMCP makes the efficient design the default one:
|
|
60
|
+
|
|
61
|
+
- **Context budgets:** token limits for tool definitions, the startup catalog, and each result, checked in CI.
|
|
62
|
+
- **Automatic discovery:** switches from exposing every tool to search-then-call once the catalog is too large.
|
|
63
|
+
- **Response shaping:** concise results by default, field selection, pagination, truncation notes, and handles for large data.
|
|
64
|
+
- **Safe execution:** declared effects, deadlines, bounded retries, idempotent writes, and approvals.
|
|
65
|
+
- **Visibility:** see exactly what the model received and what it cost.
|
|
66
|
+
- **Optional audit:** measure any MCP server, including ones not built with OunceMCP.
|
|
67
|
+
|
|
68
|
+
## Quickstart
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pipx install "ouncemcp==1.0.0rc1" # or: uv tool install --prerelease allow ouncemcp
|
|
72
|
+
ouncemcp init notes-server && cd notes-server
|
|
73
|
+
uv venv && uv pip install --prerelease allow -e ".[dev]"
|
|
74
|
+
uv run pytest && uv run ouncemcp dev server.py
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The full walkthrough is in [docs/quickstart.md](docs/quickstart.md). To learn the framework step by step, read [The OunceMCP Book](docs/book/index.md): one library server built across 15 chapters, every stage tested. A tool looks like this:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from typing import Annotated
|
|
81
|
+
|
|
82
|
+
from pydantic import BaseModel, Field
|
|
83
|
+
|
|
84
|
+
from ouncemcp import Cursor, Detail, Effect, OunceServer, Paginated, ToolContext
|
|
85
|
+
|
|
86
|
+
server = OunceServer("inventory")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class SearchInput(BaseModel):
|
|
90
|
+
region: str = Field(description="Region, e.g. ap-south-1")
|
|
91
|
+
limit: int = Field(20, ge=1, le=50)
|
|
92
|
+
cursor: str | None = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class Resource(BaseModel):
|
|
96
|
+
id: str
|
|
97
|
+
name: str
|
|
98
|
+
status: str
|
|
99
|
+
tags: Annotated[dict[str, str] | None, Detail] = None # only with response_format=detailed
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class SearchResult(BaseModel):
|
|
103
|
+
items: Annotated[list[Resource], Paginated]
|
|
104
|
+
next_cursor: Cursor = None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@server.tool(name="inventory.search", effect=Effect.READ, deadline_ms=5_000)
|
|
108
|
+
async def search(args: SearchInput, ctx: ToolContext) -> SearchResult:
|
|
109
|
+
"""Find cloud resources in a region."""
|
|
110
|
+
rows = await load_resources(args.region)
|
|
111
|
+
page = ctx.page(rows, cursor=args.cursor, limit=args.limit)
|
|
112
|
+
return SearchResult(items=page.items, next_cursor=page.next_cursor)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
server.run() # stdio; prints a token budget summary to stderr
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
What you get:
|
|
120
|
+
|
|
121
|
+
- **Declared effects:** `effect` is required and maps to MCP `readOnlyHint` and `destructiveHint`.
|
|
122
|
+
- **Typed inputs and outputs:** Pydantic models in, Pydantic models out, validated both ways.
|
|
123
|
+
- **Compact schemas:** optional fields are advertised without the `anyOf`/`null` noise.
|
|
124
|
+
- **Concise by default:** fields marked `Detail` are only returned when the agent asks for `response_format="detailed"`.
|
|
125
|
+
- **Result budgets:** every result fits its token budget and still matches its output schema. Lists are trimmed first, then long strings, then optional fields, and the agent gets a note saying what was removed and how to get more. If the smallest valid result is still too large, the agent gets an `isError` result asking for a narrower call instead of broken JSON.
|
|
126
|
+
- **Safe pagination:** mark the page list `Paginated` and the cursor `Cursor`, and use `ctx.page(...)`. If OunceMCP trims the page to fit the budget, it moves `next_cursor` so the next call resumes after the last item returned. No item is skipped or repeated. Lists are never trimmed below `min_items` (default 1). Cursors are signed: they expire, and only work for the same tool, caller and filters. Set `OUNCEMCP_CURSOR_KEYS` in production ([proposal 0003](docs/proposals/0003-signed-cursors.md)).
|
|
127
|
+
- **Automatic discovery:** `OunceServer(discovery="auto")` (the default) sends every tool while the definitions fit `Budget.startup_tokens`. Above it, the server sends `search_tools`, `describe_tool` and `call_tool` instead (279 tokens whatever the catalog), plus any `pinned` tools. Search results come in three detail levels (`name`, `summary`, `full`) and only include tools the caller is authorized to use (`@server.tool(auth=...)`). Hiding a tool is not access control: the same check runs on a guessed name. `discovery="direct"` or `"search"` overrides the choice, and `await server.measure_recall(cases)` reports how often search finds the tools agents need. See [proposal 0006](docs/proposals/0006-discovery-modes.md).
|
|
128
|
+
- **Categorized errors:** every failure is one of validation, authentication, permission, not found, rate limit, transient, ambiguous write or internal, with a `retryable` flag. Validation messages say how to fix the input without repeating it. Unexpected exceptions are never shown to the model: it gets a reference id and the details go to the log. Messages you write are redacted for URLs, addresses, hostnames, paths and credentials. Raise `InvalidInput`, `NotFound`, `RateLimited` and the other `OunceError` classes from handlers.
|
|
129
|
+
- **Execution limits:** every call has a deadline (default 30 s) and is cancelled when it passes or the client cancels. Reads are retried a few times with bounded backoff inside the deadline, and writes never are. A write that times out is reported as ambiguous, not as failed. Request size, nesting depth and calls in flight per principal are bounded (`Limits`). See [proposal 0007](docs/proposals/0007-errors-and-execution-limits.md).
|
|
130
|
+
- **Security and policy:** `ctx.identity` comes from the verified token only. `policy=` on the server or a tool decides who sees and calls it, on the declared effect, never on annotations. `audience=` refuses tokens issued for other servers, `passthrough_guard()` stops the caller's token from reaching upstream APIs, `ctx.cache` is partitioned by tenant, `ctx.issue_state` hands out handles and approvals bound to caller, request and expiry, and HTTP binds to loopback with `Host` and `Origin` checks ([proposal 0008](docs/proposals/0008-security-and-policy.md)).
|
|
131
|
+
- **Safe writes:** `idempotency=True` runs a write once per caller and arguments, and a write that times out finishes in the background so a retry gets its result instead of writing twice. `approval="required"` with a `preview` asks a person first, through the client, and refuses when nobody can be asked ([safe writes](docs/guides/safe-writes.md)).
|
|
132
|
+
- **Large results and slow work:** `OunceServer(handles=True)` adds `handles.read` and `jobs.get`. `await ctx.store_result(rows)` returns a handle to page, and `await ctx.start_job(work)` runs work in the background. Both work across replicas with a shared `RedisStore`.
|
|
133
|
+
- **Resources and prompts:** `@server.resource(uri)` and `@server.prompt()` get the same budgets, policies and verified caller as tools.
|
|
134
|
+
- **Migration and audit:** `OunceServer.wrap(existing_fastmcp_server)` adds all of the above without touching its tools, and `ouncemcp audit <url | file | -- command>` measures any MCP server ([migration guide](docs/guides/migrating-from-fastmcp.md)).
|
|
135
|
+
- **Many servers:** `ouncemcp.client.Broker` connects a host to many servers as one catalog, with namespaced tools, cross-server search, schema checks, deadlines, failure isolation, and no cross-server authority from server output ([broker](docs/guides/client-broker.md)).
|
|
136
|
+
- **Operations:** `OunceServer.from_config(name, "ouncemcp.toml")`, `/healthz`, `/readyz` and, with `metrics=True`, Prometheus `/metrics` ([deploying](docs/guides/deploying-http.md)).
|
|
137
|
+
- **Traces:** `OunceServer(trace=MemorySink())` records each call's result tokens, latency, retries and outcome, redacted by default ([proposal 0009](docs/proposals/0009-traces.md)). `ouncemcp trace calls.jsonl` writes an HTML report you can search and filter ([proposal 0020](docs/proposals/0020-report-ui.md)), and `OTelSink()` exports spans to OpenTelemetry ([proposal 0018](docs/proposals/0018-trace-viewer.md)).
|
|
138
|
+
- **Task suites:** `ouncemcp eval suite.yaml` runs YAML tasks against a server, judges outcomes on the server, and reports success, tool choice, tokens, latency and regressions against a baseline ([proposal 0019](docs/proposals/0019-eval-kit.md)).
|
|
139
|
+
- **Composite tools:** `ctx.gather(...)` runs several upstream calls in one tool call. The example `inventory.cost_review` returns 651 tokens in 1 call where paging `inventory.search` takes 9,896 tokens over 8 calls.
|
|
140
|
+
- **Testing:** `ouncemcp.testing.as_caller(...)` runs code as a verified caller, and `ouncemcp.eval.run_security_suite(server, cases)` probes for cross-tenant leaks, guessed names, cursor and handle reuse, replay, token passthrough and SSRF.
|
|
141
|
+
- **Budget checks:** `ouncemcp check server.py` counts the tokens of every tool definition as the host receives it, and fails CI when a tool goes over budget or a lint error is found. It also reports which discovery mode the server will use and why. Every lint and error links to a page explaining it.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
ouncemcp check examples/inventory/server.py
|
|
145
|
+
ouncemcp context examples/inventory/server.py inventory.search
|
|
146
|
+
ouncemcp context examples/inventory/server.py --html context.html # every tool, as a page
|
|
147
|
+
ouncemcp dev examples/inventory/server.py # hot reload, live per-call token lines
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Counts use `o200k_base` by default. Choose another tiktoken encoding with `OunceServer(tokenizer="cl100k_base")` or `ouncemcp check --tokenizer cl100k_base`, or pass your own counting function with `tokenizer=fn, tokenizer_name="my-tokenizer-v1"`. Every report names the tokenizer it used ([proposal 0004](docs/proposals/0004-pluggable-tokenizer.md)).
|
|
151
|
+
|
|
152
|
+
`ouncemcp audit` is the optional command for measuring any server. `ouncemcp eval` runs task suites, with the replay model or real models through OpenRouter, `ouncemcp bench` compares servers across models, and `ouncemcp trace` reads traces.
|
|
153
|
+
|
|
154
|
+
## Benchmark (M3)
|
|
155
|
+
|
|
156
|
+
Two pilot servers against their plain FastMCP equivalents: four models (Claude Haiku 5.5, Claude Sonnet 5.5, GPT-5.4 mini, DeepSeek V4.1 Flash), 21 tasks, 5 runs each, success judged on outcomes. See the [full results and caveats](benchmarks/results/m3-bench.md).
|
|
157
|
+
|
|
158
|
+
| | Inventory (large results) | Ticketing (writes, small results) |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| Tokens per task, OunceMCP vs plain | 58–85% fewer | 17–40% more |
|
|
161
|
+
| Task success, OunceMCP vs plain | 100% vs 75–100% | 100% vs 68–70% |
|
|
162
|
+
| Tool definitions, OunceMCP vs plain | 584 vs 244 tokens | 649 vs 366 tokens |
|
|
163
|
+
|
|
164
|
+
On these small servers the definitions are larger, mostly from output schemas. PERF-6, revised for small servers (definitions at most 2× plain, no drop in success), is met for ticketing and missed for inventory at 2.4× ([proposal 0027](docs/proposals/0027-benchmark.md)). On the plain ticketing server every model skipped the approval, deleted without permission and read another team's ticket.
|
|
165
|
+
|
|
166
|
+
## M0 results
|
|
167
|
+
|
|
168
|
+
Measured on the inventory example with the `o200k_base` tokenizer. Full method and caveats are in [docs/m0-report.md](docs/m0-report.md).
|
|
169
|
+
|
|
170
|
+
| | OunceMCP | Plain FastMCP |
|
|
171
|
+
| --- | ---: | ---: |
|
|
172
|
+
| Tool definitions (2 tools) | 488 tokens | 195 tokens |
|
|
173
|
+
| Four-task session, definitions plus results | 1,510 tokens | 32,280 tokens |
|
|
174
|
+
| Added server time per call, p50 / p95 | 0.14–0.44 ms / 0.07–0.47 ms (1.44 / 1.32 ms when truncating) | baseline |
|
|
175
|
+
|
|
176
|
+
In M1, results that are trimmed must still match the output schema. Truncated calls now add 0.70 / 0.80 ms (p50 / p95) and other calls 0.14 to 0.31 ms. Shaping a 36,000-token result down to a 2,000-token budget takes 7.3 ms. See [proposal 0002](docs/proposals/0002-schema-safe-shaping-and-pagination.md) and `benchmarks/scripts/m1_truncation.py`.
|
|
177
|
+
|
|
178
|
+
Typed output schemas make definitions larger. Results are where the savings come from. Output schemas can be set to `"on"` (default), `"off"` or `"auto"` for a server (`output_schemas=`) or one tool (`output_schema=`). In M1, `"off"` gave 247 tokens for this example, and `"auto"`, which drops a schema only where it would put a definition over the per-tool target, gave 378. `ouncemcp check` reports the output-schema share of definition tokens (241 of 504 in the current example) and states which fields it counts: `name`, `description`, `inputSchema` and `outputSchema`, not `title`, `annotations` or `_meta` ([proposal 0005](docs/proposals/0005-counting-scope-and-output-schema-modes.md)).
|
|
179
|
+
|
|
180
|
+
## Repository layout
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
src/ouncemcp/
|
|
184
|
+
core/ capabilities, budgets, response shaping, token accounting, errors, lints,
|
|
185
|
+
resources and prompts, config file
|
|
186
|
+
security/ identity, policy, audience and passthrough, caches, bound state, HTTP
|
|
187
|
+
defaults, stdio policy, URL checks
|
|
188
|
+
discovery/ direct and search discovery modes
|
|
189
|
+
execution/ deadlines, retries, limits, middleware, store, idempotency, approvals,
|
|
190
|
+
handles and jobs
|
|
191
|
+
trace/ per-call traces, redaction and metrics
|
|
192
|
+
eval/ conformance target, security test catalog and agent task suites
|
|
193
|
+
cli/ init, dev, check, context, audit, eval, trace (bench planned)
|
|
194
|
+
client/ reference client broker
|
|
195
|
+
audit/ optional audit command
|
|
196
|
+
testing.py as_caller and make_token for tests
|
|
197
|
+
examples/ pilot servers: inventory, ticketing, report, markitdown migration
|
|
198
|
+
benchmarks/ servers, tasks, scripts, published results
|
|
199
|
+
docs/ specification, research, concepts, guides, proposals
|
|
200
|
+
tests/
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Roadmap
|
|
204
|
+
|
|
205
|
+
| Milestone | Scope | Status |
|
|
206
|
+
| --- | --- | --- |
|
|
207
|
+
| M0: core spike | `OunceServer`, typed tools with effects, token counting, result budgets, one example server | Built ([M0 report](docs/m0-report.md)) |
|
|
208
|
+
| M1: v0.1 | Framework core, automatic discovery, errors, security, `init`/`dev`/`check`/`context`, docs | Built |
|
|
209
|
+
| M2: v0.2 | Safe writes, client broker, migration guide, pilots, optional `audit` | Built ([M2 report](docs/m2-report.md)) |
|
|
210
|
+
| M3: v0.5 | Eval kit, trace viewer, public benchmark, launch | Built ([benchmark](benchmarks/results/m3-bench.md)); launch waits on the repository going public |
|
|
211
|
+
| M4: v1.0 | Security review, host compatibility matrix, stable API, the book | API frozen ([0029](docs/proposals/0029-api-freeze.md)), all release gates checked, release workflow ready ([M4 report](docs/m4-report.md)); waiting on the external security review |
|
|
212
|
+
|
|
213
|
+
The full plan is in [docs/spec.md](docs/spec.md), and the supporting research is in [docs/performance-research.md](docs/performance-research.md).
|
|
214
|
+
|
|
215
|
+
## Development
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
uv venv && uv pip install -e ".[dev]"
|
|
219
|
+
uv run pytest
|
|
220
|
+
uv run ruff check .
|
|
221
|
+
uv pip install -e ".[docs]" && uv run mkdocs serve # documentation site
|
|
222
|
+
python benchmarks/scripts/m0_compare.py # token comparison
|
|
223
|
+
python benchmarks/scripts/m0_overhead.py # per-call overhead
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Contributing
|
|
227
|
+
|
|
228
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Security issues: see [SECURITY.md](SECURITY.md).
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
[Apache-2.0](LICENSE)
|