tpmjs/HOW_TO_PUBLISH_A_TOOL.md
Ajax Davis a6ec7df800 refactor: remove pricing field from TPMJS specification
Remove pricing field from the entire project as it doesn't make sense for tool metadata:

- Remove TpmjsPricingSchema and TpmjsPricing type from types package
- Remove pricing from TpmjsRichSchema validation
- Remove pricing from validateTpmjsField check
- Remove pricing documentation from /spec page
- Remove pricing examples from /publish page
- Remove pricing from HOW_TO_PUBLISH_A_TOOL.md
- Remove pricing from @tpmjs/createblogpost example package.json

The pricing field was removed from Tier 3 (Rich) metadata as it's not relevant for tool discovery and integration. Tools can document pricing in their README or documentation links instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 04:57:21 +10:00

12 KiB

How to Publish a TPMJS Tool

This guide shows you how to create and publish an AI tool that will be automatically discovered and listed on tpmjs.com.

Quick Start

  1. Create a new NPM package
  2. Add "tpmjs-tool" to the keywords array in package.json
  3. Add a tpmjs field with your tool's metadata
  4. Publish to NPM
  5. Your tool will automatically appear on tpmjs.com within 15 minutes

Step-by-Step Guide

1. Create Your NPM Package

Create a standard NPM package with your tool implementation:

mkdir my-awesome-tool
cd my-awesome-tool
npm init -y

2. Add the Required Keyword

In your package.json, add "tpmjs-tool" to the keywords array:

{
  "name": "@yourname/my-awesome-tool",
  "version": "1.0.0",
  "keywords": ["tpmjs-tool", "ai", "other-keywords"],
  ...
}

Important: The "tpmjs-tool" keyword is REQUIRED for automatic discovery!

3. Add TPMJS Metadata

Add a tpmjs field to your package.json with your tool's metadata. There are three tiers:

Tier 1: Minimal (Required Fields Only)

The bare minimum to get listed:

{
  "tpmjs": {
    "category": "text-analysis",
    "description": "A concise description of what your tool does",
    "example": "const result = await myTool({ input: 'hello' });"
  }
}

Required fields:

  • category - One of: text-analysis, code-generation, data-processing, image-generation, audio-processing, search, integration, other
  • description - Clear description of what the tool does (1-3 sentences)
  • example - Simple code example showing how to use the tool

Add parameter and return type information:

{
  "tpmjs": {
    "category": "text-analysis",
    "description": "Analyzes sentiment in text and returns a score",
    "example": "const result = await analyzeSentiment({ text: 'I love this!' });",
    "parameters": [
      {
        "name": "text",
        "type": "string",
        "description": "The text to analyze",
        "required": true
      },
      {
        "name": "language",
        "type": "string",
        "description": "Language code (e.g., 'en', 'es')",
        "required": false,
        "default": "en"
      }
    ],
    "returns": {
      "type": "SentimentResult",
      "description": "Object containing score (-1 to 1) and label (positive/negative/neutral)"
    }
  }
}

Tier 3: Rich (Full Documentation)

Complete metadata for maximum visibility:

{
  "tpmjs": {
    "category": "text-analysis",
    "description": "Advanced sentiment analysis with emotion detection",
    "example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
    "parameters": [
      {
        "name": "text",
        "type": "string",
        "description": "The text to analyze",
        "required": true
      },
      {
        "name": "language",
        "type": "string",
        "description": "Language code",
        "required": false,
        "default": "en"
      },
      {
        "name": "includeEmotions",
        "type": "boolean",
        "description": "Whether to include emotion breakdown",
        "required": false,
        "default": false
      }
    ],
    "returns": {
      "type": "SentimentResult",
      "description": "Object with score, label, and optional emotions array"
    },
    "authentication": {
      "type": "api-key",
      "required": true
    },
    "frameworks": ["vercel-ai", "langchain"],
    "links": {
      "documentation": "https://docs.example.com",
      "repository": "https://github.com/yourname/tool",
      "homepage": "https://yourwebsite.com"
    },
    "tags": ["sentiment", "nlp", "emotions", "ai"],
    "status": "stable",
    "aiAgent": {
      "useCase": "Use this tool when users need to analyze sentiment in text, detect emotions, or understand the tone of customer feedback, reviews, or social media posts.",
      "limitations": "Only supports English and Spanish. Maximum 10,000 characters per request.",
      "examples": [
        "Analyze customer review sentiment",
        "Detect emotions in user feedback",
        "Monitor social media sentiment"
      ]
    }
  }
}

4. Implement Your Tool

Write your tool's implementation. Here's the example from @tpmjs/createblogpost:

// src/index.ts
export interface BlogPostOptions {
  title: string;
  author: string;
  content: string;
  tags?: string[];
  format?: 'markdown' | 'mdx';
  excerpt?: string;
}

export interface BlogPost {
  frontmatter: {
    title: string;
    author: string;
    date: string;
    tags: string[];
    excerpt?: string;
    slug: string;
    wordCount: number;
    readingTime: number;
  };
  content: string;
  formattedOutput: string;
}

export async function createBlogPost(options: BlogPostOptions): Promise<BlogPost> {
  // Your implementation here
  const { title, author, content, tags = [], format = 'markdown', excerpt } = options;

  // Validate inputs
  if (!title || !author || !content) {
    throw new Error('Title, author, and content are required');
  }

  // Process and return result
  return {
    frontmatter: { /* ... */ },
    content,
    formattedOutput: '...'
  };
}

export default createBlogPost;

5. Build and Publish

Build your package and publish to NPM:

# Build your package
npm run build

# Publish to NPM
npm publish --access public

6. Verification

Your tool will be automatically discovered through:

  1. Keyword Search - Runs every 15 minutes, searches NPM for "tpmjs-tool"
  2. Changes Feed - Monitors NPM publishes in real-time (every 2 minutes)

After publishing, your tool should appear on https://tpmjs.com within 15 minutes!

You can verify by searching: https://tpmjs.com/api/tools?q=yourpackagename

Real Example: @tpmjs/createblogpost

Here's the complete package.json from the published example:

{
  "name": "@tpmjs/createblogpost",
  "version": "0.2.0",
  "description": "A tool for creating structured blog posts with AI-generated content",
  "type": "module",
  "keywords": ["tpmjs-tool", "blog", "content", "ai", "writing"],
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "type-check": "tsc --noEmit"
  },
  "publishConfig": {
    "access": "public"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/ajaxdavis/tpmjs.git",
    "directory": "packages/tools/createBlogPost"
  },
  "homepage": "https://tpmjs.com",
  "license": "MIT",
  "tpmjs": {
    "category": "text-analysis",
    "description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
    "example": "const post = await createBlogPost({ title: 'My First Post', author: 'John Doe', content: 'Hello World!', tags: ['intro', 'blog'] });",
    "parameters": [
      {
        "name": "title",
        "type": "string",
        "description": "The title of the blog post",
        "required": true
      },
      {
        "name": "author",
        "type": "string",
        "description": "The author of the blog post",
        "required": true
      },
      {
        "name": "content",
        "type": "string",
        "description": "The main content of the blog post",
        "required": true
      },
      {
        "name": "tags",
        "type": "string[]",
        "description": "Array of tags for categorization",
        "required": false,
        "default": []
      },
      {
        "name": "format",
        "type": "'markdown' | 'mdx'",
        "description": "Output format for the blog post",
        "required": false,
        "default": "markdown"
      },
      {
        "name": "excerpt",
        "type": "string",
        "description": "Short excerpt or summary of the post",
        "required": false
      }
    ],
    "returns": {
      "type": "BlogPost",
      "description": "A structured blog post object with frontmatter, content, and metadata including slug, wordCount, readingTime, and formattedOutput"
    },
    "authentication": {
      "required": false,
      "type": "api-key"
    },
    "frameworks": ["vercel-ai", "langchain"],
    "links": {
      "documentation": "https://tpmjs.com/tools/createblogpost",
      "repository": "https://github.com/ajaxdavis/tpmjs/tree/main/packages/tools/createBlogPost",
      "homepage": "https://tpmjs.com"
    },
    "tags": ["blog", "content", "markdown", "mdx", "writing", "seo"],
    "status": "stable",
    "aiAgent": {
      "useCase": "Use this tool when users need to generate blog posts, articles, or structured content with proper frontmatter and metadata. Ideal for content management systems, static site generators, and documentation sites.",
      "limitations": "Does not include AI content generation - you must provide the content. Only formats and structures existing content.",
      "examples": [
        "Create a blog post about TypeScript best practices",
        "Generate a tutorial post with code examples",
        "Format an article with SEO metadata"
      ]
    }
  }
}

Field Reference

Required Fields (Tier 1 - Minimal)

Field Type Description
category string Tool category (see categories below)
description string Clear description (1-3 sentences)
example string Code example showing usage

Optional Fields (Tier 2 - Basic)

Field Type Description
parameters array Array of parameter objects
returns object Return type information

Optional Fields (Tier 3 - Rich)

Field Type Description
authentication object Auth requirements
frameworks array Compatible frameworks
links object Related URLs
tags array Additional tags
status string stable, beta, or experimental
aiAgent object AI agent integration info

Categories

Choose one of these for the category field:

  • text-analysis - NLP, sentiment, summarization
  • code-generation - Code generation and transformation
  • data-processing - Data manipulation and transformation
  • image-generation - Image creation and editing
  • audio-processing - Audio/speech processing
  • search - Search and retrieval
  • integration - Third-party integrations
  • other - Anything else

Authentication Types

If your tool requires authentication:

"authentication": {
  "type": "api-key",  // or "oauth", "bearer-token", "basic"
  "required": true
}

Quality Score

Your tool gets a quality score based on:

  • Tier: Rich (1.0) > Basic (0.5) > Minimal (0.25)
  • Downloads: Logarithmic scale based on monthly NPM downloads
  • GitHub Stars: Logarithmic scale based on repository stars

Higher scores = better visibility on tpmjs.com!

Tips for Success

  1. Use descriptive names - Make your package name clear and searchable
  2. Complete metadata - Tier 3 (Rich) tools get 4x the base score
  3. Good documentation - Link to docs in the links.documentation field
  4. Active maintenance - Regular updates boost download counts
  5. AI-friendly descriptions - Write the aiAgent.useCase field as guidance for AI agents

Testing Locally

Before publishing, you can validate your tpmjs field using the validation schema:

# In the tpmjs monorepo
pnpm --filter=@tpmjs/types test

Or manually check the structure matches the examples above.

Troubleshooting

Tool not appearing after 15 minutes?

  • Check that you added "tpmjs-tool" to keywords
  • Verify your tpmjs field has required fields (category, description, example)
  • Check the NPM package is public: npm view yourpackage

Tool showing as "minimal" tier?

  • Add parameters and returns fields for Basic tier
  • Add all Rich tier fields for maximum visibility

Want to force a sync? You can manually trigger a sync (requires auth):

curl -X POST "https://tpmjs.com/api/sync/keyword" \
  -H "Authorization: Bearer YOUR_CRON_SECRET"

Support

Questions or issues?