Metadata-Version: 2.4
Name: mcp-hangar
Version: 1.5.1
Summary: Production-grade infrastructure for Model Context Protocol
Project-URL: Homepage, https://mcp-hangar.io
Project-URL: Documentation, https://mcp-hangar.io/getting-started/quickstart/
Project-URL: Repository, https://github.com/mcp-hangar/mcp-hangar
Author-email: Marcin Pyrka <marcin@mcp-hangar.io>
License: MIT
License-File: LICENSE
Keywords: ai,infrastructure,llm,mcp,model-context-protocol
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Requires-Dist: aiosqlite>=0.19.0
Requires-Dist: cryptography>=41.0.0
Requires-Dist: docker>=7.1.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: jcs>=0.2.1
Requires-Dist: mcp>=1.28.1
Requires-Dist: prometheus-client>=0.19.0
Requires-Dist: protobuf>=6.33.5
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: python-multipart>=0.0.22
Requires-Dist: pyyaml>=6.0
Requires-Dist: questionary>=2.0.0
Requires-Dist: rich>=13.0.0
Requires-Dist: structlog>=24.0.0
Requires-Dist: typer>=0.12.0
Provides-Extra: containers
Requires-Dist: testcontainers<5,>=4; extra == 'containers'
Provides-Extra: dev
Requires-Dist: hypothesis>=6.90.0; extra == 'dev'
Requires-Dist: jsonschema>=4.20.0; extra == 'dev'
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-benchmark>=5.1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.2.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.3.0; extra == 'dev'
Provides-Extra: full
Requires-Dist: fpdf2>=2.8.0; extra == 'full'
Provides-Extra: langfuse
Requires-Dist: langfuse>=2.0.0; extra == 'langfuse'
Provides-Extra: opentelemetry
Requires-Dist: opentelemetry-api>=1.22.0; extra == 'opentelemetry'
Requires-Dist: opentelemetry-exporter-otlp>=1.22.0; extra == 'opentelemetry'
Requires-Dist: opentelemetry-sdk>=1.22.0; extra == 'opentelemetry'
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.29.0; extra == 'postgres'
Description-Content-Type: text/markdown

# MCP Hangar

**Open-source control plane for MCP servers -- lifecycle, governance, and observability for your server fleet.**

[![PyPI](https://img.shields.io/pypi/v/mcp-hangar)](https://pypi.org/project/mcp-hangar/)
[![CI](https://github.com/mcp-hangar/mcp-hangar/actions/workflows/ci-core.yml/badge.svg)](https://github.com/mcp-hangar/mcp-hangar/actions/workflows/ci-core.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Why

In MCP, the tool list is a hint the client caches; the call path is the only surface a provider mediates in real time. Every governance primitive worth having -- revocation, per-tenant scoping, audit -- attaches there, or attaches to nothing. Hangar puts a control plane on that seam: one mediated path for lifecycle, policy, and telemetry across your whole MCP server fleet.

> Background: [The Advisory List -- Why MCP Governance Lives at the Call Path](https://whyisthisdown.com/posts/the-advisory-list)

## Install

```bash
pip install mcp-hangar
# or: uv pip install mcp-hangar
```

## Quickstart

Point Hangar at an MCP server in `config.yaml`:

```yaml
mcp_servers:
  github:
    mode: subprocess
    command: [uvx, mcp-server-github]
    env:
      GITHUB_TOKEN: ${GITHUB_TOKEN}
```

Then serve it:

```bash
mcp-hangar serve --config config.yaml                     # stdio (Claude Desktop)
mcp-hangar serve --config config.yaml --http --port 8000  # HTTP + REST API at /api/
```

> The 1.5 server refuses to bind a non-loopback interface without auth. For a
> quick/insecure demo, pass `--unsafe-no-auth`; for anything real, configure
> the `auth` block.

Or skip the config entirely -- get filesystem, fetch, and memory servers wired into Claude Desktop in one line:

```bash
curl -sSL https://mcp-hangar.io/install.sh | bash && mcp-hangar init -y && mcp-hangar serve
```

## What you get

- **Parallel tool calls** -- one `hangar_call` fans out to many MCP servers concurrently; all results returned together.
- **Lifecycle management** -- lazy start, health checks, single-flight cold starts, idle shutdown, and per-server circuit breaking.
- **Hot config reload** -- add or withdraw servers and tools via file watch, no restart.
- **Per-tenant tool projection** -- front-door mode presents a different executable surface per caller, fail-closed on unknown identity.
- **OAuth ingress** -- advertise as an RFC 9728 protected resource and challenge external agents for verified tokens.
- **Auth & RBAC** -- API-key and OIDC/JWT identity with role-based access; bootstrap the first administrator with `mcp-hangar auth bootstrap-admin`, and every call carries a verified principal into the audit trail.
- **Observability built in** -- OpenTelemetry traces, Prometheus metrics, structured logs, and an event-sourced audit trail.

## Configuring `tools:`

The per-server `tools:` key is overloaded and accepts two distinct forms:

- A **list of tool schemas** is a **pre-start visibility projection**. It lets a
  tool be listed before its provider has started, so callers can see it up
  front. It is not an access policy. On start, the provider's dynamic
  `tools/list` is **authoritative and replaces this projection entirely** — a
  statically-listed tool that the provider does not return becomes uncallable
  and fails with `Tool not found: <name>` at invocation (a warning naming the
  unconfirmed tool is logged at start).

- A **dict with `allow:` / `deny:`** is an **access policy** (glob-pattern,
  three-level merge) that filters which discovered tools are exposed.

```yaml
mcp_servers:
  math:
    mode: subprocess
    command: [python, -m, examples.provider_math.server]
    tools:                     # list form: pre-start schema projection
      - name: add
        description: "Add two numbers"
        inputSchema: { type: object, properties: { a: { type: number } } }
  github:
    mode: subprocess
    command: [uvx, mcp-server-github]
    tools:                     # dict form: allow/deny access policy
      allow: [create_issue, list_issues]
      deny: [delete_repository]
```

## Documentation

- [Getting Started](https://mcp-hangar.io/docs/getting-started/quickstart) &middot; [Configuration](https://mcp-hangar.io/docs/reference/configuration) &middot; [Python API](https://mcp-hangar.io/docs/guides/FACADE_API)
- [Governance & Front Door](https://mcp-hangar.io/docs/guides/FRONT_DOOR) &middot; [Authentication & RBAC](https://mcp-hangar.io/docs/guides/AUTHENTICATION) &middot; [Observability](https://mcp-hangar.io/docs/guides/OBSERVABILITY)
- [Kubernetes operator](https://github.com/mcp-hangar/mcp-hangar-operator) &middot; [Helm charts](https://github.com/mcp-hangar/helm-charts) &middot; [All docs](https://mcp-hangar.io/docs)

## License

[MIT](LICENSE)
