asap-protocol 2.4.1__tar.gz → 2.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.
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/CHANGELOG.md +70 -1
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/PKG-INFO +5 -5
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/README.md +3 -3
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/pyproject.toml +15 -9
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/__init__.py +1 -1
- asap_protocol-2.5.0/src/asap/adapters/mcp/__init__.py +17 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/auth_middleware.py +33 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/capability_map.py +74 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/config.py +70 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/errors.py +32 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/jwt_extractor.py +52 -0
- asap_protocol-2.5.0/src/asap/adapters/mcp/protected_server.py +176 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/jwks.py +10 -1
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/middleware.py +19 -5
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/delegation_storage.py +13 -2
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/storage.py +2 -3
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/client.py +19 -2
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/protocol.py +1 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/server.py +15 -3
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/registry/bot_pr.py +30 -35
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/.gitignore +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/LICENSE +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/agent.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/artifact.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/conversation.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/manifest.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/message.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/state_snapshot.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/entities/task.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/envelope.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/examples/shellclaw-jetson-capabilities.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/parts/data_part.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/parts/file_part.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/parts/resource_part.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/parts/template_part.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/parts/text_part.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/artifact_notify.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/mcp_resource_data.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/mcp_resource_fetch.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/mcp_tool_call.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/mcp_tool_result.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/message_send.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/state_query.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/state_restore.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/task_cancel.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/task_request.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/task_response.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/schemas/payloads/task_update.schema.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/approval.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/capability_mapper.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/factory.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/handler.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/adapters/openapi/spec_loader.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/agent_jwt.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/approval.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/capabilities.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/claims.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/identity.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/introspection.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/lifecycle.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/oauth2.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/oidc.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/scopes.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/self_auth.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/utils.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/auth/webauthn.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/cli/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/cli/audit_export.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/cli/compliance_check.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/cache.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/http_client.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/market.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/revocation.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/client/trust.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/keys.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/models.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/signing.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/trust.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/crypto/trust_levels.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/dnssd.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/health.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/registry.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/validation.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/discovery/wellknown.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/audit.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/delegation.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/hooks.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/metering.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/sla.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/economics/sla_storage.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/errors.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/README.md +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/a2h_approval.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/agent_failover.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/auth_patterns.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/coordinator.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/echo_agent.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/error_recovery.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/long_running.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/mcp_client_demo.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/mcp_integration.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/multi_step_workflow.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/orchestration.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/rate_limiting.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/run_demo.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/secure_agent.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/secure_handler.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/state_migration.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/storage_backends.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/streaming_agent.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/streaming_response.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/v1_3_0_showcase.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/v1_4_0_showcase.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/examples/websocket_concept.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/handlers/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/handlers/hitl.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/a2h.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/crewai.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/langchain.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/llamaindex.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/openclaw.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/pydanticai.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/smolagents.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/integrations/vercel_ai.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/serve.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/mcp/server_runner.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/base.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/constants.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/entities.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/enums.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/envelope.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/ids.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/parts.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/payloads.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/types.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/models/validators.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/dashboards/README.md +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/dashboards/asap-detailed.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/dashboards/asap-red.json +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/logging.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/metrics.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/trace_parser.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/trace_ui.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/observability/tracing.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/registry/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/registry/anti_spam.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/registry/auto_registration.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/registry/receipt_cache.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/schemas.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/machine.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/metering.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/snapshot.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/stores/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/stores/memory.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/state/stores/sqlite.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/asgi_factory.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/assertions.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/compliance.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/fixtures.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/testing/mocks.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/_auth_helpers.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/agent_routes.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/cache.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/capability_routes.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/challenge.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/circuit_breaker.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/client.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/codecs/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/codecs/lambda_codec.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/compression.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/delegation_api.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/escalation_routes.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/executors.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/handlers.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/jsonrpc.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/middleware.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/mtls.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/rate_limit.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/server.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/sla_api.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/usage_api.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/validators.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/webhook.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/transport/websocket.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/utils/__init__.py +0 -0
- {asap_protocol-2.4.1 → asap_protocol-2.5.0}/src/asap/utils/sanitization.py +0 -0
|
@@ -12,7 +12,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
12
12
|
- `extra="forbid"` on ingress payload models (`TaskRequestConfig`, `CommonMetadata`)
|
|
13
13
|
- Opt-in protection for operator APIs (`/usage`, `/sla`, `/audit`)
|
|
14
14
|
- Redis-backed `JtiReplayCache` and distributed Next.js rate limits
|
|
15
|
-
-
|
|
15
|
+
- `@asap-protocol/mcp-auth` HTTP/SSE middleware (deferred from v2.5.0 — see [2.5.0] TypeScript note and [typescript-mcp-auth-spike.md](engineering/tasks/v2.5.0/typescript-mcp-auth-spike.md))
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **CI security (`pip-audit`)**: Raised `cryptography` to `>=48.0.1,<49` (GHSA-537c-gmf6-5ccf), `python-multipart>=0.0.31` (CVE-2026-53538–53540), and `starlette>=1.3.1` (CVE-2026-54282 / CVE-2026-54283) via `pyproject.toml` floors and `tool.uv.override-dependencies`.
|
|
20
|
+
- **pydantic-ai (CVE-2026-46678)**: Optional `[pydanticai]` extra pins `pydantic-ai>=1.99.0`; removed obsolete `pip-audit` ignore from CI.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## [2.5.0] - 2026-06-24
|
|
25
|
+
|
|
26
|
+
**MCP Auth Bridge** — ASAP Host/Agent JWT and capability grants as an **opt-in**
|
|
27
|
+
authorization layer for native **stdio MCP** `tools/call` (Mode A). Unprotected
|
|
28
|
+
`MCPServer` usage is unchanged. No wire-protocol or manifest schema breaking
|
|
29
|
+
changes.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **feat(adapters): MCP Auth Bridge (`asap.adapters.mcp`)**
|
|
34
|
+
- **`protect_server(server, config)`** — wraps `MCPServer` via
|
|
35
|
+
`ProtectedMCPServer`; intercepts `_handle_tools_call` only (MCP-AUTH-006).
|
|
36
|
+
- **`MCPAuthConfig`** (`config.py`) — `host_store`, `agent_store`,
|
|
37
|
+
`capability_registry`, `tool_capability_map`, `public_tools`,
|
|
38
|
+
`enforce_grants`, `jwt_extractor`, `jti_replay_cache`, `expected_audience`.
|
|
39
|
+
- **Token carriage (stdio)** — Agent JWT in `tools/call` params
|
|
40
|
+
`_meta.asap_agent_jwt`; optional dev-only `ASAP_AGENT_JWT` when
|
|
41
|
+
`allow_env_jwt_fallback=True`.
|
|
42
|
+
- **Grant enforcement** — `verify_agent_jwt` + `CapabilityRegistry.check_grant`
|
|
43
|
+
with constraint validation on tool arguments; MCP-safe `asap:*` error codes
|
|
44
|
+
(`asap:auth_required`, `asap:invalid_token`, `asap:capability_denied`,
|
|
45
|
+
`asap:constraint_violation`).
|
|
46
|
+
- **Tool → capability mapping** — explicit `tool_capability_map`, register-time
|
|
47
|
+
metadata, or default identity (tool name == capability); optional startup
|
|
48
|
+
validation (`validate_tools_at_startup`).
|
|
49
|
+
- **Reference example** — `examples/mcp_auth_bridge/` (protected stdio server +
|
|
50
|
+
client, smoke tests in `tests/examples/test_mcp_auth_bridge_example.py`).
|
|
51
|
+
- **Docs** — [MCP Auth Bridge adapter](docs/adapters/mcp-auth-bridge.md);
|
|
52
|
+
[MCP integration](docs/mcp-integration.md) distinguishes Mode A (native MCP +
|
|
53
|
+
bridge) vs Mode B (MCP-over-ASAP envelope).
|
|
54
|
+
- **feat(compliance): `mcp-auth-bridge` profile** (`asap-compliance`) — stdio MCP
|
|
55
|
+
release gate: auth paths, grants, constraints, manifest tools ⊆ registered
|
|
56
|
+
tools (MCP-DISC-003). Requires `asap-protocol>=2.5.0`.
|
|
57
|
+
- **test(adapters/mcp)** — unit, grant, startup, and stdio integration coverage
|
|
58
|
+
(≥90% on `asap.adapters.mcp`).
|
|
59
|
+
|
|
60
|
+
### Deferred (not in v2.5.0)
|
|
61
|
+
|
|
62
|
+
- **`hide_unauthorized_tools` / `tools/list` filtering** (MCP-MAP-004) — no
|
|
63
|
+
standard JWT carriage on stdio `tools/list` today; see
|
|
64
|
+
[design lock](engineering/tasks/v2.5.0/design-lock-mcp-auth-bridge.md).
|
|
65
|
+
- **`initialize` session-token handshake** (PRD §4.3 SHOULD) — clients pass JWT
|
|
66
|
+
on each protected `tools/call` in v2.5.0.
|
|
67
|
+
|
|
68
|
+
### TypeScript
|
|
69
|
+
|
|
70
|
+
- **`@asap-protocol/mcp-auth` deferred to v2.5.0.1** — MCP-TS-001..003 (HTTP/SSE
|
|
71
|
+
Bearer middleware) are SHOULD-scope; v2.5.0 ships the Python stdio bridge as the
|
|
72
|
+
release gate. Rationale and implementation checklist:
|
|
73
|
+
[typescript-mcp-auth-spike.md](engineering/tasks/v2.5.0/typescript-mcp-auth-spike.md);
|
|
74
|
+
carry-over tracked in
|
|
75
|
+
[PRD v2.5.1 §3](product/prd/prd-v2.5.1-adapter-lab-ii.md#3-carry-over-from-v250-asap-protocolmcp-auth).
|
|
76
|
+
Existing `@asap-protocol/*` npm packages remain at **2.4.1** until a separate
|
|
77
|
+
publish.
|
|
78
|
+
|
|
79
|
+
### Migration
|
|
80
|
+
|
|
81
|
+
- **v2.4.1 → v2.5.0**: **No breaking changes.** MCP servers without
|
|
82
|
+
`protect_server` behave as before. To enforce Agent JWT + capabilities on native
|
|
83
|
+
MCP, wrap your server with `protect_server` and configure grants — see
|
|
84
|
+
[MCP Auth Bridge adapter](docs/adapters/mcp-auth-bridge.md).
|
|
16
85
|
|
|
17
86
|
---
|
|
18
87
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asap-protocol
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Async Simple Agent Protocol - A streamlined protocol for agent-to-agent communication
|
|
5
5
|
Project-URL: Homepage, https://github.com/adriannoes/asap-protocol
|
|
6
6
|
Project-URL: Documentation, https://adriannoes.github.io/asap-protocol
|
|
@@ -23,7 +23,7 @@ Requires-Python: >=3.13
|
|
|
23
23
|
Requires-Dist: aiosqlite>=0.20
|
|
24
24
|
Requires-Dist: authlib<2,>=1.6.12
|
|
25
25
|
Requires-Dist: brotli>=1.2.0
|
|
26
|
-
Requires-Dist: cryptography<
|
|
26
|
+
Requires-Dist: cryptography<49,>=48.0.1
|
|
27
27
|
Requires-Dist: fastapi>=0.136.1
|
|
28
28
|
Requires-Dist: httpx[http2]>=0.28.1
|
|
29
29
|
Requires-Dist: jcs>=0.2.0
|
|
@@ -95,7 +95,7 @@ Description-Content-Type: text/markdown
|
|
|
95
95
|
|
|
96
96
|
> A production-ready protocol for agent-to-agent communication and task coordination.
|
|
97
97
|
|
|
98
|
-
**Quick Info**: `v2.
|
|
98
|
+
**Quick Info**: `v2.5.0` (release branch; PyPI/npm publish on `v2.5.0` tag) · **npm TS [`2.4.1`](https://github.com/adriannoes/asap-protocol/releases/tag/v2.4.1)** (latest published) | `Apache 2.0` | `Python 3.13+` | [Documentation](https://github.com/adriannoes/asap-protocol/blob/main/docs/index.md) | **[PyPI `asap-protocol`](https://pypi.org/project/asap-protocol/)** | **[npm `@asap-protocol/client`](https://www.npmjs.com/package/@asap-protocol/client)** | [Changelog](https://github.com/adriannoes/asap-protocol/blob/main/CHANGELOG.md)
|
|
99
99
|
|
|
100
100
|
> 📦 Install the ASAP **Python SDK / protocol** from **`https://pypi.org/project/asap-protocol/`** — package name **`asap-protocol`** on [PyPI](https://pypi.org/project/asap-protocol/).
|
|
101
101
|
|
|
@@ -176,10 +176,10 @@ uv run python -m asap.examples.run_demo
|
|
|
176
176
|
uv run pytest -n auto --tb=short
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
With coverage:
|
|
179
|
+
With coverage (separate run — do not combine with `-n auto`):
|
|
180
180
|
|
|
181
181
|
```bash
|
|
182
|
-
uv run pytest --cov=
|
|
182
|
+
uv run pytest --tb=short --cov=asap --cov-report=term-missing --cov-fail-under=85
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
[Testing Guide](https://github.com/adriannoes/asap-protocol/blob/main/docs/testing.md) (structure, fixtures, property/load/chaos tests). [Contributing](https://github.com/adriannoes/asap-protocol/blob/main/CONTRIBUTING.md) (dev setup, CI).
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
> A production-ready protocol for agent-to-agent communication and task coordination.
|
|
9
9
|
|
|
10
|
-
**Quick Info**: `v2.
|
|
10
|
+
**Quick Info**: `v2.5.0` (release branch; PyPI/npm publish on `v2.5.0` tag) · **npm TS [`2.4.1`](https://github.com/adriannoes/asap-protocol/releases/tag/v2.4.1)** (latest published) | `Apache 2.0` | `Python 3.13+` | [Documentation](https://github.com/adriannoes/asap-protocol/blob/main/docs/index.md) | **[PyPI `asap-protocol`](https://pypi.org/project/asap-protocol/)** | **[npm `@asap-protocol/client`](https://www.npmjs.com/package/@asap-protocol/client)** | [Changelog](https://github.com/adriannoes/asap-protocol/blob/main/CHANGELOG.md)
|
|
11
11
|
|
|
12
12
|
> 📦 Install the ASAP **Python SDK / protocol** from **`https://pypi.org/project/asap-protocol/`** — package name **`asap-protocol`** on [PyPI](https://pypi.org/project/asap-protocol/).
|
|
13
13
|
|
|
@@ -88,10 +88,10 @@ uv run python -m asap.examples.run_demo
|
|
|
88
88
|
uv run pytest -n auto --tb=short
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
With coverage:
|
|
91
|
+
With coverage (separate run — do not combine with `-n auto`):
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
uv run pytest --cov=
|
|
94
|
+
uv run pytest --tb=short --cov=asap --cov-report=term-missing --cov-fail-under=85
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
[Testing Guide](https://github.com/adriannoes/asap-protocol/blob/main/docs/testing.md) (structure, fixtures, property/load/chaos tests). [Contributing](https://github.com/adriannoes/asap-protocol/blob/main/CONTRIBUTING.md) (dev setup, CI).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "asap-protocol"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.5.0"
|
|
4
4
|
description = "Async Simple Agent Protocol - A streamlined protocol for agent-to-agent communication"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "ASAP Protocol Contributors"}
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
dependencies = [
|
|
24
24
|
"aiosqlite>=0.20",
|
|
25
25
|
# Upper-bound majors per SECURITY.md dependency policy.
|
|
26
|
-
"cryptography>=
|
|
26
|
+
"cryptography>=48.0.1,<49",
|
|
27
27
|
"jcs>=0.2.0",
|
|
28
28
|
"jsonschema>=4.23.0",
|
|
29
29
|
"pydantic>=2.12.5,<3",
|
|
@@ -121,17 +121,20 @@ Issues = "https://github.com/adriannoes/asap-protocol/issues"
|
|
|
121
121
|
# - zeroconf>=0.149.5 for CVE-2026-47180/47183/47184 ([dns-sd] extra)
|
|
122
122
|
# - pyasn1>=0.6.3 for CVE-2026-30922 (DoS via unbounded recursion)
|
|
123
123
|
# - tinytag>=2.2.1 for CVE-2026-32889
|
|
124
|
-
# - cryptography>=
|
|
124
|
+
# - cryptography>=48.0.1 for GHSA-537c-gmf6-5ccf (CVE-2026-39892 / CVE-2026-34073 baseline at 46.0.7)
|
|
125
125
|
# - requests>=2.33.0 for CVE-2026-25645 (extract_zipped_paths temp file)
|
|
126
126
|
# - pillow>=12.2.0 for CVE-2026-40192 (transitive, e.g. pdf/vision stacks)
|
|
127
127
|
# - pytest>=9.0.3 for CVE-2025-71176 (dev)
|
|
128
|
-
# - python-multipart>=0.0.
|
|
128
|
+
# - python-multipart>=0.0.31 for CVE-2026-53538–53540 (FastAPI stack; prior floor 0.0.27)
|
|
129
|
+
# - starlette>=1.3.1 for CVE-2026-54282 / CVE-2026-54283 (FastAPI stack)
|
|
129
130
|
# - pygments>=2.20.0 for CVE-2026-4539
|
|
130
|
-
# - langsmith>=0.8.
|
|
131
|
+
# - langsmith>=0.8.18 for GHSA-f4xh-w4cj-qxq8 (prior: CVE-2026-45134 at >=0.8.0)
|
|
131
132
|
# - langchain-core>=1.3.3 for CVE-2026-44843
|
|
132
133
|
# - urllib3>=2.7.0 for CVE-2026-44431 / CVE-2026-44432
|
|
133
134
|
# - pip>=26.1.2 for PYSEC-2026-196 (CVE-2026-6357 baseline at 26.1)
|
|
134
135
|
# - python-dotenv>=1.2.2 for CVE-2026-28684 (transitive, e.g. pydantic-settings / uvicorn stacks)
|
|
136
|
+
# - pydantic-settings>=2.14.2 for GHSA-4xgf-cpjx-pc3j (transitive, e.g. langchain / mcp stacks)
|
|
137
|
+
# - msgpack>=1.2.1 for GHSA-6v7p-g79w-8964 (transitive, e.g. locust / cache stacks)
|
|
135
138
|
# - idna>=3.15 for CVE-2026-45409 (DoS in idna.encode; transitive via httpx/requests)
|
|
136
139
|
# - markdown>=3.10.2 for PYSEC-2026-89 (DoS in html.parser during Markdown parse; mkdocs stack)
|
|
137
140
|
# - pymdown-extensions>=10.21.3 for CVE-2026-46338 (snippets base_path prefix bypass; mkdocs stack)
|
|
@@ -141,13 +144,14 @@ override-dependencies = [
|
|
|
141
144
|
"pyjwt>=2.13.0,<3",
|
|
142
145
|
"pyasn1>=0.6.3",
|
|
143
146
|
"tinytag>=2.2.1",
|
|
144
|
-
"cryptography>=
|
|
147
|
+
"cryptography>=48.0.1,<49",
|
|
145
148
|
"requests>=2.33.0",
|
|
146
149
|
"pillow>=12.2.0",
|
|
147
150
|
"pytest>=9.0.3",
|
|
148
|
-
"python-multipart>=0.0.
|
|
151
|
+
"python-multipart>=0.0.31",
|
|
152
|
+
"starlette>=1.3.1",
|
|
149
153
|
"pygments>=2.20.0",
|
|
150
|
-
"langsmith>=0.8.
|
|
154
|
+
"langsmith>=0.8.18",
|
|
151
155
|
"langchain-core>=1.3.3",
|
|
152
156
|
"urllib3>=2.7.0",
|
|
153
157
|
"pip>=26.1.2",
|
|
@@ -156,6 +160,8 @@ override-dependencies = [
|
|
|
156
160
|
"idna>=3.15",
|
|
157
161
|
"markdown>=3.10.2",
|
|
158
162
|
"pymdown-extensions>=10.21.3",
|
|
163
|
+
"pydantic-settings>=2.14.2",
|
|
164
|
+
"msgpack>=1.2.1",
|
|
159
165
|
]
|
|
160
166
|
|
|
161
167
|
[project.scripts]
|
|
@@ -306,7 +312,7 @@ addopts = [
|
|
|
306
312
|
"--strict-markers",
|
|
307
313
|
"--strict-config",
|
|
308
314
|
]
|
|
309
|
-
# Coverage options: use explicitly when needed (e.g., pytest --cov=
|
|
315
|
+
# Coverage options: use explicitly when needed (e.g., pytest --tb=short --cov=asap --cov-report=xml --cov-fail-under=85)
|
|
310
316
|
# NOT included in addopts to avoid conflicts with pytest-xdist (-n auto)
|
|
311
317
|
testpaths = ["tests"]
|
|
312
318
|
# Note: benchmarks/ excluded from testpaths - Locust monkey-patches gevent/ssl which
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""MCP Auth Bridge adapter (v2.5.0).
|
|
2
|
+
|
|
3
|
+
Opt-in protection for native ``MCPServer`` via ``protect_server``.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from asap.adapters.mcp.auth_middleware import protect_server
|
|
9
|
+
from asap.adapters.mcp.config import MCPAuthConfig, resolve_jwt_extractor
|
|
10
|
+
from asap.adapters.mcp.protected_server import ProtectedMCPServer
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"MCPAuthConfig",
|
|
14
|
+
"ProtectedMCPServer",
|
|
15
|
+
"protect_server",
|
|
16
|
+
"resolve_jwt_extractor",
|
|
17
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""MCP Auth Bridge middleware entry point (v2.5.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from asap.adapters.mcp.config import MCPAuthConfig, resolve_jwt_extractor
|
|
6
|
+
from asap.adapters.mcp.protected_server import ProtectedMCPServer
|
|
7
|
+
from asap.mcp.server import MCPServer
|
|
8
|
+
|
|
9
|
+
__all__ = ["MCPAuthConfig", "protect_server", "resolve_jwt_extractor"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def protect_server(server: MCPServer, config: MCPAuthConfig) -> ProtectedMCPServer:
|
|
13
|
+
"""Return an MCP server with JWT and capability enforcement on ``tools/call``.
|
|
14
|
+
|
|
15
|
+
Verifies Agent JWT extraction/verification, the ``public_tools`` allowlist, and
|
|
16
|
+
(when ``enforce_grants=True``) JWT capability claims plus
|
|
17
|
+
:meth:`~asap.auth.capabilities.CapabilityRegistry.check_grant`.
|
|
18
|
+
|
|
19
|
+
``from_server`` copies register-time capability metadata onto the protected instance
|
|
20
|
+
without mutating ``config``.
|
|
21
|
+
|
|
22
|
+
See PRD v2.5.0 MCP Auth Bridge (``product/prd/prd-v2.5.0-mcp-auth-bridge.md``)
|
|
23
|
+
and design lock ADR (``engineering/tasks/v2.5.0/design-lock-mcp-auth-bridge.md``).
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
server: Native MCP server with registered tools.
|
|
27
|
+
config: Auth configuration (identity stores, capability registry, extractors).
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Protected server instance; unprotected ``MCPServer`` usage remains valid when
|
|
31
|
+
this function is not called.
|
|
32
|
+
"""
|
|
33
|
+
return ProtectedMCPServer.from_server(server, config)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Tool-to-capability resolution for MCP Auth Bridge (v2.5.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from asap.adapters.mcp.config import MCPAuthConfig
|
|
6
|
+
from asap.auth.capabilities import ConstraintViolation
|
|
7
|
+
from asap.mcp.server import MCPServer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def resolve_capability(
|
|
11
|
+
tool_name: str,
|
|
12
|
+
config: MCPAuthConfig,
|
|
13
|
+
*,
|
|
14
|
+
server: MCPServer | None = None,
|
|
15
|
+
) -> str:
|
|
16
|
+
"""Resolve an MCP tool name to an ASAP capability name.
|
|
17
|
+
|
|
18
|
+
Resolution order (MCP-MAP-001, MCP-MAP-002):
|
|
19
|
+
|
|
20
|
+
1. ``config.tool_capability_map`` (explicit runtime override)
|
|
21
|
+
2. ``server.get_tool_capability(tool_name)`` when register-time metadata is set
|
|
22
|
+
3. Identity default: ``tool_name`` unchanged
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
tool_name: Registered MCP tool name from ``tools/call``.
|
|
26
|
+
config: MCP auth configuration including capability maps.
|
|
27
|
+
server: MCP server providing register-time capability metadata.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
ASAP capability name used for grant checks.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> from asap.adapters.mcp.config import MCPAuthConfig
|
|
34
|
+
>>> from asap.auth.capabilities import CapabilityRegistry
|
|
35
|
+
>>> from asap.auth.identity import InMemoryAgentStore, InMemoryHostStore
|
|
36
|
+
>>> from asap.mcp.server import MCPServer
|
|
37
|
+
>>> agents = InMemoryAgentStore()
|
|
38
|
+
>>> config = MCPAuthConfig(
|
|
39
|
+
... host_store=InMemoryHostStore(agent_store=agents),
|
|
40
|
+
... agent_store=agents,
|
|
41
|
+
... capability_registry=CapabilityRegistry(),
|
|
42
|
+
... tool_capability_map={"search": "web_search"},
|
|
43
|
+
... )
|
|
44
|
+
>>> resolve_capability("search", config)
|
|
45
|
+
'web_search'
|
|
46
|
+
>>> resolve_capability("echo", config)
|
|
47
|
+
'echo'
|
|
48
|
+
"""
|
|
49
|
+
if tool_name in config.tool_capability_map:
|
|
50
|
+
return config.tool_capability_map[tool_name]
|
|
51
|
+
if server is not None:
|
|
52
|
+
registered = server.get_tool_capability(tool_name)
|
|
53
|
+
if registered is not None:
|
|
54
|
+
return registered
|
|
55
|
+
return tool_name
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def format_constraint_violations(violations: list[ConstraintViolation]) -> str:
|
|
59
|
+
"""Format grant constraint violations for MCP ``tools/call`` error detail.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
violations: Constraint failures from :meth:`CapabilityRegistry.check_grant`.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Human-readable detail string joined with ``; ``.
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> from asap.auth.capabilities import ConstraintViolation
|
|
69
|
+
>>> format_constraint_violations([
|
|
70
|
+
... ConstraintViolation("tokens", "max", 100, 150, "tokens: 150 exceeds maximum 100"),
|
|
71
|
+
... ])
|
|
72
|
+
'tokens: 150 exceeds maximum 100'
|
|
73
|
+
"""
|
|
74
|
+
return "; ".join(v.message for v in violations)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""MCP Auth Bridge configuration (v2.5.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
|
|
8
|
+
from asap.adapters.mcp.jwt_extractor import default_jwt_extractor
|
|
9
|
+
from asap.auth.agent_jwt import JtiReplayCache
|
|
10
|
+
from asap.auth.capabilities import CapabilityRegistry
|
|
11
|
+
from asap.auth.identity import AgentStore, HostStore
|
|
12
|
+
from asap.mcp.protocol import CallToolRequestParams
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
MCP_COMPLIANCE_ENV_VAR = "ASAP_MCP_COMPLIANCE"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class MCPAuthConfig:
|
|
20
|
+
"""Configuration for ASAP auth on a native MCP server.
|
|
21
|
+
|
|
22
|
+
JWT extraction: middleware MUST call :func:`resolve_jwt_extractor` (or
|
|
23
|
+
equivalent ``config.jwt_extractor or`` closure over
|
|
24
|
+
:func:`default_jwt_extractor` with ``allow_env_fallback=config.allow_env_jwt_fallback``).
|
|
25
|
+
Do not invoke a ``None`` extractor.
|
|
26
|
+
|
|
27
|
+
``hide_unauthorized_tools`` is reserved for MCP-MAP-004 (deferred per design-lock §6);
|
|
28
|
+
stdio ``tools/list`` has no standard JWT carriage in v2.5.0.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
>>> config = MCPAuthConfig(
|
|
32
|
+
... host_store=host_store,
|
|
33
|
+
... agent_store=agent_store,
|
|
34
|
+
... capability_registry=registry,
|
|
35
|
+
... )
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
host_store: HostStore
|
|
39
|
+
agent_store: AgentStore
|
|
40
|
+
capability_registry: CapabilityRegistry
|
|
41
|
+
tool_capability_map: dict[str, str] = field(default_factory=dict)
|
|
42
|
+
public_tools: frozenset[str] = frozenset()
|
|
43
|
+
enforce_grants: bool = True
|
|
44
|
+
hide_unauthorized_tools: bool = False
|
|
45
|
+
validate_tools_at_startup: bool = False
|
|
46
|
+
jwt_extractor: Callable[[CallToolRequestParams], str | None] | None = None
|
|
47
|
+
allow_env_jwt_fallback: bool = False
|
|
48
|
+
jti_replay_cache: JtiReplayCache | None = None
|
|
49
|
+
expected_audience: str | list[str] | None = None
|
|
50
|
+
manifest_url: str | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def resolve_jwt_extractor(config: MCPAuthConfig) -> Callable[[CallToolRequestParams], str | None]:
|
|
54
|
+
"""Return the JWT extractor for middleware (custom or default with config flags).
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
config: MCP auth configuration.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Callable that extracts an Agent JWT from ``tools/call`` params.
|
|
61
|
+
"""
|
|
62
|
+
if config.jwt_extractor is not None:
|
|
63
|
+
return config.jwt_extractor
|
|
64
|
+
|
|
65
|
+
allow_env = config.allow_env_jwt_fallback
|
|
66
|
+
|
|
67
|
+
def extract(params: CallToolRequestParams) -> str | None:
|
|
68
|
+
return default_jwt_extractor(params, allow_env_fallback=allow_env)
|
|
69
|
+
|
|
70
|
+
return extract
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""MCP-facing ASAP auth error codes and result helpers (v2.5.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from asap.mcp.protocol import CallToolResult, TextContent
|
|
8
|
+
|
|
9
|
+
AUTH_REQUIRED = "asap:auth_required"
|
|
10
|
+
INVALID_TOKEN = "asap:invalid_token"
|
|
11
|
+
CAPABILITY_DENIED = "asap:capability_denied"
|
|
12
|
+
CONSTRAINT_VIOLATION = "asap:constraint_violation"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def tool_error_result(code: str, detail: str | None = None) -> dict[str, Any]:
|
|
16
|
+
"""Build a ``tools/call`` error payload with ``isError: true``.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
code: ASAP-namespaced error code (e.g. ``asap:auth_required``).
|
|
20
|
+
detail: Optional human-readable detail appended after the code.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Dict suitable for JSON-RPC ``result`` (``CallToolResult`` shape).
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> tool_error_result(AUTH_REQUIRED)["isError"]
|
|
27
|
+
True
|
|
28
|
+
"""
|
|
29
|
+
text = code if detail is None else f"{code}: {detail}"
|
|
30
|
+
result = CallToolResult(content=[TextContent(text=text).model_dump(by_alias=True)])
|
|
31
|
+
result.is_error = True
|
|
32
|
+
return result.model_dump(by_alias=True, exclude_none=True)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""JWT extraction helpers for MCP Auth Bridge (v2.5.0)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from asap.mcp.protocol import CallToolRequestParams
|
|
8
|
+
|
|
9
|
+
_META_JWT_KEY = "asap_agent_jwt"
|
|
10
|
+
_ENV_JWT_KEY = "ASAP_AGENT_JWT"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def default_jwt_extractor(
|
|
14
|
+
params: CallToolRequestParams,
|
|
15
|
+
*,
|
|
16
|
+
allow_env_fallback: bool = False,
|
|
17
|
+
) -> str | None:
|
|
18
|
+
"""Extract Agent JWT from ``tools/call`` params or optional dev-only environment.
|
|
19
|
+
|
|
20
|
+
Reads ``params.meta["asap_agent_jwt"]`` (MCP ``_meta`` field). When
|
|
21
|
+
``allow_env_fallback`` is ``True``, falls back to ``ASAP_AGENT_JWT`` for
|
|
22
|
+
single-agent local testing only.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
params: Parsed ``tools/call`` request parameters.
|
|
26
|
+
allow_env_fallback: When ``True``, read ``ASAP_AGENT_JWT`` if meta is absent.
|
|
27
|
+
Defaults to ``False`` so production cannot inherit a process-wide token.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Stripped JWT string, or ``None`` when no token is present.
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
>>> from asap.mcp.protocol import CallToolRequestParams
|
|
34
|
+
>>> params = CallToolRequestParams.model_validate(
|
|
35
|
+
... {"name": "t", "_meta": {"asap_agent_jwt": " token "}}
|
|
36
|
+
... )
|
|
37
|
+
>>> default_jwt_extractor(params)
|
|
38
|
+
'token'
|
|
39
|
+
"""
|
|
40
|
+
meta = params.meta or {}
|
|
41
|
+
token = meta.get(_META_JWT_KEY)
|
|
42
|
+
if isinstance(token, str) and token.strip():
|
|
43
|
+
return token.strip()
|
|
44
|
+
|
|
45
|
+
if not allow_env_fallback:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
env_token = os.environ.get(_ENV_JWT_KEY)
|
|
49
|
+
if isinstance(env_token, str) and env_token.strip():
|
|
50
|
+
return env_token.strip()
|
|
51
|
+
|
|
52
|
+
return None
|