Skip to content

Commit 2e55712

Browse files
Pepanclaude
andcommitted
docs: add Claude Code configuration and project documentation
- Add .mcp.json with WorkVector and filesystem MCP server configuration - Add .ruby-version file for Ruby 3.4.2 - Add comprehensive CLAUDE.md with gem overview, architecture, and development guidelines - Update .gitignore for better project file exclusions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a378b49 commit 2e55712

File tree

8 files changed

+266
-47
lines changed

8 files changed

+266
-47
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@
66
/pkg/
77
/spec/reports/
88
/tmp/
9+
/.idea/*
10+
11+
# macOS
12+
.DS_Store
13+
.DS_Store?
14+
._*
15+
.Spotlight-V100
16+
.Trashes
17+
ehthumbs.db
18+
Thumbs.db

.mcp.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"mcpServers": {
3+
"workvector-production": {
4+
"type": "sse",
5+
"name": "WorkVector Production",
6+
"url": "https://workvector.com/mcp/sse",
7+
"headers": {
8+
"Authorization": "Bearer ${WORKVECTOR_TOKEN}"
9+
}
10+
},
11+
"filesystem-project": {
12+
"type": "stdio",
13+
"name": "Filesystem",
14+
"command": "npx",
15+
"args": [
16+
"-y",
17+
"@modelcontextprotocol/server-filesystem",
18+
"${PWD}"
19+
]
20+
}
21+
}
22+
}

.ruby-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ruby-3.4.2

CLAUDE.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code when working with the `fast_mcp_jwt_auth` gem.
4+
5+
## Gem Overview
6+
7+
FastMCp Jwt Auth provides JWT authentication for FastMcp RackTransport, enabling secure user authentication in MCP requests.
8+
It integrates seamlessly with Rails, allowing you to authenticate users using JWT tokens in a Rails application.
9+
10+
## Code Conventions
11+
12+
### Code Quality
13+
- Max 200 chars/line (soft limit - prefer readability over strict compliance)
14+
- breaking Ruby chain calls destroys the natural sentence flow and readability
15+
- 14 lines/method, 110 lines/class
16+
- Comments and tests in English
17+
- KEEP CODE DRY (Don't Repeat Yourself)
18+
19+
### Ruby/Rails Philosophy
20+
- **DO IT RUBY WAY OR RAILS WAY** - it's not Python, Java or PHP!
21+
- Strong use of Ruby metaprogramming techniques
22+
- code line should look like human sentence (e.g. `3.times do` not `for i in 0..2 do` - Ruby syntax reads like English)
23+
- keep code raising exceptions when it's programmer's fault - DO NOT validate method parameters, expect them to be correct! Only validate user input
24+
- do not repeat name of parameter in method name (e.g. `def create_new_user_from_user(user)` should be `def create_new_user_from(user)`)
25+
- do not use extra variable if used only once - saves memory and reduces GC pressure under high traffic (e.g. `user = User.find(params[:id]); user.update(...)` should be `User.find(params[:id]).update(...)`) - use `.tap do` for chaining when you need to use the object later
26+
- use metaprogramming instead of case statements (e.g. `self.send(method_name, params)` instead of `case method_name; when "find_slot"...` - let Ruby handle method dispatch and NoMethodError)
27+
- PREFER FUNCTIONAL STYLE: use flat_map, map, select over loops and temp variables (e.g. `items.flat_map(&:children).uniq` not `results = []; items.each { |i| results.concat(i.children) }; results.uniq`)
28+
- USE PATTERN MATCHING: Ruby 3.0+ `case/in` for complex conditionals instead of if/elsif chains - more expressive and catches unhandled cases
29+
- ONE CLEAR RESPONSIBILITY: each method should do one thing well - if method has "and" in description, split it (e.g. `normalize_and_search``normalize` + `search`)
30+
- FOLLOW KISS PRINCIPLE: Keep It Simple, Stupid - avoid unnecessary complexity, use simple solutions first
31+
- ALWAYS TEST YOUR CODE
32+
33+
### Error Handling
34+
- Use meaningful exception classes (not generic StandardError)
35+
- Log errors with context using the configured logger
36+
- Proper error propagation with fallback mechanisms
37+
- Use `rescue_from` for common exceptions in Rails integration
38+
39+
### Performance Considerations
40+
- Use database connection pooling efficiently
41+
- Avoid blocking operations in main threads
42+
- Cache expensive operations
43+
- Monitor thread lifecycle and cleanup
44+
45+
### Thread Safety
46+
- All operations must be thread-safe for cluster mode
47+
- Use proper synchronization when accessing shared resources
48+
- Handle thread lifecycle correctly (creation, monitoring, cleanup)
49+
- Use connection checkout/checkin pattern for database operations
50+
51+
### Gem Specific Guidelines
52+
53+
#### Configuration
54+
- Use configuration object pattern for all settings
55+
- Provide sensible defaults that work out of the box
56+
- Make all components configurable but not required
57+
- Support both programmatic and initializer-based configuration
58+
59+
#### Rails Integration
60+
- Use Railtie for automatic Rails integration
61+
- Hook into appropriate Rails lifecycle events
62+
- Respect Rails conventions for logging and error handling
63+
- Provide manual configuration options for non-Rails usage
64+
65+
#### Error Recovery
66+
- Implement automatic retry with backoff for transient errors
67+
- Provide fallback mechanisms when PubSub fails
68+
- Log errors appropriately without flooding logs
69+
- Handle connection failures gracefully
70+
71+
#### Testing
72+
- Test all public interfaces
73+
- Mock external dependencies (PostgreSQL, FastMcp)
74+
- Test error conditions and edge cases
75+
- Provide test helpers for gem users
76+
- Test both Rails and non-Rails usage
77+
78+
## Architecture
79+
80+
### Components
81+
82+
1. **FastMcpJwtAuth::Service** - Core JWT authentication service
83+
- Handles JWT token generation and validation
84+
- Integrates with FastMcp RackTransport for secure requests
85+
2. **FastMcpJwtAuth::Configuration** - Configuration management
86+
- Manages settings like JWT secret, expiration, and algorithm
87+
3. **FastMcpJwtAuth::RackTransportPatch** - Monkey patch for FastMcp transport
88+
- Overrides `send_message` to include JWT authentication
89+
4. **FastMcpJwtAuth::Railtie** - Rails integration and lifecycle management
90+
- Automatically patches FastMcp::Transports::RackTransport during Rails initialization
91+
92+
### Message Flow
93+
94+
1. **MCP Request Received** - FastMcp RackTransport receives HTTP request with Authorization header
95+
2. **JWT Extraction** - Extract Bearer token from Authorization header (`HTTP_AUTHORIZATION`)
96+
3. **Token Decoding** - Use configured `jwt_decoder` callback to decode JWT token
97+
4. **Token Validation** - Validate token expiration and other claims using `token_validator` callback
98+
5. **User Lookup** - Find user from decoded token using `user_finder` callback
99+
6. **User Assignment** - Set current user in context using `current_user_setter` callback
100+
7. **Request Processing** - Continue with normal MCP request handling
101+
8. **Cleanup** - Clear current user context using `current_resetter` callback
102+
103+
### Thread Management
104+
105+
The gem is designed to be thread-safe for use in Rails applications:
106+
107+
- **Request Isolation** - Each MCP request runs in its own thread context
108+
- **Current User Context** - Uses thread-local storage via Rails `Current` class for user context
109+
- **Monkey Patching Safety** - Patch is applied only once using thread-safe flag checking
110+
- **No Shared State** - All operations are stateless except for configuration (immutable after initialization)
111+
- **Callback Thread Safety** - User-provided callbacks (`jwt_decoder`, `user_finder`, etc.) must be thread-safe
112+
- **Automatic Cleanup** - Current user context is always cleared after request processing (even on exceptions)
113+
114+
## Dependencies
115+
116+
### Runtime Dependencies
117+
- **rails** (>= 7.0) - Required for Rails integration, Current class, and logger support
118+
119+
### Development Dependencies
120+
- **jwt** (~> 2.0) - Used in tests for JWT token generation and decoding examples
121+
- **minitest** (~> 5.16) - Test framework
122+
- **rubocop** (~> 1.21) - Ruby code style enforcement
123+
- **rubocop-minitest** (~> 0.25) - Minitest-specific RuboCop rules
124+
- **rubocop-rails** (~> 2.0) - Rails-specific RuboCop rules
125+
126+
### External Dependencies
127+
- **FastMcp** - The gem monkey patches `FastMcp::Transports::RackTransport` (not declared as dependency to avoid circular dependencies)
128+
- **JWT Library** - Users must provide their own JWT decoder implementation (commonly `jwt` gem)
129+
130+
## Development
131+
132+
### Running Tests
133+
```bash
134+
bundle exec rake test
135+
```
136+
137+
### Linting
138+
```bash
139+
bundle exec rubocop
140+
```
141+
142+
### Console
143+
```bash
144+
bundle exec rake console
145+
```
146+
147+
## WorkVector Task Access
148+
- To read a task from WorkVector, use the workvector-production MCP server:
149+
1. Use `ListMcpResourcesTool` to get all available resources
150+
2. Load template using `ReadMcpResourceTool` with URI "template://task"
151+
3. Parse the task URL (e.g., https://workvector.com/jchsoft/tasks/8383) to extract account_code and task_id
152+
4. Load task content using the template with account_code and task_id parameters
153+
- To log work progress, use `mcp__workvector-production__LogWorkProgressTool` with account_code, task_id, description and progress_percent. Log progress incrementally as you work on the task!
154+
- **IMPORTANT**: Always set progress_percent to max 90% on first task completion - leave a few percent for potential follow-ups and adjustments

lib/fast_mcp_jwt_auth.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ def self.config
2626
def self.logger
2727
Rails.logger
2828
end
29+
30+
# DRY logging with consistent prefix
31+
def self.log_debug(message)
32+
logger&.debug "FastMcpJwtAuth: #{message}"
33+
end
34+
35+
def self.log_info(message)
36+
logger&.info "FastMcpJwtAuth: #{message}"
37+
end
38+
39+
def self.log_warn(message)
40+
logger&.warn "FastMcpJwtAuth: #{message}"
41+
end
2942
end
3043

3144
# Load patch after module is fully defined

lib/fast_mcp_jwt_auth/rack_transport_patch.rb

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ module RackTransportPatch
1010

1111
def self.apply_patch!
1212
if @patch_applied
13-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: RackTransport patch already applied, skipping"
13+
FastMcpJwtAuth.log_debug "RackTransport patch already applied, skipping"
1414
return
1515
end
1616

1717
unless defined?(FastMcp::Transports::RackTransport)
18-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: FastMcp::Transports::RackTransport not defined yet, skipping patch"
18+
FastMcpJwtAuth.log_debug "FastMcp::Transports::RackTransport not defined yet, skipping patch"
1919
return
2020
end
2121

2222
unless FastMcpJwtAuth.config.enabled
23-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: JWT authentication disabled, skipping patch"
23+
FastMcpJwtAuth.log_debug "JWT authentication disabled, skipping patch"
2424
return
2525
end
2626

27-
FastMcpJwtAuth.logger&.info "FastMcpJwtAuth: Applying JWT authentication patch to FastMcp::Transports::RackTransport"
27+
FastMcpJwtAuth.log_info "Applying JWT authentication patch to FastMcp::Transports::RackTransport"
2828

2929
patch_transport_class
3030
@patch_applied = true
31-
FastMcpJwtAuth.logger&.info "FastMcpJwtAuth: JWT authentication patch applied successfully"
31+
FastMcpJwtAuth.log_info "JWT authentication patch applied successfully"
3232
end
3333

3434
def self.patch_transport_class
@@ -54,24 +54,22 @@ def authenticate_user_from_jwt(request)
5454
auth_header = request.env["HTTP_AUTHORIZATION"]
5555
return unless auth_header&.start_with?("Bearer ")
5656

57-
jwt_token = auth_header.sub("Bearer ", "")
58-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: Extracted JWT token from Authorization header"
59-
60-
authenticate_user_with_token(jwt_token)
57+
auth_header.sub("Bearer ", "").tap do |jwt_token|
58+
FastMcpJwtAuth.log_debug "Extracted JWT token from Authorization header"
59+
authenticate_user_with_token(jwt_token)
60+
end
6161
rescue StandardError => e
62-
FastMcpJwtAuth.logger&.warn "FastMcpJwtAuth: JWT token authentication failed: #{e.message}"
62+
FastMcpJwtAuth.log_warn "JWT token authentication failed: #{e.message}"
6363
end
6464

6565
def authenticate_user_with_token(jwt_token)
6666
return unless FastMcpJwtAuth.config.jwt_decoder
6767

68-
decoded_token = FastMcpJwtAuth.config.jwt_decoder.call(jwt_token)
69-
return unless decoded_token
70-
71-
return unless token_valid?(decoded_token)
68+
FastMcpJwtAuth.config.jwt_decoder.call(jwt_token)&.tap do |decoded_token|
69+
next unless token_valid?(decoded_token)
7270

73-
user = find_user_from_token(decoded_token)
74-
assign_current_user(user) if user
71+
find_user_from_token(decoded_token)&.tap { |user| assign_current_user(user) }
72+
end
7573
end
7674

7775
def token_valid?(decoded_token)
@@ -83,9 +81,9 @@ def token_valid?(decoded_token)
8381
def find_user_from_token(decoded_token)
8482
return unless FastMcpJwtAuth.config.user_finder
8583

86-
user = FastMcpJwtAuth.config.user_finder.call(decoded_token)
87-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: Authenticated user: #{user}" if user
88-
user
84+
FastMcpJwtAuth.config.user_finder.call(decoded_token)&.tap do |user|
85+
FastMcpJwtAuth.log_debug "Authenticated user: #{user}"
86+
end
8987
end
9088

9189
def assign_current_user(user)

lib/fast_mcp_jwt_auth/railtie.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ class Railtie < Rails::Railtie
77
initializer "fast_mcp_jwt_auth.apply_patch", after: :load_config_initializers do
88
Rails.application.config.after_initialize do
99
if FastMcpJwtAuth.config.enabled
10-
FastMcpJwtAuth.logger&.debug "FastMcpJwtAuth: Attempting to apply RackTransport patch"
10+
FastMcpJwtAuth.log_debug "Attempting to apply RackTransport patch"
1111
FastMcpJwtAuth::RackTransportPatch.apply_patch!
1212
else
13-
FastMcpJwtAuth.logger&.info "FastMcpJwtAuth: JWT authentication disabled"
13+
FastMcpJwtAuth.log_info "JWT authentication disabled"
1414
end
1515
end
1616
end

0 commit comments

Comments
 (0)