MCP Resource Server with OAuth 2.0 Token Introspection
A production-ready Model Context Protocol (MCP) server that implements secure authentication and authorization using OAuth 2.0 token introspection (RFC 7662). Designed to work seamlessly with Keycloak and other OAuth 2.0 authorization servers.
- OAuth 2.0 Token Introspection (RFC 7662)
- RFC 9728 Protected Resource Metadata support
- Keycloak Integration ready out of the box
- Scope-based Authorization with configurable required scopes
- Audience Validation ensuring tokens are issued for this resource server
- MCP Tools with built-in authentication
- Multiple Transports (SSE and Streamable HTTP)
- Environment-based Configuration
- Python 3.10+
- Keycloak or another OAuth 2.0 authorization server
- pip or uv package manager
-
Clone the repository
git clone https://github.com/repson/mcp-authz.git cd mcp-authz -
Install dependencies
pip install -r requirements.txt
-
Configure environment variables
cp .env.example .env # Edit .env with your configuration -
Run the server
python -m mcp_authz.server
Configure the server using environment variables. See .env.example for all available options.
| Variable | Default | Description |
|---|---|---|
HOST |
localhost |
Server host address |
PORT |
3000 |
Server port |
AUTH_HOST |
localhost |
Authorization server host |
AUTH_PORT |
8080 |
Authorization server port |
AUTH_REALM |
master |
Keycloak realm name |
OAUTH_CLIENT_ID |
mcp-server |
OAuth 2.0 client ID |
OAUTH_CLIENT_SECRET |
(required) | OAuth 2.0 client secret |
MCP_SCOPE |
mcp:tools |
Required OAuth scope |
TRANSPORT |
streamable-http |
Transport type (sse or streamable-http) |
# Using Python module
python -m mcp_authz.server
# Or if installed as package
mcp-authzThe server exposes MCP tools that require valid OAuth tokens:
import httpx
# Obtain token from authorization server first
token = "your-oauth-token"
# Call MCP tool with authentication
response = httpx.post(
"http://localhost:3000/tools/add_numbers",
headers={"Authorization": f"Bearer {token}"},
json={"a": 5, "b": 3}
)
print(response.json())
# {"operation": "addition", "operand_a": 5, "operand_b": 3, "result": 8, "timestamp": "..."}mcp-authz/
├── mcp_authz/ # Main package
│ ├── __init__.py
│ ├── server.py # FastMCP server setup
│ ├── config.py # Configuration management
│ ├── auth/ # Authentication module
│ │ ├── __init__.py
│ │ └── token_verifier.py # OAuth token introspection
│ └── tools/ # MCP tools
│ └── __init__.py
├── tests/ # Test suite
├── docs/ # Documentation
│ ├── setup.md # Setup guide
│ └── api.md # API reference
└── requirements.txt # Dependencies
Run the test suite:
# Install dev dependencies
pip install pytest pytest-asyncio pytest-cov
# Run all tests
pytest
# Run with coverage
pytest --cov=mcp_authz --cov-report=html- Setup Guide - Detailed installation and Keycloak configuration
- API Reference - Complete API documentation
- Tokens are validated via OAuth 2.0 introspection endpoint
- Audience (
aud) claim validation ensures tokens are intended for this server - Scope validation enforces authorization policies
- HTTPS required in production (enforced by token verifier)
- Client credentials securely loaded from environment variables
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- FastMCP - MCP Python SDK
- Keycloak - OAuth 2.0 Authorization Server
- RFC 7662 - OAuth 2.0 Token Introspection
- RFC 9728 - OAuth 2.0 Protected Resource Metadata
- Ensure
OAUTH_CLIENT_SECRETis correct - Check that the token has the required scope (
mcp:toolsby default) - Verify audience claim matches the server URL
- Confirm
AUTH_HOSTandAUTH_PORTare correct - Check that Keycloak/auth server is running
- Verify network connectivity
For more help, see docs/setup.md or open an issue.