mcp-eval-gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +270 -0
- package/dist/chunk-6UIMILU4.js +479 -0
- package/dist/chunk-6UIMILU4.js.map +1 -0
- package/dist/cli.cjs +547 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +524 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +81 -0
- package/dist/index.d.ts +81 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/package.json +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Guillermo Gette
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# mcp-eval-gateway
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/mcp-eval-gateway)
|
|
4
|
+
[](https://github.com/guillegette/mcp-eval-gateway/actions/workflows/ci.yml)
|
|
5
|
+
|
|
6
|
+
Run LLM tool-use evaluations against MCP servers with the [Vercel AI SDK](https://ai-sdk.dev/). The agent loop, tagged response extraction, scoring, and Markdown report follow the pattern in Anthropic's [tool evaluation cookbook](https://github.com/anthropics/anthropic-cookbook).
|
|
7
|
+
|
|
8
|
+
## Get started
|
|
9
|
+
|
|
10
|
+
You need Node.js 22 or later.
|
|
11
|
+
|
|
12
|
+
1. Add the package as a development dependency:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install --save-dev mcp-eval-gateway
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Create the eval files:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx mcp-eval-gateway init
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The command writes two files. It does not overwrite them if they already exist.
|
|
25
|
+
|
|
26
|
+
`eval/config.ts`:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
export default {
|
|
30
|
+
model: 'gateway/anthropic/claude-sonnet-4-6',
|
|
31
|
+
threshold: 0.8,
|
|
32
|
+
mcp: {
|
|
33
|
+
url: 'http://localhost/mcp',
|
|
34
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`eval/tasks.yaml`:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
- name: ping
|
|
43
|
+
prompt: Call the ping tool and return its text
|
|
44
|
+
expected: pong
|
|
45
|
+
required: true
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To write the files under a different folder:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx mcp-eval-gateway init --dir src/eval
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
These files are a starting point. Point the config at your MCP server, write the tasks you want to evaluate, then run the evals. The next three sections cover each step.
|
|
55
|
+
|
|
56
|
+
## Connect the MCP server
|
|
57
|
+
|
|
58
|
+
The `mcp` field in `eval/config.ts` is how the runner opens a session with your MCP server. The runner passes that object to [`toolsFromMcp`](#toolsfrommcp), a function in this package that connects and exposes the server's tools to the model.
|
|
59
|
+
|
|
60
|
+
The generated config reads the server credential from `process.env.MCP_API_KEY`. Rename or remove that variable to match whatever your server expects in its headers.
|
|
61
|
+
|
|
62
|
+
Use one of the following shapes.
|
|
63
|
+
|
|
64
|
+
### Use a running server
|
|
65
|
+
|
|
66
|
+
Point `url` at a Streamable HTTP MCP server. This is what `init` writes.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
export default {
|
|
70
|
+
model: 'gateway/anthropic/claude-sonnet-4-6',
|
|
71
|
+
threshold: 0.8,
|
|
72
|
+
mcp: {
|
|
73
|
+
url: 'https://example.com/mcp',
|
|
74
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Replace fetch
|
|
80
|
+
|
|
81
|
+
Keep `url` and `headers`. Pass `fetch` to wrap the request (extra headers, a test server, or a custom client).
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
export default {
|
|
85
|
+
model: 'gateway/anthropic/claude-sonnet-4-6',
|
|
86
|
+
threshold: 0.8,
|
|
87
|
+
mcp: {
|
|
88
|
+
url: 'http://localhost/mcp',
|
|
89
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
90
|
+
fetch: async (input, init) => {
|
|
91
|
+
const headers = new Headers(init?.headers);
|
|
92
|
+
headers.set('X-Test-Run', '1');
|
|
93
|
+
return fetch(input, { ...init, headers });
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Call an in-process handler
|
|
100
|
+
|
|
101
|
+
Pass `fetch` that calls your route handler. No network hop. This is the Next.js App Router pattern.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { POST } from '../app/mcp/route.js';
|
|
105
|
+
|
|
106
|
+
export default {
|
|
107
|
+
model: 'gateway/anthropic/claude-sonnet-4-6',
|
|
108
|
+
threshold: 0.8,
|
|
109
|
+
mcp: {
|
|
110
|
+
url: 'http://localhost/mcp',
|
|
111
|
+
fetch: (input: string | URL, init?: RequestInit) =>
|
|
112
|
+
POST(new Request(input, init)),
|
|
113
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Write the tasks
|
|
119
|
+
|
|
120
|
+
`eval/tasks.yaml` lists the tasks the model must complete against your server's tools. Each task must include `name`, `prompt`, and `expected`. The runner sends `prompt` to the model with the MCP tools available and scores the final response against `expected`. Set `required` to `true` when a failed task must fail the run.
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
- name: ping
|
|
124
|
+
prompt: Call the ping tool and return its text
|
|
125
|
+
expected: pong
|
|
126
|
+
required: true
|
|
127
|
+
- name: search-empty
|
|
128
|
+
prompt: Search for a document called "does not exist" and report what you find
|
|
129
|
+
expected: No matching document
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Run the evals
|
|
133
|
+
|
|
134
|
+
The default config uses a `gateway/` model (see [Choose models](#choose-models)), which needs `AI_GATEWAY_API_KEY`. Store it in a `.env` file in the project root, next to any values your config reads:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
AI_GATEWAY_API_KEY=your-gateway-key
|
|
138
|
+
MCP_API_KEY=your-server-credential
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then start the runner from the project root:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx mcp-eval-gateway
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The runner loads `.env` when that file exists, then loads the config and `eval/tasks.yaml`. It picks the first of `config.ts`, `config.mts`, `config.mjs`, or `config.js` that exists. It evaluates every `model` in the config in one MCP session, writes a Markdown report, and exits with status 1 if any model fails `threshold` or a `required` task.
|
|
148
|
+
|
|
149
|
+
## CLI flags
|
|
150
|
+
|
|
151
|
+
Each flag takes one value. The following table describes the flags:
|
|
152
|
+
|
|
153
|
+
| Flag | Purpose | Default |
|
|
154
|
+
| --- | --- | --- |
|
|
155
|
+
| `--dir DIR` | Folder under the project root that contains `config.*` and `tasks.yaml` | `eval` |
|
|
156
|
+
| `--env-file ENV_FILE` | Env file to load instead of `.env` | Load `.env` when that file exists |
|
|
157
|
+
| `--model MODEL` | Run this model only, even if it is not in the config list | Run every `model` in the config |
|
|
158
|
+
|
|
159
|
+
The following command evaluates one model and loads config from `src/eval`:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx mcp-eval-gateway \
|
|
163
|
+
--dir src/eval \
|
|
164
|
+
--env-file .env.local \
|
|
165
|
+
--model gateway/anthropic/claude-sonnet-4-6
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
If `--env-file` points at a missing file, the runner exits with an error. Values already set in the process environment are not overwritten when an env file is loaded.
|
|
169
|
+
|
|
170
|
+
## Choose models
|
|
171
|
+
|
|
172
|
+
`model` in `eval/config.ts` is a string, an array of strings, or a `LanguageModel` instance from the AI SDK.
|
|
173
|
+
|
|
174
|
+
Model strings have the form `PROVIDER/ID`. The prefix before the first `/` picks the provider; the rest is the model ID that provider expects. The following table lists the providers:
|
|
175
|
+
|
|
176
|
+
| Prefix | Example | Package | Credentials |
|
|
177
|
+
| --- | --- | --- | --- |
|
|
178
|
+
| `gateway/` | `gateway/anthropic/claude-sonnet-4-6` | None (built into the AI SDK) | `AI_GATEWAY_API_KEY` |
|
|
179
|
+
| `anthropic/` | `anthropic/claude-sonnet-4-6` | `@ai-sdk/anthropic` | `ANTHROPIC_API_KEY` |
|
|
180
|
+
| `openai/` | `openai/gpt-5.2` | `@ai-sdk/openai` | `OPENAI_API_KEY` |
|
|
181
|
+
| `bedrock/` | `bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0` | `@ai-sdk/amazon-bedrock` | AWS credentials |
|
|
182
|
+
|
|
183
|
+
`init` writes a `gateway/` model. The gateway is built into the AI SDK, needs no extra package, and gives one `AI_GATEWAY_API_KEY` access to models from every provider. For the other prefixes, install the listed provider package (they are optional peer dependencies) and set its credentials.
|
|
184
|
+
|
|
185
|
+
To evaluate several models in one run, set `model` to an array. Every model runs against the same MCP session and the same tasks:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
export default {
|
|
189
|
+
model: [
|
|
190
|
+
'gateway/anthropic/claude-sonnet-4-6',
|
|
191
|
+
'gateway/openai/gpt-5.2',
|
|
192
|
+
],
|
|
193
|
+
threshold: 0.8,
|
|
194
|
+
mcp: {
|
|
195
|
+
url: 'http://localhost/mcp',
|
|
196
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
To run one model without editing the config, pass `--model` on the command line. A `LanguageModel` instance built in code is used as-is; strings are resolved through the table above.
|
|
202
|
+
|
|
203
|
+
## Add a GitHub Actions step
|
|
204
|
+
|
|
205
|
+
After checkout, Node.js 22 setup, and `npm ci`, add an eval step. Pass secrets through the job environment instead of a `.env` file:
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
- name: Run MCP evals
|
|
209
|
+
run: npx mcp-eval-gateway
|
|
210
|
+
env:
|
|
211
|
+
AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }}
|
|
212
|
+
MCP_API_KEY: ${{ secrets.MCP_API_KEY }}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
When GitHub provides `GITHUB_STEP_SUMMARY`, the runner writes the Markdown report to the job summary. The step fails when accuracy is below `threshold` or when a `required` task fails.
|
|
216
|
+
|
|
217
|
+
## Call the library
|
|
218
|
+
|
|
219
|
+
For a script or Vitest file, import from `mcp-eval-gateway`. The following example connects to an MCP server, runs one task, and asserts the result:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
import { toolsFromMcp, runEvals, assertEvalResult } from 'mcp-eval-gateway';
|
|
223
|
+
|
|
224
|
+
const { tools, close } = await toolsFromMcp({
|
|
225
|
+
url: 'https://example.com/mcp',
|
|
226
|
+
headers: { Authorization: `Bearer ${process.env.MCP_API_KEY}` },
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const result = await runEvals({
|
|
231
|
+
model: 'gateway/anthropic/claude-sonnet-4-6',
|
|
232
|
+
tools,
|
|
233
|
+
tasks: [
|
|
234
|
+
{
|
|
235
|
+
name: 'ping',
|
|
236
|
+
prompt: 'Call ping and return its text',
|
|
237
|
+
expected: 'pong',
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
assertEvalResult(result, { threshold: 0.8 });
|
|
242
|
+
} finally {
|
|
243
|
+
await close();
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The following exports are available:
|
|
248
|
+
|
|
249
|
+
- `initEvalProject(rootDir, options)`: create `config.ts` and `tasks.yaml` in the eval folder. `options` can include `dir`.
|
|
250
|
+
- `runEvalProject(rootDir, options)`: load a project folder and run the same path as the CLI. `options` can include `dir`, `envFile`, and `model`.
|
|
251
|
+
- `runEvals(options)`: run tasks against an existing tool set. Pass `model`, `tools`, and `tasks`. You can also pass `maxSteps`, `systemPrompt`, and `scorer`.
|
|
252
|
+
- `toolsFromMcp(options)`: connect to an MCP server and build tools. See the [*toolsFromMcp*](#toolsfrommcp) section of this document.
|
|
253
|
+
- `assertEvalResult(result, options)`: throw when a required task fails or accuracy is below `threshold`.
|
|
254
|
+
- `resolveModel(model)`: turn a `PROVIDER/ID` string into a `LanguageModel`.
|
|
255
|
+
- `writeGitHubSummary(result)`: append the report to `GITHUB_STEP_SUMMARY`. The CLI already does this.
|
|
256
|
+
- `EVALUATION_PROMPT`: default system prompt for the agent loop.
|
|
257
|
+
|
|
258
|
+
### toolsFromMcp
|
|
259
|
+
|
|
260
|
+
`toolsFromMcp` opens an MCP session and returns `{ tools, close }` for `runEvals`. The `mcp` object in `eval/config.ts` is the same options object: pass `url` with optional `fetch` and `headers`, or pass a `transport` from the MCP SDK (stdio, SSE, or custom). The CLI already calls `toolsFromMcp` for you.
|
|
261
|
+
|
|
262
|
+
What shipped in each version is on [Releases](https://github.com/guillegette/mcp-eval-gateway/releases).
|
|
263
|
+
|
|
264
|
+
## Contributing
|
|
265
|
+
|
|
266
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). To report a vulnerability, see [SECURITY.md](SECURITY.md).
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT
|