From 0882a3e0e59d20ce98fb6af6a234bcdb951453c5 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Fri, 24 Jan 2025 15:23:24 +0000 Subject: [PATCH] Formatting --- client/src/App.tsx | 6 ++-- client/src/components/OAuthCallback.tsx | 18 +++++----- client/src/lib/auth.ts | 48 ++++++++++++++----------- client/src/lib/constants.ts | 8 ++--- client/src/lib/hooks/useConnection.ts | 7 ++-- client/vite.config.ts | 3 +- server/src/index.ts | 15 +++++--- 7 files changed, 60 insertions(+), 45 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 8deba66..246e035 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -227,7 +227,7 @@ const App = () => { newUrl.searchParams.delete("serverUrl"); window.history.replaceState({}, "", newUrl.toString()); // Show success toast for OAuth - toast.success('Successfully authenticated with OAuth'); + toast.success("Successfully authenticated with OAuth"); // Connect to the server connectMcpServer(); } @@ -446,8 +446,8 @@ const App = () => {
{!serverCapabilities?.resources && - !serverCapabilities?.prompts && - !serverCapabilities?.tools ? ( + !serverCapabilities?.prompts && + !serverCapabilities?.tools ? (

The connected server does not support any MCP capabilities diff --git a/client/src/components/OAuthCallback.tsx b/client/src/components/OAuthCallback.tsx index 4729e71..a7439df 100644 --- a/client/src/components/OAuthCallback.tsx +++ b/client/src/components/OAuthCallback.tsx @@ -1,6 +1,6 @@ -import { useEffect, useRef } from 'react'; -import { handleOAuthCallback } from '../lib/auth'; -import { SESSION_KEYS } from '../lib/constants'; +import { useEffect, useRef } from "react"; +import { handleOAuthCallback } from "../lib/auth"; +import { SESSION_KEYS } from "../lib/constants"; const OAuthCallback = () => { const hasProcessedRef = useRef(false); @@ -14,12 +14,12 @@ const OAuthCallback = () => { hasProcessedRef.current = true; const params = new URLSearchParams(window.location.search); - const code = params.get('code'); + const code = params.get("code"); const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL); if (!code || !serverUrl) { - console.error('Missing code or server URL'); - window.location.href = '/'; + console.error("Missing code or server URL"); + window.location.href = "/"; return; } @@ -30,8 +30,8 @@ const OAuthCallback = () => { // Redirect back to the main app with server URL to trigger auto-connect window.location.href = `/?serverUrl=${encodeURIComponent(serverUrl)}`; } catch (error) { - console.error('OAuth callback error:', error); - window.location.href = '/'; + console.error("OAuth callback error:", error); + window.location.href = "/"; } }; @@ -45,4 +45,4 @@ const OAuthCallback = () => { ); }; -export default OAuthCallback; \ No newline at end of file +export default OAuthCallback; diff --git a/client/src/lib/auth.ts b/client/src/lib/auth.ts index d4eddb7..0417731 100644 --- a/client/src/lib/auth.ts +++ b/client/src/lib/auth.ts @@ -1,32 +1,34 @@ -import pkceChallenge from 'pkce-challenge'; -import { SESSION_KEYS } from './constants'; +import pkceChallenge from "pkce-challenge"; +import { SESSION_KEYS } from "./constants"; export interface OAuthMetadata { authorization_endpoint: string; token_endpoint: string; } -export async function discoverOAuthMetadata(serverUrl: string): Promise { +export async function discoverOAuthMetadata( + serverUrl: string, +): Promise { try { - const url = new URL('/.well-known/oauth-authorization-server', serverUrl); + const url = new URL("/.well-known/oauth-authorization-server", serverUrl); const response = await fetch(url.toString()); if (response.ok) { const metadata = await response.json(); return { authorization_endpoint: metadata.authorization_endpoint, - token_endpoint: metadata.token_endpoint + token_endpoint: metadata.token_endpoint, }; } } catch (error) { - console.warn('OAuth metadata discovery failed:', error); + console.warn("OAuth metadata discovery failed:", error); } // Fall back to default endpoints const baseUrl = new URL(serverUrl); return { - authorization_endpoint: new URL('/authorize', baseUrl).toString(), - token_endpoint: new URL('/token', baseUrl).toString() + authorization_endpoint: new URL("/authorize", baseUrl).toString(), + token_endpoint: new URL("/token", baseUrl).toString(), }; } @@ -44,19 +46,25 @@ export async function startOAuthFlow(serverUrl: string): Promise { // Build authorization URL const authUrl = new URL(metadata.authorization_endpoint); - authUrl.searchParams.set('response_type', 'code'); - authUrl.searchParams.set('code_challenge', codeChallenge); - authUrl.searchParams.set('code_challenge_method', 'S256'); - authUrl.searchParams.set('redirect_uri', window.location.origin + '/oauth/callback'); + authUrl.searchParams.set("response_type", "code"); + authUrl.searchParams.set("code_challenge", codeChallenge); + authUrl.searchParams.set("code_challenge_method", "S256"); + authUrl.searchParams.set( + "redirect_uri", + window.location.origin + "/oauth/callback", + ); return authUrl.toString(); } -export async function handleOAuthCallback(serverUrl: string, code: string): Promise { +export async function handleOAuthCallback( + serverUrl: string, + code: string, +): Promise { // Get stored code verifier const codeVerifier = sessionStorage.getItem(SESSION_KEYS.CODE_VERIFIER); if (!codeVerifier) { - throw new Error('No code verifier found'); + throw new Error("No code verifier found"); } // Discover OAuth endpoints @@ -64,20 +72,20 @@ export async function handleOAuthCallback(serverUrl: string, code: string): Prom // Exchange code for tokens const response = await fetch(metadata.token_endpoint, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, body: JSON.stringify({ - grant_type: 'authorization_code', + grant_type: "authorization_code", code, code_verifier: codeVerifier, - redirect_uri: window.location.origin + '/oauth/callback' - }) + redirect_uri: window.location.origin + "/oauth/callback", + }), }); if (!response.ok) { - throw new Error('Token exchange failed'); + throw new Error("Token exchange failed"); } const data = await response.json(); diff --git a/client/src/lib/constants.ts b/client/src/lib/constants.ts index b882179..e302b52 100644 --- a/client/src/lib/constants.ts +++ b/client/src/lib/constants.ts @@ -1,6 +1,6 @@ // OAuth-related session storage keys export const SESSION_KEYS = { - CODE_VERIFIER: 'mcp_code_verifier', - SERVER_URL: 'mcp_server_url', - ACCESS_TOKEN: 'mcp_access_token', -} as const; \ No newline at end of file + CODE_VERIFIER: "mcp_code_verifier", + SERVER_URL: "mcp_server_url", + ACCESS_TOKEN: "mcp_access_token", +} as const; diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index dda734a..de2d29e 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -1,5 +1,8 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; -import { SSEClientTransport, SseError } from "@modelcontextprotocol/sdk/client/sse.js"; +import { + SSEClientTransport, + SseError, +} from "@modelcontextprotocol/sdk/client/sse.js"; import { ClientNotification, ClientRequest, @@ -149,7 +152,7 @@ export function useConnection({ const headers: HeadersInit = {}; const accessToken = sessionStorage.getItem(SESSION_KEYS.ACCESS_TOKEN); if (accessToken) { - headers['Authorization'] = `Bearer ${accessToken}`; + headers["Authorization"] = `Bearer ${accessToken}`; } const clientTransport = new SSEClientTransport(backendUrl, { diff --git a/client/vite.config.ts b/client/vite.config.ts index bda10e5..b3d0f45 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -5,8 +5,7 @@ import { defineConfig } from "vite"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - server: { - }, + server: {}, resolve: { alias: { "@": path.resolve(__dirname, "./src"), diff --git a/server/src/index.ts b/server/src/index.ts index c215f34..4d8ac42 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -4,7 +4,10 @@ import cors from "cors"; import { parseArgs } from "node:util"; import { parse as shellParseArgs } from "shell-quote"; -import { SSEClientTransport, SseError } from "@modelcontextprotocol/sdk/client/sse.js"; +import { + SSEClientTransport, + SseError, +} from "@modelcontextprotocol/sdk/client/sse.js"; import { StdioClientTransport, getDefaultEnvironment, @@ -14,7 +17,7 @@ import express from "express"; import { findActualExecutable } from "spawn-rx"; import mcpProxy from "./mcpProxy.js"; -const SSE_HEADERS_PASSTHROUGH = ['authorization']; +const SSE_HEADERS_PASSTHROUGH = ["authorization"]; const defaultEnvironment = { ...getDefaultEnvironment(), @@ -67,7 +70,6 @@ const createTransport = async (req: express.Request) => { for (const key of SSE_HEADERS_PASSTHROUGH) { if (req.headers[key] === undefined) { continue; - } const value = req.headers[key]; @@ -103,7 +105,10 @@ app.get("/sse", async (req, res) => { backingServerTransport = await createTransport(req); } catch (error) { if (error instanceof SseError && error.code === 401) { - console.error("Received 401 Unauthorized from MCP server:", error.message); + console.error( + "Received 401 Unauthorized from MCP server:", + error.message, + ); res.status(401).json(error); return; } @@ -176,4 +181,4 @@ app.get("/config", (req, res) => { }); const PORT = process.env.PORT || 3000; -app.listen(PORT, () => { }); +app.listen(PORT, () => {});