Skip to content

Commit 1fc0a8f

Browse files
authored
feat(multi-instance): Multi-Instance OAuth Federation with per-session introspection (#277)
* feat(oauth): add multi-instance OAuth federation infrastructure - Add InstanceRegistry service for managing multiple GitLab instances - Add InstanceRateLimiter for per-instance concurrent request limiting - Add instance configuration schema and loader (YAML/JSON/env var support) - Extend TokenContext with apiUrl for per-request instance routing - Extend OAuthSession with gitlabApiUrl for session-to-instance binding - Update enhancedFetch to use context URL with rate limiting integration - Update ConnectionManager for per-instance introspection caching - Add gitlabApiUrl field to Prisma schema for PostgreSQL storage - Add unit tests for InstanceRateLimiter and instance config schemas This lays the foundation for #274 multi-instance support. Users can now configure multiple GitLab instances via GITLAB_INSTANCES env var or GITLAB_INSTANCES_FILE config file. Per-session instance routing and rate limiting are handled automatically. Related to #274 * test(multi-instance): add comprehensive tests for instance infrastructure - Add unit tests for instances-loader (config loading from file/env/legacy) - Add unit tests for InstanceRegistry (singleton, registration, rate limiting) - Add integration tests for InstanceRegistry (real GitLab interaction) These tests verify the multi-instance OAuth federation infrastructure introduced in the previous commit: - Configuration loading from YAML/JSON files and environment variables - Instance registration and URL normalization - Per-instance rate limiting with slot acquisition - Introspection caching with TTL - Connection status tracking - Integration with ConnectionManager Related to #274 * feat(multi-instance): add namespace tier detection, CLI commands, and context switching - Add NamespaceTierDetector service with per-session caching (5-min TTL) - GraphQL query for namespace plan detection - Feature availability mapping per tier (free/premium/ultimate) - CRITICAL: tier is per-NAMESPACE, not per-instance (gitlab.com users may have mixed) - Add CLI instance management commands (instances-command.ts) - list: show configured instances - add: interactive instance configuration - remove: guidance for removal - test: connection testing with version info - info: detailed instance information - sample-config: generate yaml/json templates - Extend OAuth flow with instance selection - AuthCodeFlowState/DeviceFlowState now carry selectedInstance/selectedInstanceLabel - callback.ts and authorize.ts use selectedInstance for session gitlabApiUrl - Add context switching support (blocked in OAuth mode) - ContextManager.switchInstance() for static token mode - Clears namespace tier cache on switch - Re-initializes ConnectionManager for new instance - Sends tools/list_changed notification to clients - Extend ConnectionManager with reinitialize() for instance switching Related to #274 * docs(multi-instance): add comprehensive documentation for multi-instance support - Add docs/guide/multi-instance.md - getting started guide - Add docs/advanced/federation.md - architecture deep dive - Add docs/advanced/tier-detection.md - namespace tier detection explanation - Add docs/advanced/context-switching.md - instance switching behavior - Add docs/configuration/instances.md - instance configuration reference - Add docs/configuration/rate-limiting.md - rate limiting reference - Add docs/cli/instances.md - CLI commands reference - Update README.md with multi-instance section - Update sidebar navigation in vitepress config Related to #274 * fix(multi-instance): improve security and URL parsing robustness - Mask OAuth clientSecret when displaying instance configuration - Use password prompt instead of text for OAuth secret input - Fix npm -> yarn in YAML package install message - Add isExpired field to InstanceSummary introspection for TTL awareness - Fix port vs OAuth client ID parsing (use valid port range 1-65535) - Strip paths/query/fragments from GitLab URLs in schema - Add space-separated URL support in GITLAB_INSTANCES parsing - Document rate limit slot retention during retries - Document per-instance TLS limitation - Clarify reinitialize() URL handling in ConnectionManager Related to #274 * test(tier-detector): add unit tests for NamespaceTierDetector - Add comprehensive unit tests for getFeaturesForTier() - Add tests for clearNamespaceTierCache() with session-specific clearing - Add tests for getNamespaceTier() including GraphQL queries - Add tests for cache TTL expiration (5 min) - Add tests for plan name normalization (gold/silver/bronze) - Add tests for isFeatureAvailable() and cache metrics - Coverage: 97.64% statements, 93.02% branches, 100% functions * fix(cli): enumerate safe fields in config display Replace spread operator with explicit field list when showing instance configuration to user. Displays url, label, oauth.clientId, oauth.scopes, and hasSecret flag without exposing actual secrets. * fix(cli): remove oauth field access from config logging Show only oauthConfigured boolean flag instead of accessing oauth object fields. Satisfies CodeQL sensitive data rule. * test(cli): instances-command and instances-loader unit tests - instances-command: list, add, remove, test, info, sample-config - instances-loader: YAML loading, space-separated URLs parsing - addInstance: OAuth flow, cancel handling at each prompt step - testInstance: HTTP responses, network errors, registry init - showInstanceInfo: full info display, missing optional fields * fix(config): support subpath GitLab deployments and improve URL parsing - instances-schema: preserve pathname in GitLabUrlSchema for subpath deployments - instances-schema: rewrite parseInstanceUrlString with right-to-left parsing - instances-schema: distinguish port numbers (1-65535) from OAuth clientIds - instances-loader: handle both MODULE_NOT_FOUND and ERR_MODULE_NOT_FOUND - ConnectionManager: document multi-instance GraphQL endpoint limitation - fetch: document extractBaseUrl subpath limitation * test(rate-limiter): queue timeout rejection scenario Add test for queued request timeout after queueTimeout expires. Validates that requests waiting in queue are properly rejected with timing out error when the configured timeout is reached. * test(multi-instance): add OAuth mode and instance switching tests - Add OAuth unauthenticated version detection tests - Add ensureIntrospected caching path tests - Add reinitialize method tests - Add switchInstance tests (OAuth blocked, static mode) - Add invalid scope configuration tests - Add reset without initial context test * test(config): add module export tests for index files - Add tests for cli/instances/index.ts exports - Add tests for config/index.ts exports * test(context-manager): add switchInstance success path test - Add mocks for ConnectionManager.reinitialize and clearNamespaceTierCache - Add test verifying successful instance switch completes correctly - Validates scope clearing, notification sending, and return values * fix(multi-instance): dynamic GraphQL endpoint selection for OAuth - Add setEndpoint() method to GraphQLClient for runtime endpoint switching - Update ensureIntrospected() to derive endpoint from token context apiUrl - Update initialize() to accept optional instanceUrl parameter - Fix extractBaseUrl() to preserve subpath for GitLab deployments - Add rateLimitBaseUrl parameter in NamespaceTierDetector - Fix sessionId parsing with lastIndexOf for cache metrics * fix(security): mask sensitive OAuth data in CLI output - Remove clientId from instance info display (show only "configured") - Mask clientSecret in JSON sample config output * test(cli): verify OAuth data masking in instances command - Add test for clientSecret masking in JSON sample config - Add test for invalid JSON fallback behavior - Verify clientId is not exposed in instance info output * fix(multi-instance): subpath support and instance URL tracking - Fix extractBaseUrl to handle API suffix in middle of path (indexOf vs endsWith) - Preserve subpath in GraphQL endpoint derivation (e.g., /gitlab/api/v4 -> /gitlab/api/graphql) - Add getCurrentInstanceUrl() method to ConnectionManager - Fix previousUrl in switchInstance to use actual current instance - Update test comment to reflect lastIndexOf usage * test(ConnectionManager): add getCurrentInstanceUrl tests - Test null return before initialization - Test instance URL return after initialization - Test null return after reset * test(multi-instance): add OAuth endpoint derivation and cache tests - Add tests for OAuth GraphQL endpoint transformation (/api/v4 -> /api/graphql) - Add tests for InstanceRegistry introspection cache path - Add tests for extractBaseUrl function with subpath handling - Fix GraphQLClient mock to include endpoint property - Export extractBaseUrl for direct unit testing * fix(multi-instance): registry init check and cross-platform path handling - Add InstanceRegistry.isInitialized() guard in switchInstance() - Replace process.env.HOME with os.homedir() in instances-loader - Sync docs OAuth display format with actual CLI output - Correct env var name in instances-loader module docstring - Add explanatory notes on endpoint mutation and rate limit semantics * feat(multi-instance): add per-instance connection pool with HTTP/2 support - Add InstanceConnectionPool service managing per-instance HTTP connections - Implement Undici Pool with keepalive and connection multiplexing - Add getGraphQLClient() to InstanceRegistry for thread-safe client access - Add getInstanceClient() to ConnectionManager for per-instance clients - Remove singleton endpoint mutation in favor of per-instance clients - Support per-instance TLS configuration (insecureSkipVerify) * test(connection-pool): add unit tests for InstanceConnectionPool - Test singleton pattern and configuration - Test getGraphQLClient with auth headers and reuse - Test getDispatcher for pool access - Test getStats and getInstanceStats - Test destroyPool and destroyAll cleanup - Test URL normalization (trailing slash, /api/v4, /api/graphql) - Test TLS configuration (insecureSkipVerify) - 31 tests covering all public methods * docs(cli): clarify non-sensitive data in console output - logConfigPreview explicitly excludes OAuth credentials - sample-config outputs placeholder values, not real data * fix(registry): add /api/graphql suffix stripping to normalizeUrl Align InstanceRegistry.normalizeUrl() with InstanceConnectionPool to handle GraphQL endpoint URLs consistently across both services. * docs(multi-instance): clarify design decisions in code - Explain scope clearing order in switchInstance() - Document setHeaders thread-safety in connection pool - Note pool stats availability for future HTTP/2 integration * fix(multi-instance): use per-instance detectors in ensureIntrospected - Create GitLabVersionDetector with per-instance client when URL differs - Create SchemaIntrospector with per-instance client when URL differs - Ensures introspection targets correct GitLab instance in OAuth mode * test(multi-instance): verify ensureIntrospected and normalizeUrl - Test ensureIntrospected early return when already introspected - Test InstanceRegistry URL normalization for /api/graphql suffix * fix(pool): use Proxy pattern for thread-safe auth header injection - Replace setHeaders mutation with request-level header injection - Avoid cross-session header leakage in concurrent OAuth scenarios - Base GraphQL client remains headerless (shared per instance) - Proxy intercepts request/rawRequest calls to merge auth headers * test(context): assert scope cleared after failed switchInstance - Verify hasScope() returns false after switch attempt fails - Complete test coverage for switchInstance error path * fix(pool): add explicit return types to Proxy handler - Satisfy @typescript-eslint/no-unsafe-return rule - Add RequestFn type alias for cleaner code * fix(pool): correct Proxy header injection for graphql-request API - Only merge headers when 3+ args (last arg is requestHeaders) - For 1-2 args, append headers as new argument - Add tests for request/rawRequest header injection scenarios - Verify headers don't pollute variables object * fix(config): normalize URL and cache key consistency - Add /api/graphql suffix stripping to getInstanceByUrl and GitLabUrlSchema - Support whitespace-separated URLs (space, tab, newline) in env var - Use instanceUrl as introspection cache key for multi-instance consistency * test(registry): verify pool stats and GraphQL client retrieval - Test getGraphQLClient returns client for registered instances - Test getConnectionPoolStats and getInstancePoolStats methods - Test resetWithPools destroys connection pools - Test /api/graphql URL normalization in getInstanceByUrl * fix(rate-limiter): make release() idempotent to prevent counter corruption - Wrap release function with guard to ignore duplicate calls - Add /api/graphql suffix stripping to legacy GITLAB_API_URL normalization - Add tests verifying double-release is safely ignored * fix(connection): track introspected instance URL for multi-instance safety - Add introspectedInstanceUrl field to track which instance is cached - Only return early from ensureIntrospected() if same instance - Prevents using wrong instance's schema data in multi-instance OAuth * test(loader): verify /api/graphql stripping from GITLAB_API_URL * test(instances-schema): add edge case tests for URL normalization - Add test for /api/graphql suffix stripping - Add test for subpath with trailing slash normalization - Add test for subpath preservation with API suffix removal - Add test for double-slash edge case that normalizes to origin - Add test for invalid URL with protocol but malformed structure Improves line coverage to 100% for instances-schema.ts. * fix: address Copilot review threads - Fix cache key mismatch between initialize() and ensureIntrospected() by adding fallback lookup for legacy endpoint-keyed cache entries - Fix extractBaseUrl() to validate API suffix is complete path segment preventing false matches on paths like /api/v4foo - Fix RateLimitMetrics docs to match actual interface (no instanceUrl) - Fix test to assert successful switch instead of expecting failure * feat(fetch): integrate per-instance HTTP/2 connection pooling Wire InstanceConnectionPool's Undici dispatchers into enhancedFetch: - Add getDispatcher() to InstanceRegistry for encapsulated access - Modify doFetch() to accept optional instanceDispatcher parameter - Get per-instance dispatcher in enhancedFetch before making requests - Fall back to global dispatcher if instance not yet registered Also fixes Copilot review issues: - Fix extractBaseUrl() to scan for all occurrences of API suffixes - Set introspectedInstanceUrl in initialize() to avoid re-introspection - Clear introspectedInstanceUrl in reset() to prevent stale cache This enables true HTTP/2 multiplexing and connection reuse per-instance, with per-instance TLS configuration support. * test(fetch): add per-instance dispatcher tests and document connection pool - Add static import of InstanceRegistry for test isolation - Add getDispatcher tests for registered/unregistered instances - Add rate limit slot acquisition test with registry initialized - Document InstanceConnectionPool architecture in federation.md - Update request flow diagram with HTTP/2 connection pool layer * fix(multi-instance): correct introspected instance URL tracking and lazy pool creation - Use baseUrl instead of GITLAB_BASE_URL for introspectedInstanceUrl in initialize() - Add lazy pool creation in getDispatcher() for registered instances - Ensures per-instance TLS settings are applied for REST-only calls - Add test for lazy pool creation behavior * fix(multi-instance): use origin for Undici Pool and reduce log noise - Extract origin from normalized URL for Undici Pool creation - Fixes subpath-deployed GitLab instances (e.g., https://example.com/gitlab) - Change unregistered instance rate limit log from warn to debug level * fix(cli): mask clientSecret in sample config output and deprecate setEndpoint - Mask clientSecret in both JSON and YAML sample config formats - Use allowlist pattern for config preview logging - Deprecate GraphQLClient.setEndpoint() for per-instance clients * fix(rate-limiter): add bounds check to prevent negative activeRequests - Add Math.max(0, ...) guard in release() to handle edge cases - Expand extractBaseUrl comment explaining nested loop necessity * docs: clarify security and design decisions in code comments - instances-command.ts: note that config with secrets never reaches logging - instances-schema.ts: explain multi-strategy parsing rationale - fetch.ts: add thundering herd note for slot retention during backoff * docs(fetch): clarify global vs per-instance dispatcher TLS handling - Update createDispatcher JSDoc to explain fallback-only role - Add security note about non-sensitive fields in CLI output * docs: expand inline explanations for regex masking and loop exit - instances-command.ts: document YAML regex pattern coverage - fetch.ts: clarify labeled break exits both loops on match * docs: clarify sessionId format and URL parsing rationale - NamespaceTierDetector: note that sessionId is UUID (no colons) - fetch.ts: explain why endsWith won't work for mid-path suffixes - instances-command.ts: note regex won't re-match masked values * docs(cli): explain why clientId is shown in output User just entered the clientId and needs the exact value for their config.
1 parent e2df2e7 commit 1fc0a8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+9669
-91
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ A [Model Context Protocol](https://modelcontextprotocol.io) server that connects
3737
- **Auto-discovery** — Detects GitLab config from git remotes
3838
- **Fine-grained control** — Enable/disable tool groups, filter actions, customize descriptions
3939
- **Docker support**`ghcr.io/structured-world/gitlab-mcp:latest`
40+
- **Multi-instance** — Connect to multiple GitLab instances with per-instance OAuth and rate limiting
41+
42+
## Multi-Instance Support
43+
44+
Connect to multiple GitLab instances simultaneously:
45+
46+
```bash
47+
# Via environment variable
48+
GITLAB_INSTANCES="https://gitlab.com https://git.company.io"
49+
50+
# Via configuration file
51+
GITLAB_INSTANCES_FILE=~/.config/gitlab-mcp/instances.yaml
52+
```
53+
54+
Features:
55+
- Per-instance OAuth applications
56+
- Per-instance rate limiting
57+
- Per-namespace tier detection (Free/Premium/Ultimate)
58+
- Automatic schema introspection per instance
59+
60+
See [Multi-Instance Setup](https://gitlab-mcp.sw.foundation/guide/multi-instance) for details.
4061

4162
## Documentation
4263

@@ -46,6 +67,7 @@ Full documentation is available at **[gitlab-mcp.sw.foundation](https://gitlab-m
4667
|---------|-------------|
4768
| [Installation](https://gitlab-mcp.sw.foundation/guide/installation/npm) | npm, Docker, VS Code, Codex |
4869
| [Configuration](https://gitlab-mcp.sw.foundation/guide/configuration) | Environment variables, feature flags |
70+
| [Multi-Instance](https://gitlab-mcp.sw.foundation/guide/multi-instance) | Multiple GitLab instances, federation |
4971
| [Tool Reference](https://gitlab-mcp.sw.foundation/tools/) | All 44 tools with parameters |
5072
| [OAuth Setup](https://gitlab-mcp.sw.foundation/security/oauth) | Team authentication with Claude |
5173
| [TLS/HTTPS](https://gitlab-mcp.sw.foundation/advanced/tls) | Production deployment with SSL |

docs/.vitepress/config.mts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,21 @@ export default defineConfig({
103103
collapsed: false,
104104
items: [
105105
{ text: "Environment Variables", link: "/guide/configuration" },
106+
{ text: "Multi-Instance", link: "/guide/multi-instance" },
106107
{ text: "Auto-Discovery", link: "/guide/auto-discovery" },
107108
{ text: "Transport Modes", link: "/guide/transport" },
108109
],
109110
},
110111
],
112+
"/configuration/": [
113+
{
114+
text: "Configuration Reference",
115+
items: [
116+
{ text: "Instance Configuration", link: "/configuration/instances" },
117+
{ text: "Rate Limiting", link: "/configuration/rate-limiting" },
118+
],
119+
},
120+
],
111121
"/cli/": [
112122
{
113123
text: "CLI Reference",
@@ -116,6 +126,7 @@ export default defineConfig({
116126
{ text: "setup", link: "/cli/setup" },
117127
{ text: "init", link: "/cli/init" },
118128
{ text: "install", link: "/cli/install" },
129+
{ text: "instances", link: "/cli/instances" },
119130
{ text: "docker", link: "/cli/docker" },
120131
{ text: "list-tools", link: "/cli/list-tools" },
121132
],
@@ -258,6 +269,9 @@ export default defineConfig({
258269
items: [
259270
{ text: "TLS / HTTPS", link: "/advanced/tls" },
260271
{ text: "Customization", link: "/advanced/customization" },
272+
{ text: "Federation Architecture", link: "/advanced/federation" },
273+
{ text: "Tier Detection", link: "/advanced/tier-detection" },
274+
{ text: "Context Switching", link: "/advanced/context-switching" },
261275
],
262276
},
263277
],

docs/advanced/context-switching.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
---
2+
title: Context Switching
3+
description: "How GitLab MCP handles switching between GitLab instances"
4+
head:
5+
- - meta
6+
- name: keywords
7+
content: context switching, instance switching, OAuth, static token, manage_context, MCP
8+
---
9+
10+
# Context Switching
11+
12+
How GitLab MCP handles switching between GitLab instances depending on authentication mode.
13+
14+
## Behavior by Auth Mode
15+
16+
| Mode | Instance Switching | Required Action |
17+
|------|-------------------|-----------------|
18+
| OAuth | **Blocked** | User must re-authenticate |
19+
| Static Token | Allowed via `manage_context` | Re-introspection + tool validation |
20+
21+
## OAuth Mode
22+
23+
In OAuth mode, the session is tied to a specific GitLab instance:
24+
25+
```
26+
User → OAuth Flow → Instance Selection → Authentication → Session
27+
28+
Session bound to
29+
selected instance
30+
```
31+
32+
### Why Switching is Blocked
33+
34+
OAuth tokens are issued by a specific GitLab instance. Using an OAuth token from gitlab.com against git.company.io would fail authentication.
35+
36+
### How to Switch Instances
37+
38+
To work with a different instance in OAuth mode:
39+
40+
1. End current session (logout)
41+
2. Initiate new OAuth flow
42+
3. Select the desired instance
43+
4. Authenticate with that instance
44+
45+
```json
46+
// Attempting to switch in OAuth mode
47+
// manage_context
48+
{
49+
"action": "switch_instance",
50+
"instanceUrl": "https://git.company.io"
51+
}
52+
53+
// Error response
54+
{
55+
"error": "Cannot switch instances in OAuth mode. Please re-authenticate with the desired GitLab instance."
56+
}
57+
```
58+
59+
## Static Token Mode
60+
61+
In static token mode (using `GITLAB_TOKEN`), instance switching is allowed via `manage_context`.
62+
63+
### Switching Instances
64+
65+
```json
66+
// manage_context
67+
{
68+
"action": "switch_instance",
69+
"instanceUrl": "https://git.company.io"
70+
}
71+
```
72+
73+
### What Happens on Switch
74+
75+
1. **Validate instance** - Check instance is registered
76+
2. **Clear namespace cache** - Old tier data is invalid
77+
3. **Re-introspect** - Fetch version and schema for new instance
78+
4. **Re-validate tools** - Check tools against new schema
79+
5. **Notify client** - Send `tools/list_changed` if tools changed
80+
81+
### Response Format
82+
83+
```json
84+
{
85+
"success": true,
86+
"instance": "https://git.company.io",
87+
"label": "Corporate GitLab",
88+
"version": "16.8.0",
89+
"availableTools": 42,
90+
"disabledTools": [
91+
"manage_work_items", // Work Items API not available in v16.8
92+
"browse_iterations" // Requires newer version
93+
],
94+
"message": "Switched to Corporate GitLab (v16.8.0). 2 tools disabled due to schema differences."
95+
}
96+
```
97+
98+
## Tool Re-validation
99+
100+
Different GitLab versions have different GraphQL schemas. When switching instances:
101+
102+
### Schema Validation
103+
104+
Tools declare required GraphQL types and widgets:
105+
106+
```typescript
107+
const manageWorkItemsTool = {
108+
name: 'manage_work_items',
109+
requiredGraphQLTypes: ['WorkItem', 'WorkItemType'],
110+
requiredWidgets: ['DESCRIPTION', 'LABELS', 'ASSIGNEES'],
111+
// ...
112+
};
113+
```
114+
115+
On instance switch:
116+
1. Fetch GraphQL schema for new instance
117+
2. Check each tool's requirements against schema
118+
3. Disable tools with missing types/widgets
119+
4. Report disabled tools to user
120+
121+
### Version Compatibility
122+
123+
| GitLab Version | Work Items API | Iterations | OKRs |
124+
|----------------|----------------|------------|------|
125+
| 17.0+ | Full support | Full | Full |
126+
| 16.x | Partial | Full | Limited |
127+
| 15.x | Not available | Partial | Not available |
128+
129+
## Namespace Tier Cache
130+
131+
When switching instances:
132+
133+
```
134+
Before switch:
135+
Session namespace cache:
136+
"gitlab-org" → Ultimate
137+
"my-group" → Free
138+
139+
After switch:
140+
Session namespace cache:
141+
(cleared - invalid for new instance)
142+
```
143+
144+
The cache is cleared because:
145+
- Namespace paths may not exist on new instance
146+
- Same path may have different tier on new instance
147+
- Old cache data would cause incorrect feature checks
148+
149+
## Multi-Token Presets
150+
151+
For advanced setups, you can configure presets with different tokens for different instances:
152+
153+
```yaml
154+
# profiles.yaml
155+
presets:
156+
gitlab-com:
157+
host: https://gitlab.com
158+
token: glpat-gitlab-token
159+
160+
corporate:
161+
host: https://git.company.io
162+
token: glpat-corporate-token
163+
```
164+
165+
Switch between presets:
166+
167+
```json
168+
// manage_context
169+
{
170+
"action": "switch_preset",
171+
"preset": "corporate"
172+
}
173+
```
174+
175+
This also triggers re-introspection and tool validation.
176+
177+
## Best Practices
178+
179+
### OAuth Mode
180+
181+
- Configure all needed instances upfront
182+
- Use instance labels for easy identification
183+
- Plan workflows around single-instance sessions
184+
185+
### Static Token Mode
186+
187+
- Use presets for frequently-switched instances
188+
- Ensure tokens have appropriate scopes for each instance
189+
- Be aware of tool availability differences between versions
190+
191+
### Mixed Environments
192+
193+
If your team uses both OAuth and static tokens:
194+
- OAuth users: One session per instance
195+
- Static token users: Can switch freely
196+
- Document which approach each team member uses
197+
198+
## Related Documentation
199+
200+
- [Multi-Instance Setup](/guide/multi-instance) - Getting started guide
201+
- [Federation Architecture](/advanced/federation) - Technical deep dive
202+
- [Tier Detection](/advanced/tier-detection) - Namespace tier detection
203+
- [Configuration Reference](/configuration/instances) - Configuration options

0 commit comments

Comments
 (0)