TPMJS vs Custom MCP Servers

A custom MCP server gives you full control. TPMJS gives you a registry with automated schema extraction, quality scoring, and a pluggable executor — so you can focus on agent logic.

What a Custom MCP Server Requires

Building an MCP server means implementing the full protocol stack yourself:

Transport layer

HTTP and/or SSE endpoint, message framing, connection lifecycle, keep-alive handling. Each transport has different buffering and error semantics.

JSON-RPC 2.0 dispatch

Method routing for initialize, tools/list, tools/call, ping. Error codes, request ID tracking, batch handling.

Schema per tool

Each tool needs a hand-written inputSchema (JSON Schema), description, and handler. Schemas must stay synchronized with the implementation.

Ops surface

Deployment, monitoring, auth, rate limiting, error handling, logging. Each server is an independent service to maintain.

What TPMJS Handles for You

Discovery Pipeline

Three-phase async pipeline: (1) npm changes feed monitors for tpmjs keyword, (2) enrichment extracts JSON schemas from tool exports and runs health checks, (3) metrics calculates quality scores daily from downloads and GitHub stars.

MCP Serving

Collections are exposed as MCP endpoints at /api/mcp/[user]/[slug]/[transport]. Both HTTP and SSE transports, API key auth with scoped permissions, per-key rate limiting.

Pluggable Execution

Default executor runs on Railway. Or point to any HTTPS endpoint via custom executor config. Contract: accepts package name + tool name + params + env, returns output + execution time.

Side-by-Side

CapabilityCustom MCP ServerTPMJS
Protocol implementationYou implement JSON-RPC 2.0 transport, message framing, error serializationBuilt-in HTTP + SSE transports with standard JSON-RPC 2.0
Schema definitionHand-write inputSchema per toolAuto-extracted from tool exports during enrichment sync
Input validationImplement per toolZod schemas generated from inputSchema, validated at execution
Tool discoveryOnly available to your own codebaseBM25-scored search API with category filtering
Quality signalNoneMulti-factor score (0-1.0): tier + log(downloads) + log(stars) + metadata richness
Health monitoringYou build itAutomated health checks (import + execution) during enrichment phase
VersioningManage per servernpm semver — tools versioned independently
Spec updatesYou migrate when MCP spec changesRegistry handles protocol updates centrally

Code Comparison

Custom MCP server — you own the stack

// server.ts — transport + routing
import { Server } from '@modelcontextprotocol/sdk/server';

const server = new Server({
  name: 'my-tools',
  version: '1.0.0',
});

// Hand-write each tool schema
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: 'search_web',
    description: 'Search the web',
    inputSchema: {
      type: 'object',
      properties: {
        query: { type: 'string' },
        limit: { type: 'number' },
      },
      required: ['query'],
    },
  }],
}));

// Hand-write each tool handler
server.setRequestHandler(CallToolRequestSchema, async (req) => {
  switch (req.params.name) {
    case 'search_web':
      return { content: [{ type: 'text', text: '...' }] };
    // ... repeat for every tool
  }
});

// You handle transport, deployment, monitoring

TPMJS — publish to npm, get MCP for free

// package.json — declare the tool
{
  "name": "@my-org/search-web",
  "keywords": ["tpmjs"],
  "tpmjs": {
    "category": "web",
    "tools": [{
      "name": "searchWeb",
      "description": "Search the web"
    }]
  }
}

// src/index.ts — export the tool
import { tool } from 'ai';
import { z } from 'zod';

export const searchWeb = tool({
  description: 'Search the web',
  parameters: z.object({
    query: z.string(),
    limit: z.number().optional(),
  }),
  execute: async ({ query, limit }) => {
    // Your implementation
  },
});

// npm publish
// Schema extracted automatically
// Available via MCP, CLI, and web search

When a custom server makes sense

  • Tools that require long-lived state or WebSocket connections
  • Internal tools that should never be published externally
  • Custom transport requirements beyond HTTP/SSE

When TPMJS fits better

  • Tools that can be stateless request/response
  • You want discovery — others should find and use your tools
  • You want quality scoring and health monitoring for free
  • You want to publish once and serve via MCP, CLI, and HTTP
  • You want to compose tools from multiple authors into collections

Publish a tool, get MCP serving for free.

Add the tpmjs keyword to your package.json. Schema extraction, discovery, and MCP serving are handled automatically.