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

@trainheroic-unofficial/core

v3.1.0

Published

Shared MCP tool layer for TrainHeroic, used by the local and Cloudflare servers.

Readme

@trainheroic-unofficial/core

The shared MCP (Model Context Protocol) tool layer for TrainHeroic. Each tool (a function an AI assistant can call) is defined once here and reused by both servers: the local stdio server (@trainheroic-unofficial/coach-mcp) and the hosted Cloudflare worker (@trainheroic-unofficial/cloudflare). You only need this package if you are building your own MCP server; to use the tools, run one of those servers.

Part of the trainheroic-unofficial workspace.

Contents

How a server uses it

A server builds a ToolContext and passes it, along with its MCP server instance, to the registerXxxTools(server, ctx) functions (the register* names below are the real exports; registerXxxTools is shorthand for all of them). ToolContext is { client, index }: an authenticated TrainHeroicClient (from @trainheroic-unofficial/js) and anything implementing the ExerciseIndex interface (the in-memory ExerciseLibrary here, or the hosted worker's D1-backed store).

Install it alongside the MCP SDK and the js client (both peers you construct from):

npm install @trainheroic-unofficial/core @trainheroic-unofficial/js @modelcontextprotocol/[email protected]
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import { TrainHeroicClient, ExerciseLibrary } from "@trainheroic-unofficial/js";
import {
  registerReadTools,
  registerExerciseTools,
  registerWorkoutTools,
  // registerAthleteTools, registerTeamTools, registerAnalyticsTools, registerMessagingTools
  type ToolContext,
} from "@trainheroic-unofficial/core";

const client = new TrainHeroicClient(
  process.env.TRAINHEROIC_EMAIL!,
  process.env.TRAINHEROIC_PASSWORD!,
);
const index = new ExerciseLibrary(client);

serveStdio(() => {
  const server = new McpServer({ name: "trainheroic", version: "1.0.0" });
  const ctx: ToolContext = { client, index };
  registerReadTools(server, ctx);
  registerExerciseTools(server, ctx);
  registerWorkoutTools(server, ctx);
  return server;
});

Because the context depends on the ExerciseIndex interface rather than a concrete store, the same tools run against the local in-memory library and the hosted D1 (Cloudflare's SQLite database) mirror without change.

What the tools cover

Each register* function registers a group of tools, and the individual tool names the model sees are snake_case (e.g. analytics_query, exercise_resolve). The groups:

  • coach reads (profile, athletes, teams, programs, notifications, analytics catalog)
  • athlete management (registerAthleteTools, the coach's roster view: invite, archive, restore)
  • team management (create, rename, delete, join codes)
  • analytics report pulls (analytics_query: readiness, 1RM (one-rep max) and working-max history, training summary, compliance, lift progress)
  • exercise library operations (resolve, search, get, sync, create, forget, stats)
  • the workout/session lifecycle (build a draft, read it back, publish, unpublish, copy, save as template, remove)
  • messaging (list, read, draft, send, delete)

Every endpoint reaches the model through a typed tool; the surface has no raw-request escape hatch. (registerAthleteTools here is the coach's roster view, distinct from the athlete's own training tools that the athlete server registers.)

Tools return their result in-band. A failure comes back as an error result the model can read and self-correct from. Reads are annotated read-only. Athlete-facing or destructive actions (publish, unpublish, remove, send, delete, archive, team/code delete) pass through a confirmation gate. The gate prefers MCP multi-round-trip elicitation (input_required); when the client already confirmed, it accepts an explicit confirm: true argument. It fails closed if neither condition is met.

The D1-backed warehouse sync tools live in the cloudflare package because they depend on its storage.

Develop

Run pnpm install once at the repo root (Node >= 24, pnpm 11), then from this package:

pnpm build       # tsdown
pnpm typecheck
pnpm test
pnpm exec vitest run test/confirm.test.ts   # one file