( serverName: string, config: ScopedMcpServerConfig, )
| 47 | * mcp__<server>__*, so this pseudo-tool is removed automatically). |
| 48 | */ |
| 49 | export function createMcpAuthTool( |
| 50 | serverName: string, |
| 51 | config: ScopedMcpServerConfig, |
| 52 | ): Tool<InputSchema, McpAuthOutput> { |
| 53 | const url = getConfigUrl(config) |
| 54 | const transport = config.type ?? 'stdio' |
| 55 | const location = url ? `${transport} at ${url}` : transport |
| 56 | |
| 57 | const description = |
| 58 | `The \`${serverName}\` MCP server (${location}) is installed but requires authentication. ` + |
| 59 | `Call this tool to start the OAuth flow — you'll receive an authorization URL to share with the user. ` + |
| 60 | `Once the user completes authorization in their browser, the server's real tools will become available automatically.` |
| 61 | |
| 62 | return { |
| 63 | name: buildMcpToolName(serverName, 'authenticate'), |
| 64 | isMcp: true, |
| 65 | mcpInfo: { serverName, toolName: 'authenticate' }, |
| 66 | isEnabled: () => true, |
| 67 | isConcurrencySafe: () => false, |
| 68 | isReadOnly: () => false, |
| 69 | toAutoClassifierInput: () => serverName, |
| 70 | userFacingName: () => `${serverName} - authenticate (MCP)`, |
| 71 | maxResultSizeChars: 10_000, |
| 72 | renderToolUseMessage: () => `Authenticate ${serverName} MCP server`, |
| 73 | async description() { |
| 74 | return description |
| 75 | }, |
| 76 | async prompt() { |
| 77 | return description |
| 78 | }, |
| 79 | get inputSchema(): InputSchema { |
| 80 | return inputSchema() |
| 81 | }, |
| 82 | async checkPermissions(input): Promise<PermissionDecision> { |
| 83 | return { behavior: 'allow', updatedInput: input } |
| 84 | }, |
| 85 | async call(_input, context) { |
| 86 | // claude.ai connectors use a separate auth flow (handleClaudeAIAuth in |
| 87 | // MCPRemoteServerMenu) that we don't invoke programmatically here — |
| 88 | // just point the user at /mcp. |
| 89 | if (config.type === 'claudeai-proxy') { |
| 90 | return { |
| 91 | data: { |
| 92 | status: 'unsupported' as const, |
| 93 | message: `This is a claude.ai MCP connector. Ask the user to run /mcp and select "${serverName}" to authenticate.`, |
| 94 | }, |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | // performMCPOAuthFlow only accepts sse/http. needs-auth state is only |
| 99 | // set on HTTP 401 (UnauthorizedError) so other transports shouldn't |
| 100 | // reach here, but be defensive. |
| 101 | if (config.type !== 'sse' && config.type !== 'http') { |
| 102 | return { |
| 103 | data: { |
| 104 | status: 'unsupported' as const, |
| 105 | message: `Server "${serverName}" uses ${transport} transport which does not support OAuth from this tool. Ask the user to run /mcp and authenticate manually.`, |
| 106 | }, |
no test coverage detected