cimd-reader
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
CIMD Validator
A Next.js App Router application for validating whether MCP OAuth clients use Client ID Metadata Documents (CIMD), fall back to Dynamic Client Registration (DCR), or send static client IDs.
Stack
Next.js App Router and Vercel route handlers
TypeScript
Tailwind CSS
Turso/libSQL
Drizzle ORM
Related MCP server: mcp-oauth-dcr
Local Setup
Install dependencies:
npm installCreate local environment variables:
cp .env.example .env.localCreate and seed the local libSQL database:
npm run db:setupRun the app:
npm run devOpen http://localhost:3000.
Turso Setup
Create a Turso database and set these variables locally and in Vercel:
TURSO_DATABASE_URL=libsql://YOUR_DATABASE.turso.io
TURSO_AUTH_TOKEN=YOUR_TURSO_TOKEN
NEXT_PUBLIC_BASE_URL=https://YOUR_DOMAINThen run:
npm run db:migrate
npm run db:seedFor Vercel, add the same environment variables in the project settings before deploying.
OAuth Test Endpoints
/.well-known/oauth-authorization-server/authorize/token/register/mcp
MCP Client Setup
Add this Streamable HTTP MCP server URL to the client being tested:
https://cimd-reader.akxen.tech/mcpCodex CLI:
codex mcp add cimd_reader \
--url https://cimd-reader.akxen.tech/mcp \
--oauth-resource https://cimd-reader.akxen.tech/mcp
codex mcp login cimd_readerClaude Code:
claude mcp add --transport http \
cimd_reader \
https://cimd-reader.akxen.tech/mcpVS Code mcp.json:
{
"servers": {
"cimd_reader": {
"type": "http",
"url": "https://cimd-reader.akxen.tech/mcp",
"oauth": {
"clientId": "https://vscode.dev/oauth/client-metadata.json"
}
}
}
}The authorization server advertises CIMD support. /authorize logs the request, classifies the client behavior, validates HTTPS URL client_id values as CIMD metadata documents, stores the result, then redirects to redirect_uri with a unique diagnostic authorization code. /token returns a unique diagnostic bearer token. /register logs DCR attempts and returns a new opaque client ID on every registration. These endpoints remain diagnostic stubs; they are not a production OAuth authorization server.
Dashboard
/shows named client cards with latest observed behavior, CIMD validation, and MCP versions. Names reported by new clients remain readable without implying a verified product association. Failed checks without any successful metadata history and unidentified clients are retained in the expandable “Other OAuth observations” section. A known client's latest failure remains on its main card./clients/[id]shows known metadata, latest OAuth attempt, raw metadata JSON, validation errors, and warnings./sessionslists validation sessions./sessions/[id]shows an OAuth request timeline./api/clientsreturns client data as JSON./api/sessionsreturns session data as JSON./protocolslists unique MCP protocol observations across clients, newest protocol revision first, then most recently observed./api/protocolsreturns the same history as JSON. Client cards and detail pages include protocol observations linked by diagnostic bearer tokens.
OAuth Identity and Product Attribution
An OAuth identity is the exact (issuer, client_id) pair. Client ID URLs are not normalized, and reported names are display information. Distinct registrations and metadata URLs remain separate even when they report the same name. Legacy rows without an issuer retain null; the migration does not invent historical issuers or product ownership.
Migration 0006 restores reviewed product associations for nine exact historical DCR identities. It runs once and preserves later operator mappings, unbindings, and visibility choices. Current MCPJam, OpenCode, Lovable, and Stella metadata endpoints are recognized by exact URL. A custom metadata document can display its reported name while keeping its distinct identity and unresolved product association.
Cards, details, sessions, and protocol history use the same identity resolver. Product attribution requires an explicit identity mapping, a unique configured metadata URL, or an explicitly recognized metadata endpoint/namespace. Ambiguous configured URLs remain unresolved. New clients can display reported names once an authorization attempt and token exchange share the same identity and session. Failed or unidentified observations remain inspectable in the secondary section, and incomplete attempts remain in sessions. Legacy name-based detail URLs work only when the label identifies one completed identity; they never merge evidence.
Use an identity's identities[].id from /api/clients or /api/sessions to manage an explicit mapping in the configured database:
# Bind an identity to an existing product, or provide a name to create one.
npm run clients:manage -- bind <identity-id> <product-id> "Product name"
npm run clients:manage -- unbind <identity-id>
# Visibility is explicit; names and substrings never silently filter cards.
npm run clients:manage -- visibility <product-id> hidden "Reason for hiding"
npm run clients:manage -- visibility <product-id> visibleHiding a product hides its card and detail page while preserving raw session and protocol evidence. To hide an unmapped identity, first bind it to a product. Seeding does not reset visibility or explicit identity mappings.
MCP Protocol History
Run npm run db:migrate before serving the updated app locally. Vercel runs migrations before each build using the deployment's database credentials. Missing Vercel database configuration fails the build. Migration 0004 adds persistent protocol history; 0005 adds issuer fields, identity mappings, explicit visibility, and diagnostic code/token correlation. Existing OAuth and protocol rows are preserved. Migrations can be replayed.
Authenticated /mcp requests record legacy initialize exchanges, modern server/discover probes, and explicit per-request protocol versions. Each distinct OAuth identity link, reported client name, application release, identity source, negotiation phase, version evidence, outcome, and server-supported version set has one row. Repeated observations atomically increment a count and update first/last seen timestamps. Different releases and version outcomes remain separate, including failures.
The history distinguishes a successful initialization from a server counter-offer, discovery, an accepted request, and a rejected request. Legacy clients proposing an unsupported revision receive a supported legacy counter-offer. Modern requests with unsupported versions receive an error listing supported revisions. Counter-offers and discovery alone are not counted as evidence of client usage on dashboard cards.
Protocol acceptance and method outcomes are reported separately, including for historical observations. An unsupported method such as resources/list returns a JSON-RPC -32601 error over HTTP 200, preserving the live session and the accepted protocol version. The server advertises tools; resources and prompts are optional capabilities that it does not advertise. HTTP 404 is reserved for missing/expired sessions rather than ordinary RPC method failures.
Reported names and releases come from initialize clientInfo, modern _meta client information, or the user agent as a fallback. Product ownership comes from the OAuth identity linked to the unique diagnostic bearer token, even if MCP reports a different name. Tokens are stored only as hashes and expire after one hour. The legacy shared test-access-token remains accepted for compatibility, but its observations and historical rows without an identity link remain global; they are never assigned to a product using a name match. Unique authorization codes correlate simultaneous exchanges to their exact sessions; legacy token requests use session inference only when one matching authorization exists.
This history records observed versions, not every version a client may support. Existing initialize logs did not retain server responses and are not backfilled as negotiated versions; new structured history starts after migration and deployment.
See the modern versioning rules and legacy initialization rules.
npm run smoke:protocols uses a temporary local database to verify negotiation, persistence, deduplication, ordering, and the history API.
SSRF Protections
The CIMD metadata fetcher:
Requires HTTPS and a path, and rejects credentials, fragments, and dot path segments.
Rejects localhost hostnames.
Rejects private, loopback, link-local, carrier-grade NAT, multicast, and metadata IP ranges.
Resolves hostnames and blocks unsafe DNS results, including IPv4-mapped IPv6 and reserved ranges.
Pins the connection to vetted DNS addresses while retaining hostname-based TLS verification.
Rejects HTTP redirects without following them.
Uses a five-second deadline across DNS, connection, and body reading.
Caps response body size.
Sends no credentials or cookies.
Parses and validates JSON only after the fetch checks pass.
CIMD Regression
Run npm run test:cimd for the isolated CIMD regression suite. It creates and removes a temporary database and intercepts DNS/HTTPS responses with deterministic fixtures; it never writes to the configured Turso database or contacts fixture hosts.
Coverage includes required fields and malformed JSON, exact client ID matching, OAuth defaults, native loopback and custom-scheme redirects, secret/private-key rejection, IPv4/IPv6 SSRF cases, DNS rebinding prevention, HTTP failures and redirects, byte limits, DNS/header/body timeouts, persisted validation results, token correlation, client cards/details/API, hosted connectors, and coexistence with protocol history. npm run verify:local also runs this suite.
The validator targets this diagnostic server's public/native authorization-code profile (token_endpoint_auth_method: none), not every possible OAuth grant or confidential-client authentication method. Metadata fetching follows the CIMD discovery requirements. Invalid CIMD evidence is logged and shown as a failed check while the diagnostic authorization flow continues. A visible card is not proof of a successful CIMD validation.
npm run test:identity covers identity separation, opaque DCR IDs, legacy registrations, concurrent code correlation, consistent card/detail/session attribution, and token-linked protocol history. npm run verify:local runs migration, build, MCP smoke tests, protocol smoke tests, and the regression suites. GitHub Actions runs the same checks using temporary databases on pushes and pull requests.
After npm run build, npm run test:dashboard checks a production-shaped history with legacy DCR registrations, known metadata endpoints, custom clients, and failed or unidentified observations. It starts the production server on a temporary local port and verifies the rendered cards and detail pages as well as exact identity preservation and one-time migration behavior. It also runs in verify:local and CI.
Seed Data
The seed script creates placeholder cards for:
Visual Studio Code.
Claude Code.
MCPJam.
Cursor.
Codex CLI.
This server cannot be deployed
Maintenance
Related MCP Connectors
Demo banking MCP server: accounts, transactions and payments. OAuth 2.1 with DPoP.
Experimental MCP server for current empirical verification of explicit public HTTPS endpoint claims.
Prove real MCP clients can connect: 5-client x 3-IdP OAuth matrix with shim fixes.
Preflight MCP OAuth compatibility with structured evidence and remediation guidance.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceA configurable OAuth 2.0 authorization server and OAuth-protected MCP server for end-to-end testing of OAuth-protected MCP flows, including failure injection and control plane.-
- AlicenseNot gradedqualityDmaintenanceA demo MCP server protected by OAuth (DCR), enabling hands-on exploration of OAuth flow for local MCP servers.MIT
- FlicenseNot gradedqualityDmaintenanceAn MCP authorization server implementing OAuth2/OIDC flows, supporting dynamic client registration, PKCE, consent screens, and client ID metadata documents for MCP authorization.-
- FlicenseNot gradedqualityFmaintenanceEnables testing an MCP v2 streamable HTTP server protected by Supabase OAuth 2.1, including Dynamic Client Registration, consent flow, and token-based identity verification for Claude clients.-