wafpass-mcp
Secure MCP server that exposes WAFpass REST endpoints as tools for AI assistants, with role-based filtering and token validation.
README
WAF++ MCP Bridge
A secure Model Context Protocol server that exposes WAFpass (WAF++ backend) REST endpoints as MCP tools for AI assistants.
Architecture
sequenceDiagram
actor User
participant AI_Client as AI Client (MCP Host)
participant MCP as wafpass-mcp (this bridge)
participant IdP as Keycloak / IdP
participant API as wafpass-server
User->>IdP: Authenticate (OIDC/SAML)
IdP-->>User: IdP tokens
User->>API: Exchange IdP tokens for WAF++ JWT
API-->>User: WAF++ access token
User->>AI_Client: Start AI session
AI_Client->>MCP: SSE /sse with Authorization: Bearer <WAF++ token>
MCP->>API: Introspect token (GET /auth/me) or verify HS256 locally
API-->>MCP: User profile {id, username, role, is_active}
alt Token invalid
MCP-->>AI_Client: 401 Unauthorized
else Token valid
AI_Client->>MCP: tools/list
MCP-->>AI_Client: Tools filtered by user's role
AI_Client->>MCP: tools/call (e.g. list runs)
MCP->>MCP: Validate arguments against OpenAPI schema
MCP->>API: Proxy request with same Bearer token
API-->>MCP: Backend response (row-level auth applied)
MCP-->>AI_Client: MCP TextContent(result)
end
Security model
- IdP-agnostic: The bridge does not talk to Keycloak/Entra/Okta directly. It trusts tokens issued by the upstream
wafpass-server, which handles the actual OIDC/SAML flows. - OIDC pass-through: The AI client inherits the user's WAF++ SSO context by presenting the same Bearer token.
- Least privilege:
tools/listis filtered by the authenticated user's role. Unauthorized tools are invisible. - Context propagation: Every backend call forwards the original
Authorization: Bearerheader so WAFpass can apply endpoint- and row-level authorization. - Strict validation: Tool arguments are validated against Pydantic models generated from the WAFpass OpenAPI spec.
Quick start
Python (local)
# 1. Install dependencies
pip install -e ".[dev]"
# 2. Configure
cp .env.example .env
# Edit .env to point at your WAFpass backend and choose token validation mode.
# 3. Start the bridge
python -m wafpass_mcp.main
The SSE endpoint is available at http://localhost:3001/sse.
Docker Compose (local development)
For local development the bridge can also be built from its Dockerfile and started alongside the rest of the WAF++ stack. From the repository root:
docker compose up -d wafpass-mcp
The service builds from ./wafpass-mcp, depends on wafpass-server, and exposes port 3001. Override WAFPASS_TOKEN_MODE or WAFPASS_JWT_SECRET via .env if you are not using the default introspection mode.
Release artifact:
wafpass-mcpis released as a Python package on PyPI. TheDockerfileexists only for local convenience indocker-compose.yml; the release workflow does not publish a Docker image.
Configuration
| Variable | Default | Description |
|---|---|---|
WAFPASS_API_BASE_URL |
http://localhost:8000 |
Upstream WAFpass API |
WAFPASS_TOKEN_MODE |
introspection |
introspection (call /auth/me) or jwt_secret (local HS256) |
WAFPASS_JWT_SECRET |
(empty) | Required for jwt_secret mode; must match backend secret |
MCP_HOST |
0.0.0.0 |
Bridge bind host |
MCP_PORT |
3001 |
Bridge bind port |
LOG_LEVEL |
INFO |
Logging level |
Token validation modes
- introspection (recommended): The bridge calls
GET /auth/meon WAFpass for every new SSE connection. This is IdP-agnostic, works with any backend secret rotation, and lets WAFpass revoke tokens instantly. - jwt_secret: The bridge verifies the HS256 signature locally. Faster but requires sharing the secret and does not detect token revocation.
Tool registration and role filtering
At startup the bridge fetches http://<WAFPASS_API_BASE_URL>/openapi.json and converts each safe operation into an MCP tool:
- Tool names use the OpenAPI
operationIdwhen present (e.g.list_runs_runs_get,get_run_runs__run_id__get), otherwise a generated name likeget_health. - Path parameters become required tool arguments.
- Query parameters become optional tool arguments.
- Request bodies become top-level tool arguments.
- Operations in
SKIP_OPERATIONS(login, OIDC callbacks, etc.) are never exposed. ROLE_MAPassigns a minimum required role per endpoint. Thelist_toolshandler removes tools the caller's role cannot execute.
Example tool call flow
Authenticated as an engineer:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
The response includes list_runs_runs_get, get_run_runs__run_id__get, get_runs_id_findings_get, etc., but not admin-only tools like get_sso_config_sso_config_get.
Verified against the live ../docker-compose.yml stack: the bridge loads 113 tools for admin, 102 tools for clevel, and intermediate counts for higher roles.
Calling list_runs_runs_get:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_runs_runs_get",
"arguments": {"limit": 5}
}
}
The bridge proxies this to GET /runs?limit=5 with the user's Bearer token. WAFpass applies group-based row filtering and returns only the runs the user may see.
Both the SSE
GET /sseand everyPOST /messages/request must carry the sameAuthorization: Bearer <WAF++ token>header.
Development
pytest
ruff check wafpass_mcp tests scripts
mypy wafpass_mcp tests scripts
These same checks run in GitHub Actions:
.github/workflows/ci.yml— runs on every pull request and push tomain..github/workflows/release.yml— builds, runs lint/type/tests, publishes to PyPI, and creates a GitHub release on every push tomain.
Test scripts
scripts/ contains standalone MCP-over-SSE clients for manual end-to-end checks:
# list all tools visible to the token's role
python scripts/mcp_list_tools.py <WAF++_TOKEN>
# call one tool and print the backend response
python scripts/mcp_call_tool_test.py <WAF++_TOKEN>
# minimal client that prints init + first 10 tools
python scripts/mcp_client_test.py <WAF++_TOKEN>
Deployment notes
- Run behind a TLS-terminating reverse proxy in production.
- Prefer
WAFPASS_TOKEN_MODE=introspectionso the bridge does not need to store the JWT secret. - Keep the bridge on a separate network path from the IdP; it only needs outbound access to WAFpass.
Contributing and security
CONTRIBUTING.md— how to set up local development, run tests, and open pull requests.TECH.md— architecture, request lifecycle, OpenAPI mapping, and token validation details.SECURITY.md— supported versions, vulnerability reporting, and security-sensitive configuration.CODE_OF_CONDUCT.md— community standards and enforcement.LICENSE— Apache License 2.0.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。