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

@invokta/mcp

v0.9.0

Published

MCP server adapters and a plain client facade for Invokta Action Engines.

Downloads

3,370

Readme

@invokta/mcp

MCP adapters and a plain-type client facade for Invokta Action Engines. The adapters publish an engine's capabilities over MCP stdio and stateless Streamable HTTP; the client facade connects to an MCP server and returns plain JSON values.

The official MCP SDK is confined to this package (ADR 0006). No SDK type, transport object, schema, or credential crosses the public API. The normative contracts live in docs/ and the ADRs; a conflict between this file and an ADR is resolved in favor of the ADR.

Serving an engine

import { serveMcpHttp, serveMcpStdio } from "@invokta/mcp";

await serveMcpStdio(engine, { principal });

const server = await serveMcpHttp(engine, {
  port: 3000,
  auth: { mode: "required", authenticate: (request) => resolve(request) },
});

Both adapters execute every tool call through engine.invoke, so the CLI, direct calls, and MCP share one execution path. serveMcpHttp is stateless and requires an explicit auth choice: mode: "required" with an authenticate hook, or the deliberately verbose mode: "dangerously-disabled-for-development". When auth.resourceMetadata is supplied, the server publishes the RFC 9728 protected resource metadata document and answers unauthenticated requests with a WWW-Authenticate challenge naming it. Authorization servers must use HTTPS; a loopback HTTP resource may name a loopback HTTP authorization server for local development.

The protocol endpoint is /mcp by default. path mounts it under a prefix so several engines can share one origin, each behind its own loopback-bound server and its own resource identifier (ADR 0039):

const orders = await serveMcpHttp(ordersEngine, {
  port: 3101,
  path: "/e/orders/mcp",
  allowedHosts: ["gateway.example.com"],
  auth: {
    mode: "required",
    authenticate,
    resourceMetadata: {
      resource: "https://gateway.example.com/e/orders/mcp",
      authorizationServers: ["https://gateway.example.com"],
    },
  },
});

A mount path is an absolute path of unreserved ASCII segments, at most 256 bytes, without a dot segment, an empty segment, percent encoding, a query, a fragment, or a trailing slash, and its final segment is mcp. The resource must use exactly that path, and its metadata is served at /.well-known/oauth-protected-resource<path>.

Tool names are derived from capability IDs with toMcpToolName, which keeps dotted domain IDs visible to clients that enforce ^[a-zA-Z0-9_-]{1,64}$ (ADR 0025). validateMcpToolCatalog(engine) fails closed with an McpToolNameCollisionError when two capability IDs would publish the same tool name.

Connecting as a client

import { connectMcpClient } from "@invokta/mcp";

const connection = await connectMcpClient({
  transport: "http",
  url: "https://engine.example.com/mcp",
  authentication: { type: "bearer", token },
});
const { tools } = await connection.listTools();
await connection.close();

A target is either stdio (command, args, cwd, env) or http (URL, plus none, bearer, or headers authentication). Every failure is an McpClientError carrying one of INVALID_TARGET, SPAWN_FAILED, CONNECTION_FAILED, AUTHENTICATION_FAILED, PROTOCOL_ERROR, TIMEOUT, LIMIT_EXCEEDED, or CANCELLED.

Interactive OAuth

beginMcpOAuthAuthorization performs discovery, dynamic client registration, and PKCE preparation, then returns one validated authorization URL. finish exchanges the single-use code and returns the same plain McpClientConnection. Tokens, PKCE material, and registration artifacts stay in process memory and are cleared on close (ADR 0023, amended by ADR 0031).

Protected resource metadata is read only from the MCP resource's own origin. The authorization servers that document advertises are then trusted for authorization-server metadata and, once that metadata validates with a matching issuer, the endpoints it publishes — dynamic client registration, the authorization endpoint, and the token endpoint — are trusted on their own origins too, so an engine can delegate to a hosted identity provider that serves its OAuth endpoints apart from its issuer.

Inspecting OAuth discovery

import { inspectMcpOAuth } from "@invokta/mcp";

const inspection = await inspectMcpOAuth({
  transport: "http",
  url: "https://engine.example.com/mcp",
  authentication: { type: "oauth" },
});

for (const step of inspection.steps) {
  console.log(step.name, step.outcome, step.summary, step.hint ?? "");
}
function inspectMcpOAuth(
  target: McpOAuthClientTarget,
  options?: McpClientOperationOptions,
): Promise<McpOAuthInspection>;

interface McpOAuthInspection {
  readonly steps: readonly McpOAuthStep[];
  readonly ready: boolean;
}

interface McpOAuthStep {
  readonly name:
    | "challenge"
    | "resource-metadata"
    | "authorization-server-metadata"
    | "registration";
  readonly outcome: "ok" | "failed" | "skipped";
  readonly summary: string;
  readonly hint?: string;
  readonly detail?: McpJsonValue;
}

The inspection is read-only. It sends one unauthenticated MCP request to observe the 401 challenge, reads the protected resource metadata and the first advertised authorization server's RFC 8414 document, and reports whether that server advertises a registration endpoint. It never authorizes, never registers, never sends a credential, and leaves nothing behind.

Every step is reported. A step that needed the output of a failed step is skipped and says so. A network error, an unexpected status, a malformed document, or a document that fails validation is a failed step with a one-line summary and a remediation hint; detail carries the document when one was read. ready is true only when an interactive authorization could be attempted. An McpClientError is thrown only for an invalid target descriptor or a cancelled operation.