( serverName: string, capabilities: ServerCapabilities | undefined, pluginSource: string | undefined, )
| 212 | * this gate only decides whether the notification handler registers. |
| 213 | */ |
| 214 | export function gateChannelServer( |
| 215 | serverName: string, |
| 216 | capabilities: ServerCapabilities | undefined, |
| 217 | pluginSource: string | undefined, |
| 218 | ): ChannelGateResult { |
| 219 | // Channel servers declare `experimental['claude/channel']: {}` (MCP's |
| 220 | // presence-signal idiom — same as `tools: {}`). Truthy covers `{}` and |
| 221 | // `true`; absent/undefined/explicit-`false` all fail. Key matches the |
| 222 | // notification method namespace (notifications/claude/channel). |
| 223 | if (!capabilities?.experimental?.['claude/channel']) { |
| 224 | return { |
| 225 | action: 'skip', |
| 226 | kind: 'capability', |
| 227 | reason: 'server did not declare claude/channel capability', |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | // Overall runtime gate. After capability so normal MCP servers never hit |
| 232 | // this path. Before auth/policy so the killswitch works regardless of |
| 233 | // session state. |
| 234 | if (!isChannelsEnabled()) { |
| 235 | return { |
| 236 | action: 'skip', |
| 237 | kind: 'disabled', |
| 238 | reason: 'channels feature is not currently available', |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | const channelAuth = buildChannelNotificationAuthState( |
| 243 | getAuthRuntime().getCurrentSession(), |
| 244 | ) |
| 245 | |
| 246 | // OAuth-only. API key users (console) are blocked — there's no |
| 247 | // channelsEnabled admin surface in console yet, so the policy opt-in |
| 248 | // flow doesn't exist for them. Drop this when console parity lands. |
| 249 | if (!channelAuth.hasOauthChannelSession) { |
| 250 | return { |
| 251 | action: 'skip', |
| 252 | kind: 'auth', |
| 253 | reason: 'channels requires managed Noumena authentication (run /login)', |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | // Teams/Enterprise opt-in. Managed orgs must explicitly enable channels. |
| 258 | // Default OFF — absent or false blocks. Keyed off subscription tier, not |
| 259 | // "policy settings exist" — a team org with zero configured policy keys |
| 260 | // (remote endpoint returns 404) is still a managed org and must not fall |
| 261 | // through to the unmanaged path. |
| 262 | const sub = channelAuth.subscriptionType |
| 263 | const managed = channelAuth.isManagedTeamOrEnterprise |
| 264 | const policy = managed ? getSettingsForSource('policySettings') : undefined |
| 265 | if (managed && policy?.channelsEnabled !== true) { |
| 266 | return { |
| 267 | action: 'skip', |
| 268 | kind: 'policy', |
| 269 | reason: |
| 270 | 'channels not enabled by org policy (set channelsEnabled: true in managed settings)', |
| 271 | } |
no test coverage detected