feat: McpToken — HTTP-mode mcplocal, CLI verbs, audit plumbing #50
@@ -46,7 +46,13 @@ export async function refreshProjectUpstreams(
|
|||||||
servers = await mcpdClient.get<McpdServer[]>(path);
|
servers = await mcpdClient.get<McpdServer[]>(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return syncUpstreams(router, mcpdClient, servers);
|
// Downstream upstream-proxy calls go through `mcpdClient` too. In HTTP-mode
|
||||||
|
// mcplocal the pod has no credentials of its own, so the default token on
|
||||||
|
// `mcpdClient` is an empty string — every /api/v1/mcp/proxy call would 401.
|
||||||
|
// Bind a per-request client with the caller's bearer so each McpdUpstream
|
||||||
|
// forwards the same identity that passed project discovery.
|
||||||
|
const upstreamClient = authToken ? mcpdClient.withToken(authToken) : mcpdClient;
|
||||||
|
return syncUpstreams(router, upstreamClient, servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ export class McpdClient {
|
|||||||
return new McpdClient(this.baseUrl, this.token, { ...this.extraHeaders }, timeoutMs);
|
return new McpdClient(this.baseUrl, this.token, { ...this.extraHeaders }, timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new client with a different Bearer token. The HTTP-mode mcplocal
|
||||||
|
* pod has no credentials of its own — each incoming client request carries
|
||||||
|
* its McpToken, and this method is how we thread that token through to the
|
||||||
|
* McpdUpstream instances created during project discovery.
|
||||||
|
*/
|
||||||
|
withToken(token: string): McpdClient {
|
||||||
|
return new McpdClient(this.baseUrl, token, { ...this.extraHeaders }, this.timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
async get<T>(path: string): Promise<T> {
|
async get<T>(path: string): Promise<T> {
|
||||||
return this.request<T>('GET', path);
|
return this.request<T>('GET', path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ function mockMcpdClient(servers: Array<{ id: string; name: string; transport: st
|
|||||||
forward: vi.fn(async () => ({ status: 200, body: servers })),
|
forward: vi.fn(async () => ({ status: 200, body: servers })),
|
||||||
withTimeout: vi.fn(() => client),
|
withTimeout: vi.fn(() => client),
|
||||||
withHeaders: vi.fn(() => client),
|
withHeaders: vi.fn(() => client),
|
||||||
|
withToken: vi.fn(() => client),
|
||||||
};
|
};
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user