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

@postman/test-mcp-server

v1.0.0

Published

MCP Server for E2E testing of the Postman MCP Client

Downloads

96

Readme

Test MCP Server for MCP E2E Tests

A test MCP server used for E2E tests in the MCP Client. This originally was based off of the MCP Everything Server, but has been given new capabilities which the MCP Client handles.

Building

npm install
npm run build

Running

STDIO Transport (Default)

npm start
# or

```node dist/index.js stdio

### SSE Transport
```bash
npm run start:sse
# or
node dist/index.js sse

Streamable HTTP Transport

npm run start:streamableHttp
# or
node dist/index.js streamableHttp

Streamable HTTP with OAuth2 Authentication

npm run start:streamableHttp:auth
# or
node dist/index.js streamableHttp --auth

This transport requires OAuth2 Bearer token authentication for all MCP endpoints.

Available Tools

| Tool | Description | |------|-------------| | echo | Echoes back the input | | add | Adds two numbers | | longRunningOperation | Demonstrates progress updates | | printEnv | Prints environment variables | | sampleLLM | Samples from an LLM using MCP's sampling feature | | getTinyImage | Returns a small test image | | annotatedMessage | Demonstrates content annotations | | getResourceReference | Returns a resource reference | | getResourceLinks | Returns multiple resource links | | structuredContent | Returns structured content with schema | | zip | Creates a zip file from URLs | | listRoots | Lists MCP roots (if client supports) | | startElicitation | Demonstrates user input elicitation (if client supports) |

Available Prompts

| Prompt | Description | |--------|-------------| | simple_prompt | A prompt without arguments | | complex_prompt | A prompt with temperature and style arguments | | resource_prompt | A prompt that includes an embedded resource |

Resources

The server provides 100 static resources:

  • Even-numbered resources contain plaintext
  • Odd-numbered resources contain binary data
  • Accessible via URI pattern: test://static/resource/{id}

Project Structure

src/
├── index.ts              # Main entry point with transport selection
├── logger.ts             # Pino logger configuration
├── server/
│   └── index.ts          # Server creation and request handler wiring
├── tools/
│   ├── index.ts          # Tool registry, listing, and call routing
│   ├── types.ts          # Tool type definitions
│   ├── constants.ts      # Tool names enum and constants
│   └── definitions/      # Individual tool definitions
│       ├── echo.ts
│       ├── add.ts
│       └── ...           # One file per tool
├── prompts/
│   └── index.ts          # Prompt definitions and handlers
├── resources/
│   └── index.ts          # Resource definitions and handlers
├── oauth/
│   ├── index.ts          # OAuth module exports
│   ├── config.ts         # OAuth configuration
│   ├── types.ts          # OAuth type definitions
│   ├── stores.ts         # In-memory token/client stores
│   ├── helpers.ts        # Token generation utilities
│   ├── middleware.ts     # Auth middleware
│   └── routes.ts         # OAuth endpoints
└── transports/
    ├── stdio.ts              # Standard I/O transport
    ├── sse.ts                # Server-Sent Events transport
    └── streamableHttpServer.ts # Streamable HTTP (with optional OAuth2)

Scripts

| Command | Description | |---------|-------------| | npm run build | Compile TypeScript to JavaScript | | npm run clean | Remove dist/ and build artifacts | | npm run clean:all | Remove dist/, node_modules/, logs, and all generated files | | npm run lint | Check for linting errors | | npm run lint:fix | Fix auto-fixable linting errors | | npm run format | Format code with Prettier | | npm run format:check | Check if code is formatted | | npm run watch | Watch mode for development | | npm start | Start with STDIO transport | | npm run start:stdio | Start with STDIO transport | | npm run start:sse | Start with SSE transport | | npm run start:streamableHttp | Start with Streamable HTTP transport | | npm run start:streamableHttp:auth | Start with Streamable HTTP + OAuth2 | | npm test | Run all tests | | npm run test:watch | Run tests in watch mode | | npm run test:unit | Run only unit tests | | npm run test:e2e | Run only E2E tests | | npm run test:coverage | Run tests with coverage report |

Testing

This project uses Vitest for testing, with both unit and end-to-end (E2E) tests.

Test Structure

src/
├── tools/
│   └── __tests__/           # Unit tests for tools
│       ├── echo.test.ts
│       ├── add.test.ts
│       ├── getTinyImage.test.ts
│       └── index.test.ts
├── prompts/
│   └── __tests__/           # Unit tests for prompts
│       └── index.test.ts
├── resources/
│   └── __tests__/           # Unit tests for resources
│       └── index.test.ts
└── oauth/
    └── __tests__/           # Unit tests for OAuth
        ├── helpers.test.ts
        └── middleware.test.ts

e2e/                         # End-to-end tests
├── helpers/
│   └── server.ts            # Test helpers for server management
├── stdio.test.ts            # STDIO transport tests
├── sse.test.ts              # SSE transport tests
├── streamableHttp.test.ts   # Streamable HTTP transport tests
└── oauth.test.ts            # OAuth2 flow tests

Running Tests

# Run all tests
npm test

# Run tests in watch mode (during development)
npm run test:watch

# Run only unit tests
npm run test:unit

# Run only E2E tests
npm run test:e2e

# Run tests with coverage report
npm run test:coverage

Unit Tests

Unit tests verify individual components in isolation:

  • Tools: Test handler outputs for each tool (echo, add, getTinyImage, etc.)
  • Prompts: Test prompt generation and completion handling
  • Resources: Test resource creation, listing, pagination, and reading
  • OAuth: Test token generation, validation, and middleware

Example test:

import { describe, it, expect } from "vitest";
import { handler } from "../definitions/echo.js";

describe("echo tool", () => {
  it("should echo the message back", async () => {
    const result = await handler({ message: "hello" }, mockExtra, mockContext);
    expect(result.content[0].text).toBe("Echo: hello");
  });
});

E2E Tests

E2E tests spin up the actual server and test real client-server communication:

  • STDIO Transport: Tests using StdioClientTransport
  • SSE Transport: Tests using SSEClientTransport
  • Streamable HTTP Transport: Tests using StreamableHTTPClientTransport
  • OAuth Flow: Tests full OAuth2 flows (client_credentials, authorization_code with PKCE, refresh_token)

E2E tests verify:

  • Server startup and connection
  • Tool listing and execution
  • Prompt listing and retrieval
  • Resource listing, pagination, and reading
  • OAuth token issuance, introspection, and revocation
  • Authenticated MCP requests

Prerequisites for Testing

Before running tests, ensure the project is built:

npm run build

E2E tests require the built dist/ files since they spawn server processes.

Configuration

Configure logging via environment variables:

| Variable | Description | Default | |----------|-------------|---------| | LOG_LEVEL | Log level (trace, debug, info, warn, error, fatal) | debug |

Component Loggers

The codebase uses child loggers for different components:

  • server - Core server operations
  • transport - Transport layer (stdio, sse, http)
  • tools - Tool execution
  • oauth - OAuth2 authentication

OAuth2 Configuration

Configure via environment variables (optional, defaults provided for testing):

  • OAUTH_CLIENT_ID - Client ID (default: mcp-client)
  • OAUTH_CLIENT_SECRET - Client secret (default: mcp-secret)
  • OAUTH_TOKEN_SECRET - Secret for signing tokens (change in production!)
  • PORT - Server port (default: 3001)

Supported Grant Types

| Grant Type | Description | |------------|-------------| | client_credentials | Server-to-server authentication | | authorization_code | User authorization flow (with optional PKCE) | | refresh_token | Refresh an expired access token |

Getting a Token (Client Credentials)

curl -X POST http://localhost:3001/oauth/token \
  -d "grant_type=client_credentials" \
  -d "client_id=mcp-client" \
  -d "client_secret=mcp-secret"

Authorization Code Flow (with PKCE)

  1. Generate PKCE values (client-side):
# Generate code_verifier (43-128 chars)
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '=' | tr '/+' '_-')

# Generate code_challenge (S256)
CODE_CHALLENGE=$(echo -n $CODE_VERIFIER | openssl sha256 -binary | base64 | tr -d '=' | tr '/+' '_-')
  1. Redirect user to authorization endpoint:
http://localhost:3001/oauth/authorize?
  response_type=code&
  client_id=mcp-client&
  redirect_uri=http://localhost:3000/callback&
  scope=mcp:read%20mcp:write&
  state=random-state&
  code_challenge=$CODE_CHALLENGE&
  code_challenge_method=S256
  1. Exchange code for tokens:
curl -X POST http://localhost:3001/oauth/token \
  -d "grant_type=authorization_code" \
  -d "code=<authorization-code>" \
  -d "redirect_uri=http://localhost:3000/callback" \
  -d "client_id=mcp-client" \
  -d "code_verifier=$CODE_VERIFIER"

Refreshing Tokens

curl -X POST http://localhost:3001/oauth/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<your-refresh-token>" \
  -d "client_id=mcp-client"

Response (for authorization_code and refresh_token grants):

{
  "access_token": "uuid-token.signature",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_uuid...",
  "scope": "mcp:read mcp:write"
}

Using the Token

Include the token in all MCP requests:

curl -X POST http://localhost:3001/mcp \
  -H "Authorization: Bearer <your-access-token>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'

OAuth2 Endpoints

| Endpoint | Method | Description | |----------|--------|-------------| | /.well-known/oauth-authorization-server | GET | Authorization Server Metadata (RFC 8414) | | /oauth/register | POST | Dynamic Client Registration (RFC 7591) | | /oauth/authorize | GET | Authorization endpoint for authorization_code flow | | /oauth/token | POST | Token endpoint (all grant types) | | /oauth/introspect | POST | Token introspection (RFC 7662) | | /oauth/revoke | POST | Token revocation (RFC 7009) | | / | GET | Server info and endpoint documentation |

Authorization Server Metadata

Clients can discover OAuth2 configuration automatically:

curl http://localhost:3001/.well-known/oauth-authorization-server

Response:

{
  "issuer": "http://localhost:3001",
  "authorization_endpoint": "http://localhost:3001/oauth/authorize",
  "token_endpoint": "http://localhost:3001/oauth/token",
  "registration_endpoint": "http://localhost:3001/oauth/register",
  "introspection_endpoint": "http://localhost:3001/oauth/introspect",
  "revocation_endpoint": "http://localhost:3001/oauth/revoke",
  "grant_types_supported": ["client_credentials", "authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic", "none"],
  "code_challenge_methods_supported": ["plain", "S256"],
  "scopes_supported": ["mcp:read", "mcp:write"]
}

Dynamic Client Registration

Register a new client dynamically:

curl -X POST http://localhost:3001/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My MCP Client",
    "grant_types": ["authorization_code", "refresh_token"],
    "redirect_uris": ["http://localhost:3000/callback"],
    "scope": "mcp:read mcp:write"
  }'

Response:

{
  "client_id": "client-abc123...",
  "client_secret": "xyz789...",
  "client_id_issued_at": 1234567890,
  "client_secret_expires_at": 0,
  "client_name": "My MCP Client",
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "client_secret_post",
  "scope": "mcp:read mcp:write"
}

Use the returned client_id and client_secret to obtain access tokens.

Adding New Capabilities

Adding a New Tool

Each tool lives in its own file under src/tools/definitions/. To add a new tool:

  1. Create a new file src/tools/definitions/myNewTool.ts:

    import { z } from "zod";
    import { zodToJsonSchema } from "zod-to-json-schema";
    import type { ToolDefinition, ToolHandler, ToolContext } from "../types.js";
    
    // Tool name (exported for use in index.ts)
    export const name = "myNewTool";
    
    // Schema for input validation
    const inputSchema = z.object({
      param1: z.string().describe("Description of param1"),
    });
    
    // Tool definition with description and JSON schema
    export const definition: ToolDefinition = {
      description: "Description of what the tool does",
      inputSchema: zodToJsonSchema(inputSchema),
    };
    
    // Handler implementation
    export const handler: ToolHandler = async (args, extra, context) => {
      const { param1 } = inputSchema.parse(args);
      // Your implementation here
      return {
        content: [{ type: "text", text: `Result: ${param1}` }],
      };
    };
  2. Register it in src/tools/index.ts:

    import * as myNewTool from "./definitions/myNewTool.js";
    
    // Add to tools array in getTools()
    {
      name: myNewTool.name,
      description: myNewTool.definition.description,
      inputSchema: myNewTool.definition.inputSchema,
    }
    
    // Add to handleToolCall()
    if (name === myNewTool.name) {
      return myNewTool.handler(args, extra, context);
    }

Adding a New Prompt

  1. Add the prompt name to src/prompts/index.ts:

    export enum PromptName {
      // ... existing prompts
      MY_PROMPT = "my_prompt",
    }
  2. Register it in getPrompts() and implement in getPrompt().

Adding a New Resource

Modify src/resources/index.ts to add new resource types or extend the resource generation logic.