Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 48 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ If this project saves you time, please give it a star — it really helps visibi
docker run --rm -p 80:80 --net=host \
-e EXTERNAL_URL=http://localhost \
-e PROXY_URL=http://localhost:8080 \
-e GLOBAL_SECRET=$(openssl rand -hex 32) \
-e PASSWORD=changeme \
-v ./data:/data \
ghcr.io/sigbit/mcp-auth-proxy:latest
Expand Down Expand Up @@ -53,7 +52,6 @@ For a simpler approach to publish local MCP servers over OAuth, consider [MCP Wa
| `DATA_PATH` | No | Data directory path | `./data` |
| `EXTERNAL_URL` | No | External URL for OAuth callbacks | `http://localhost` |
| `PROXY_URL` | No | Target MCP server URL | `http://localhost:8080` |
| `GLOBAL_SECRET` | No | Global secret for session encryption | `supersecret` |
| `GOOGLE_CLIENT_ID` | No | Google OAuth client ID | - |
| `GOOGLE_CLIENT_SECRET` | No | Google OAuth client secret | - |
| `GOOGLE_ALLOWED_USERS` | No | Comma-separated list of allowed Google emails | - |
Expand Down Expand Up @@ -87,7 +85,6 @@ Download the latest binary from [releases](https://github.com/sigbit/mcp-auth-pr
./mcp-auth-proxy \
--external-url "http://localhost:8081" \
--proxy-url "http://localhost:8080" \
--global-secret "$(openssl rand -hex 32)" \
--google-client-id "your-google-client-id" \
--google-client-secret "your-google-client-secret" \
--google-allowed-users "[email protected],[email protected]" \
Expand All @@ -103,7 +100,6 @@ Download the latest binary from [releases](https://github.com/sigbit/mcp-auth-pr
docker run --rm -p 8081:8081 --net=host \
-e EXTERNAL_URL=http://localhost:8081 \
-e PROXY_URL=http://localhost:8080 \
-e GLOBAL_SECRET=$(openssl rand -hex 32) \
-e GOOGLE_CLIENT_ID="your-google-client-id" \
-e GOOGLE_CLIENT_SECRET="your-google-client-secret" \
-e GOOGLE_ALLOWED_USERS="[email protected],[email protected]" \
Expand All @@ -114,3 +110,51 @@ docker run --rm -p 8081:8081 --net=host \
-v ./data:/data \
ghcr.io/sigbit/mcp-auth-proxy:latest
```

## 👨‍💻 For Developers

### Commit Message Guidelines

This project follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification for commit messages. This helps with automated versioning, changelog generation, and makes the commit history more readable.

#### Format

```
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

#### Types

- **feat**: A new feature
- **fix**: A bug fix
- **docs**: Documentation only changes
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **perf**: A code change that improves performance
- **test**: Adding missing tests or correcting existing tests
- **build**: Changes that affect the build system or external dependencies
- **ci**: Changes to our CI configuration files and scripts
- **chore**: Other changes that don't modify src or test files
- **revert**: Reverts a previous commit

#### Examples

```
feat: add GitHub OAuth provider support
fix: resolve token expiration handling
docs: update OAuth setup instructions
refactor: simplify authentication middleware
ci: add automated release workflow
```

#### Breaking Changes

Breaking changes should be indicated by a `!` after the type/scope:

```
feat!: change authentication API to support multiple providers
```
3 changes: 0 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func main() {
var dataPath string
var externalURL string
var proxyURL string
var globalSecret string
var googleClientID string
var googleClientSecret string
var googleAllowedUsers string
Expand Down Expand Up @@ -72,7 +71,6 @@ func main() {
dataPath,
externalURL,
proxyURL,
globalSecret,
googleClientID,
googleClientSecret,
googleAllowedUsersList,
Expand All @@ -95,7 +93,6 @@ func main() {
rootCmd.Flags().StringVarP(&dataPath, "data", "d", getEnvWithDefault("DATA_PATH", "./data"), "Path to the data directory")
rootCmd.Flags().StringVarP(&externalURL, "external-url", "e", getEnvWithDefault("EXTERNAL_URL", "http://localhost"), "External URL for the proxy")
rootCmd.Flags().StringVarP(&proxyURL, "proxy-url", "p", getEnvWithDefault("PROXY_URL", "http://localhost:8080"), "Proxy URL for the proxy")
rootCmd.Flags().StringVarP(&globalSecret, "global-secret", "s", getEnvWithDefault("GLOBAL_SECRET", "supersecret"), "Global secret for the proxy")

// Google OAuth configuration
rootCmd.Flags().StringVar(&googleClientID, "google-client-id", getEnvWithDefault("GOOGLE_CLIENT_ID", ""), "Google OAuth client ID")
Expand Down
9 changes: 5 additions & 4 deletions pkg/mcp-proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package mcpproxy

import (
"context"
"crypto/sha256"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -37,7 +36,6 @@ func Run(
dataPath string,
externalURL string,
proxyURL string,
globalSecret string,
googleClientID string,
googleClientSecret string,
googleAllowedUsers []string,
Expand All @@ -54,8 +52,11 @@ func Run(
if parsedExternalURL.Path != "" {
return fmt.Errorf("external URL must not have a path, got: %s", parsedExternalURL.Path)
}
sha256Hash := sha256.Sum256([]byte(globalSecret))
secret := sha256Hash[:]

secret, err := utils.LoadOrGenerateSecret(path.Join(dataPath, "secret"))
if err != nil {
return fmt.Errorf("failed to load or generate secret: %w", err)
}

var config zap.Config
if os.Getenv("MODE") == "debug" {
Expand Down
18 changes: 18 additions & 0 deletions pkg/utils/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@ import (
"os"
)

func LoadOrGenerateSecret(secretPath string) ([]byte, error) {
_, err := os.Stat(secretPath)
if os.IsNotExist(err) {
secret := make([]byte, 32)
Copy link

Copilot AI Aug 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The secret size of 32 bytes is a magic number. Consider defining it as a constant (e.g., const SecretSize = 32) to improve code maintainability and make the intention clearer.

Suggested change
secret := make([]byte, 32)
const SecretSize = 32
func LoadOrGenerateSecret(secretPath string) ([]byte, error) {
_, err := os.Stat(secretPath)
if os.IsNotExist(err) {
secret := make([]byte, SecretSize)

Copilot uses AI. Check for mistakes.
if _, err := rand.Read(secret); err != nil {
return nil, fmt.Errorf("failed to generate secret: %w", err)
}
if err := os.WriteFile(secretPath, secret, 0600); err != nil {
return nil, fmt.Errorf("failed to save secret: %w", err)
}
return secret, nil
}
if err != nil {
return nil, fmt.Errorf("failed to stat secret file: %w", err)
}
return os.ReadFile(secretPath)
Comment thread
hrntknr marked this conversation as resolved.
Outdated
}

func LoadOrGeneratePrivateKey(keyPath string) (*rsa.PrivateKey, error) {
_, err := os.Stat(keyPath)
if os.IsNotExist(err) {
Expand Down