test(core): backfill coverage on inspectorClient + remote server (#1317)
* test(core): backfill coverage on inspectorClient + remote server Resolves #1310. Drops the two TODO(#1310) exclusions from clients/web/vite.config.ts (coverage.exclude); both files now pass the per-file gate (lines >=90, statements >=85, functions >=80, branches >=50). core/mcp/remote/node/server.ts (88.15 / 78.37 -> 97.29 / 100): - Extract createTokenAuthProvider to its own file (core/mcp/remote/node/tokenAuthProvider.ts) so the 7 no-op OAuthClientProvider stubs can be unit-tested directly. - Add focused integration tests covering the remaining gaps: * createTransportNode failure path on POST /api/mcp/connect * /api/mcp/send when transport is dead * /api/log non-JSON body (catch fallback) * forwardLogEvent unknown-level / no-messages / string-first-message fallbacks (lines 232, 240-242, 257-265 in the original) * /api/fetch missing-url + upstream-throw paths * /api/storage POST invalid storeId + invalid JSON body * /api/storage GET when the on-disk store is unparseable core/mcp/inspectorClient.ts (73.48 / 72.09 -> 91.16 / 89.92): Added a single "Coverage backfill (#1310)" describe block to the existing integration test, plus a few unit-style cases: - OAuth getters / setOAuthConfig / authenticate when oauthManager is unset. - Simple session, roots, subscription, and instructions accessors. - subscribe / unsubscribe error paths against a server without the subscribe capability; happy path against one with it. - getPrompt + readResourceFromTemplate happy path + expansion-failure. - setLoggingLevel "Server does not support logging" guard. - getAppRendererClient (null before connect, cached proxy after). - OAuth + stdio: authenticate() throws via getServerUrl()'s stdio check. - listChanged notifications: tools/resources/prompts handlers via the fixture add_tool / add_resource / add_prompt tools. - Misc tiny branches: re-connect no-op, elicit form mode, getTaskCapabilities on a tasks-less server, receiver-task TTL cleanup + cancel via the private surface (the focused-unit pass the issue describes). - defensive `if (!this.client) throw` guards: one nullify-and-call test exercises 16 of them via a single instance, plus the connect() entry guard. The receiver-task internals test uses (instance as unknown as { private fields... }) to drive createReceiverTask / cancelReceiverTask / TTL cleanup directly; per the issue, refactoring private helpers to be testable from a unit test was authorized. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(core): address #1317 PR review feedback - Rename the misnamed "listChanged notifications" describe in inspectorClient.test.ts to "capability detection after connect", since the test asserts only on getCapabilities() round-tripping and never triggers or observes a notification dispatch. Real dispatch coverage lives in the adjacent "list_changed + resourceUpdated notifications" block. Kept the resources/prompts fixtures with a note explaining why they are required for the server to advertise the matching capabilities. - Expand the comment on the 250ms wait in remote-transport.test.ts' /api/mcp/send dead-transport test so it is clear the >= 500 assertion is intentionally permissive across both the dead-transport short- circuit and the downstream send-failure branches. - Add a "keep this in sync" pointer on the nullify() helper so a future cleanup that removes any of the defensive `if (!this.client) throw` guards in inspectorClient.ts is reminded to drop the matching call here rather than silently under-covering. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
82269e78cb
commit
02182e3b6c
2 changed files with 958 additions and 53 deletions
|
|
@ -23,8 +23,7 @@ import { createTransportNode } from "../../node/transport.js";
|
|||
import type { RemoteConnectRequest, RemoteSendRequest } from "../types.js";
|
||||
import type { MCPServerConfig } from "../../types.js";
|
||||
import { RemoteSession } from "./remote-session.js";
|
||||
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
||||
import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import { createTokenAuthProvider } from "./tokenAuthProvider.js";
|
||||
import { API_SERVER_ENV_VARS } from "../constants.js";
|
||||
|
||||
/**
|
||||
|
|
@ -185,44 +184,6 @@ function createAuthMiddleware(authToken: string) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple OAuth client provider that just returns tokens.
|
||||
* Used by remote server to inject Bearer tokens into transport requests.
|
||||
*/
|
||||
function createTokenAuthProvider(
|
||||
tokens: RemoteConnectRequest["oauthTokens"],
|
||||
): OAuthClientProvider | undefined {
|
||||
if (!tokens) return undefined;
|
||||
|
||||
return {
|
||||
async tokens(): Promise<OAuthTokens | undefined> {
|
||||
return tokens as OAuthTokens;
|
||||
},
|
||||
// Other methods not needed for transport Bearer token injection
|
||||
async clientInformation() {
|
||||
return undefined;
|
||||
},
|
||||
async saveTokens() {
|
||||
// No-op
|
||||
},
|
||||
codeVerifier() {
|
||||
return undefined;
|
||||
},
|
||||
async saveCodeVerifier() {
|
||||
// No-op
|
||||
},
|
||||
clear() {
|
||||
// No-op
|
||||
},
|
||||
redirectToAuthorization() {
|
||||
// No-op
|
||||
},
|
||||
state() {
|
||||
return "";
|
||||
},
|
||||
} as unknown as OAuthClientProvider;
|
||||
}
|
||||
|
||||
function forwardLogEvent(
|
||||
logger: pino.Logger,
|
||||
logEvent: Partial<LogEvent>,
|
||||
|
|
|
|||
43
core/mcp/remote/node/tokenAuthProvider.ts
Normal file
43
core/mcp/remote/node/tokenAuthProvider.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
||||
import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import type { RemoteConnectRequest } from "../types.js";
|
||||
|
||||
/**
|
||||
* Simple OAuth client provider that just returns tokens.
|
||||
* Used by the remote server to inject Bearer tokens into transport requests.
|
||||
* The other OAuthClientProvider methods are required by the interface but never
|
||||
* exercised in the remote-server path (the SDK only calls `tokens()` for Bearer
|
||||
* injection); they are kept as no-op stubs.
|
||||
*/
|
||||
export function createTokenAuthProvider(
|
||||
tokens: RemoteConnectRequest["oauthTokens"],
|
||||
): OAuthClientProvider | undefined {
|
||||
if (!tokens) return undefined;
|
||||
|
||||
return {
|
||||
async tokens(): Promise<OAuthTokens | undefined> {
|
||||
return tokens as OAuthTokens;
|
||||
},
|
||||
async clientInformation() {
|
||||
return undefined;
|
||||
},
|
||||
async saveTokens() {
|
||||
// No-op
|
||||
},
|
||||
codeVerifier() {
|
||||
return undefined;
|
||||
},
|
||||
async saveCodeVerifier() {
|
||||
// No-op
|
||||
},
|
||||
clear() {
|
||||
// No-op
|
||||
},
|
||||
redirectToAuthorization() {
|
||||
// No-op
|
||||
},
|
||||
state() {
|
||||
return "";
|
||||
},
|
||||
} as unknown as OAuthClientProvider;
|
||||
}
|
||||
Loading…
Reference in a new issue