Skip to content

Commit dbd6169

Browse files
committed
Support bearer token
1 parent 0870a81 commit dbd6169

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ CLIENT_PORT=8080 SERVER_PORT=9000 npx @modelcontextprotocol/inspector node build
3838

3939
For more details on ways to use the inspector, see the [Inspector section of the MCP docs site](https://modelcontextprotocol.io/docs/tools/inspector). For help with debugging, see the [Debugging guide](https://modelcontextprotocol.io/docs/tools/debugging).
4040

41+
### Authentication
42+
43+
The inspector supports bearer token authentication for SSE connections. Enter your token in the UI when connecting to an MCP server, and it will be sent in the Authorization header.
44+
4145
### From this repository
4246

4347
If you're working on the inspector itself:

client/src/App.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ const App = () => {
9797
>([]);
9898
const [roots, setRoots] = useState<Root[]>([]);
9999
const [env, setEnv] = useState<Record<string, string>>({});
100+
const [bearerToken, setBearerToken] = useState<string>(() => {
101+
return localStorage.getItem("lastBearerToken") || "";
102+
});
100103

101104
const [pendingSampleRequests, setPendingSampleRequests] = useState<
102105
Array<
@@ -160,6 +163,7 @@ const App = () => {
160163
args,
161164
sseUrl,
162165
env,
166+
bearerToken,
163167
proxyServerUrl: PROXY_SERVER_URL,
164168
onNotification: (notification) => {
165169
setNotifications((prev) => [...prev, notification as ServerNotification]);
@@ -195,6 +199,10 @@ const App = () => {
195199
localStorage.setItem("lastTransportType", transportType);
196200
}, [transportType]);
197201

202+
useEffect(() => {
203+
localStorage.setItem("lastBearerToken", bearerToken);
204+
}, [bearerToken]);
205+
198206
// Auto-connect if serverUrl is provided in URL params (e.g. after OAuth callback)
199207
useEffect(() => {
200208
const serverUrl = params.get("serverUrl");
@@ -382,6 +390,8 @@ const App = () => {
382390
setSseUrl={setSseUrl}
383391
env={env}
384392
setEnv={setEnv}
393+
bearerToken={bearerToken}
394+
setBearerToken={setBearerToken}
385395
onConnect={connectMcpServer}
386396
stdErrNotifications={stdErrNotifications}
387397
/>

client/src/components/Sidebar.tsx

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ interface SidebarProps {
3535
setSseUrl: (url: string) => void;
3636
env: Record<string, string>;
3737
setEnv: (env: Record<string, string>) => void;
38+
bearerToken: string;
39+
setBearerToken: (token: string) => void;
3840
onConnect: () => void;
3941
stdErrNotifications: StdErrNotification[];
4042
}
@@ -51,11 +53,14 @@ const Sidebar = ({
5153
setSseUrl,
5254
env,
5355
setEnv,
56+
bearerToken,
57+
setBearerToken,
5458
onConnect,
5559
stdErrNotifications,
5660
}: SidebarProps) => {
5761
const [theme, setTheme] = useTheme();
5862
const [showEnvVars, setShowEnvVars] = useState(false);
63+
const [showBearerToken, setShowBearerToken] = useState(false);
5964
const [shownEnvVars, setShownEnvVars] = useState<Set<string>>(new Set());
6065

6166
return (
@@ -110,15 +115,43 @@ const Sidebar = ({
110115
</div>
111116
</>
112117
) : (
113-
<div className="space-y-2">
114-
<label className="text-sm font-medium">URL</label>
115-
<Input
116-
placeholder="URL"
117-
value={sseUrl}
118-
onChange={(e) => setSseUrl(e.target.value)}
119-
className="font-mono"
120-
/>
121-
</div>
118+
<>
119+
<div className="space-y-2">
120+
<label className="text-sm font-medium">URL</label>
121+
<Input
122+
placeholder="URL"
123+
value={sseUrl}
124+
onChange={(e) => setSseUrl(e.target.value)}
125+
className="font-mono"
126+
/>
127+
</div>
128+
<div className="space-y-2">
129+
<Button
130+
variant="outline"
131+
onClick={() => setShowBearerToken(!showBearerToken)}
132+
className="flex items-center w-full"
133+
>
134+
{showBearerToken ? (
135+
<ChevronDown className="w-4 h-4 mr-2" />
136+
) : (
137+
<ChevronRight className="w-4 h-4 mr-2" />
138+
)}
139+
Authentication
140+
</Button>
141+
{showBearerToken && (
142+
<div className="space-y-2">
143+
<label className="text-sm font-medium">Bearer Token</label>
144+
<Input
145+
placeholder="Bearer Token"
146+
value={bearerToken}
147+
onChange={(e) => setBearerToken(e.target.value)}
148+
className="font-mono"
149+
type="password"
150+
/>
151+
</div>
152+
)}
153+
</div>
154+
</>
122155
)}
123156
{transportType === "stdio" && (
124157
<div className="space-y-2">

client/src/lib/hooks/useConnection.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ interface UseConnectionOptions {
3737
sseUrl: string;
3838
env: Record<string, string>;
3939
proxyServerUrl: string;
40+
bearerToken?: string;
4041
requestTimeout?: number;
4142
onNotification?: (notification: Notification) => void;
4243
onStdErrNotification?: (notification: Notification) => void;
@@ -57,6 +58,7 @@ export function useConnection({
5758
sseUrl,
5859
env,
5960
proxyServerUrl,
61+
bearerToken,
6062
requestTimeout = DEFAULT_REQUEST_TIMEOUT_MSEC,
6163
onNotification,
6264
onStdErrNotification,
@@ -228,9 +230,11 @@ export function useConnection({
228230
// Inject auth manually instead of using SSEClientTransport, because we're
229231
// proxying through the inspector server first.
230232
const headers: HeadersInit = {};
231-
const tokens = await authProvider.tokens();
232-
if (tokens) {
233-
headers["Authorization"] = `Bearer ${tokens.access_token}`;
233+
234+
// Use manually provided bearer token if available, otherwise use OAuth tokens
235+
const token = bearerToken || (await authProvider.tokens())?.access_token;
236+
if (token) {
237+
headers["Authorization"] = `Bearer ${token}`;
234238
}
235239

236240
const clientTransport = new SSEClientTransport(backendUrl, {

0 commit comments

Comments
 (0)