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

shared-mcp-runtime

v0.5.0

Published

Stage-aware MCP tool exposure runtime for reducing MCP Tax

Readme

shared-mcp-runtime

A stage-aware MCP tool exposure runtime for reducing MCP Tax.

shared-mcp-runtime is designed for MCP-based agents that suffer from tool schema overload. Instead of exposing every business tool as soon as an MCP server starts, it keeps the server in an idle state, exposes only control tools, and reveals task-specific tools only when the agent enters the relevant stage.

The runtime is harness-agnostic. The installer includes a ClaudeCode-friendly adapter and generic/custom modes for other agent harnesses.

The core idea is simple:

idle
  -> set_task_context / activate_domain
  -> expose only the tools needed for the current stage
  -> work
  -> clear_task_context
  -> idle

This reduces the hidden cost of full tool exposure: token overhead, attention competition, accidental tool calls, and long-context degradation.

Why

Traditional MCP usage often looks like this:

MCP server starts
  -> all tool schemas are injected into the agent context
  -> the model chooses from every available tool

That is fine for a small tool set. It becomes fragile when an agent uses many MCP servers and dozens or hundreds of tools. Tool descriptions and input schemas become part of the model's working context, even when most of them are irrelevant to the current task.

shared-mcp-runtime treats tool visibility as part of context engineering:

  • Business tools are hidden by default.
  • The agent declares the current task or stage.
  • The server dynamically exposes only relevant tools.
  • The tool set can be cleared after the stage or task ends.

Core Concepts

set_task_context

Sets the current task context, such as skill, goal, stage, language, or file type. Tool providers can use this context to decide which tools should be visible.

activate_domain

A lightweight domain switch for simpler MCP servers that only need idle/active behavior.

clear_task_context

Clears active task/domain state and returns the MCP server to idle mode.

action

An optional set_task_context field that immediately executes the first tool for a stage after the context is set. This reduces the one-turn delay caused by dynamic tools/list refreshes.

mcp.proxy.js

A wrapper for third-party MCP servers. It adds idle-mode gating without changing the child server's source code.

Basic Usage

import { createToolExposureRuntime } from "shared-mcp-runtime";

const exposure = createToolExposureRuntime({
  name: "example-mcp",
  enableTaskContext: true,
  toolProvider: async (ctx) => {
    if (!ctx.task.hasTask) {
      return { tools: [], handlers: [] };
    }

    if (ctx.task.stage !== "generation") {
      return { tools: [], handlers: [] };
    }

    return {
      tools: [
        {
          name: "hello",
          description: "Say hello during the generation stage.",
          inputSchema: { type: "object", properties: {} },
        },
      ],
      handlers: [
        {
          name: "hello",
          handler: async () => ({
            content: [{ type: "text", text: "hello" }],
          }),
        },
      ],
    };
  },
});

await exposure.refreshTools();

In this example, hello is not visible while the server is idle. It appears only after the agent sets a task context whose stage is generation.

Proxy Usage

Both separated and equals-style arguments are supported:

node ./mcp.proxy.js \
  --name=playwright \
  --child-cmd=npx \
  --child-arg=-y \
  --child-arg=@playwright/mcp@latest

On Windows, use npx.cmd as the child command if your MCP host does not resolve .cmd shims automatically.

One-Command Install

The easiest path is interactive install:

npx shared-mcp-runtime@latest --interactive

Equivalent npm exec form:

npm exec --package shared-mcp-runtime@latest -- shared-mcp-install --interactive

It asks for the MCP config path and the MCP you want to wrap, then writes the dynamic proxy entry for you. For ClaudeCode, it also installs the required global calling rule into CLAUDE.md by default.

You can also use shared-mcp-install after global install:

npm install -g shared-mcp-runtime
shared-mcp-install --interactive

For scripted setup, pass all values directly. The installer writes a dynamic proxy entry into an MCP config file and wraps an existing child MCP server without changing the child server's source code.

Install Playwright with a preset:

shared-mcp-install \
  --config /path/to/.mcp.json \
  --preset playwright

Windows:

shared-mcp-install `
  --harness claude-code `
  --config D:\ClaudeCode\.mcp.json `
  --preset playwright

Install any npm-based MCP package:

shared-mcp-install \
  --config /path/to/.mcp.json \
  --name my-mcp \
  --package some-mcp-package

If the package needs extra arguments, append them with --package-arg:

shared-mcp-install `
  --config D:\ClaudeCode\.mcp.json `
  --name filesystem `
  --package @modelcontextprotocol/server-filesystem `
  --package-arg D:\ClaudeCode\project

If the server name already exists, add --force to replace it. The installer creates a timestamped backup by default before writing the config.

To install the MCP proxy without touching global instructions:

shared-mcp-install --config /path/to/.mcp.json --preset playwright --no-rule

For other harnesses, either provide a global instruction/memory path:

shared-mcp-install \
  --harness custom \
  --config /path/to/mcp.json \
  --memory /path/to/global-instructions.md \
  --preset playwright

Or print the rule and add it to your harness manually:

shared-mcp-install print-rule --harness generic

Advanced users can still pass the full child command:

shared-mcp-install --config /path/to/.mcp.json --name playwright --child "npx -y @playwright/mcp@latest"

For local development without a global install:

node ./bin/install-proxy.js --config /path/to/.mcp.json --preset playwright

You can preview without writing:

npx shared-mcp-runtime@latest --config /path/to/.mcp.json --preset playwright --dry-run

Example .mcp.json entry:

{
  "mcpServers": {
    "playwright": {
      "command": "node",
      "args": [
        "path/to/shared-mcp-runtime/mcp.proxy.js",
        "--name=playwright",
        "--child-cmd=npx",
        "--child-arg=-y",
        "--child-arg=@playwright/mcp@latest"
      ]
    }
  }
}

Harness Rules

Dynamic tool exposure changes the first-call pattern. The harness needs this rule somewhere in its global instructions:

For stage-aware MCPs, avoid calling set_task_context alone and then calling a
business tool in the same assistant turn. If the first business action is known,
pass action and action_args inside set_task_context so the MCP refreshes
internally and executes the first tool immediately.

ClaudeCode adapter:

  • MCP config: .mcp.json
  • Global rule: CLAUDE.md next to that config

Generic/custom adapter:

  • MCP config: pass --config
  • Global rule: pass --memory, or use print-rule

What This Is Not

This project is not a generic JSON-RPC boilerplate library.

The core module does not try to own MCP transport/protocol handling. It focuses on dynamic tool exposure and MCP context governance. Host adapters can connect these primitives to stdio MCP, HTTP MCP, SDK-based servers, or custom harnesses.

For heavy execution work, a good pattern is:

MCP: thin, stage-aware capability entry
CLI/script: heavy execution engine
Skill/prompt: task routing and workflow policy

Verify

npm test

Publish

The package is prepared for npm as shared-mcp-runtime.

Before the first publish:

npm login
npm publish

To verify the publish package contents without publishing:

npm pack --dry-run

Context Engineering Report

See docs/mcp_context_engineering_report.md for the tool-exposure analysis, migration notes, and validation results.