Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
|
2b87798d91 | ||
|
31c75a30b8 | ||
|
bc92618798 | ||
|
3a3d3724b5 |
3 changed files with 66 additions and 4 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "mcp-remote",
|
"name": "mcp-remote",
|
||||||
"version": "0.0.9",
|
"version": "0.0.10-1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"mcp-remote": "dist/cli/proxy.js"
|
"mcp-remote": "dist/cli/proxy.js"
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
get redirectUrl(): string {
|
get redirectUrl(): string {
|
||||||
return `http://localhost:${this.options.callbackPort}${this.callbackPath}`
|
return `http://127.0.0.1:${this.options.callbackPort}${this.callbackPath}`
|
||||||
}
|
}
|
||||||
|
|
||||||
get clientMetadata() {
|
get clientMetadata() {
|
||||||
|
@ -229,7 +229,7 @@ export function setupOAuthCallbackServer(options: OAuthCallbackServerOptions) {
|
||||||
})
|
})
|
||||||
|
|
||||||
const server = app.listen(options.port, () => {
|
const server = app.listen(options.port, () => {
|
||||||
console.error(`OAuth callback server running at http://localhost:${options.port}`)
|
console.error(`OAuth callback server running at http://127.0.0.1:${options.port}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -299,7 +299,7 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(serverUrl)
|
const url = new URL(serverUrl)
|
||||||
const isLocalhost = url.hostname === 'localhost' && url.protocol === 'http:'
|
const isLocalhost = (url.hostname === 'localhost' || url.hostname === '127.0.0.1') && url.protocol === 'http:'
|
||||||
|
|
||||||
if (!(url.protocol == 'https:' || isLocalhost)) {
|
if (!(url.protocol == 'https:' || isLocalhost)) {
|
||||||
console.error(usage)
|
console.error(usage)
|
||||||
|
|
|
@ -70,6 +70,10 @@ export type UseMcpResult = {
|
||||||
* @returns Auth URL that can be used to manually open a new window
|
* @returns Auth URL that can be used to manually open a new window
|
||||||
*/
|
*/
|
||||||
authenticate: () => Promise<string | undefined>
|
authenticate: () => Promise<string | undefined>
|
||||||
|
/**
|
||||||
|
* Clear all localStorage items for this server
|
||||||
|
*/
|
||||||
|
clearStorage: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoredState = {
|
type StoredState = {
|
||||||
|
@ -120,6 +124,44 @@ class BrowserOAuthClientProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all storage items related to this server
|
||||||
|
* @returns The number of items cleared
|
||||||
|
*/
|
||||||
|
clearStorage(): number {
|
||||||
|
const prefix = `${this.storageKeyPrefix}_${this.serverUrlHash}`;
|
||||||
|
const keysToRemove = [];
|
||||||
|
|
||||||
|
// Find all keys that match the prefix
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i);
|
||||||
|
if (key && key.startsWith(prefix)) {
|
||||||
|
keysToRemove.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check for any state keys
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i);
|
||||||
|
if (key && key.startsWith(`${this.storageKeyPrefix}:state_`)) {
|
||||||
|
// Load state to check if it's for this server
|
||||||
|
try {
|
||||||
|
const state = JSON.parse(localStorage.getItem(key) || '{}');
|
||||||
|
if (state.serverUrlHash === this.serverUrlHash) {
|
||||||
|
keysToRemove.push(key);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore JSON parse errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all matching keys
|
||||||
|
keysToRemove.forEach(key => localStorage.removeItem(key));
|
||||||
|
|
||||||
|
return keysToRemove.length;
|
||||||
|
}
|
||||||
|
|
||||||
private hashString(str: string): string {
|
private hashString(str: string): string {
|
||||||
// Simple hash function for browser environments
|
// Simple hash function for browser environments
|
||||||
let hash = 0
|
let hash = 0
|
||||||
|
@ -722,6 +764,25 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
||||||
}
|
}
|
||||||
}, [disconnect])
|
}, [disconnect])
|
||||||
|
|
||||||
|
// Clear all localStorage items for this server
|
||||||
|
const clearStorage = useCallback(() => {
|
||||||
|
if (!authProviderRef.current) {
|
||||||
|
addLog('warn', 'Cannot clear storage: auth provider not initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the provider's method to clear storage
|
||||||
|
const clearedCount = authProviderRef.current.clearStorage();
|
||||||
|
|
||||||
|
// Clear auth-related state in the hook
|
||||||
|
authUrlRef.current = undefined;
|
||||||
|
setAuthUrl(undefined);
|
||||||
|
metadataRef.current = undefined;
|
||||||
|
codeVerifierRef.current = undefined;
|
||||||
|
|
||||||
|
addLog('info', `Cleared ${clearedCount} storage items for server`);
|
||||||
|
}, [addLog]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
tools,
|
tools,
|
||||||
|
@ -732,6 +793,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult {
|
||||||
retry,
|
retry,
|
||||||
disconnect,
|
disconnect,
|
||||||
authenticate,
|
authenticate,
|
||||||
|
clearStorage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue