npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pactflow/pact-mcp-plugin

v0.1.0

Published

Pact contract testing for Model Context Protocol (MCP) servers and clients. Ships an ergonomic TypeScript consumer/provider DX and provisions the Rust matching engine (the Pact `mcp` plugin) on install.

Readme

@pactflow/pact-mcp-plugin

Ergonomic TypeScript DX for Pact MCP contract testing. You connect your real @modelcontextprotocol/sdk Client / Server — no stubbing, no service decomposition. All matching runs in the Rust engine; this package is a thin orchestration + DX layer.

Install

npm install @pactflow/pact-mcp-plugin

On install, a postinstall step downloads the matching engine binary (the Pact mcp plugin) for your platform from GitHub releases and installs it to ~/.pact/plugins/mcp-<version>/, where both the Pact plugin driver and this package look for it. The install never hard-fails: if the download can't run (offline, air-gapped, unsupported platform) it prints guidance and you can provision later with:

npx pact-mcp-install          # re-run the download
# or, from source:  ./scripts/install-local.sh   (in the plugin repo)

Opt out of the automatic download with PACT_MCP_SKIP_INSTALL=1 (e.g. in CI where you provision the engine yourself).

Consumer

import { McpPact, like } from "@pactflow/pact-mcp-plugin";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";

await new McpPact({ consumer: "weather-agent", provider: "weather-mcp" })
  .whenClientCallsTool("get_weather", { city: "Melbourne" })
  .willRespondWith({ content: [{ type: "text", text: like("Sunny, 22C") }], isError: false })
  .executeTest(async ({ transport }) => {
    const client = new Client({ name: "weather-agent", version: "1.0.0" }); // your REAL client
    await client.connect(transport);
    const res = await client.callTool({ name: "get_weather", arguments: { city: "Melbourne" } });
    expect(res.content[0].text).toContain("22C");
  });
// -> writes ./pacts/weather-agent-weather-mcp.json

like, regex, number, integer, boolean, notEmpty are authoring helpers that emit the engine's inline matcher DSL. (They intentionally do not re-use pact-js's own matcher objects — the MCP content matcher consumes inline-DSL leaf strings, a different format. Matching itself is 100% in the Rust engine.)

Provider

import { McpProviderVerifier } from "@pactflow/pact-mcp-plugin";

// stdio — the engine spawns your real server
await new McpProviderVerifier({ provider: "weather-mcp", pactUrls: ["./pacts/weather-agent-weather-mcp.json"] })
  .withServerTransport({ type: "stdio", command: "node", args: ["dist/server.js"] })
  .verify();

// http — verify a running / deployed server, with auth
await new McpProviderVerifier({ provider: "weather-mcp", pactUrls: ["./pacts/weather-agent-weather-mcp.json"] })
  .withServerTransport({
    type: "http",
    url: "https://mcp.example.com/mcp",
    auth: { type: "bearer", token: "${MCP_TOKEN}" }, // or apiKey / headers
  })
  .verify();

HTTP + auth

Both the consumer mock (new McpPact({ …, mockTransport: "http" })) and provider verification support Streamable HTTP. Auth kinds: bearer, apiKey { header, value }, headers { … }. Secret values may use ${ENV} interpolation and are never written to the pact — they live only on the verification/transport config. See docs/usage.md.

How it works — the consumer flow (Option B)

pact-js's synchronous-message plugin flow does not expose a live in-memory mock transport that the consumer's real Client connects to: withPluginContents(...).executeTest(cb) hands the callback the configured contents and writes the pact — there is no live consumer mock (the only live-transport path, startTransport, needs a listening-socket mock, i.e. the HTTP transport, which is Phase 2). See docs/decisions/0006-ts-adapter-consumer-flow.md.

So this adapter:

  1. Authors + emits a real pact via the pact-js V4 plugin flow (which invokes the Rust engine's ConfigureInteraction).
  2. Spawns the Rust engine's stdio mock (pact-mcp-plugin mock, reusing the engine matcher) reading that pact, and hands your real Client a StdioClientTransport connected to it. stdio is a first-class MCP transport, so this is a genuine real-Client ↔ real-mock exchange — matching stays in Rust.
  3. On teardown, asserts the mock recorded no mismatches.

The provider verifier and the conformance gate delegate to the engine's verify / compare CLI subcommands (same Rust functions as the gRPC VerifyInteraction / CompareContents), so there is no TypeScript-side matching anywhere.

Engine binary resolution

resolveEngine() looks for the pact-mcp-plugin binary (.exe on Windows) in order:

  1. PACT_MCP_ENGINE env var,
  2. ~/.pact/plugins/mcp-<version>/ (provisioned by the postinstall / pact-mcp-install, or a release install),
  3. a local rust/target/{release,debug} dev build.

Test

npm install
npm test   # consumer + provider + conformance gate (drives the Rust engine)

Requires node, and the engine binary resolvable as above.

Not yet implemented

  • In-memory withServer(inMemoryFactory) provider verification (needs an in-memory→engine bridge; the stdio/http transport paths are provided instead).
  • OAuth2 auth (Phase 4). The AuthProvider seam is ready for it.