Skip to content

Conversation

@ctcanbol
Copy link
Contributor

🐛 Problem

When using the --enabled-tools flag or ENABLED_TOOLS environment variable to filter available tools, the OAuth authorization flow was still requesting permissions for all tools instead of only the filtered ones.

Example:

# Even with this filter:
npx @softeria/ms-365-mcp-server --enabled-tools "mail" --http 3000

# OAuth would request ALL scopes:
scope=Mail.Send+Mail.Read.Shared+Mail.Send.Shared+User.Read.All+Mail.ReadWrite+
      Calendars.ReadWrite+Calendars.Read.Shared+Files.ReadWrite+Notes.Read+
      Notes.Create+Tasks.ReadWrite+Contacts.ReadWrite+User.Read+Chat.Read+
      ChatMessage.Read+ChatMessage.Send+Team.ReadBasic.All+...

🔍 Root Cause

The architecture had a timing mismatch:

  1. Scope building (buildScopesFromEndpoints()) happened early in initialization
  2. It processed all endpoints from endpoints.json regardless of tool filtering
  3. Tool filtering (registerGraphTools()) happened later during tool registration
  4. OAuth used the pre-built scopes that included everything

✅ Solution

Modified the scope building pipeline to respect tool filtering:

  1. src/auth.ts: Added enabledToolsPattern parameter to buildScopesFromEndpoints()

    • Filters endpoints by tool name before extracting scopes
    • Uses the same regex pattern logic as tool registration
    • Logs filtered scope count for debugging
  2. src/index.ts: Pass args.enabledTools to scope builder during initialization

  3. src/server.ts: Pass this.options.enabledTools to scope builder in OAuth discovery endpoints

    • /.well-known/oauth-authorization-server
    • /.well-known/oauth-protected-resource

📝 Changes

Modified Files:

  • src/auth.ts - Enhanced buildScopesFromEndpoints() with tool filtering
  • src/index.ts - Pass enabled tools pattern to scope builder
  • src/server.ts - Pass enabled tools pattern in OAuth endpoints

🧪 Testing

Before:

# Filter to only mail tools
ENABLED_TOOLS="mail" npx @softeria/ms-365-mcp-server --http 3000

# OAuth URL contained 20+ scopes for all services

After:

# Filter to only mail tools
ENABLED_TOOLS="mail" npx @softeria/ms-365-mcp-server --http 3000

# OAuth URL now contains only mail-related scopes:
# Mail.Send, Mail.Read.Shared, Mail.Send.Shared, Mail.ReadWrite, User.Read

Test Steps:

  1. Build the project: npm run build
  2. Clear existing tokens: npx @softeria/ms-365-mcp-server --logout
  3. Start with filtered tools: npx @softeria/ms-365-mcp-server --http 3000 --enabled-tools "mail|calendar" -v
  4. Check OAuth authorization URL - should only contain Mail and Calendar scopes
  5. Verify logs show: Building scopes with tool filter pattern: mail|calendar

💡 Benefits

  • Principle of Least Privilege: Only request permissions actually needed
  • Better User Experience: Users see fewer permission prompts
  • Security: Reduces attack surface by limiting granted permissions
  • Consistency: Tool filtering now works end-to-end (registration + OAuth)

🔄 Backward Compatibility

Fully backward compatible

  • No breaking changes
  • When no tool filter is specified, behavior is identical to before
  • All existing configurations continue to work

📚 Related

  • Fixes issue where OAuth scope filtering was not implemented
  • Aligns with README documentation on tool filtering (lines 355-356)
  • Complements existing --read-only mode for granular access control

@eirikb
Copy link
Contributor

eirikb commented Nov 14, 2025

Hi. This looks good to me, but please update the formatting thing.

@ctcanbol
Copy link
Contributor Author

Hi. This looks good to me, but please update the formatting thing.

fixed!

@eirikb
Copy link
Contributor

eirikb commented Nov 14, 2025

Nice! Thanks :)

@eirikb eirikb merged commit 09e4eb3 into Softeria:main Nov 14, 2025
2 checks passed
@github-actions
Copy link

🎉 This PR is included in version 0.24.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants