npm package: @fathurifki/api-mock-wrapper
Description: API mock wrapper with fetch, optional logging, and MCP client support
Latest version: 1.0.0

# @vwhybe/api-mock-wrapper

[![npm version](https://img.shields.io/npm/v/@vwhybe/api-mock-wrapper.svg)](https://www.npmjs.com/package/@vwhybe/api-mock-wrapper)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

TypeScript/JavaScript client for mock APIs with optional request/response logging, shaped responses (no `res.json()`), and MCP (Model Context Protocol) client support. Works in Node and the browser.

**MCP integration:** The package includes an MCP server. Add it to Cursor (or any MCP client) so the AI can **get the request log** (`get_request_log`) and **hit the API by description** (e.g. “get all users” → `hit_api` with method and path).

## Table of contents

- [Install](#install)
- [Quick start](#quick-start)
- [MCP server setup](#mcp-server-setup)
- [Usage](#usage)
- [API reference](#api-reference)
- [Log UI (tracing)](#log-ui-tracing)
- [Requirements](#requirements)
- [Development](#development)
- [Publishing to npm](#publishing-to-npm)
- [License](#license)

## Install

```bash
npm install @vwhybe/api-mock-wrapper
```

- **Node:** 18+
- **Module:** ESM only (`"type": "module"` or `.mjs`)

## Quick start

```ts
import { createApiMockWrapper } from '@vwhybe/api-mock-wrapper';

const api = createApiMockWrapper('https://api.example.com', {}, true, false);
const { data, status } = await api.getJson('/users');
// data is already parsed; no await res.json()
```

## MCP server setup

The package includes an MCP server with two tools: **`get_request_log`** (in-memory request/response log) and **`hit_api`** (call the API by method, path, optional body). Set **`MCP_BASE_URL`** to your API base URL in the client config.

| Client | Config file |
|--------|-------------|
| Cursor | `~/.cursor/mcp.json` |
| VS Code / GitHub Copilot | `.vscode/mcp.json` (workspace) or **MCP: Open User Configuration** |
| GitHub Copilot CLI | `~/.copilot/mcp-config.json` or `<PROJECT_ROOT>/.copilot/mcp-config.json` |

**Full setup (npx vs node path, JSON per client):** [docs/mcp-setup.md](docs/mcp-setup.md).

## Usage

### Shaped responses (no `res.json()`)

```ts
const api = createApiMockWrapper('http://localhost:3000', {}, true, false);

const { data, status, ok, headers } = await api.getJson<User[]>('/api/users');
await api.postJson('/api/users', { name: 'Jane' });
await api.putJson('/api/users/1', { name: 'Jane' });
await api.deleteJson('/api/users/1');
```

### Raw fetch

```ts
const res = await api.get('/api/users');
const data = await res.json();
```

### With MCP client (in-app)

When `mcp: true`, you can call MCP tools (e.g. `list_endpoints`, `create_endpoint`) in addition to fetch:

```ts
import { createApiMockWrapper } from '@vwhybe/api-mock-wrapper';

const api = createApiMockWrapper('http://localhost:3000', {}, true, true);

const { data } = await api.getJson('/api/users');

const mcp = await api.getMcpClient();
const tools = await mcp.listTools();
await mcp.callTool('list_endpoints', {});
await mcp.disconnect();
```

Configure the MCP server via `config.mcpTransport: { command, args }` (default: `npm run start --workspace=@vwhybe/mcp-mockapi-server`).

## API reference

### Constructor / factory

| Argument  | Type     | Description |
|----------|----------|-------------|
| `url`    | `string` | Base URL for requests. |
| `config` | `object` | Optional. Fetch options and/or `mcpTransport: { command, args }`. |
| `log`    | `boolean`| If `true`, log each request/response (console + in-memory buffer). |
| `mcp`    | `boolean`| If `true`, `getMcpClient()` is available. |

### Instance methods

| Method | Returns | Description |
|--------|---------|-------------|
| `get(path)`, `post(path, body?)`, `put(path, body?)`, `delete(path)` | `Promise<Response>` | Raw fetch. |
| `getJson<T>(path)`, `postJson<T>(path, body?)`, `putJson<T>(path, body?)`, `deleteJson<T>(path)` | `Promise<ApiResponse<T>>` | Fetch and return `{ data, status, ok, headers }`. |
| `request(path, init?)` | `Promise<Response>` | Low-level fetch. |
| `requestJson<T>(path, init?)` | `Promise<ApiResponse<T>>` | Low-level fetch with shaped response. |
| `url(path)` | `string` | Resolve path to full URL. |
| `getMcpClient()` | `Promise<McpClientFacade>` | MCP client (`listTools`, `callTool`, `disconnect`). Only when `mcp: true`. |

### Log buffer (when `log: true`)

- **`getLogEntries()`** – Returns a copy of the in-memory log entries (browser & Node).
- **`clearLogEntries()`** – Clears the buffer.

### Log UI server (Node only)

Import from the `log-ui` subpath to avoid pulling `node:http` into browser bundles:

```ts
import { serveLogUI } from '@vwhybe/api-mock-wrapper/log-ui';
serveLogUI(3967);  // open http://localhost:3967
```

- **`serveLogUI(port?)`** – Starts HTTP server (default port 3967) with tracing UI (HTMX + Tailwind). Use in the same Node process as the wrapper.
- **`createLogServer(port)`** – Returns the server without calling `listen()`.

### Types

- **`ApiResponse<T>`** – `{ data: T | null, status, ok, headers }`
- **`RequestLogEntry`** – `{ type, timestamp, method, path, url?, status?, durationMs?, message?, responseBody?, responseHeaders?, requestHeaders? }`

## Log UI (tracing)

When `log: true`, entries are stored in an in-memory buffer.

- **Node:** Use `serveLogUI(port)` from `@vwhybe/api-mock-wrapper/log-ui` in the same process that uses the wrapper. Open the URL to see a table with expandable rows (response JSON and headers).
- **Browser (React, Vite, etc.):** Use `getLogEntries()` and `clearLogEntries()` in your own UI: poll `getLogEntries()` and render a table; optionally show `responseBody` and `responseHeaders` in expandable rows.

## Requirements

- **Node.js** ≥ 18
- **ESM** – package is `"type": "module"`; use in ESM only.
- **Dependencies:** `@modelcontextprotocol/sdk`, `zod` (installed automatically).

## Development

```bash
git clone <repo-url>
cd vwhybe-api-mcp-wrapper
npm install
npm run build
npm run test:local
```

- **`npm run build`** – Compile TypeScript to `dist/`.
- **`npm run test:local`** – Quick fetch + log test (no mock server required).

### Install from a local path (before publishing)

In the consumer project’s `package.json`:

```json
"dependencies": {
  "@vwhybe/api-mock-wrapper": "file:../vwhybe-api-mcp-wrapper"
}
```

Then run `npm install` in the consumer. If you use pnpm/Yarn workspaces and see `EUNSUPPORTEDPROTOCOL ... workspace:*`, add the dependency with `pnpm add file:../vwhybe-api-mcp-wrapper` (or equivalent) in that project instead of installing from the workspace root.

## Publishing to npm

1. **Log in** (one-time): `npm login`
2. **Scope:** Package is scoped as `@vwhybe/api-mock-wrapper`. Ensure your npm user has access to the `vwhybe` scope, or publish under your own scope and update `name` in `package.json`.
3. **Build and publish:**

   ```bash
   npm run build
   npm publish --access public
   ```

   Use `--access public` for scoped packages the first time.

4. **Version bumps:** Use [semver](https://semver.org/). For a new release:

   ```bash
   npm version patch   # or minor / major
   npm publish
   ```

The `prepublishOnly` script runs `npm run build` before publish. Published files include `dist/` and `README.md` (see `files` in `package.json`).

## License

MIT