Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

Commit a817fb2

Browse files
authored
Merge pull request #68 from runbasehq/dev
Add OpenRouter provider
2 parents 7b101e2 + 3645ceb commit a817fb2

File tree

8 files changed

+784
-56
lines changed

8 files changed

+784
-56
lines changed

packages/mcp-check/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# mcp-testing-library
22

3+
## 0.4.7
4+
5+
### Patch Changes
6+
7+
- Add OpenRouter provider:
8+
- Free models available for testing at no cost
9+
- Retries added to handle common `429` and `529` errors on free models
10+
311
## 0.4.6
412

513
### Patch Changes

packages/mcp-check/bin/cli.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class SimpleLogBatcher {
6464
const runJestCommand = (
6565
jestTasks: string[],
6666
onTaskUpdate: (updatedTasks: Task[]) => void,
67-
initialTasks: Task[]
67+
initialTasks: Task[],
6868
): Promise<void> => {
6969
return new Promise((resolve) => {
7070
const tasks = new Map<string, Task>();
@@ -77,7 +77,7 @@ const runJestCommand = (
7777

7878
const logBatcher = new SimpleLogBatcher(() => {
7979
const sortedTasks = Array.from(tasks.values()).sort(
80-
(a, b) => a.orderIndex - b.orderIndex
80+
(a, b) => a.orderIndex - b.orderIndex,
8181
);
8282
onTaskUpdate([...sortedTasks]);
8383
});
@@ -95,7 +95,7 @@ const runJestCommand = (
9595

9696
const updateTaskStatus = (
9797
taskName: string,
98-
status: "running" | "completed" | "failed"
98+
status: "running" | "completed" | "failed",
9999
) => {
100100
const task = tasks.get(taskName);
101101
if (task) {
@@ -145,7 +145,7 @@ const runJestCommand = (
145145
{
146146
stdio: "pipe",
147147
env: { ...process.env, FORCE_COLOR: "1" },
148-
}
148+
},
149149
);
150150

151151
jestTasks.forEach((taskName) => {
@@ -285,7 +285,7 @@ const padToWidth = (str: string, width: number): string => {
285285

286286
const getStatusIndicator = (
287287
status: "running" | "completed" | "failed",
288-
frame: number
288+
frame: number,
289289
): string => {
290290
if (status === "running") {
291291
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -338,7 +338,7 @@ const TaskManager = () => {
338338
(updatedTasks) => {
339339
setTasks(updatedTasks);
340340
},
341-
initialTasks
341+
initialTasks,
342342
);
343343
} catch (error) {
344344
console.error("Failed to initialize:", error);
@@ -421,7 +421,7 @@ const TaskManager = () => {
421421
{logs
422422
.slice(
423423
uiState.scrollPosition,
424-
uiState.scrollPosition + (terminalHeight - 6)
424+
uiState.scrollPosition + (terminalHeight - 6),
425425
)
426426
.map((entry, i) => (
427427
<Box key={`log-${i + uiState.scrollPosition}`} marginTop={1}>
@@ -446,10 +446,10 @@ const TaskManager = () => {
446446

447447
const rightLines: string[] = [];
448448
rightLines.push(
449-
`${currentTask?.name || "No task"} - ${currentTask?.status || "Loading..."}`
449+
`${currentTask?.name || "No task"} - ${currentTask?.status || "Loading..."}`,
450450
);
451451
rightLines.push(
452-
`Logs: ${currentTask?.logs.length || 0} entries | Press Enter to view details`
452+
`Logs: ${currentTask?.logs.length || 0} entries | Press Enter to view details`,
453453
);
454454
rightLines.push("");
455455

packages/mcp-check/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mcp-check",
33
"module": "dist/src/index.js",
4-
"version": "0.4.6",
4+
"version": "0.4.7",
55
"type": "module",
66
"main": "dist/src/index.js",
77
"types": "dist/src/index.d.ts",

packages/mcp-check/src/providers/anthropic.ts

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import Anthropic from "@anthropic-ai/sdk";
22
import { Provider } from "./provider.js";
3-
import type { StreamResult, NormalizedChunk, NormalizedChunkAnthropic } from "../chunks/types.js";
3+
import type {
4+
StreamResult,
5+
NormalizedChunk,
6+
NormalizedChunkAnthropic,
7+
} from "../chunks/types.js";
48
import type { McpServer } from "../index.js";
59
import type { ProviderConfig } from "./types.js";
6-
import type { BetaRawContentBlockDeltaEvent, BetaRawContentBlockStartEvent, BetaRawContentBlockStopEvent } from "@anthropic-ai/sdk/resources/beta.js";
10+
import type {
11+
BetaRawContentBlockDeltaEvent,
12+
BetaRawContentBlockStartEvent,
13+
BetaRawContentBlockStopEvent,
14+
} from "@anthropic-ai/sdk/resources/beta.js";
715
import type { BetaRateLimitError } from "@anthropic-ai/sdk/resources";
816

9-
type AnthropicChunk = BetaRawContentBlockDeltaEvent | BetaRawContentBlockStartEvent | BetaRawContentBlockStopEvent | BetaRateLimitError;
17+
type AnthropicChunk =
18+
| BetaRawContentBlockDeltaEvent
19+
| BetaRawContentBlockStartEvent
20+
| BetaRawContentBlockStopEvent
21+
| BetaRateLimitError;
1022
/**
1123
* Type alias for Anthropic model names.
1224
*
@@ -18,7 +30,14 @@ type AnthropicChunk = BetaRawContentBlockDeltaEvent | BetaRawContentBlockStartEv
1830
* const model: AnthropicModel = "claude-3-haiku-20240307";
1931
* ```
2032
*/
21-
export type AnthropicModel = Anthropic.Model;
33+
34+
type OnlyLiteralStrings<T> = T extends string
35+
? string extends T
36+
? never
37+
: T
38+
: never;
39+
40+
export type AnthropicModel = OnlyLiteralStrings<Anthropic.Model>;
2241

2342
/**
2443
* Provider for Anthropic Claude models.
@@ -129,7 +148,9 @@ export class AnthropicProvider extends Provider {
129148
url: this.mcpServer.url,
130149
name: this.mcpServer.name,
131150
type: "url",
132-
...(this.mcpServer.authorizationToken && { authorization_token: this.mcpServer.authorizationToken }),
151+
...(this.mcpServer.authorizationToken && {
152+
authorization_token: this.mcpServer.authorizationToken,
153+
}),
133154
},
134155
],
135156
betas: ["mcp-client-2025-04-04"],
@@ -194,7 +215,6 @@ export class AnthropicProvider extends Provider {
194215
};
195216
}
196217

197-
198218
/**
199219
* Normalizes Anthropic-specific chunks into the unified NormalizedChunk format.
200220
*
@@ -227,16 +247,20 @@ export class AnthropicProvider extends Provider {
227247
};
228248
}
229249

230-
const baseChunk: Pick<NormalizedChunkAnthropic, "provider" | "timestamp" | "index" | "originalChunk"> = {
250+
const baseChunk: Pick<
251+
NormalizedChunkAnthropic,
252+
"provider" | "timestamp" | "index" | "originalChunk"
253+
> = {
231254
provider: "anthropic",
232255
timestamp,
233256
index: chunk.index,
234257
originalChunk: chunk,
235258
};
236259

237-
238-
239-
if (chunk.type === "content_block_start" && chunk.content_block.type === "text") {
260+
if (
261+
chunk.type === "content_block_start" &&
262+
chunk.content_block.type === "text"
263+
) {
240264
return {
241265
...baseChunk,
242266
type: "text_start",
@@ -246,7 +270,10 @@ export class AnthropicProvider extends Provider {
246270
};
247271
}
248272

249-
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
273+
if (
274+
chunk.type === "content_block_delta" &&
275+
chunk.delta.type === "text_delta"
276+
) {
250277
if (!this.config.silent) {
251278
process.stdout.write(
252279
JSON.stringify({
@@ -260,7 +287,7 @@ export class AnthropicProvider extends Provider {
260287
...baseChunk,
261288
type: "text_delta",
262289
data: { textDelta: chunk.delta.text },
263-
}
290+
};
264291
}
265292

266293
if (
@@ -287,7 +314,10 @@ export class AnthropicProvider extends Provider {
287314
};
288315
}
289316

290-
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
317+
if (
318+
chunk.type === "content_block_delta" &&
319+
chunk.delta.type === "input_json_delta"
320+
) {
291321
return {
292322
...baseChunk,
293323
type: "tool_call_delta",
@@ -297,7 +327,10 @@ export class AnthropicProvider extends Provider {
297327
};
298328
}
299329

300-
if (chunk.type === "content_block_start" && chunk.content_block.type === "mcp_tool_result") {
330+
if (
331+
chunk.type === "content_block_start" &&
332+
chunk.content_block.type === "mcp_tool_result"
333+
) {
301334
return {
302335
...baseChunk,
303336
type: "tool_result",
@@ -306,12 +339,10 @@ export class AnthropicProvider extends Provider {
306339
isError: chunk.content_block.is_error,
307340
toolResult: chunk.content_block.content,
308341
},
309-
}
342+
};
310343
}
311344

312-
if (
313-
chunk.type === "content_block_stop"
314-
) {
345+
if (chunk.type === "content_block_stop") {
315346
if (!this.config.silent) {
316347
process.stdout.write(
317348
JSON.stringify({

packages/mcp-check/src/providers/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AnthropicProvider } from "./anthropic.js";
55
import { OpenAIProvider } from "./openai.js";
66
import type { ProviderConfig } from "./types.js";
77
import { Provider } from "./provider.js";
8-
import { type OpenRouterModel } from "./openrouter.js";
8+
import { OpenRouterProvider, type OpenRouterModel } from "./openrouter.js";
99

1010
/**
1111
* @fileoverview Provider factory and type exports for MCP AI providers.
@@ -56,8 +56,8 @@ export type { OpenRouterModel } from "./openrouter.js";
5656
* ```
5757
*/
5858
export type ModelName =
59-
| `anthropic/${AnthropicModel}`
6059
| `openai/${OpenAIModel}`
60+
| `anthropic/${AnthropicModel}`
6161
| `openrouter/${OpenRouterModel}`;
6262

6363
/**
@@ -122,6 +122,7 @@ export function createProvider(
122122
}
123123

124124
if (model.startsWith("openrouter/")) {
125+
return new OpenRouterProvider(mcpServer, promptText, config);
125126
}
126127

127128
throw new Error(`Error: unknown provider for model: ${model}.`);

0 commit comments

Comments
 (0)