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

@mcp-layer/test-server

v1.0.2

Published

Feature-rich MCP server for integration testing and local development.

Readme

@mcp-layer/test-server

@mcp-layer/test-server is a feature-complete MCP server used for integration tests and local experiments. It mirrors the tool, resource, prompt, sampling, elicitation, notification, and MCP Apps features expected by the official SDK so clients can validate end-to-end behavior against a single, real server.

The rest of this workspace depends on a real MCP server to validate protocols. This server:

  • Runs over stdio (and optional HTTP/SSE transports)
  • Exercises all major MCP capabilities
  • Exposes stable fixtures for tests and demos

Table of Contents

Installation

# npm
npm install @mcp-layer/test-server
# pnpm
pnpm add @mcp-layer/test-server
# yarn
yarn add @mcp-layer/test-server

Requirements: Node.js 20+ (or Deno/Bun with Node compatibility).

Quick start

Stdio transport

npx mcp-test-server

Streamable HTTP + SSE transport

npx mcp-test-server-http --port 3333

This exposes:

  • Streamable HTTP on /mcp
  • SSE compatibility on /sse (GET stream + POST messages with ?sessionId=...)

SSE is kept for legacy MCP clients. Streamable HTTP clients should use only /mcp.

What it provides

Tools

  • echo -- returns text, structured output
  • add -- arithmetic + structured output
  • annotated -- tool annotations + _meta coverage
  • dashboard -- MCP Apps UI metadata via _meta.ui
  • files -- emits resource_link payloads
  • present -- mixed content types (text/markdown/image/audio/resource/resource_link)
  • summaries -- sampling support
  • booking -- elicitation support
  • roots -- roots capability
  • note-update -- mutable resources
  • logs -- logging notifications
  • progress -- progress notifications
  • rebalance -- debounced list updates

Resources

  • resource://manual -- markdown manual
  • note://{topic}/{detail} -- template-backed resources with completions
  • ui://dashboard/app.html -- MCP Apps HTML UI

Prompts

  • welcome -- prompt arguments with completions

MCP Apps

  • dashboard tool advertises _meta.ui.resourceUri
  • ui://dashboard/app.html serves HTML and _meta.ui settings (csp, permissions)

Structure

  • src/tools/* -- tool implementations
  • src/resources/* -- resource + template handlers
  • src/prompts/* -- prompt definitions
  • src/data/* -- shared manual text and fixtures
  • src/shared/* -- utilities and capability checks

Spec support matrix

| Feature | Status | Notes | | --- | --- | --- | | Tools (structured outputs, resource links) | yes | echo, add, files, summaries, booking, roots, logs, progress, rebalance. | | Tool annotations + metadata | yes | annotated exposes annotations + _meta. | | MCP Apps (UI resources) | yes | dashboard tool exposes _meta.ui.resourceUri, ui://dashboard/app.html serves HTML. | | Mixed content outputs | yes | present emits text/markdown/image/audio/resource/resource_link. | | Resources & dynamic templates | yes | resource://manual, note://{topic}/{detail} with completions. | | Prompts & completion API | yes | welcome prompt + completion/complete. | | Sampling (sampling/createMessage) | yes | summaries tool proxies sampling and validates responses. | | Elicitation (elicitation/create) | yes | booking tool requests alternate booking info. | | Roots (roots/list) | yes | roots tool lists file URIs from capable clients. | | Resource subscriptions/updates | yes | resources/subscribe + note-update tool emit notifications/resources/updated. | | Logging notifications | yes | logs tool emits notifications/message. | | Progress notifications | yes | progress tool streams notifications/progress. | | Debounced list notifications | yes | rebalance tool coalesces updates. | | Alternate transports (Streamable HTTP / SSE) | yes | mcp-test-server-http bootstraps both. | | Auth/OAuth proxying | no | Out of scope for this fixture. |

Usage in tests

Use it as the real server target for integration tests:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

const transport = new StdioClientTransport({
  command: process.execPath,
  args: [require.resolve('@mcp-layer/test-server/src/bin.js')]
});

const client = new Client({ name: 'demo', version: '0.0.0' });
await client.connect(transport);

Use this programmatic helper when you need a mounted localhost HTTP endpoint in tests:

import { startHttpServer } from '@mcp-layer/test-server/http';

const server = await startHttpServer({ port: 0 });
const url = `http://127.0.0.1:${server.port}`;

// streamable HTTP endpoint
const mcp = `${url}/mcp`;
// legacy SSE endpoint
const sse = `${url}/sse`;

await server.close();

Testing

pnpm test --filter @mcp-layer/test-server

The suite boots the real binary, exercises all tools/resources/prompts, verifies notifications, and asserts MCP Apps metadata so this fixture remains trustworthy.

Extending the server

When adding capabilities:

  1. Implement the feature in src/*.
  2. Add or update a test in test/index.test.js.
  3. Document it in this README.

Runtime Error Reference

This section is written for high-pressure debugging moments. These errors are intentionally emitted by the test server to exercise client and REST error-handling paths.

Protocol failure

Thrown from: registerCrash.crashTool

This error is intentionally thrown by the crash tool. It simulates an MCP tool that fails at protocol/runtime level so downstream layers can validate error mapping and HTTP problem responses.

Step-by-step resolution:

  1. Confirm you actually invoked the crash tool (tools crash exec) and not a production tool.
  2. If this appeared unexpectedly, verify test fixture/tool name selection.
  3. In integration tests, assert the expected failure shape (isError/problem details) instead of treating it as an infra bug.
  4. Use a non-crashing test tool when validating success paths.
await t.test('error mapping', async function errorCase() {
  await assert.rejects(client.callTool({ name: 'crash', arguments: {} }));
});

await t.test('success path', async function successCase() {
  const result = await client.callTool({ name: 'slow', arguments: {} });
  assert.equal(result.isError, false);
});

first failure

Thrown from: registerFlap.flapTool

This error is intentionally thrown on the first invocation of the flap tool. The second and later calls succeed, which is useful for circuit-breaker recovery tests.

Step-by-step resolution:

  1. Confirm this is the first call in the process lifetime; first-call failure is expected behavior.
  2. If you need deterministic success, warm up the tool once before the measured assertion.
  3. For resilience tests, assert both phases: failure first, success next.
  4. Reset server state between test cases when first-call semantics matter.
await assert.rejects(client.callTool({ name: 'flap', arguments: {} }));
const ok = await client.callTool({ name: 'flap', arguments: {} });
assert.equal(ok.isError, false);

progress tool aborted

Thrown from: registerProgress.progressTool

This error is raised when the progress tool sees extra.signal.aborted before or during loop processing. It represents explicit cancellation of long-running MCP work.

Step-by-step resolution:

  1. Check client/request timeout and cancellation behavior for this call.
  2. Confirm you did not pass an already-aborted signal into the tool execution context.
  3. Increase timeout or delay cancellation if you expect completion.
  4. For cancellation tests, assert abort behavior explicitly instead of treating this as unexpected.
const controller = new AbortController();
const result = await client.callTool({
  name: 'progress',
  arguments: { steps: 3, delayMs: 20 },
  signal: controller.signal
});
assert.equal(result.isError, false);

progress tool aborted

Thrown from: registerProgress.progressTool.sleep

This error is raised when cancellation occurs while progress is sleeping between step notifications. It is the mid-flight cancellation branch of the same tool.

Step-by-step resolution:

  1. Correlate abort timing with delayMs and steps in the progress request.
  2. If completion is required, avoid cancelling during the sleep interval.
  3. If cancellation is expected, assert this specific branch so tests remain intentional.
  4. Tune delayMs in tests to make cancel timing deterministic.
const controller = new AbortController();
const pending = client.callTool({
  name: 'progress',
  arguments: { steps: 5, delayMs: 100 },
  signal: controller.signal
});

setTimeout(function abortLater() {
  controller.abort();
}, 30);

await assert.rejects(pending);

Invalid --port value "{value}".

Thrown from: port

This happens when mcp-test-server-http is started with a non-integer or out-of-range --port argument. The HTTP fixture only accepts numeric TCP ports in the 0-65535 range.

Step-by-step resolution:

  1. Pass --port as a base-10 integer (--port 3333).
  2. Avoid host:port strings (127.0.0.1:3333) and non-numeric values.
  3. If you use environment variables, ensure the value is present and parseable.
  4. In tests, reserve an ephemeral port first and pass that numeric value.
npx mcp-test-server-http --port 3333

License

MIT