Skip to main content
Browser-adapted Model Context Protocol TypeScript SDK with modifications to support dynamic tool registration required by the W3C Web Model Context API.

Installation

npm install @mcp-b/webmcp-ts-sdk
# or
pnpm add @mcp-b/webmcp-ts-sdk

Why This Package Exists

The official MCP TypeScript SDK has a restriction that prevents registering server capabilities (like tools) after a transport connection is established. This is enforced by this check in the Server class:
public registerCapabilities(capabilities: ServerCapabilities): void {
    if (this.transport) {
        throw new Error('Cannot register capabilities after connecting to transport');
    }
    ...
}
For the Web Model Context API, this restriction is incompatible because:
  1. Tools arrive dynamically - Web pages call window.navigator.modelContext.provideContext({ tools: [...] }) at any time
  2. Transport must be ready immediately - The MCP server/transport needs to be connected when the page loads
  3. Asynchronous registration - Tools are registered as the page’s JavaScript executes, potentially long after initialization
This package solves the problem by pre-registering tool capabilities before the transport connects, allowing dynamic tool registration to work seamlessly.

Modifications from Official SDK

BrowserMcpServer Class

The BrowserMcpServer extends McpServer with these changes:
export class BrowserMcpServer extends BaseMcpServer {
  constructor(serverInfo, options?) {
    // Pre-register tool capabilities in constructor
    const enhancedOptions = {
      ...options,
      capabilities: mergeCapabilities(options?.capabilities || {}, {
        tools: { listChanged: true }
      })
    };
    super(serverInfo, enhancedOptions);
  }

  async connect(transport: Transport) {
    // Ensure capabilities are set before connecting
    // This bypasses the "cannot register after connect" restriction
    return super.connect(transport);
  }
}
Key Difference: Capabilities are registered before connecting, allowing tools to be added dynamically afterward.

What’s Re-Exported

This package re-exports almost everything from the official SDK:

Types

  • All MCP protocol types (Tool, Resource, Prompt, etc.)
  • Request/response schemas
  • Client and server capabilities
  • Error codes and constants

Classes

  • Server - Base server class (unchanged)
  • McpServer - Aliased to BrowserMcpServer with our modifications

Utilities

  • Transport interface
  • mergeCapabilities helper
  • Protocol version constants

Usage

Use it exactly like the official SDK:
import { McpServer } from '@mcp-b/webmcp-ts-sdk';
import { TabServerTransport } from '@mcp-b/transports';

const server = new McpServer({
  name: 'my-web-app',
  version: '1.0.0'
});

// Connect transport first
const transport = new TabServerTransport({ allowedOrigins: ['*'] });
await server.connect(transport);

// Now you can register tools dynamically (this would fail with official SDK)
server.registerTool('my-tool', {
  description: 'A dynamically registered tool',
  inputSchema: { message: z.string() },
  outputSchema: { result: z.string() }
}, async ({ message }) => {
  return {
    content: [{ type: 'text', text: `Echo: ${message}` }],
    structuredContent: { result: `Echo: ${message}` }
  };
});

Architecture

Maintenance Strategy

This package is designed for minimal maintenance:
  • ~50 lines of custom code
  • Automatic updates for types, protocol, validation via official SDK dependency
  • Single modification point - only capability registration behavior
  • Type-safe - no prototype hacks or unsafe casts

Syncing with Upstream

When the official SDK updates:
  1. Update the catalog version in pnpm-workspace.yaml
  2. Run pnpm install to get latest SDK
  3. Test that capability registration still works
  4. Update this README if SDK behavior changes
The modification is minimal and unlikely to conflict with upstream changes.

Use Cases

Web Model Context API

This package is primarily used by @mcp-b/global to implement the W3C Web Model Context API:
// In @mcp-b/global implementation
import { McpServer } from '@mcp-b/webmcp-ts-sdk';

const server = new McpServer({
  name: 'WebModelContext',
  version: '1.0.0'
});

// Connect immediately
await server.connect(transport);

// Later, when page calls navigator.modelContext.provideContext()
window.navigator.modelContext.provideContext({
  tools: [/* dynamically registered tools */]
});
// This works because capabilities were pre-registered

Single-Page Applications

Perfect for SPAs where tools are registered as components mount:
import { McpServer } from '@mcp-b/webmcp-ts-sdk';

// Set up server at app start
const server = new McpServer({ name: 'my-spa', version: '1.0.0' });
await server.connect(transport);

// Later, in a React component
useEffect(() => {
  server.registerTool('component-tool', config, handler);
  return () => server.unregisterTool('component-tool');
}, []);

Differences from Official SDK

FeatureOfficial SDK@mcp-b/webmcp-ts-sdk
Tool registration before connect✅ Yes✅ Yes
Tool registration after connect❌ No✅ Yes
Static server capabilities✅ Yes✅ Yes
Dynamic capability announcements❌ No✅ Yes (tools)
listChanged capabilityManual✅ Pre-registered

Resources

License

MIT - see LICENSE for details

Support