Mock Server
FreeNot checkedA test MCP server that validates gateway connectivity, identity propagation, and provides mock tools for testing purposes.
About
A test MCP server that validates gateway connectivity, identity propagation, and provides mock tools for testing purposes.
README
A test MCP server that runs behind mcp-auth-gateway. It exists to validate the platform plumbing — not to be a real product.
Purpose
This server is used to verify:
- gateway → backend MCP server connectivity
- path-based
/mock/mcprouting - gateway-signed
X-MCP-Identityverification - propagation of the user
loginid - the Streamable HTTP MCP transport
- GitOps / Kubernetes deployment
How it fits in
client ──TLS──> mcp-auth-gateway ──/mock/mcp──> mock-mcp-server (this repo)
(Keycloak / OAuth, (verifies X-MCP-Identity,
mints X-MCP-Identity) runs MCP tools)
- It runs only behind the gateway. External clients reach it exclusively via
https://gateway.mcp.aidev.samsungds.net/mock/mcp. - It does NOT do Keycloak / OAuth verification itself. All external auth is the gateway's job.
- It DOES verify the gateway's internal
X-MCP-IdentityJWT on/mcpand every slash-delimited path below it, rejecting anything missing or invalid with401. - Tools read the caller's identity — especially
loginid— through a sharedget_current_user()helper; they never parse HTTP headers directly.
Identity: X-MCP-Identity
The gateway injects a signed internal JWT:
X-MCP-Identity: <gateway-signed-internal-jwt>
Example payload:
{
"iss": "mcp-auth-gateway",
"aud": "mock-mcp-server",
"sub": "keycloak-user-sub",
"loginid": "user.loginid",
"username": "user.name",
"email": "[email protected]",
"groups": ["engineering"],
"scopes": ["mcp:mock:use"],
"request_id": "01J...",
"iat": 1730000000,
"nbf": 1730000000,
"exp": 1730000060
}
Verified on every /mcp request:
- JWT signature
iss == mcp-auth-gatewayaud == mock-mcp-server- integer
iat,nbf, andexp, with five seconds of clock skew exp > iat,exp >= nbf, and a maximum lifetime of five minutes- canonical, non-empty
sub,loginid, and optional scalar/list values - exactly one non-empty
X-MCP-Identityheader (duplicates and combined values are rejected)
The MVP uses shared-secret HS256 via MCP_IDENTITY_JWT_SECRET; the secret
must contain at least 32 bytes. The verifier
lives behind a small abstraction (identity.IdentityVerifier) so a production
RS256 / JWKS implementation can be dropped in without touching tools or
middleware.
loginid usage
loginid is the primary per-user key. Tools use it to build deterministic,
user-scoped mock data (mock_profile, mock_search) and to echo the caller's
identity (echo, whoami).
Endpoints
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /healthz |
none | liveness |
| GET | /readyz |
none | readiness |
| ANY | /mcp[/...] |
X-MCP-Identity (JWT) |
Streamable HTTP MCP endpoint |
Requests to /mcp or /mcp/... without a valid X-MCP-Identity are rejected at
the HTTP layer with 401 Unauthorized before reaching any tool. Similar names
such as /mcpish are not part of this authentication boundary.
MCP tools
| Tool | Input | Returns |
|---|---|---|
whoami |
– | full identity asserted by the gateway |
echo |
message: str |
{ loginid, message } |
mock_profile |
– | deterministic mock profile derived from loginid |
mock_search |
query: str |
deterministic, user-scoped mock search results |
Configuration
All configuration is via environment variables.
| Variable | Default | Notes |
|---|---|---|
APP_HOST |
0.0.0.0 |
|
APP_PORT |
8080 |
container port |
MCP_ENDPOINT |
/mcp |
Streamable HTTP path |
MCP_IDENTITY_ISSUER |
mcp-auth-gateway |
required iss |
MCP_IDENTITY_AUDIENCE |
mock-mcp-server |
required aud |
MCP_IDENTITY_ALGORITHM |
HS256 |
verifier algorithm |
MCP_IDENTITY_JWT_SECRET |
– | required, at least 32 bytes unless dev mode is on |
MCP_IDENTITY_DEV_MODE |
false |
if true, unauthenticated calls get a dummy user |
LOG_LEVEL |
info |
MCP_IDENTITY_JWT_SECRETis mandatory in production; the server refuses to start if it is missing or shorter than 32 bytes.MCP_IDENTITY_DEV_MODE=trueis only for local development. It defaults tofalseand must never be enabled in the cluster.
Local development
Requirements: Python ≥ 3.11 and uv.
# 1. install
uv sync --locked --extra dev
# 2. run the server
export MCP_IDENTITY_JWT_SECRET=dev-only-secret-that-is-at-least-32-bytes
export MCP_IDENTITY_DEV_MODE=false
python -m mock_mcp_server.main
Generate a dev identity token
Without the gateway you must supply your own X-MCP-Identity JWT:
export MCP_IDENTITY_JWT_SECRET=dev-only-secret-that-is-at-least-32-bytes
python scripts/make-dev-identity-token.py \
--loginid test.user \
--subject test-sub \
--aud mock-mcp-server
# -> export X_MCP_IDENTITY='<jwt>'
eval "$(python scripts/make-dev-identity-token.py --loginid test.user --subject test-sub)"
Test with curl
/mcp speaks Streamable HTTP (JSON-RPC). In stateless JSON mode you can call a
tool directly:
# health (no auth)
curl -s localhost:8080/healthz
# whoami (requires identity)
curl -s localhost:8080/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "X-MCP-Identity: ${X_MCP_IDENTITY}" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami","arguments":{}}}'
# missing identity -> 401
curl -i -s localhost:8080/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Test with MCP Inspector
Use the integrated gateway/Keycloak workflow from the sibling GitOps repository rather than connecting Inspector directly to this internal backend:
cd ../mcp-platform-gitops
scripts/local-build-push.sh
scripts/local-up.sh
scripts/local-inspector.sh
The launcher pins @modelcontextprotocol/[email protected]. In its OAuth
settings use client ID mcp-inspector, no client secret, scope
openid mcp:mock:use, and the preselected Streamable HTTP gateway URL
http://gateway.localhost:8080/mock/mcp.
Run the tests
uv run pytest # or: .venv/bin/python -m pytest
Docker
Image name (pushed to cr.aidev.samsungds.net/mcp-platform):
cr.aidev.samsungds.net/mcp-platform/mock-mcp-server:<commit-sha>
Build & push:
REGISTRY=cr.aidev.samsungds.net \
IMAGE_TAG="$(git rev-parse HEAD)" \
CA_CERT_FILE=/path/to/system-ca.pem \
PUSH=1 \
scripts/build-and-push.sh
The image installs production dependencies from the checked-in uv.lock with
frozen semantics, runs as a non-root user, exposes 8080, and ships a
HEALTHCHECK against /readyz. Tag images by commit SHA (no latest in the
cluster) so GitOps pins an immutable deployment reference.
Deployment (mcp-platform-gitops)
Full Kubernetes / GitOps manifests live in mcp-platform-gitops, not here.
This repo only ships the app and image. The gitops repo should deploy it as a
ClusterIP Service with these values:
| Setting | Value |
|---|---|
| Namespace | mcp-gateway |
| Service name | mock-mcp-server |
| Service type | ClusterIP |
| Container port | 8080 |
| Internal DNS | http://mock-mcp-server.mcp-gateway.svc.cluster.local:8080 |
| Internal MCP URL | http://mock-mcp-server.mcp-gateway.svc.cluster.local:8080/mcp |
| External MCP URL | https://gateway.mcp.aidev.samsungds.net/mock/mcp (gateway) |
Required Secret (mcp-internal-signing, key jwt-secret) holds the shared HS256
secret, which must match the gateway's signing secret and contain at least 32
bytes.
Container env:
env:
- name: MCP_IDENTITY_JWT_SECRET
valueFrom:
secretKeyRef:
name: mcp-internal-signing
key: jwt-secret
- name: MCP_IDENTITY_ISSUER
value: mcp-auth-gateway
- name: MCP_IDENTITY_AUDIENCE
value: mock-mcp-server
Probes: GET /healthz (liveness), GET /readyz (readiness), both on 8080.
Do NOT create a public Ingress
This service must never be exposed with its own public Ingress / LoadBalancer.
- It performs no external authentication (no Keycloak, no OAuth). It only trusts
the gateway-signed
X-MCP-Identity. A direct public route would let anyone reach/mcpwhile bypassing the gateway's real authentication. - All external access must go through the gateway, which authenticates the user,
mints
X-MCP-Identity, and routes/mock/mcpto thisClusterIPService.
The only external entry point is:
https://gateway.mcp.aidev.samsungds.net/mock/mcp
Project layout
src/mock_mcp_server/
__init__.py
main.py # ASGI app factory + uvicorn entrypoint
settings.py # env-based configuration (fails fast)
identity.py # X-MCP-Identity JWT verification (HS256; RS256-ready)
middleware.py # pure-ASGI identity enforcement (401) + scope injection
context.py # McpUserContext + get_current_user()
tools.py # whoami / echo / mock_profile / mock_search
scripts/
make-dev-identity-token.py
tests/
Install Mock Server in Claude Desktop, Claude Code & Cursor
unyly install mock-mcp-serverInstalls 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 mock-mcp-server -- uvx mock-mcp-serverFAQ
Is Mock Server MCP free?
Yes, Mock Server MCP is free — one-click install via Unyly at no cost.
Does Mock Server need an API key?
No, Mock Server runs without API keys or environment variables.
Is Mock Server hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Mock Server in Claude Desktop, Claude Code or Cursor?
Open Mock Server 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
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Mock Server with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
