npm.io
1.2.0 • Published 3d ago

@enpilink/console

Licence
MIT
Version
1.2.0
Deps
4
Size
3.4 MB
Vulns
0
Weekly
0
Stars
1

The open, account-free full-stack framework for MCP Apps — and the ChatGPT Apps SDK.

Build type-safe MCP servers whose tools render interactive React views inside Claude, ChatGPT, VS Code, Goose, and any other MCP-Apps-compatible host.

License: MIT MCP Apps Account-free Tunnel: srv.us Interaction types TypeScript Node CI PRs welcome

a fork of alpic-ai/skybridge · powered by

Enpitech


Account-free by design

Local dev, public tunneling, and deploy all work with no account, no token, and no vendor lock-in:

  • Account-free tunneling via srv.us — open and SSH-based, no signup. enpilink dev --tunnel gives you a public /mcp URL in seconds and auto-generates an SSH key at ~/.enpilink/id_ed25519 the first time.
  • No telemetry — zero analytics, no network calls, no embedded keys.
  • Deploy anywhereenpilink build produces a standard Node server (node dist/__entry.js); self-host on any platform or container.
  • All five mcp-ui interaction typestool, prompt, link, intent, and notify.

MCP Apps compliance

enpilink is a compliant MCP Apps framework, built on the official @modelcontextprotocol/ext-apps extension (stable spec 2026-01-26). It serves view resources for both runtimes so the same view runs in either host:

  • ui://views/ext-apps/* — MCP Apps (Claude, Goose, VS Code, …)
  • ui://views/apps-sdk/* — ChatGPT Apps SDK

The mcp-ui interaction types

An interaction type is one of the structured messages a view sends back to its host. The mcp-ui standard defines five, and enpilink supports all five (views send them through hooks, never raw postMessage):

Type Hook Behavior
tool useCallTool real on both runtimes
prompt useSendFollowUpMessage real on both runtimes
link useOpenExternal real on both runtimes
intent useIntent no spec equivalent on either runtime; best-effort extension, may no-op on hosts that don't route it
notify useNotify real MCP notifications/message on MCP Apps; best-effort extension on the ChatGPT Apps SDK

These five are the standard's view→host actions. They're a subset of the full hook API below (the rest of the hooks read host context or control your own view). New to all this? See PRESENTATION.md for a plain-language, diagram-led tour.

notify and intent are guarded and additive: they never throw and degrade to a no-op (or a log line) on hosts without support. See docs/guides/interaction-types.mdx for the full per-runtime matrix.

All view hooks

Everything a view can do from inside the iframe — import from enpilink/web. Hooks never touch raw postMessage; the bridge picks the right runtime call.

Hook What it does Runtime
Interaction
useCallTool Call a server tool from the view; returns { callTool, callToolAsync, data, status, error } with pending/success/error state. both
useSendFollowUpMessage Send a text message to the model as a user follow-up turn (prompt). both
useNotify Surface a notification/status to the host: notify({ message, level?, title?, data? }). both — real notifications/message on MCP Apps, best-effort on Apps SDK
useIntent Express a high-level intent for the host to route: sendIntent({ name, params? }). both — best-effort extension, may no-op
Navigation / links
useOpenExternal Open a URL outside the iframe via the host (use instead of window.open). both
useSetOpenInAppUrl Override the URL the host's fullscreen "Open in app" affordance points to. Apps SDK only (throws on MCP Apps)
useRequestClose Ask the host to dismiss/close the view. both
Layout / display
useDisplayMode Read and request the display mode — inline / pip / fullscreen. both
useRequestModal Open the view in a host modal overlay; returns { isOpen, params, open }. both
useRequestSize Ask the host to resize the iframe to fit your content. both
useLayout Read the visual environment — max height, safe-area insets, theme. both
Context / data
useToolInfo Read the typed input / output / metadata of the tool call that rendered this view. both
useViewState [state, setState] persisted on the host across remounts of the view. both
useUser Session-stable user/environment info (device type, hover/touch capability). both
Files
useFiles Host file operations — upload, getDownloadUrl, selectFiles (native picker). Apps SDK only (throws on MCP Apps)
useDownload Download an MCP EmbeddedResource / ResourceLink's contents via the host. both
Advanced
useRegisterViewTool Let the view expose its own tool to the host/model (app-provided tool). MCP Apps only (no-op on Apps SDK)

"both" = works on MCP Apps (Claude, Goose, VS Code…) and the ChatGPT Apps SDK. Apps-SDK-only hooks throw on MCP Apps; MCP-Apps-only hooks no-op on the Apps SDK.


Observability & Admin

enpilink ships an opt-in observability + admin layer — off by default, with zero overhead and zero network when disabled (still no telemetry to us).

  • Observability — set ENPILINK_ANALYTICS=1 to record per-tool-call volume, latency (p50/p95/p99), and error rate, viewable in the Console Dashboard with a live log stream. Try it with demo data: enpilink dev --mock (deterministic, in-memory, no real traffic). See docs/guides/observability.mdx.
  • Configuration — a typed config layer with env > file > DB precedence, a Configuration admin tab for runtime settings, env-only masked secrets, and a change audit log. See docs/guides/configuration.mdx.
  • Admin (production) — expose the Dashboard + Configuration in prod with enpilink start --admin + ENPILINK_ADMIN_TOKEN (refuses to start without a token). Two-tier auth keeps /mcp and the SPA shell public while gating the data APIs behind a static bearer token; for SSO, front it with a reverse proxy (Cloudflare Access / oauth2-proxy / Tailscale) or self-hosted OIDC. See docs/guides/admin.mdx.
  • Storage — pluggable adapters: memory (dev), sqlite (prod default, ENPILINK_DB_PATH), postgres (ENPILINK_DB_URL/DATABASE_URL/PG*), plus registerStorageAdapter for custom backends, and optional OpenTelemetry metrics export (ENPILINK_OTEL=1 + OTEL_EXPORTER_OTLP_ENDPOINT). See docs/guides/storage.mdx.

Documentation

New here? Read PRESENTATION.md first — a plain-language, diagram-led tour of the whole platform (what it solves, the standards, the technology, and how interaction types relate to hooks). No prior knowledge needed.

There's no hosted docs site yet — the full docs run locally with Mintlify:

pnpm install
pnpm docs:dev          # serves the docs at http://localhost:3000

What's inside docs/:

  • API reference (docs/api-reference/) — a page per hook and core API (useCallTool, useNotify, useViewState, registerTool, …), each with the signature, a runnable example, and runtime support. This is the "what can I actually do with this hook" reference.
  • Guides (docs/guides/) — task-oriented: communicating with the model, managing state, host-environment context, fetching data, the interaction types, and the observability / configuration / admin / storage layer.
  • Concepts & fundamentals — MCP Apps vs the Apps SDK, write-once-run-everywhere, type safety, and data flow.
  • Quickstart — create a new app, add to an existing server, deploy, migrate.

Tip: you can also read any page directly as Markdown in docs/ on GitHub — e.g. docs/api-reference/use-notify.mdx.


Quickstart

Prerequisites
  • Node.js ≥ 22
  • ssh (ships with macOS/Linux) — only needed for --tunnel
Run the built-in kitchen-sink demo

The fastest way to see everything is the bundled kitchen-sink showcase (a fictional store, Northwind): 9 tools, 9 views, all 4 interaction types, every host hook, deterministic mock data.

git clone https://github.com/enpitech/enpilink
cd enpilink && pnpm install && pnpm run build

cd examples/kitchen-sink
pnpm dev          # Console + HMR at http://localhost:3000/
pnpm dev:tunnel   # opens an account-free srv.us tunnel and prints a public /mcp URL

Then connect it to Claude:

  1. Copy the printed https://<hash>.srv.us/mcp URL.
  2. In Claude → Settings → Connectors → Add custom connector, paste that URL.
  3. Paste the contents of examples/kitchen-sink/specs/SYSTEM_PROMPT.md into your Claude project instructions (MCP can't set a host system prompt, so this tells the assistant which tools to call).
Scaffold a new app
npm create enpilink@latest my-app

POC distribution caveat. enpilink and @enpilink/console are not yet published to npm, so a freshly scaffolded app's npm install will fail on the workspace:* ranges in the templates. For real distribution, publish both packages to npm and run node scripts/bump.js <version> to rewrite the templates' workspace:* ranges to ^<version>. Until then, scaffold inside this monorepo (the templates resolve via the workspace) or use local pnpm pack tarballs. See Status below.

The account-free tunnel under the hood is just one SSH command:

ssh srv.us -R 1:localhost:<port>

enpilink wraps this with auto key-gen (~/.enpilink/id_ed25519), URL parsing, and auto-reconnect.


CLI

enpilink dev [--tunnel] [-p <port>] [--open] [--mock]   # dev server + Console + HMR (alias: enpi)
enpilink build                                           # compile server + views → dist/
enpilink start [--admin]                                 # run the production build (node dist/__entry.js)
enpilink create [dir]                                    # scaffold a new app (passthrough to create-enpilink)
Production gotcha

The production entry reads the __PORT environment variable (NOT PORT), defaulting to 3000:

__PORT=8080 node dist/__entry.js

enpilink start sets __PORT for you. enpilink build also rewrites server @/… path aliases automatically, so you do not need tsc-alias in your own build scripts.


Repo layout

enpilink/
├── packages/
│   ├── core/             → npm "enpilink": server framework + React hooks + Vite plugin + CLI (oclif + Ink)
│   ├── console/          → "@enpilink/console": dashboard / config / playground / docs web UI
│   └── create-enpilink/  → "create-enpilink": scaffolder (templates: blank, demo)
├── examples/
│   ├── kitchen-sink/     → the all-features showcase ("Northwind"); basis of the demo template
│   └── manifest-ui/      → minimal single-view smoke-test example
├── docs/                 → Mintlify documentation
├── skills/               → agent skill for building enpilink apps
└── scripts/              → version bump / overrides helpers

Status

This is a POC fork. Today:

  • Local dev, Console, HMR, build, and self-host all work account-free.
  • The account-free srv.us tunnel is live-verified end-to-end (the printed /mcp URL round-trips over a real public tunnel and survives reconnects).
  • Real npm distribution requires publishing enpilink + @enpilink/console to npm, then running node scripts/bump.js <version>. Until then, npm create enpilink is workspace-linked (works inside this repo / via local tarballs, not from a bare npm install).

Attribution & license

enpilink is released under the MIT License. It is forked from alpic-ai/skybridge (MIT); the original copyright is retained in LICENSE, and the fork's changes are summarized in NOTICE.

Built and maintained by the Enpitech team.