Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Server Mcp Oauth

FreeMaintained

DEPRECATED: use a dedicated authorization server with @onivoro/server-mcp-auth. Embedded OAuth 2.1 authorization server for MCP — wraps the MCP SDK auth router

GitHubEmbed

About

DEPRECATED: use a dedicated authorization server with @onivoro/server-mcp-auth. Embedded OAuth 2.1 authorization server for MCP — wraps the MCP SDK auth router into NestJS

README

Every lib-server-*, lib-isomorphic-* and lib-browser-* project is released together at one shared version (projectsRelationship: "fixed" in nx.json). Packages are built into dist/ and published from there with public access.

Publishing happens in GitHub Actions (.github/workflows/publish.yml) through npm trusted publishing, so every package gets a provenance attestation and no npm token is stored anywhere. The workflow runs when a v<version> release tag is pushed. Pushes to main or any other branch never publish.

The workflow has two jobs:

  • build first checks that the tag matches every package's version and points at a commit on main. It then installs with npm ci --ignore-scripts, builds every package and uploads dist/libs. It has read-only repo access and can't get an npm token.
  • publish runs in the npm-publish GitHub environment. It downloads the build, installs and checks out nothing, and runs npm publish --provenance for each version not on npm yet. It's the only job allowed to request the short-lived npm token.

Only repository admins can create v* tags, the npm-publish environment accepts only v* tags, and every package trusts only this workflow in that environment. A run from a branch, from an edited copy of the workflow, or from a fork can't publish.

Release

Be on main with a clean working tree.

npm run release:minor                     # or release:patch / release:major
npm run release:push
  1. release:minor checks that you're on main with a clean working tree that matches origin/main. It lists every commit since the last release tag, and every change to build, release and dependency files, and asks you to confirm, because the release publishes all of it. It then runs nx release version. That bumps every package, updates the internal @onivoro/* dependency versions, commits chore(release): v<version> and tags v<version>. It then builds every package locally, so a broken build fails before anything is pushed.
  2. release:push pushes main and the new release tag together: if either is rejected, neither is pushed. The tag starts publish.yml, which builds and publishes every package.

If a publish fails partway, rerun the failed job from the Actions tab. Versions already on npm are skipped.

Trusted publishing setup

Each package on npm must trust publish.yml in onivoro/monorepo, run in the npm-publish environment. Set this up once, and again for each new library after its first publish (npm can only add trust to a package that already exists):

npm login
npm run release:trust                     # pass -- --dry-run to preview, or -- @onivoro/<name> for one package

release:trust runs npm trust github for every package that doesn't trust the workflow yet. It then sets every package to "Require two-factor authentication and disallow tokens" (npm access set mfa=publish), so a leaked npm token can't publish it; trusted publishing still works. Finally it lists the npm org's members and your npm tokens for you to review. Every npm call needs a one-time password, so the script asks for a code from your authenticator app and reuses it until npm rejects it: expect a new code about every 30 seconds, not one per call.

New trust starts out "Pending validation" and expires unless a publish uses it within about 48 hours, so release soon after adding it. npm trust list doesn't show that trust expired; the package's settings page on npmjs.com does. Expired trust makes the publish job fail with OIDC token exchange error - package not found (visible because the job logs npm at verbose level) and then 404 Not Found - PUT. To replace it, run npm run release:trust -- --renew (optionally naming packages), then release or rerun the failed job within the 48 hours.

A brand-new package needs a few extra steps before CI can publish it; see Adding a package.

Adding a package

CI can't publish a package that doesn't exist on npm yet, because npm only accepts trust settings for an existing package. Bootstrap each new package once, between merging it and the next release. If a release tag is pushed first, the publish job fails on the new package.

1. Create the library

Copy an existing library from the same runtime folder, for example libs/server/mcp-audit, and rename every path and name in it.

  • project.json: name must be lib-<runtime>-<name>, such as lib-server-foo, so nx release includes it in the shared version. Keep the build target's outputPath at dist/libs/<runtime>/<name>, and keep the nx-release-publish target.
  • package.json needs:
    • name: @onivoro/<runtime>-<name>.
    • version: the current shared version. Copy it from libs/server/common/package.json. publish.yml refuses a release tag that doesn't match every package's version.
    • repository: { "type": "git", "url": "https://github.com/onivoro/monorepo.git" }. Provenance fails without it.
    • license, main, types and files, as in the library you copied.
    • exports and engines: run npm run manifests:fix, which writes the standard ones (see Package manifests). CI fails until they're there.
  • tsconfig.base.json: add the @onivoro/<runtime>-<name> path mapping.

Nothing in publish.yml or .github/CODEOWNERS needs changing, because both match every libs/*/*/package.json.

2. Merge it

Open a pull request. CODEOWNERS asks for your review because the change adds a package.json and project.json.

3. Publish the first version by hand

On an up-to-date main, logged in to npm, publish only the new package at the current shared version:

npm login
npx nx release publish --projects=lib-<runtime>-<name> --otp=<code>

This version is published from your machine, so it has no provenance attestation. Every later version comes from CI and has one.

4. Trust the workflow

Run this in your own terminal app, because npm only asks for two-factor approval in an interactive terminal:

npm run release:trust -- @onivoro/<runtime>-<name>

Naming the package limits the run to it: it reads the package's trust settings, adds trust and sets two-factor-only publishing, usually on a single one-time password. Without a name the script walks all packages.

5. Release as usual, within 48 hours

npm run release:minor and npm run release:push. CI now publishes the new package with the others. Release within about 48 hours of step 4, or the new trust expires; see Trusted publishing setup.

Package manifests

Every library's package.json is copied into dist/ by the build, so it is what npm publishes. tools/package-manifests.js keeps two fields the same in all of them:

  • engines: { "node": ">=22.16.0" }. 22.16 is the floor the root package.json declares. CI builds and tests only on Node 24 (24.20.0), so CI doesn't check that floor: it was checked by hand when the field was added, by building and testing every library on Node 22.16.0. There is no upper bound, so Node 24 LTS and later install without engine warnings. A package that needs a newer Node can declare a higher >= floor of its own, such as >=24, and the script keeps it.

  • exports: a map that keeps every import that worked before it was added working:

    {
      ".": { "types": "./src/index.d.ts", "default": "./src/index.js" },
      "./package.json": "./package.json",
      "./*.js": "./*.js",
      "./*": "./*.js"
    }
    

    . is the package entry, with types first for TypeScript's node16, nodenext and bundler resolution. Every other subpath a package declares stays as written, wildcards included, such as @onivoro/server-aws-observability/bootstrap, and so do any extra conditions on . (import, node and so on). ./*.js and ./* keep deep imports resolving, with or without the .js extension (@onivoro/server-common/src/lib/functions/configure-api-app.function), and TypeScript finds the .d.ts beside each .js. Only directory imports such as @onivoro/x/src/lib, and requests for files other than .js and package.json, no longer resolve. main and types stay for TypeScript's legacy node resolution and older bundlers.

npm run manifests:check                   # check every libs/*/*/package.json
npm run manifests:fix                     # write the standard fields, keeping every declared subpath and condition
npm run manifests:test                    # the script's own tests (node --test)
node tools/package-manifests.js --dist    # after a build: check dist/libs, and that each explicit export target exists

manifests:fix never drops, reorders or rewrites what a package declares. In any of these cases it leaves that file unchanged, names the conflict and exits non-zero, so you can resolve it by hand:

  • The . entry's types or default differ from the package's types and main.
  • The . entry's conditions are in a different order from the standard one: types first, the rest as declared, default last. Order decides resolution, because the first matching condition wins.
  • The . entry has conditions but no types. Adding types first would change what TypeScript resolves.
  • ./package.json, ./*.js or ./* maps to something else.
  • engines.node is something other than a >= floor at or above 22.16.0.

manifests:check reports the same conflicts. release:build runs the --dist check after building. That check walks nested conditions and fallback arrays, and reports any target that isn't a path.

Checks

.github/workflows/ci.yml runs on every pull request into main and on main after each merge. It checks the formatting of the changed files (nx format:check; locally, a Husky pre-commit hook runs Prettier on staged files through lint-staged), checks that every library's package.json declares the standard exports map and engines (npm run manifests:check, see Package manifests), runs every project's unit tests, builds every published library and checks the built manifests. Like publish.yml, it installs with no install scripts, has a read-only token and no secrets, and pins its actions to commit SHAs. The check job must pass before a pull request can merge (see the main ruleset below). The Nest 11 smoke test (npm run smoke:nest11) runs only locally.

Repository settings

publish.yml relies on these GitHub settings for onivoro/monorepo. npm run release:github-settings applies them (as a repo admin with gh logged in) and can be run again at any time:

  • npm-publish environment: deployments limited to v* tags.
  • release tags ruleset: only repository admins can create, move or delete v* tags.
  • main ruleset: blocks deleting and force-pushing main, and requires a pull request with one approval, plus code owner review for the build and release files in .github/CODEOWNERS, and a passing check job from ci.yml. Admins can bypass it, which release:push needs.
  • Actions: only GitHub-owned actions are allowed, they must be pinned to full commit SHAs, and the default GITHUB_TOKEN is read-only. Dependabot (.github/dependabot.yml) opens a weekly pull request that updates the pinned SHAs and their version comments.
  • Security: secret scanning with push protection, Dependabot alerts and security updates, and private vulnerability reporting (see SECURITY.md).

Two settings the script can't apply:

Previewing

npm run release:dry-run -- minor          # preview the version bump
npm run release:publish:dry-run           # preview what would be published

from github.com/onivoro/monorepo

Install Server Mcp Oauth in Claude Desktop, Claude Code & Cursor

Recommended · one command, every IDE
unyly install server-mcp-oauth

Installs into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.

First time? Get the CLI: curl -fsSL https://unyly.org/install | sh

Or configure manually

Run in your terminal:

claude mcp add server-mcp-oauth -- npx -y @onivoro/server-mcp-oauth

Step-by-step: how to install Server Mcp Oauth

FAQ

Is Server Mcp Oauth MCP free?

Yes, Server Mcp Oauth MCP is free — one-click install via Unyly at no cost.

Does Server Mcp Oauth need an API key?

No, Server Mcp Oauth runs without API keys or environment variables.

Is Server Mcp Oauth hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Server Mcp Oauth in Claude Desktop, Claude Code or Cursor?

Open Server Mcp Oauth on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Server Mcp Oauth with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All ai MCPs