How to define MCP servers once and use them in Claude Code, Codex, and OpenCode (across all your machines)
A practical way to stop copy/pasting MCP JSON into three different tools and get one consistent tool surface across providers and machines.
- CLI
- 0.1.0
- Preview ref
- f36aa45
If you’ve ever set up MCP servers “properly”, you’ve probably done this dance:
- paste MCP JSON into Claude Code
- paste a slightly different MCP JSON into Codex
- discover OpenCode uses another location
- do it again on your laptop and your server
It works.
It’s also how you end up with sessions that behave differently depending on which machine you’re on.
What I actually want is:
- define tools once
- make them available consistently
- still keep machine-specific tools machine-specific
This guide is about that workflow.
TL;DR
- Decide what you want MCP for (browser automation, GitHub, docs search, internal tools).
- The common failure mode is config drift: different MCP JSON on different machines/providers.
- A better model is “one tool library + explicit apply scopes”.
- In Happier, you can define MCP servers once, detect existing provider MCP configs, preview the effective tool set for a session, and apply servers to:
- all machines
- one machine
- one workspace on one machine
The problem
MCP is a great idea, but the naive setup path is brittle:
- multiple config files
- multiple machines
- multiple providers
So the question isn’t “can I run MCP?”
It’s:
can I make the tool surface consistent enough that I trust it?
What I tried first (and where I bounced off)
- Copy/paste JSON everywhere: works until you forget one machine.
- Only set it up on one provider: then you lose the whole point of portability.
- Keep tools per-project only: good for some cases, but painful for universal tools like GitHub.
If you’re new to Happier
If you haven’t seen Happier before: it’s an open-source companion app (mobile/web/desktop) for running sessions like Claude Code, Codex, and OpenCode across machines.
The relevant part here is: it gives you one place to manage MCP servers and apply them consistently.
Get set up:
- How to run Happier from your phone
- GitHub: https://github.com/happier-dev/happier
- Install/download: https://github.com/happier-dev/happier#how-it-works
- Discord: https://discord.gg/W6Pb8KuHfg
A workflow that works
1) Treat tools as a library, not a pile of JSON
The moment you have more than one machine, MCP config becomes infrastructure.
So I treat it like a library:
- saved
- reviewable
- scoped
2) Use “Configured vs Detected vs Preview” as your mental model
In Happier, MCP servers are organized into three tabs:
- Configured: servers you manage in the app
- Detected: servers found in provider-native config files (Claude, Codex, OpenCode)
- Preview: the effective tool set for a specific backend + machine + workspace
Preview is the secret weapon.
It answers: “what will this session actually see?”
3) Apply the right scope: all machines vs one machine vs one workspace
Most drift comes from not being explicit about scope.
Rules that work:
- remote HTTP/SSE servers → all machines
- local stdio servers installed via
npx→ one machine - project-local servers → one workspace on one machine
4) Keep secrets out of JSON (and stop leaking tokens)
Any time you paste a token directly into MCP JSON, you create secret sprawl:
- it ends up in shell history
- it ends up in dotfiles
- it ends up in screenshots
- it eventually ends up in a repo by accident
What I want instead is:
- a place to store secrets once
- a way to reference them from MCP config without embedding them
- a way to reuse that safely across machines
Happier supports three value sources for MCP server headers/env:
- Saved Secrets (recommended)
- machine env references like
${MY_TOKEN} - plain text (avoid this unless it’s genuinely not sensitive)
That “Saved Secrets” option is the big unlock for multi-machine MCP.
You bind the secret once, and then your MCP server definition can stay identical across machines.
Worked example: GitHub MCP server with an Authorization header (Saved Secret)
A very common pattern is a remote MCP server (HTTP/SSE) that needs:
Authorization: Bearer <token>
Here’s the full end-to-end setup that avoids ever pasting the token into JSON.
Step 1: create a GitHub token
Create a GitHub token with the minimum scopes you need (classic PAT or fine-grained token).
(Which scopes you need depends on what MCP tools you plan to call — repos, issues, PRs, etc.)
Step 2: save the token as a Saved Secret
In Happier:
- Settings → Saved Secrets (or Settings → Secrets)
- New secret
- Name it something you’ll recognize, e.g.
github_pat_work - Paste the token value
Now the value lives in Happier’s encrypted settings store instead of your config files.
Step 3: add the GitHub MCP server in Happier
In Happier:
- Settings → MCP servers → Add server
- Choose Remote HTTP or Remote SSE (depending on what the server supports)
- Give it a name, e.g.
github
Then set:
- Applies to: usually All machines (because remote servers are portable)
Step 4: set the Authorization header using the Saved Secret
In the MCP server config, add a header:
- Header name:
Authorization - Header value:
Bearer <your-saved-secret>
The important part is how you reference the secret:
- don’t paste the token value
- select/reference your Saved Secret (e.g.
github_pat_work) in the header value field
In the header editor, you can choose the value source:
- Literal (plain text)
- Saved Secret
When you choose Saved Secret, Happier stores a reference to the secret (not the secret value) and resolves it at runtime when testing/launching the MCP server.
Step 5: Test, then Preview
- Use Test to verify Happier can:
- resolve the Saved Secret reference,
- connect/start the server,
- and list tools.
- Use Preview (backend + machine + workspace) to confirm the GitHub tools are actually present for the session you care about.
If Test works but Preview shows 0 tools for the session, it’s almost always a scope mismatch (All machines vs One machine vs Workspace).
(Optional) Why this works (implementation detail)
When you pick Saved Secret in the env/header editor, the UI stores a small typed reference (a secret id), not the secret itself.
That’s why you can:
- reuse the same MCP server definition across machines without copying the token around
- rotate the secret value in one place without touching MCP JSON
You don’t need to know the internal type names to use this — but it’s the reason the model is robust.
Example: local stdio MCP server that needs env vars
For stdio servers (local command), many READMEs say to set env vars.
The trick is to avoid turning that into “everyone exports secrets in their shell rc files forever.”
A better pattern is:
- store the value once as a saved secret
- bind it to the required env var name for that server
5) Define a custom MCP server (local stdio)
Happier supports local command MCP servers (stdio).
In Settings → MCP servers → Add server, you can:
- paste a command line (Happier splits command + args)
- choose scope (one machine is usually correct for local installs)
- add env vars (prefer saved secrets)
Then use Test to confirm it starts and lists tools.
6) Define a custom MCP server (remote HTTP/SSE)
For remote servers:
- set scope to all machines
- add headers (prefer saved secrets)
- test it once
7) Preview the effective tool set before you start an important session
If you only take one habit from this guide, make it this:
- use Preview to see what tools the session will actually get
Preview combines:
- Happier-managed MCP servers that apply by default
- provider-native MCP servers detected for that backend/context
- servers that are available but not currently applied
It turns “why doesn’t this session have the GitHub tool?” into a 10‑second answer.
8) Test the server before you trust it
A small habit that saves time:
- test the MCP server
- verify it lists tools
This catches wrong command lines and missing installs early.
Why this works (and what breaks)
This setup works because it separates three things that usually get tangled:
- Definition (what the MCP server is)
- Scope (where it should apply)
- Secrets (how it authenticates)
When it breaks, it’s usually one of these:
- wrong scope (all-machines vs one-machine)
- missing machine install for a local stdio server
- secret not resolvable (saved secret not bound, env var missing)
- provider-native MCP config shadowing what you expected
Troubleshooting
The MCP server doesn’t start
- check the command line
- verify it exists on the selected machine
- if it’s
npx, verify Node is installed and reachable on that machine
Tools show in Configured, but not in a session
- check Preview for that backend + machine + workspace
- confirm “Applies to” scope matches this session
Auth fails (401/403)
- replace inline tokens with Saved Secrets
- ensure the header/env is referencing the saved secret correctly
- retest the server