pypi Python analyzed 2.21.0

mcp-hangar

v2.21.0
pypi

MCP policy enforcement plane — deterministic policy on every Model Context Protocol call: identity, RFC 8707 audience binding, tool schema digest pinning, full audit trail. Python, self-hosted, MIT.

maintainer
mcp-hangar
licence
MIT
first seen
2026-08-14
last seen
2026-09-17
releases · 30d
30
short id

Drift inferred · capture-to-capture

No drift recorded — single capability capture; advisories appear once its surface changes.

capabilities 0 tools
transport stdio · streamable-http · http verified reported listed in the official MCP registry counts 0 tools · 0 res · 0 prompts permission surface via code analysis

No tools enumerated yet for this server.

skills & danger signals pypi-sdist
prompt-surface shipped agent-instruction files + hidden-content / dangerous-code findings — quoted from the analyzed source

analyzed v2.21.0 · analyzer v33 · 2d ago

skills & prompt files 1

  • agent-rules mcp_hangar-2.21.0/AGENTS.md

danger signals7

  • suspicious endpoint 169.254.169.254 (cloud metadata) mcp_hangar-2.21.0/tests/unit/test_security_identity_and_network.py :35 validate_no_ssrf("http://169.254.169.254/latest/meta-data/")
  • suspicious endpoint 169.254.169.254 (cloud metadata) mcp_hangar-2.21.0/tests/unit/test_ssrf_provenance.py :140 "http://169.254.169.254/latest/meta-data/",
  • suspicious endpoint 169.254.169.254 (cloud metadata) mcp_hangar-2.21.0/tests/unit/test_unguarded_config_endpoints.py :46 _, warnings = _run({"meta": {"mode": "remote", "endpoint": "http://169.254.169.254/latest/meta-data/"}})
  • over-broad OAuth scope delete_repo mcp_hangar-2.21.0/tests/unit/test_egress_l7.py :30 action, _ = evaluate_tool("delete_repo", rules, ToolAction.DENY)
  • over-broad OAuth scope delete_repo mcp_hangar-2.21.0/tests/unit/test_egress_l7_enforcement.py :46 _server(L7Policy(tools=ToolRules(deny=("delete_*",)))).invoke_tool("delete_repo", {})
  • over-broad OAuth scope delete_repo mcp_hangar-2.21.0/tests/unit/test_set_l7_policy_handler.py :56 server.invoke_tool("delete_repo", {})
  • committed secret Google API key mcp_hangar-2.21.0/tests/unit/test_output_redactor.py :237 AIzaSy…(39 chars, redacted)
code evidence v2.21.0 · pypi-sdist
evidence-backed findings quoted directly from the published source artifact — not inferred

code files: 1144

filesystem 244

  • fs (weak) mcp_hangar-2.21.0/examples/discovery/test_container_discovery.py :21 from pathlib import Path
  • fs mcp_hangar-2.21.0/fuzz/fuzz_access_precedence.py :19 from pathlib import Path
  • fs mcp_hangar-2.21.0/fuzz/fuzz_policy_evaluate.py :14 from pathlib import Path
  • fs mcp_hangar-2.21.0/fuzz/fuzz_policy_parse.py :19 from pathlib import Path
  • fs (weak) mcp_hangar-2.21.0/scripts/build_changelog.py :42 from pathlib import Path
  • fs (weak) mcp_hangar-2.21.0/scripts/check_dead_symbols.py :37 import pathlib
  • fs (weak) mcp_hangar-2.21.0/scripts/check_decision_coverage.py :32 import pathlib
  • fs (weak) mcp_hangar-2.21.0/scripts/dump_api_routes.py :36 import pathlib
  • fs (weak) mcp_hangar-2.21.0/scripts/promote_upgrade_notes.py :52 from pathlib import Path
  • fs (weak) mcp_hangar-2.21.0/scripts/release_please_guard.py :42 from pathlib import Path
  • fs (weak) mcp_hangar-2.21.0/scripts/smoke_published_artifact.py :43 from pathlib import Path
  • fs (weak) mcp_hangar-2.21.0/scripts/validate_config.py :20 from pathlib import Path
show 28 more
  • fs mcp_hangar-2.21.0/src/mcp_hangar/application/services/secrets_resolver.py :9 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/auth/bootstrap.py :8 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/sqlite_store.py :17 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/sqlite_tap_store.py :10 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/compliance/cef_exporter.py :13 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/compliance/jsonlines_exporter.py :8 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/compliance/leef_exporter.py :7 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/compliance/syslog_exporter.py :9 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/domain/contracts/installer.py :10 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/domain/model/circuit_breaker.py :49 whether to close (on success) or re-open (on failure).
  • fs mcp_hangar-2.21.0/src/mcp_hangar/domain/services/image_builder.py :6 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/domain/services/task_consent.py :69 def open(self, task_key: TaskKey, input_key: str) -> None:
  • fs mcp_hangar-2.21.0/src/mcp_hangar/domain/services/tool_access_resolver.py :451 a documented deny list that failed open (#1164). Defaults to
  • fs mcp_hangar-2.21.0/src/mcp_hangar/facade.py :40 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/fastmcp_server/task_relay_handlers.py :715 consent_gate.open(key, input_key)
  • fs mcp_hangar-2.21.0/src/mcp_hangar/gc.py :3 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/discovery/docker_source.py :27 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/discovery/filesystem_source.py :28 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/discovery/registry.py :28 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/installers.py :18 import shutil
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/container.py :18 import shutil
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/docker.py :3 import shutil
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/subprocess.py :4 import shutil
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/backends/sqlite.py :18 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/database.py :11 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/database_common.py :11 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/dispatch_checkpoint.py :11 from pathlib import Path
  • fs mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/sqlite_event_store.py :10 from pathlib import Path

204 more not shown — this panel samples each group; the count above is the real total.

shell / exec 76

  • shell (weak) mcp_hangar-2.21.0/examples/discovery/test_container_discovery.py :22 import subprocess
  • shell (weak) mcp_hangar-2.21.0/examples/rugpull/recording/client.py :5 import subprocess
  • shell (weak) mcp_hangar-2.21.0/scripts/build_changelog.py :44 import subprocess
  • shell (weak) mcp_hangar-2.21.0/scripts/smoke_published_artifact.py :46 import subprocess
  • shell mcp_hangar-2.21.0/src/mcp_hangar/domain/services/image_builder.py :8 import subprocess
  • shell mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/container.py :19 import subprocess
  • shell mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/docker.py :4 import subprocess
  • shell mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/subprocess.py :5 import subprocess
  • shell mcp_hangar-2.21.0/src/mcp_hangar/stdio_client.py :8 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/_hangar_executable.py :24 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/benchmark/tracing_overhead.py :43 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/ci/test_release_pr_checks_are_refired.py :22 import subprocess
show 28 more
  • shell (weak) mcp_hangar-2.21.0/tests/ci/test_the_changelog_gate_diffs_from_the_merge_base.py :22 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/ci/test_the_changelog_gate_lets_a_dependency_bump_through.py :14 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/ci/test_the_release_push_is_made_as_the_app.py :24 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/_capability_block_harness.py :27 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_builder_config_takes_effect.py :25 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_caller_error_does_not_count_against_a_group_member.py :25 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_capability_block_stops_the_call_that_found_it.py :29 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_client_over_stdio_gets_a_verdict.py :31 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_cold_group_reports_no_healthy_members_and_still_routes.py :19 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_config_dict_validator_refuses_a_served_call.py :18 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_dead_servers_reason_reads_the_same_on_every_surface.py :25 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_front_door_is_ready_once_its_catalogue_is_projected.py :33 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_front_door_member_of_several_groups_is_governed_by_each.py :28 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_front_door_task_call_is_governed_by_its_group.py :51 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_given_up_server_reads_dead_on_the_served_path.py :42 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_group_member_named_directly_is_governed_on_the_served_app.py :38 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_hot_loaded_server_has_its_log.py :21 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_leftover_circuit_breaker_row_is_ignored.py :20 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_passing_health_check_returns_a_member_to_rotation.py :33 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_reload_is_served_whole.py :22 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_reload_keeps_an_l7_policy_set_over_the_api.py :21 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_reload_restarts_only_what_changed.py :19 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_server_a_reload_adds_has_its_log.py :21 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_a_task_follow_up_is_checked_against_current_tool_access.py :27 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_append_at_end_on_one_postgres.py :24 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_audit_export_switch_bootstrap.py :21 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_audit_log_pipeline_bootstrap.py :25 import subprocess
  • shell (weak) mcp_hangar-2.21.0/tests/integration/test_each_replica_exposes_its_group_circuit.py :23 import subprocess

36 more not shown — this panel samples each group; the count above is the real total.

network 47

  • net (weak) mcp_hangar-2.21.0/examples/auth-keycloak/test_keycloak_integration.py :7 import httpx
  • net (weak) mcp_hangar-2.21.0/examples/auth-keycloak/test_oidc_local.py :30 import httpx
  • net (weak) mcp_hangar-2.21.0/scripts/smoke_published_artifact.py :45 import socket
  • net mcp_hangar-2.21.0/src/mcp_hangar/application/discovery/security_validator.py :27 import aiohttp
  • net mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/jwt_authenticator.py :490 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/opa_authorizer.py :15 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/compliance/syslog_exporter.py :6 import socket
  • net mcp_hangar-2.21.0/src/mcp_hangar/domain/contracts/authentication.py :123 without the transport-layer concerns of extracting them from requests.
  • net mcp_hangar-2.21.0/src/mcp_hangar/domain/security/ssrf.py :32 import socket
  • net mcp_hangar-2.21.0/src/mcp_hangar/domain/value_objects/config.py :19 from urllib.parse import urlparse
  • net mcp_hangar-2.21.0/src/mcp_hangar/http_client.py :25 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/launchers/http.py :67 from urllib.parse import urlparse
show 28 more
  • net mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/registry/client.py :11 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/server/api/middleware.py :19 from urllib.parse import parse_qs
  • net mcp_hangar-2.21.0/src/mcp_hangar/server/bootstrap/__init__.py :24 import socket
  • net mcp_hangar-2.21.0/src/mcp_hangar/server/cli/commands/add.py :111 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/server/cli/commands/remove.py :81 import httpx
  • net mcp_hangar-2.21.0/src/mcp_hangar/server/cli/commands/status.py :53 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/benchmark/tracing_overhead.py :41 import socket
  • net (weak) mcp_hangar-2.21.0/tests/integration/_front_door_harness.py :35 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/integration/test_audit_export_switch_bootstrap.py :20 import socket
  • net (weak) mcp_hangar-2.21.0/tests/integration/test_audit_log_pipeline_bootstrap.py :24 import socket
  • net (weak) mcp_hangar-2.21.0/tests/live/conftest.py :24 import socket
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t0_last_healthy.py :12 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t0_projection_metrics.py :25 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t0_reload_keeps_the_front_door.py :36 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t0_smoke.py :9 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t0_tool_access.py :35 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t2_apikey.py :39 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t2_auth.py :33 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t2_session_suspension.py :48 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/live/test_t2_tenant_scoped_grants.py :40 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_a_failed_start_closes_its_client.py :29 import socket
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_events_carry_their_producer.py :135 import socket
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_jwt_authenticator.py :386 with patch("httpx.get", return_value=mock_response):
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_opa_authorizer.py :83 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_opa_verdict_is_typed.py :89 import httpx
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_otlp_audit_exporter.py :399 import socket
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_sdk_pin_bounds.py :91 httpx 1.0 drops `httpx.AsyncClient`, which the proxy path uses throughout.
  • net (weak) mcp_hangar-2.21.0/tests/unit/test_session_id_retirement.py :24 """Return a fake ``httpx.Client.post`` that records the outbound headers."""

7 more not shown — this panel samples each group; the count above is the real total.

secrets 5

  • secrets mcp_hangar-2.21.0/src/mcp_hangar/server/api/middleware.py :756 allow_credentials = os.environ.get("MCP_CORS_CREDENTIALS", "false").lower() == "true"
  • secrets mcp_hangar-2.21.0/src/mcp_hangar/server/bootstrap/__init__.py :558 if os.environ.get("HANGAR_LICENSE_KEY"):
  • secrets mcp_hangar-2.21.0/src/mcp_hangar/server/bootstrap/observability.py :131 secret_key=os.getenv("LANGFUSE_SECRET_KEY", _expand_env(langfuse_dict.get("secret_key", ""))),
  • secrets (weak) mcp_hangar-2.21.0/tests/unit/test_bootstrap_components_loading.py :142 assert os.environ.get("HANGAR_LICENSE_KEY") == "hk_v1_test"
  • secrets (weak) mcp_hangar-2.21.0/tests/unit/test_secrets_resolver.py :96 os.environ["PRECEDENCE_SECRET"] = "env_value"

database 19

  • db (weak) mcp_hangar-2.21.0/scripts/migrate_db.py :165 import asyncpg
  • db mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/sqlite_store.py :19 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/auth/infrastructure/sqlite_tap_store.py :8 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/database_common.py :12 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/dispatch_checkpoint.py :12 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/sqlite_event_store.py :11 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/persistence/sqlite_management_lease.py :31 import sqlite3
  • db mcp_hangar-2.21.0/src/mcp_hangar/infrastructure/truncation/redis_cache.py :84 import redis
  • db (weak) mcp_hangar-2.21.0/tests/integration/_leftover_circuit_row_harness.py :26 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/integration/test_append_at_end_on_one_postgres.py :57 import psycopg2
  • db (weak) mcp_hangar-2.21.0/tests/unit/cli/test_auth_bootstrap_admin.py :83 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/unit/cli/test_the_bootstrap_claim_is_not_spent_on_an_unusable_grant.py :22 import sqlite3
show 7 more
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_both_backends_are_peers.py :54 assert "import psycopg2" not in source
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_event_upcasting.py :6 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_events_are_persisted.py :14 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_postgres_metrics_history_store.py :51 # connection factory, not to this file. A stray `import psycopg2`
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_replay_does_not_drop_the_approval_gate.py :176 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_sqlite_auth_store.py :112 import sqlite3
  • db (weak) mcp_hangar-2.21.0/tests/unit/test_sqlite_tap_store.py :3 import sqlite3

declared dependencies 38

  • mcp@==2.0.0
  • mcp-types@==2.0.0
  • structlog@>=24.0.0
  • pydantic@>=2.0.0
  • httpx@>=0.25.0,<1
  • prometheus-client@>=0.19.0
  • pyjwt@>=2.8.0
  • cryptography@>=41.0.0
  • pyyaml@>=6.0
  • docker@>=7.1.0
  • aiosqlite@>=0.19.0
  • typer@>=0.12.0
show 26 more
  • rich@>=13.0.0
  • questionary@>=2.0.0
  • python-multipart@>=0.0.22
  • protobuf@>=6.33.5
  • jcs@>=0.2.1
  • click@>=8.3.3
  • pytest@>=8.0.0
  • pytest-cov@>=4.1.0
  • pytest-asyncio@>=0.23.0
  • pytest-timeout@>=2.2.0
  • pytest-benchmark@>=5.1.0
  • ruff@==0.16.7
  • import-linter@==2.15
  • mypy@>=1.8.0
  • hypothesis@>=6.90.0
  • jsonschema@>=4.20.0
  • atheris@>=3.1.0; sys_platform ==
  • and@python_version >=
  • kubernetes@>=29.0.0
  • langfuse@>=2.0.0
  • opentelemetry-api@>=1.35.0
  • opentelemetry-sdk@>=1.35.0
  • opentelemetry-exporter-otlp@>=1.35.0
  • psycopg2-binary@>=2.9.9
  • redis@>=5.0.0
  • fpdf2@>=2.8.0

transport_posture 1

  • binds all interfaces (0.0.0.0) mcp_hangar-2.21.0/tests/unit/test_security_critical_paths.py :61 lifecycle.run_http(host="0.0.0.0", port=8000, unsafe_no_auth=False)