Server Mcp Oauth
FreeMaintainedDEPRECATED: use a dedicated authorization server with @onivoro/server-mcp-auth. Embedded OAuth 2.1 authorization server for MCP — wraps the MCP SDK auth router
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:
buildfirst checks that the tag matches every package's version and points at a commit onmain. It then installs withnpm ci --ignore-scripts, builds every package and uploadsdist/libs. It has read-only repo access and can't get an npm token.publishruns in thenpm-publishGitHub environment. It downloads the build, installs and checks out nothing, and runsnpm publish --provenancefor 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
release:minorchecks that you're onmainwith a clean working tree that matchesorigin/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 runsnx release version. That bumps every package, updates the internal@onivoro/*dependency versions, commitschore(release): v<version>and tagsv<version>. It then builds every package locally, so a broken build fails before anything is pushed.release:pushpushesmainand the new release tag together: if either is rejected, neither is pushed. The tag startspublish.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:namemust belib-<runtime>-<name>, such aslib-server-foo, sonx releaseincludes it in the shared version. Keep thebuildtarget'soutputPathatdist/libs/<runtime>/<name>, and keep thenx-release-publishtarget.package.jsonneeds:name:@onivoro/<runtime>-<name>.version: the current shared version. Copy it fromlibs/server/common/package.json.publish.ymlrefuses 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,typesandfiles, as in the library you copied.exportsandengines: runnpm 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 rootpackage.jsondeclares. 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, withtypesfirst for TypeScript'snode16,nodenextandbundlerresolution. 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,nodeand so on)../*.jsand./*keep deep imports resolving, with or without the.jsextension (@onivoro/server-common/src/lib/functions/configure-api-app.function), and TypeScript finds the.d.tsbeside each.js. Only directory imports such as@onivoro/x/src/lib, and requests for files other than.jsandpackage.json, no longer resolve.mainandtypesstay for TypeScript's legacynoderesolution 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'stypesordefaultdiffer from the package'stypesandmain. - The
.entry's conditions are in a different order from the standard one:typesfirst, the rest as declared,defaultlast. Order decides resolution, because the first matching condition wins. - The
.entry has conditions but notypes. Addingtypesfirst would change what TypeScript resolves. ./package.json,./*.jsor./*maps to something else.engines.nodeis 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-publishenvironment: deployments limited tov*tags.release tagsruleset: only repository admins can create, move or deletev*tags.mainruleset: blocks deleting and force-pushingmain, and requires a pull request with one approval, plus code owner review for the build and release files in.github/CODEOWNERS, and a passingcheckjob fromci.yml. Admins can bypass it, whichrelease:pushneeds.- Actions: only GitHub-owned actions are allowed, they must be pinned to full commit SHAs, and the default
GITHUB_TOKENis 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:
- Org 2FA: require two-factor authentication at https://github.com/organizations/onivoro/settings/security.
- Admins: every repository admin can create release tags, so every admin can publish. Keep everyone else at write access or lower.
Previewing
npm run release:dry-run -- minor # preview the version bump
npm run release:publish:dry-run # preview what would be published
Install Server Mcp Oauth in Claude Desktop, Claude Code & Cursor
unyly install server-mcp-oauthInstalls 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-oauthStep-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
Opencode Omniroute Plugin
OpenCode plugin for the OmniRoute AI Gateway. Drives dynamic model discovery, /connect auth flow, and multi-instance OmniRoute providers via the official @openc
by GitHub ActionsRoblox Studio
Enables AI coding tools to control Roblox Studio for workspace exploration, instance manipulation, and script management. It provides tools for playtesting, sce
by paralovAntigravity Drawio
MCP server that enables AI assistants to create, parse, render, and validate Draw.io diagrams programmatically.
by S-SUJAN-SFetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
by modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
by xuzexin-hzMCP-Agent
A simple, composable framework to build agents using Model Context Protocol by [LastMile AI](https://www.lastmileai.dev)
by lastmile-aiSpring AI MCP Client
Provides auto-configuration for MCP client functionality in Spring Boot applications.
mcp.natoma.ai
A Hosted MCP Platform to discover, install, manage and deploy MCP servers by [Natoma Labs](https://www.natoma.ai)
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
