# mockserver-client-node 

> Communicate with a [MockServer](https://mock-server.com/) from any node or grunt build

[![Build status](https://badge.buildkite.com/368c3b69e959f29725d8ab582f8d75dedddceee196d39b6d28.svg?style=square&theme=slack)](https://buildkite.com/mockserver/mockserver-client-node)

[![NPM](https://nodei.co/npm/mockserver-client.png?downloads=true&stars=true)](https://nodei.co/npm/mockserver-client/) 

# Community

* Roadmap:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/orgs/mock-server/projects/1"><img height="20px" src="https://mock-server.com/images/GitHub_Logo-md.png" alt="GitHub Project"></a>
* Feature Requests:&nbsp;&nbsp;&nbsp;<a href="https://github.com/mock-server/mockserver-monorepo/issues"><img height="20px" src="https://mock-server.com/images/GitHub_Logo-md.png" alt="Github Issues"></a>
* Issues / Bugs:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/mock-server/mockserver-monorepo/issues"><img height="20px" src="https://mock-server.com/images/GitHub_Logo-md.png" alt="Github Issues"></a>
* Discussions:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/mock-server/mockserver-monorepo/discussions"><img height="20px" src="https://mock-server.com/images/GitHub_Logo-md.png" alt="GitHub Discussions"></a>

## Getting Started

[MockServer](https://mock-server.com/) allows you to mock any system you integrate with via HTTP or HTTPS (i.e. (REST) services, web sites, etc). Please note that it is a third party project that needs java.

This npm module allows any grunt or node project to easily communicate with a running [MockServer](https://mock-server.com/) instance.

As an addition to this module for communicating with a running MockServer there is a second project that can be used to start and stop a MockServer called [mockserver-node](https://www.npmjs.org/package/mockserver-node).

The MockServer client can be created as follows:

```js
var mockServer = require('mockserver-client'),
    mockServerClient = mockServer.mockServerClient // MockServer and proxy client
```
**Note:** this assumes you have an instance of MockServer running on port 1080.
For more information on how to do so check [mockserver-node](https://www.npmjs.org/package/mockserver-node).

## Setup Expectation

A simple expectation can be set up as follows:

```js
mockServerClient("localhost", 1080)
    .mockSimpleResponse('/somePath', { name: 'value' }, 203)
    .then(
        function(result) {
            // do something next
        }, 
        function(error) {
            // handle error
        }
    );
```

A more complex expectation can be set up like this:

```js
mockServerClient("localhost", 1080)
    .mockAnyResponse(
        {
            'httpRequest': {
                'method': 'POST',
                'path': '/somePath',
                'queryStringParameters': [
                    {
                        'name': 'test',
                        'values': [ 'true' ]
                    }
                ],
                'body': {
                    'type': "STRING",
                    'value': 'someBody'
                }
            },
            'httpResponse': {
                'statusCode': 200,
                'body': JSON.stringify({ name: 'value' }),
                'delay': {
                    'timeUnit': 'MILLISECONDS',
                    'value': 250
                }
            },
            'times': {
                'remainingTimes': 1,
                'unlimited': false
            }
        }
    )
    .then(
        function(result) {
            // do something next
        }, 
        function(error) {
            // handle error
        }
    );
```

For the full documentation see [MockServer - Creating Expectations](https://mock-server.com/mock_server/creating_expectations.html).

### Fluent `when().respond()` API

The same expectation can also be built with a chainable API that mirrors the Java
client's `when(...)` / `ForwardChainExpectation`:

```js
mockServerClient("localhost", 1080)
    .when({ path: '/somePath' })
    .respond({ statusCode: 200, body: 'some_response_body' });
```

To set the number of matches, time-to-live, priority or expectation id, use the
chainable `.withTimes()` / `.withTimeToLive()` / `.withPriority()` / `.withId()`
builders before the terminal action — this is the **recommended** style because it
is unambiguous and order-independent:

```js
mockServerClient("localhost", 1080)
    .when({ path: '/somePath' })
    .withTimes(2)
    .withTimeToLive({ unlimited: false, timeToLive: 60, timeUnit: 'SECONDS' })
    .withPriority(10)
    .withId('my-id')
    .forward({ host: 'localhost', port: 8081 });
```

> **⚠️ Positional argument order differs from the procedural methods.** `when(...)`
> takes its optional arguments as `when(request, times, timeToLive, priority)` to
> match the **Java** client. This is **not** the order used by the Node procedural
> methods (`mockSimpleResponse`, `respondWith*`, etc.), which take
> `(…, times, priority, timeToLive, id)`. In particular `when(req, 2, 5)` sets
> `timeToLive = 5` (which expects an object, so it is ignored) and leaves the
> priority unset — it does **not** set the priority to `5`. To avoid this footgun,
> prefer the `.withTimes()` / `.withTimeToLive()` / `.withPriority()` builders shown
> above rather than positional arguments.

If you do pass them positionally, the order is `(request, times, timeToLive, priority)`:

```js
mockServerClient("localhost", 1080)
    .when({ path: '/somePath' }, 2, { unlimited: false, timeToLive: 60, timeUnit: 'SECONDS' }, 10)
    .respond({ statusCode: 201 });
```

The chain returned by `when(...)` exposes the builders `withTimes`, `withTimeToLive`,
`withPriority`, `withId` and the terminal actions `respond` (httpResponse, a template,
or a class-callback), `forward` (httpForward, a template, a class-callback, or an
override-forwarded-request), `error` (httpError), `callback` (a local JS response
callback over the callback WebSocket) and `forwardCallback` (a local JS forward
callback). The action is auto-detected from the object shape: a plain object with a
string `template`/`templateType` becomes a template action, one with a `callbackClass`
becomes a server-side class-callback, otherwise it is the natural response/forward
action. Each terminal method returns the same promise as the procedural builders, so
it can be awaited or used with `.then(...)`.

### Advanced Response Builders

For non-HTTP and streaming protocols there are dedicated builders that take a path (or full request matcher)
plus the response action object, with optional `times`, `priority`, `timeToLive`, and `id` arguments:

```javascript
// Server-Sent Events (SSE)
client.respondWithSse('/events', {
    events: [
        { event: 'message', data: 'first' },
        { event: 'message', data: 'second' }
    ],
    closeConnection: true
});

// WebSocket
client.respondWithWebSocket('/ws', {
    messages: [ { text: 'hello' } ],
    closeConnection: false
});

// DNS
client.respondWithDns('example.com', {
    answerRecords: [
        { name: 'example.com', type: 'A', ttl: 300, value: '127.0.0.1' }
    ],
    responseCode: 'NOERROR'
});

// Raw binary
client.respondWithBinary('/binary', {
    binaryData: Buffer.from('hello').toString('base64')
});

// gRPC server-streaming
client.respondWithGrpcStream('/my.Service/StreamItems', {
    statusName: 'OK',
    messages: [
        { json: '{"value":"first"}' },
        { json: '{"value":"second"}' }
    ],
    closeConnection: true
});
```

### AI Agent Mock Builders (MCP & A2A)

Declarative builders generate the full set of expectations needed to mock an AI
agent endpoint. `client.mcpMock(path)` mocks an [MCP](https://modelcontextprotocol.io)
(Model Context Protocol) server, and `client.a2aMock(path)` mocks an
[A2A](https://a2a-protocol.org) (Agent-to-Agent) agent. Both return a fluent
builder; call `.applyTo()` to register the generated expectations, or `.build()`
to obtain the raw expectation array. They are also exported as standalone
factories (`require('mockserver-client').a2aMock`).

```javascript
// Mock an A2A agent: a static agent-card document over GET plus JSON-RPC 2.0
// tasks/send, tasks/get and tasks/cancel over POST.
client.a2aMock('/a2a')
    .withAgentName('TranslatorAgent')
    .withAgentDescription('Translates text between languages')
    .withSkill('translate')
        .withName('Translation')
        .withDescription('Translates text')
        .withTag('i18n')
        .withExample('Translate hello to Spanish')
    .and()
    // optional SSE streaming (advertises capabilities.streaming and streams
    // status-update / artifact-update events):
    .withStreaming()
    // optional push notifications (echoes the config and POSTs each completed
    // task to the webhook while still replying to the caller):
    .withPushNotifications('http://localhost:1234/callback')
    // custom handler matched by a regex over the inbound message text:
    .onTaskSend()
        .matchingMessage('translate.*')
        .respondingWith('Hola')
    .and()
    .applyTo();   // returns a promise; omit the client arg to use this client
```

### SRE Helpers (SLO verdicts & chaos experiments)

`verifySLO(criteria)` evaluates service-level objectives over the recorded SLI
samples and resolves the verdict (PASS / INCONCLUSIVE); it rejects on a FAIL
verdict, and on a disabled/invalid request (start MockServer with
`sloTrackingEnabled=true`). `startChaosExperiment(experiment)` runs a scheduled
multi-stage chaos experiment (only one experiment is active at a time).

```javascript
// Evaluate SLOs over the last 60s of forwarded traffic
client.verifySLO({
    name: 'checkout-slo',
    window: { type: 'LOOKBACK', lookbackMillis: 60000 },
    minimumSampleCount: 10,
    objectives: [
        { sli: 'LATENCY_P95', comparator: 'LESS_THAN', threshold: 250 },
        { sli: 'ERROR_RATE', comparator: 'LESS_THAN_OR_EQUAL', threshold: 0.01 }
    ]
}).then(
    function (verdict) { /* verdict.result === 'PASS' | 'INCONCLUSIVE' */ },
    function (failure) { /* FAIL verdict body, or enablement guidance */ }
);

// Run a two-stage chaos experiment against an upstream host
client.startChaosExperiment({
    name: 'rolling-brownout',
    stages: [
        { durationMillis: 30000, profiles: { 'api.example.com': { errorStatus: 503, errorProbability: 0.25 } } },
        { durationMillis: 30000, profiles: { 'api.example.com': { latency: { value: 500, timeUnit: 'MILLISECONDS' } } } }
    ]
});
```

## Verify Requests

It is also possible to verify that request were made:

```js
mockServerClient("localhost", 1080)
    .verify(
        {
            'method': 'POST',
            'path': '/somePath',
            'body': 'someBody'
        }, 
        1, true
    )
    .then(
        function() {
            // do something next
        }, 
        function(failure) {
            // handle verification failure
        }
    );
```
It is furthermore possible to verify that sequences of requests were made in a specific order:

```js
mockServerClient("localhost", 1080)
    .verifySequence(
        {
            'method': 'POST',
            'path': '/somePathOne',
            'body': 'someBody'
        },
        {
            'method': 'GET',
            'path': '/somePathTwo'
        },
        {
            'method': 'GET',
            'path': '/somePathThree'
        }
    )
    .then(
        function() {
            // do something next
        }, 
        function(failure) {
            // handle verification failure
        }
    );
```

For the full documentation see [MockServer - Verifying Requests](https://mock-server.com/mock_server/verification.html).

## Interactive Breakpoints

The client supports matcher-driven interactive breakpoints over the callback WebSocket. Register a breakpoint matcher to pause forwarded/proxied exchanges at specific phases and inspect/modify/continue them via callback handlers.

### Register a breakpoint

```js
// REQUEST phase only
client.addRequestBreakpoint(
    { path: '/api/.*' },
    function (request) {
        // inspect or modify the request; return a request to continue or a response to abort
        request.path = '/api/modified';
        return request;
    }
).then(function (breakpointId) {
    console.log('Breakpoint registered:', breakpointId);
});

// REQUEST + RESPONSE phases
client.addRequestAndResponseBreakpoint(
    { path: '/api/.*' },
    function (request) { return request; },           // REQUEST handler
    function (request, response) { return response; } // RESPONSE handler
).then(function (breakpointId) {
    console.log('Breakpoint registered:', breakpointId);
});

// All phases with stream frame handler
client.addBreakpoint(
    { path: '/stream/.*' },
    ['REQUEST', 'RESPONSE', 'RESPONSE_STREAM', 'INBOUND_STREAM'],
    function (request) { return request; },
    function (request, response) { return response; },
    function (pausedFrame) {
        // pausedFrame has: correlationId, streamId, sequenceNumber, direction, phase, body (base64)
        return { action: 'CONTINUE' };
        // Other actions: MODIFY (with body), DROP, INJECT (with body), CLOSE
    }
).then(function (breakpointId) {
    console.log('Breakpoint registered:', breakpointId);
});
```

### Manage breakpoints

```js
// List all matchers
client.listBreakpointMatchers().then(function (result) {
    console.log(result.matchers);
});

// Remove a specific matcher
client.removeBreakpointMatcher(breakpointId);

// Clear all matchers
client.clearBreakpointMatchers();
```

## Using in tests

The client supports TC39 explicit resource management, so a `using` / `await using`
binding resets the server automatically when it goes out of scope — no manual
`afterEach(() => client.reset())` needed:

```js
const { mockServerClient } = require('mockserver-client');

it('records the request', async () => {
    await using client = mockServerClient('localhost', 1080);
    // ... register expectations, make requests ...
    // the server is reset when `client` goes out of scope
});
```

If your runtime/transpiler does not yet support `await using`, reset explicitly
in a Jest/Mocha hook:

```js
const { mockServerClient } = require('mockserver-client');
const client = mockServerClient('localhost', 1080);

afterEach(() => client.reset());
```

## Start / Launch MockServer

This package (`mockserver-client`) is the REST/WebSocket client for communicating with a running MockServer. To **download and launch** a local MockServer instance (no Java or Docker required), use the companion [`mockserver-node`](https://www.npmjs.org/package/mockserver-node) package:

```shell
npx -p mockserver-node mockserver run -p 1080
```

`mockserver-node` downloads a self-contained platform bundle (`mockserver-<version>-<os>-<arch>`) from the GitHub Release, verifies its SHA-256, caches it per-user, and starts it. See the [mockserver-node README](https://www.npmjs.org/package/mockserver-node) for full details including environment variables (`MOCKSERVER_BINARY_BASE_URL`, `MOCKSERVER_BINARY_CACHE`, `MOCKSERVER_SKIP_BINARY_DOWNLOAD`) and supported platforms (linux/darwin/windows on x86_64/aarch64).

## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).

## Changelog

All notable and significant changes are detailed in the [MockServer changelog](https://github.com/mock-server/mockserver-monorepo/blob/master/changelog.md) 

---

Task submitted by [James D Bloom](https://blog.jamesdbloom.com)

## AI Assistant Integration

MockServer includes a built-in [MCP](https://modelcontextprotocol.io) (Model Context Protocol) server that enables AI coding assistants to create expectations, verify requests, and debug HTTP traffic programmatically.

- **MCP Endpoint:** `http://localhost:1080/mockserver/mcp`
- **AI Documentation:** [llms.txt](https://www.mock-server.com/llms.txt)
- **Setup Guide:** [AI Integration](https://www.mock-server.com/mock_server/ai_mcp_setup.html)
