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

@softacus-software/elwis-mcp-core

v0.1.0

Published

Shared ELWIS domain logic: entity resolution, application scoping and access contracts, consumed by the ELWIS backend and the ELWIS MCP servers.

Readme

@softacus-software/elwis-mcp-core

Shared ELWIS domain logic — entity resolution, application scoping, and the access contract — consumed by the ELWIS backend assistant and by the ELWIS MCP servers, so all three run the same code instead of three divergent copies.

This package contains no transport. It never opens a socket, reads an environment variable, or knows what MCP is. Everything it does goes through a port that the consumer implements.

The seam

Domain logic takes its data access as a parameter:

ResolveEntity(api, kind, applicationId, nameOrAlias)

api satisfies ElwisReadPort. The MCP servers implement it over HTTP; the backend implements it in-process against tenant services. Same logic, different adapter.

ElwisReadPort      whoAmI · systemAttributes · list · getOne · listRecords
ElwisWritePort     create · update · softDelete · createArtifact · updateArtifact ·
                   softDeleteArtifact · createLinks
ElwisApiPort       both

Only the read port is exercised by the current conformance suite. Write coverage lands with the write slice.

Install and build

npm install
npm run verify     # build + tests + dual-module consumption check

npm run build emits dist/esm and dist/cjs, each stamped with its own type field.

TypeScript is pinned to ~5.9.3 on purpose. The ELWIS backend is on 5.9 and the Data MCP on 6.0; declarations are emitted by the lower compiler so both consumers can read them.

main and types are set alongside exports on purpose. The backend compiles with module: commonjs and no moduleResolution, which defaults to node10 — and node10 ignores exports entirely. Removing the legacy fields silently breaks that consumer.

The conformance suite

The point of this package is that two adapters behave identically. RunReadPortConformance is how you prove it — the same cases run against the HTTP adapter and the in-process adapter.

import { RunReadPortConformance } from '@softacus-software/elwis-mcp-core';

const results = await RunReadPortConformance(myAdapter, {
  applicationId, applicationName, kind: 'data-type', knownEntityName, knownEntityId,
});
const failed = results.filter(r => !r.passed);

It is framework-agnostic: no test runner is imported, cases return results rather than asserting, so consumers can drive it from jest, node:test, or a script.

Every case carries a why. The load-bearing one is excludes-soft-deleted: the HTTP adapter gets soft-delete filtering for free because it injects deleted: null into every filter, while an adapter reading collections directly does not. Without that case, an in-process adapter would quietly surface deleted entities into resolution and into user-facing pickers.

The suite is itself tested: test/conformance.test.ts runs it against a deliberately broken adapter and asserts that it fails.

Resolution behaviour

ResolveEntity and ResolveOneId are ported verbatim from elwis-data-mcp, including the $or-to-name fallback for backends that reject $or with a 400. That fidelity is deliberate: the extraction has to be provably behaviour-neutral before anything consumes it.

ResolveOneStrict is new and nothing calls it yet. It exists because the current assistant answers a missed lookup with a raw validator message:

That answer won't work — Invalid string: must match pattern /^[a-f\d]{24}$/i

ResolveOneStrict instead throws NotFoundError carrying the entities that do exist, so a caller can say "no data type called X here — did you mean one of these, or shall I create it?" AmbiguityError covers the multiple-match case.

HTTP host (./host)

The ./host subpath (ServeMcpHttp, ElwisJwtVerifier) is the one exception to "no transport" above: it is an actual node:http listener. elwis-docs-mcp and elwis-data-mcp use it to serve MCP over HTTP with a bearer token instead of stdio.

It binds 127.0.0.1 unless the caller passes a different host; accepts only POST /mcp (a GET is answered 405 Allow: POST — neither server sends server-initiated messages, so the standing text/event-stream a GET would otherwise open carries nothing and exists only to be held open); and caps both concurrent token verifications (maxConcurrentVerifications) and concurrent live sessions (maxConcurrentSessions), so a caller with no valid credential at all cannot force unbounded verification work, and a caller who does verify cannot hold an unbounded number of built servers open. Neither cap, nor the bind address, is read from an environment variable by this package itself — each server that embeds ServeMcpHttp wires its own env vars for these and documents them in its own README's operator section.

This is a library entry point, not a runnable server on its own: nothing in this package listens by itself outside of a test.

Errors

ElwisApiError carries status, so shared logic can branch on an HTTP status without importing a transport. IsElwisApiError also accepts the Data MCP's existing ElwisHttpError by shape, so the standalone server does not have to change its error class to adopt this package.

Status

Phase 1 of the capability-layer plan: extracted, tested, buildable, with no consumer yet. Phase 2 switches elwis-data-mcp over and deletes its copies — until that lands, the logic exists twice, which is the one thing this package is meant to prevent.