Implement OAuth callback support for MCP servers
- Add react-router-dom dependency for routing support - Create OAuthCallback component with animated background and loading spinner - Add routing to App.tsx with /oauth/callback route - Match styling with main app using animated-bg-container - Use onMcpAuthorization from use-mcp library for OAuth handling - Library already handles multiple server differentiation via state parameter - Each MCP server gets unique OAuth flow identified by state containing server URL - Clean up unused imports and variables in McpServerModal
This commit is contained in:
parent
32a6bf5abd
commit
78f0e364a6
5 changed files with 78 additions and 5 deletions
|
|
@ -26,6 +26,7 @@
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-router-dom": "^7.6.2",
|
||||||
"rehype-highlight": "^7.0.2",
|
"rehype-highlight": "^7.0.2",
|
||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "^4.0.14",
|
||||||
|
|
|
||||||
45
examples/chat-ui/pnpm-lock.yaml
generated
45
examples/chat-ui/pnpm-lock.yaml
generated
|
|
@ -41,6 +41,9 @@ importers:
|
||||||
react-markdown:
|
react-markdown:
|
||||||
specifier: ^10.1.0
|
specifier: ^10.1.0
|
||||||
version: 10.1.0(@types/react@19.1.3)(react@19.1.0)
|
version: 10.1.0(@types/react@19.1.3)(react@19.1.0)
|
||||||
|
react-router-dom:
|
||||||
|
specifier: ^7.6.2
|
||||||
|
version: 7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
rehype-highlight:
|
rehype-highlight:
|
||||||
specifier: ^7.0.2
|
specifier: ^7.0.2
|
||||||
version: 7.0.2
|
version: 7.0.2
|
||||||
|
|
@ -1196,6 +1199,10 @@ packages:
|
||||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
cookie@1.0.2:
|
||||||
|
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
cors@2.8.5:
|
cors@2.8.5:
|
||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
@ -2139,6 +2146,23 @@ packages:
|
||||||
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
react-router-dom@7.6.2:
|
||||||
|
resolution: {integrity: sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
|
||||||
|
react-router@7.6.2:
|
||||||
|
resolution: {integrity: sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
react@19.1.0:
|
react@19.1.0:
|
||||||
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -2207,6 +2231,9 @@ packages:
|
||||||
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
|
resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.1:
|
||||||
|
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||||
|
|
||||||
setprototypeof@1.2.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
|
|
@ -3520,6 +3547,8 @@ snapshots:
|
||||||
|
|
||||||
cookie@0.7.2: {}
|
cookie@0.7.2: {}
|
||||||
|
|
||||||
|
cookie@1.0.2: {}
|
||||||
|
|
||||||
cors@2.8.5:
|
cors@2.8.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
|
|
@ -4669,6 +4698,20 @@ snapshots:
|
||||||
|
|
||||||
react-refresh@0.17.0: {}
|
react-refresh@0.17.0: {}
|
||||||
|
|
||||||
|
react-router-dom@7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
react: 19.1.0
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
react-router: 7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
|
||||||
|
react-router@7.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
cookie: 1.0.2
|
||||||
|
react: 19.1.0
|
||||||
|
set-cookie-parser: 2.7.1
|
||||||
|
optionalDependencies:
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
react@19.1.0: {}
|
react@19.1.0: {}
|
||||||
|
|
||||||
rehype-highlight@7.0.2:
|
rehype-highlight@7.0.2:
|
||||||
|
|
@ -4794,6 +4837,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.1: {}
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
sharp@0.33.5:
|
sharp@0.33.5:
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
|
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
|
||||||
import ChatApp from "./components/ChatApp";
|
import ChatApp from "./components/ChatApp";
|
||||||
|
import { OAuthCallback } from "./components/OAuthCallback";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<>
|
<Router>
|
||||||
<ChatApp />
|
<Routes>
|
||||||
</>
|
<Route path="/oauth/callback" element={<OAuthCallback />} />
|
||||||
|
<Route path="/" element={<ChatApp />} />
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useRef, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { X, Info, Settings, Plus, Trash2, Power, PowerOff } from 'lucide-react'
|
import { X, Info, Settings, Plus, Trash2, Power, PowerOff } from 'lucide-react'
|
||||||
import { useMcp, type Tool } from 'use-mcp/react'
|
import { useMcp, type Tool } from 'use-mcp/react'
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ const McpServerModal: React.FC<McpServerModalProps> = ({
|
||||||
const stored = localStorage.getItem('mcpServerToolCounts')
|
const stored = localStorage.getItem('mcpServerToolCounts')
|
||||||
return stored ? JSON.parse(stored) : {}
|
return stored ? JSON.parse(stored) : {}
|
||||||
})
|
})
|
||||||
const logRef = useRef<HTMLDivElement>(null)
|
// const logRef = useRef<HTMLDivElement>(null) // Removed for now as debug logs not implemented in multi-server version
|
||||||
|
|
||||||
// Save servers to localStorage whenever they change
|
// Save servers to localStorage whenever they change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
22
examples/chat-ui/src/components/OAuthCallback.tsx
Normal file
22
examples/chat-ui/src/components/OAuthCallback.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { onMcpAuthorization } from 'use-mcp'
|
||||||
|
|
||||||
|
export function OAuthCallback() {
|
||||||
|
useEffect(() => {
|
||||||
|
onMcpAuthorization()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen animated-bg-container flex items-center justify-center p-4">
|
||||||
|
<div className="bg-white rounded-lg shadow-xl p-8 text-center max-w-md w-full">
|
||||||
|
<h1 className="text-2xl font-bold text-zinc-900 mb-4">Authenticating...</h1>
|
||||||
|
<p className="text-zinc-600 mb-2">Please wait while we complete your authentication.</p>
|
||||||
|
<p className="text-sm text-zinc-500">This window should close automatically.</p>
|
||||||
|
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue