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
| Capability | Custom MCP Server | TPMJS |
|---|---|---|
| Protocol implementation | You implement JSON-RPC 2.0 transport, message framing, error serialization | Built-in HTTP + SSE transports with standard JSON-RPC 2.0 |
| Schema definition | Hand-write inputSchema per tool | Auto-extracted from tool exports during enrichment sync |
| Input validation | Implement per tool | Zod schemas generated from inputSchema, validated at execution |
| Tool discovery | Only available to your own codebase | BM25-scored search API with category filtering |
| Quality signal | None | Multi-factor score (0-1.0): tier + log(downloads) + log(stars) + metadata richness |
| Health monitoring | You build it | Automated health checks (import + execution) during enrichment phase |
| Versioning | Manage per server | npm semver — tools versioned independently |
| Spec updates | You migrate when MCP spec changes | Registry 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, monitoringTPMJS — 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 searchWhen 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.