trackmcp
Back to directory

Define intent once. Photon turns a single TypeScript file into CLI tools, MCP servers, and web interfaces.

98 stars TypeScriptOthers Updated Aug 12, 2026
mcpai-toolsbeamclaude-codeclaude-desktopcli-toolcloudflare-workerscursordeveloper-toolsmarketplacemcp-serversmodel-context-protocolsingle-filetypescript

Documentation

npm version
npm downloads
License: MIT
TypeScript
Node
MCP
Docs

One TypeScript capability becomes the whole agent stack.

Photon is the fastest way to turn a small, verified TypeScript method into

something humans can operate and agents can trust. Write the capability once;

Photon derives the interfaces, contracts, and runtime behavior around it:

  • MCP server for Claude, ChatGPT, Cursor, and agents
  • Embedded app UI for chat clients that support MCP app resources
  • CLI tool for scripts, demos, and automation
  • Beam web interface for humans
  • Web routes, schedules, webhooks, retries, state, and audit history when the

capability grows into a production workflow

Photon is free and open source software released under the MIT license.

Full documentation lives at photon.portel.dev.

Related Portel project: NCP gives agents

one natural MCP interface to discover and run tools across a whole tool

ecosystem. Photon builds reliable agent-facing capabilities; NCP helps agents

find and use them alongside every other MCP.

Try it in two minutes:

bash
bun add -g @portel/photon
photon new my-tool
photon

That opens Beam, the generated human UI. Add `photon mcp install my-tool` when

you want the same capability inside Claude Desktop or another MCP client.

*Interfaces are optional. Intent is mandatory.*

bash
gh repo star portel-dev/photon

From one method to every surface

The weather example is intentionally small: one TypeScript method, a few

docblock tags, and one `@ui` HTML asset. Photon turns that into a CLI command,

Beam UI, MCP tool, and embedded app surface for MCP app-capable chat clients.

Claude Desktop can run it from a local stdio MCP command; ChatGPT developer

mode can connect to the same Photon over a public HTTPS `/mcp` endpoint.

Real clients, same Photon:

ChatGPT developer mode rendering the Photon weather UI from a public HTTPS /mcp endpoint.

Claude Desktop rendering the same Photon through local MCP.

Follow the step-by-step tutorial

or open the runnable example in

`examples/weather-showcase`.

The tutorial also includes Beam, CLI, and a concept animation for the full

transformation.


The Photon Promise

Photon is the modern dev stack for the agentic age: each photon is a small,

auditable brick that can be used by humans, agents, schedulers, webhooks, and

apps without rewriting the same capability for every interface.

That is the core idea: **tiny trusted capabilities compose into larger

systems**. A photon can start as a helper method, become a CLI command, render

as an app, run on a schedule, accept webhooks, and still expose a clean

agent-readable contract.


Example

typescript
// hello.photon.ts
export default class Hello {
  greet(name: string) {
    return `Hello, ${name}!`;
  }
}

That's a complete photon. From this single file you get:

code
$ photon cli hello greet --name Ada        # CLI
$ photon                                    # Web UI at localhost:3008
$ photon mcp hello                          # MCP server for Claude, Cursor, etc.

No decorators. No registration. No server boilerplate.

Just define the intent. Photon handles the rest.


Quick Start

From zero to an MCP server connected to Claude Desktop in three commands:

bash
bun add -g @portel/photon
photon new my-tool                  # Scaffolds ./my-tool.photon.ts in your CWD
photon mcp install my-tool          # Registers it in Claude Desktop's config
# Restart Claude Desktop. Your tool is live.

Prefer the web dashboard? Skip step 3 and run `photon` instead — it opens Beam, the auto-generated UI.

Or try without installing globally:

bash
bunx @portel/photon new my-tool
bunx @portel/photon mcp install my-tool

# pnpm users can use pnpm dlx instead:
pnpm dlx @portel/photon new my-tool
pnpm dlx @portel/photon mcp install my-tool

> Requires Node.js 20+. TypeScript is compiled internally; no `tsconfig.json` needed.

>

> Where do photon files live? `./` (a project directory you cd into) or `~/.photon/` (global, auto-discovered). User settings persist under `~/.photon/state//`. See Where things live.

How It Works

You write a TypeScript class. Methods are your capabilities. Types describe what's valid. Comments explain the intent. Photon reads all of it and generates three interfaces from one file. Same logic. Same validation. Same data.

code
analytics.photon.ts  →  Web UI (Beam)  ·  CLI  ·  MCP Server for AI

The more you express, the more Photon derives:

What you writeWhat Photon derives
Method signaturesTool definitions: names, inputs, outputs
Type annotationsInput validation rules, UI field types
JSDoc commentsDocumentation for AI clients and human users
Constructor parametersConfig UI, environment variable mapping, runtime injection (`Photon`, `Cloudflare`, `CloudflareEnv`)
`@tags`Validation, formatting, scheduling, webhooks

When you add a `@param city {@pattern ^[a-zA-Z\s]+$}` annotation, Beam validates it in the form, the CLI validates it before running, and the MCP schema enforces it for the AI. One annotation. Three consumers.

Three ways to author

`extends Photon` is one shape. You can also inject `Photon` as a constructor parameter when you already extend something else, or compose without inheritance — same API either way. CF resources reach the photon through a separate `Cloudflare` injection so portable photons stay portable. See docs/guides/PHOTON-INJECTION.md.


Beam: Human Exploration

Beam is the web dashboard. Every photon becomes an interactive form automatically. Run `photon`. That's the whole command.

The UI is fully auto-generated from your method signatures: field types, validation, defaults, layouts. You never write frontend code. When you add a `{@choice a,b,c}` tag to a parameter, Beam renders a dropdown. When you mark a string as `{@format email}`, the field validates email format. The UI evolves as your code does.

When forms aren't the right interface for what you're building, you can replace Beam's auto-generated view with your own HTML. A global named after your photon is auto-injected (e.g., `analytics.onResult(data => ...)`) — no framework required. `window.photon.url` is also injected and resolves to the Beam base URL so your HTML can construct fetch paths correctly whether running locally or behind a reverse proxy.

> Custom UIs follow the official MCP Apps Extension and work across compatible hosts. See the Custom UI Guide.

Photons that declare HTTP routes with `@get`, `@post`, `@put`, `@patch`, or `@delete` are shown in Beam as web apps. Routes support dynamic path segments (e.g. `@get /items/:id`) matched by specificity: literal segments win over parameters. Beam proxies requests to those routes and injects an `x-photon-base-path` header so the app can construct correct absolute paths regardless of where Beam is hosted.


AI Agents: Machine Invocation

Photon ships separate, tested MCP adapters: sessionful MCP 2025 over stdio and

Streamable HTTP, plus stateless MCP `2026-07-28` release-candidate support over

Streamable HTTP. See the

compatibility matrix and runnable clients,

or run `photon doctor mcp` against your installed runtime.

bash
photon info analytics --mcp
json
{
  "mcpServers": {
    "analytics": {
      "command": "photon",
      "args": ["mcp", "analytics"]
    }
  }
}

Paste into your AI client's config. Your photon is now an MCP server. Claude can call your methods. Cursor can call your methods. Any MCP-compatible host can call your methods.

The AI sees the same thing a human sees in Beam: the method names, the parameter descriptions from your JSDoc, the validation rules from your types. The JSDoc comment you wrote to document the tool for yourself is what Claude reads to decide when and how to call it.

The MCP tools themselves work with Claude Desktop, Claude Code, Cursor, and any MCP-compatible client. When your photon has a custom UI, clients that support the MCP Apps Extension can render it natively, as shown in the weather proof above.


How a Photon Evolves

Here is how a photon grows. Each step adds one thing and gets multiple capabilities from it.

Add comments: AI understands your intent

typescript
/**
 * Weather - Check weather forecasts worldwide
 */
export default class Weather {
  /**
   * Get the weather forecast for a city
   * @param city City name (e.g., "London")
   */
  async forecast(params: { city: string }) { ... }
}

The class description becomes how AI clients introduce the tool to users. The `@param` description is what the AI reads before deciding what value to pass. Same comments. Human help text and AI contract at once.

Declare configuration: a settings tool appears

typescript
export default class Weather {
  /** User-tunable knobs. Photon auto-generates a `settings` tool from this. */
  protected settings = {
    /** Units for forecast values */
    units: 'metric',
    /** Polling interval in seconds */
    pollIntervalSec: 300,
  };

  async forecast(params: { city: string }) {
    const res = await fetch(`...?units=${this.settings.units}`);
    return await res.json();
  }
}

`protected settings` is the canonical way to expose runtime knobs. Photon reads the JSDoc on each property, generates an MCP `settings` tool with typed inputs, and persists user changes to `~/.photon/state//-settings.json`. Inside methods, `this.settings` is a read-only Proxy. To change a value, the user (or AI) calls the auto-generated `settings` tool.

For secrets that should never be persisted in a settings file (API keys, tokens), use a constructor parameter instead. Photon maps the parameter name to an env var:

typescript
export default class Weather {
  constructor(private apiKey: string) {}  // → WEATHER_API_KEY
}

The constructor pattern is for primitives that come from `.env`. The `protected settings` pattern is for everything else, including any knob the user should be able to change at runtime without restarting. When in doubt, reach for `settings`.

Add tags: behavior extends across all surfaces

typescript
/**
 * @dependencies node-fetch@^3.0.0
 */
export default class Weather {
  /**
   * @param city City name {@example London} {@pattern ^[a-zA-Z\s]+$}
   * @param days Number of days {@min 1} {@max 7}
   * @format table
   */
  async forecast(params: { city: string; days?: number }) { ... }
}

`@dependencies` installs `node-fetch` automatically on first run, no manual package install needed. The `{@pattern}` validates in the form, the CLI, and the MCP schema simultaneously. `days` becomes a number spinner with bounds. `@format table` renders the result as a table in Beam. One annotation, three surfaces.

System CLI dependencies

If your photon wraps a command-line tool, declare it and Photon enforces it at load time:

typescript
/**
 * @cli ffmpeg - https://ffmpeg.org/download.html
 */
export default class VideoProcessor {
  async convert({ input, format }: { input: string; format: string }) {
    // ffmpeg is guaranteed to exist when this runs
  }
}

What Comes for Free

Things you don't build because Photon handles them:

Auto-UIForms, field types, validation, layouts generated from your signatures
Stateful instancesMultiple named instances of the same photon, each with isolated state
Persistent memory`this.memory` gives your photon per-instance key-value storage, no database needed
Scheduled execution`@scheduled` runs any method on a cron schedule
Webhooks`@webhook` exposes any method as an HTTP endpoint
OAuth (client)Built-in OAuth 2.0 flows for Google, GitHub, Microsoft
OAuth Authorization ServerIssue tokens to MCP clients yourself: CIMD + DCR, PKCE, OIDC id_token, RFC 8693 token exchange
SQLite persistenceAudit log, execution history, and OAuth grants survive daemon restart (bun:sqlite or better-sqlite3)
Daemon ops`photon ps` lists and controls scheduled jobs, webhooks, and live sessions
Distributed locks`@locked` serializes access: one caller at a time, across processes
Cross-photon calls`this.call()` invokes another photon's methods
Cloudflare runtime`this.cf.r2('blobs')`, `this.cf.d1('app')`, `this.cf.kv('cache')` — same shape locally (miniflare) and deployed (real bindings). See CF-BINDINGS.md
Real-time events`this.emit()` fires named events to the browser UI with zero wiring
Live rendering`this.render()` pushes formatted output to CLI and Beam in real time
Delegated LLM`this.sample()` asks the driving agent's model to generate text — no API key, agent pays
Inline confirm / input`this.confirm()` and `this.elicit()` route through the client's native UI (Beam dialog, Claude prompt)
Scoped remote access`photon claim` generates a short-lived code to scope a remote MCP session to one directory
Standalone binaries`photon build` compiles any photon to a single executable via Bun
Dependency management`@dependencies` auto-installs npm packages on first run

Coordination: Locks + Events

Two primitives. Together they unlock a class of things that are surprisingly hard to build today.

Locks serialize access. When a method is marked `@locked`, only one caller can execute at a time, whether that caller is a human in Beam, a CLI script, or an AI agent. Everyone else waits their turn.

Events push state changes to any browser UI in real time. `this.emit({ event: 'boardUpdated', data: board })` on the server becomes `chess.onBoardUpdated(handler)` in your custom UI — named after your photon file. No WebSockets to configure. No polling. Events are delivered via SSE through the MCP Streamable HTTP transport.

Together: turn-based coordination with live state.

typescript
export default class Chess {
  /** Make a move. Locks ensure human and AI alternate turns. */
  /** @locked */
  async move(params: { from: string; to: string }) {
    const result = await this.applyMove(params.from, params.to);

    // Browser UI updates instantly, no polling needed
    this.emit({ event: 'boardUpdated', data: result.board });
    this.emit({ event: 'turnChanged', data: { next: result.nextPlayer } });

    return result;
  }
}
javascript
// In your custom UI (ui/chess.html)
// The global `chess` is auto-injected, named after your photon file
chess.onBoardUpdated(board => renderBoard(board));
chess.onTurnChanged(({ next }) => showTurn(next));

// Call server methods directly
chess.move({ from: 'e2', to: 'e4' });

A human moves through Beam. Claude is configured with the MCP server. The lock ensures they truly alternate. Events keep the board live on both sides. That's a fully functional turn-based chess game, human vs AI, in about 50 lines of application logic.

The same pattern applies beyond games: approval workflows where a human reviews before AI continues, collaborative tools where edits from any source appear instantly, simulations where steps must execute in strict sequence, any system where who acts next matters.


MCP Primitives on `this`

The MCP protocol's user-facing primitives are surfaced as plain methods

on every photon instance — no decorators, no capability flags, no SDK

imports. The runtime routes each call through whichever surface the

request arrived on (Beam, Claude Desktop, Cursor, CLI).

typescript
export default class Editor {
  async summarize(params: { text: string }) {
    // Ask the driving agent's LLM. No API key. Agent pays.
    return await this.sample({
      prompt: `Summarize in one sentence:\n\n${params.text}`,
      maxTokens: 128,
    });
  }

  async deploy() {
    if (!(await this.confirm('Ship to production?'))) return;
    const env = await this.elicit({
      ask: 'select',
      message: 'Which environment?',
      options: ['staging', 'prod'],
    });
    await this.run(env);
  }
}
PrimitiveWhat it does
`await this.sample({ prompt })`Delegates LLM generation to the caller's model via MCP sampling
`await this.confirm(question)`Yes/no prompt — returns `boolean`
`await this.elicit(params)`Arbitrary input (text, select, form, file, etc.)
`this.status(msg)` / `this.progress(v)`Live feedback during long work; routes to SSE stream in Beam
`this.roots`MCP workspace roots declared by the connected client (`roots/list`)
`this.notifyResourceUpdated(uri)`Push `notifications/resources/updated` to subscribed clients

Full reference: `docs/reference/MCP-PRIMITIVES.md`.


Remote Access: Claim Codes

By default every installed photon is visible to every connected MCP

client. When you want to pair a *remote* agent with a *subset* of your

photons — your phone driving Beam, a teammate reviewing one project,

a CI agent scoped to a single directory — generate a claim code:

bash
$ photon claim --scope /workspace/proj --ttl 4h --label "phone"
✓ Claim code: R3K-9QZ
  Scope:      /workspace/proj
  Expires in: 4h

The remote client presents the code as the `Mcp-Claim-Code` header on

its MCP session. `tools/list` then only exposes photons whose source

lives under that directory. Sessions without a code keep full access —

the feature is strictly opt-in.

Full reference: `docs/reference/CLAIM-CODES.md`.


Marketplace

A curated set of photons is ready to install. The public gallery is now kept

small on purpose: polished apps and tools in one place, teaching examples in

another.

bash
photon search boards
photon add boards

You can also install directly from any GitHub repository using qualified refs:

bash
photon add owner/repo/photon-name

Browse the Photon Apps marketplace

for ready-to-use photons, or the

Photon Examples marketplace

for focused learning examples. You can also host a private marketplace for your

team: internal tools that stay off the public internet.


Commands

bash
# Run
photon                            # Open Beam UI
photon mcp                  # Run as MCP server
photon mcp  --dev           # MCP server with hot reload
photon cli  [method]        # Run as CLI tool

# Install from GitHub
photon beam owner/repo/name       # Install & open in Beam
photon cli owner/repo/name method # Install & run via CLI

# Create
photon maker new            # Scaffold a new photon

# Build
photon build                # Compile to standalone binary
photon build  --with-app    # Include Beam UI in binary

# Manage
photon info                       # List all photons
photon info  --mcp          # Get MCP client config
photon maker validate       # Check for errors

# Marketplace
photon add                  # Install photon
photon search              # Search marketplace
photon upgrade                    # Upgrade all

# Ops
photon doctor                     # Diagnose environment
photon test                       # Run tests
photon ps                         # Observe & control scheduled jobs, webhooks, sessions

`photon ps`: scheduled jobs, webhooks, and sessions

`photon ps` is the operator surface for the daemon. Without arguments

it prints a four-section snapshot — ACTIVE schedules, DECLARED-but-

not-enrolled, WEBHOOKS, and ACTIVE SESSIONS.

bash
photon ps                          # full snapshot
photon ps --json                   # structured output for scripts
photon ps --type active            # one section only
photon ps --base ~/Projects/kith   # filter to one PHOTON_DIR

Two-step model. A `@scheduled` annotation in source is DECLARED

until enrolled. Enrollment is per-machine, persistent, and explicit:

bash
photon ps enable  newsletter:sendDigest    # DECLARED → ACTIVE
photon ps disable newsletter:sendDigest    # ACTIVE → suppressed (survives restart)
photon ps pause   newsletter:sendDigest    # stop firing without removing enrollment
photon ps resume  newsletter:sendDigest    # undo pause
photon ps history newsletter:sendDigest    # last 20 firings: timestamp, status, error

For manual cron schedules without a `@scheduled` tag, use the Beam Pulse

panel ("Add schedule") or call `this.schedule.create()` from photon code.

`this.schedule.create()` (programmatic schedules) skips DECLARED and

goes straight to ACTIVE. See

`docs/GUIDE.md#scheduling`

for the full reference, the daemon state layout, and `.photon-no-host`

for multi-host setups.

Install from GitHub

Use qualified refs to install and run photons directly from any GitHub repository:

bash
photon beam Arul-/photons/claw        # Install from GitHub, open in Beam
photon cli Arul-/photons/todo add     # Install from GitHub, run method

The format is `owner/repo/photon-name`. Transitive `@photon` dependencies from the same repo are resolved automatically.

Compile to Binary

Build standalone executables from any photon — no Node.js required on the target machine:

bash
photon build my-tool                         # Binary for current platform
photon build my-tool -t bun-linux-x64        # Cross-compile for Linux
photon build my-tool --with-app              # Embed Beam UI as a desktop app

Uses Bun's compiler under the hood. The binary bundles the photon, its `@dependencies`, and transitive `@photon` deps into a single file.


Tag Reference

TagWhereWhat it does
`@dependencies`ClassAuto-install npm packages on first run
`@cli`ClassDeclare system CLI dependencies, checked at load time
`@format`MethodResult rendering (table, list, markdown, code, etc.)
`@param ... {@choice a,b,c}`ParamDropdown selection in Beam
`@param ... {@choice-from method}`ParamDynamic dropdown populated from another method's return value
`@param ... {@format email}`ParamInput validation and field type
`@param ... {@min N} {@max N}`ParamNumeric range constraints
`@ui`Class/MethodLink a custom HTML template
`@auth`ClassRequire or describe MCP authentication and populate `this.caller`
`@scope`MethodOverride the inferred OAuth scope for a protected MCP tool call
`@expose`MethodAuto-bind to `POST /api/` for SPA fetch (`public` skips the SameSite gate)
`@get /path`MethodHTTP-only GET route; shown as a web app in Beam, not an MCP tool. Supports `:param` segments
`@post /path`MethodHTTP-only POST route; shown as a web app in Beam, not an MCP tool. Supports `:param` segments
`@put /path`MethodHTTP-only PUT route; shown as a web app in Beam, not an MCP tool. Supports `:param` segments
`@patch /path`MethodHTTP-only PATCH route; shown as a web app in Beam, not an MCP tool. Supports `:param` segments
`@delete /path`MethodHTTP-only DELETE route; shown as a web app in Beam, not an MCP tool. Supports `:param` segments
`@resource `MethodDynamic MCP resource resolver (canonical form; replaces `@Static`)
`@prompt`MethodMCP prompt template (canonical form; replaces `@Template`)
`@webhook`MethodExpose as HTTP endpoint
`@scheduled`MethodRun on a cron schedule
`@locked`MethodDistributed lock across processes
`@autorun`MethodAuto-execute when selected in Beam
`@mcp`ClassInject another MCP server as a dependency
`@icon`Class/MethodSet emoji icon

> See the full Tag Reference for all 30+ tags with examples.


Documentation

Start here:

Guide
Getting StartedInstall, build, and run your first photon in 5 minutes
From Method to Chat AppWeather showcase: CLI, Beam, MCP, and embedded app UI from one method
Core ConceptsThe 6 ideas behind Photon
Tag ReferencePublic reference for every docblock tag Photon understands
Output FormatsVisual gallery of every `@format` type
Intent MetadataHow comments, schemas, annotations, and formats map to native surfaces
SettingsDeclare runtime knobs with `protected settings` (the canonical config pattern)
TroubleshootingCommon issues and solutions

Go deeper:

Topic
Custom UIBuild rich interactive interfaces with the photon bridge API
OAuthBuilt-in OAuth 2.0 with Google, GitHub, Microsoft
MCP JWT AuthSecure deployed MCP tool calls with short-lived scoped JWTs
MCP Client RegistrationRegister MCP clients with Photon's AS via CIMD or DCR
ObservabilityOpenTelemetry traces, metrics, logs, and structured errors
Protocol FeaturesCapability handshake, structured errors, trace correlation
Daemon Pub/SubReal-time cross-process messaging
WebhooksHTTP endpoints for external services
LocksDistributed locks for exclusive access
Advanced PatternsLifecycle hooks, dependency injection, interactive workflows
Marketplace ConfigurationSharing settings across related photons in one marketplace
DeploymentDocker, Cloudflare Workers, AWS Lambda, Systemd

Operate:

Topic
The Photon DaemonLifecycle, PHOTON_DIR resolution, resilience, troubleshooting
SecurityBest practices and audit checklist
Marketplace PublishingCreate and share team marketplaces
Best PracticesPatterns for production photons

Reference: Complete Developer Guide · Tag Reference · Naming Conventions · Architecture · Lifecycle & Ingress · PHOTON_DIR & Namespace · Changelog · Contributing


Open Source

Photon is free and open source under the MIT license.

The project is still evolving and contributions are welcome.

Frequently asked questions

What is photon?

photon is Define intent once. Photon turns a single TypeScript file into CLI tools, MCP servers, and web interfaces.

How do I install photon?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is photon open source?

Yes — it is hosted on GitHub at https://github.com/portel-dev/photon and has 98 stars.

Related MCP tools

AVIDS2memorix

Open-source cross-agent memory layer for coding agents via MCP. Compatible with Claude Code, Codex, Cursor, Windsurf, Gemini CLI, Antigravity, OpenClaw, Hermes Agent, Oh-my-Pi, Pi, Copilot, Kiro, OpenCode, and Trae.

721 TypeScript
ai-codingclaude-codecopilot+17
riponcmprojectmem

Open-source coding agent memory. Records issues, attempts, fixes and decisions, then warns your agent before it repeats an approach that already failed. Native MCP server for Claude Code, Cursor, Antigravity and Codex. 100% local, no cloud, no telemetry. MIT.

796 Python
ai-agentsai-memoryai-tools+17
KnockOutEZwigolo

The go-to web for your AI coding agent — local-first search, fetch, crawl & research over MCP. No API keys, no cloud, $0/query. Public beta.

4,906 TypeScript
mcpagentai+17
bgauryyoctocode

Code research platform for AI agents; find, understand, and prove context across your code and all of GitHub, in a fraction of the tokens. One toolset, MCP or CLI

923 TypeScript
aiclaude-aicursor-ai+17
IvanMurzakUnity-MCP

AI Skills, MCP Tools, and CLI for Unity Engine. Full AI develop and test loop. Use cli for quick setup. Efficient token usage, advanced tools. Any C# method may be turned into a tool by a single line. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.

4,137 C#
aiai-integrationgame-development+16
jgravellejcodemunch-mcp

Cut AI token costs 95%+ on code exploration. The leading MCP server for precise, symbol-level GitHub code retrieval via tree-sitter AST. Works with Claude Code, Cursor & any MCP client. 313B+ tokens saved.

2,651 Python
claudeclaude-codeai-coding+17

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP