FastMcp JWT Auth
JWT Authorization header authentication extension for FastMcp RackTransport.
This gem extends the FastMcp gem to enable JWT-based user authentication via Authorization headers in Rails applications. It provides configurable callbacks for token decoding, user lookup, and validation.
Problem
FastMcp::Transports::RackTransport doesn't have built-in JWT authentication support. For integrating with external MCP clients that use JWT tokens for authentication, you need a way to:
- Extract JWT tokens from Authorization headers
- Decode and validate the tokens
- Find users based on token payload
- Set
Current.user
for the request duration
Solution
This gem provides a monkey patch for FastMcp::Transports::RackTransport
that:
- Extracts JWT tokens from
Authorization: Bearer
headers - Decodes tokens using configurable callbacks
- Validates token expiration and other claims
- Finds users using configurable lookup logic
- Sets
Current.user
for request duration - Cleans up
Current
after request processing
Installation
Prerequisites: This gem requires the fast-mcp gem to be installed first.
Add both gems to your application's Gemfile:
gem 'fast-mcp' # Required base gem
gem 'fast_mcp_jwt_auth', github: 'jchsoft/fast_mcp_jwt_auth' # This extension
And then execute:
bundle install
Note: The fast-mcp
gem provides the core MCP (Model Context Protocol) server functionality, while this gem extends it with JWT authentication support.
Usage
Automatic Integration
No configuration needed for basic usage! Just add the gem to your Gemfile and configure the callbacks.
The gem will:
- ✅ Automatically patch FastMcp::Transports::RackTransport during Rails initialization
- ✅ Extract JWT tokens from Authorization: Bearer headers automatically
- ✅ Use Rails.logger for logging (no configuration required)
- ✅ Handle errors gracefully with fallback to normal request processing
MCP Server Configuration
⚠️ IMPORTANT: This gem enables JWT authentication for your Rails application when used with the fast_mcp
gem. For MCP clients to authenticate with your Rails app, they need to send JWT tokens in the Authorization: Bearer
header.
Client-Side MCP Configuration
When your Rails app is running as an MCP server (using fast_mcp
gem and fast_mcp_jwt_auth
gem), MCP clients need to be configured with proper authentication headers to connect to it.
For example create or update your .mcp.json
configuration file:
cp .mcp.json.example .mcp.json
Critical: The headers
section with Authorization: Bearer
is essential for JWT authentication:
{
"mcpServers": {
"your-rails-app": {
"type": "sse",
"name": "Your Rails MCP Server",
"url": "https://your-rails-app.com/mcp/sse",
"headers": {
"Authorization": "Bearer ${JWT_TOKEN}"
}
}
}
}
Real Example - WorkVector Integration
{
"mcpServers": {
"workvector-production": {
"type": "sse",
"name": "WorkVector Production",
"url": "https://workvector.com/mcp/sse",
"headers": {
"Authorization": "Bearer ${WORKVECTOR_TOKEN}"
}
}
}
}
Why Headers are Critical
❌ This WON'T work - missing authentication:
{
"mcpServers": {
"your-app": {
"type": "sse",
"url": "https://your-app.com/mcp/sse"
}
}
}
✅ This WILL work - includes JWT authentication header:
{
"mcpServers": {
"your-app": {
"type": "sse",
"url": "https://your-app.com/mcp/sse",
"headers": {
"Authorization": "Bearer ${JWT_TOKEN}"
}
}
}
}
Environment Variables
Use environment variables for sensitive tokens in your .mcp.json
:
-
${WORKVECTOR_TOKEN}
- Your WorkVector authentication token -
${MCP_JWT_TOKEN}
- JWT token for other MCP servers -
${PWD}
- Current working directory path
Set these in your environment or .env
file:
export WORKVECTOR_TOKEN="your_workvector_token_here"
export MCP_JWT_TOKEN="your_jwt_token_here"
Security Best Practices
- ✅ Never commit
.mcp.json
to version control (it's in.gitignore
) - ✅ Use environment variables for tokens instead of hardcoding them
- ✅ Keep tokens secure and rotate them regularly
- ✅ Use the example file as a template for new environments
Configuration
Create an initializer to configure JWT decoding and user lookup:
# config/initializers/fast_mcp_jwt_auth.rb
FastMcpJwtAuth.configure do |config|
config.enabled = true
# JWT token decoding callback
config.jwt_decoder = ->(jwt_token) do
JWT.decode(jwt_token, Rails.application.credentials.secret_key_base, true, algorithm: 'HS256')[0]
end
# User lookup callback
config.user_finder = ->(decoded_token) do
User.find_by(authentication_token: decoded_token['authentication_token'])
end
# Optional: Token validation callback (defaults to expiration check)
config.token_validator = ->(decoded_token) do
decoded_token['exp'].nil? || decoded_token['exp'] >= Time.current.to_i
end
# Optional: Custom current user setter (defaults to Current.user=)
config.current_user_setter = ->(user) do
Current.user = user
end
# Optional: Custom context resetter (defaults to Current.reset)
config.current_resetter = -> do
Current.reset
end
end
WorkVector Integration Example
For WorkVector-style JWT integration using JwtIdClaim:
# config/initializers/fast_mcp_jwt_auth.rb
FastMcpJwtAuth.configure do |config|
config.enabled = true
# Use JwtIdClaim for token decoding (WorkVector pattern)
config.jwt_decoder = ->(jwt_token) do
JwtIdClaim.decode(jwt_token)
end
# Find user by authentication_token from JWT payload
config.user_finder = ->(decoded_token) do
User.find_by(authentication_token: decoded_token[:authentication_token])
end
end
Configuration Callbacks
The gem provides these configurable callbacks:
-
jwt_decoder
: Callback for JWT token decoding (required) -
user_finder
: Callback for user lookup from decoded token (required) -
token_validator
: Callback for token validation (optional, defaults to expiration check) -
current_user_setter
: Callback for setting current user (optional, defaults toCurrent.user=
) -
current_resetter
: Callback for resetting current context (optional, defaults toCurrent.reset
)
How It Works
- Request Processing: When FastMcp processes an MCP request, the patch intercepts it
-
Header Extraction: Looks for
Authorization: Bearer <token>
header -
Token Decoding: Uses configured
jwt_decoder
callback to decode the JWT -
Token Validation: Validates token using
token_validator
callback -
User Lookup: Finds user using
user_finder
callback -
Context Setting: Sets current user using
current_user_setter
callback - Request Processing: Continues with normal MCP request processing
-
Cleanup: Resets current context using
current_resetter
callback
Error Handling
The gem handles errors gracefully:
- Invalid JWT tokens are logged as warnings but don't break request processing
- Missing or malformed Authorization headers are ignored silently
- Decoding errors fall back to normal request processing without authentication
- User lookup failures result in no authentication but normal request processing
Requirements
- Ruby >= 3.1.0
- Rails >= 7.0
- FastMcp gem
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
Testing
rake test
rubocop
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/jchsoft/fast_mcp_jwt_auth.
License
The gem is available as open source under the terms of the MIT License.