Skip to content

Commit 639dc61

Browse files
committed
Detect: parallelize schema probes + /mcp probe, 5s timeout
Sequential 5-path schema probing (up to 7s each) plus the new /mcp probe and oauth chain pushed heavy domains past the worker time budget. Probe the spec paths concurrently, run /mcp discovery alongside the other checks, drop the per-request timeout to 5s.
1 parent 7f7d629 commit 639dc61

1 file changed

Lines changed: 9 additions & 8 deletions

File tree

src/lib/detect.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export interface DetectionResult {
5757
errors: string[];
5858
}
5959

60-
const TIMEOUT_MS = 7000;
60+
const TIMEOUT_MS = 5000;
6161

6262
async function get(
6363
fetchImpl: FetchLike,
@@ -149,16 +149,16 @@ async function checkLlmsTxt(fetchImpl: FetchLike, domain: string): Promise<boole
149149
*/
150150
async function checkApiSchema(fetchImpl: FetchLike, domain: string) {
151151
const paths = ["/api/schema/", "/openapi.json", "/swagger.json", "/api/openapi.json", "/v1/openapi.json"];
152-
for (const p of paths) {
152+
// Probe all candidate paths concurrently; keep the first (by order) that is a spec.
153+
const results = await Promise.all(paths.map(async (p) => {
153154
const hit = await get(fetchImpl, `https://${domain}${p}`);
154-
if (!hit || !hit.res.ok) continue;
155+
if (!hit || !hit.res.ok) return undefined;
155156
const ct = hit.res.headers.get("content-type") ?? "";
156157
const doc = asJson(hit.text, ct);
157158
const isOpenapi = /openapi/i.test(ct) || Boolean(doc && (doc.openapi || doc.swagger));
158-
if (!isOpenapi) continue;
159-
return { url: `https://${domain}${p}`, format: "openapi" as const, version: doc?.openapi ?? doc?.swagger };
160-
}
161-
return undefined;
159+
return isOpenapi ? { url: `https://${domain}${p}`, format: "openapi" as const, version: doc?.openapi ?? doc?.swagger } : undefined;
160+
}));
161+
return results.find(Boolean);
162162
}
163163

164164
/** Read an OAuth Authorization Server metadata doc (RFC 8414) for capabilities. */
@@ -249,6 +249,7 @@ async function discoverMcpEndpoint(fetchImpl: FetchLike, domain: string): Promis
249249

250250
export async function detect(domain: string, fetchImpl: FetchLike = fetch): Promise<DetectionResult> {
251251
const errors: string[] = [];
252+
const discoverMcpEndpointResult = discoverMcpEndpoint(fetchImpl, domain); // start concurrently
252253
const [apiCatalog, serverCard, agentCard, agentSkills, llmsTxt, apiSchema, apiOAuth] = await Promise.all([
253254
checkApiCatalog(fetchImpl, domain).catch((e) => (errors.push(`api-catalog: ${e}`), undefined)),
254255
checkServerCard(fetchImpl, domain).catch((e) => (errors.push(`server-card: ${e}`), undefined)),
@@ -258,7 +259,7 @@ export async function detect(domain: string, fetchImpl: FetchLike = fetch): Prom
258259
checkApiSchema(fetchImpl, domain).catch(() => undefined),
259260
checkApiOAuth(fetchImpl, domain).catch(() => undefined),
260261
]);
261-
const probedMcp = await discoverMcpEndpoint(fetchImpl, domain).catch(() => undefined);
262+
const probedMcp = await discoverMcpEndpointResult.catch(() => undefined);
262263

263264
// Collect MCP endpoints from the server card + api-catalog, then probe each
264265
// for self-onboarding capability.

0 commit comments

Comments
 (0)