Skip to main content
Glama
Ramzanelayodath

json-to-model

json-to-model MCP Server

An MCP (Model Context Protocol) server for Claude Code, Codex CLI, or any other MCP-compatible client that works like Postman combined with a code generator: give it an API endpoint, it fetches the response and returns a ready-to-use model/POJO class in your configured language — with login and refresh-token handling built in, so you don't have to keep pasting fresh tokens by hand.


What it does

  1. You configure it once — your target language, optional baseUrl, and (optionally) your login/refresh token endpoints. Either run setup_auth directly, or type /json-to-model in Claude Code and it will interview you for these values (see Setup process below).

  2. From then on, you ask Claude Code to hit an endpoint — e.g. "generate a model from https://api.example.com/users/1 called User", or (if you configured a baseUrl) just "generate a model from /users/1".

  3. The server calls the API (attaching a valid auth token automatically if one is configured), reads the JSON response, and returns:

    • a status/shape summary line (e.g. Status: 200 OK | Response: array with 12 items) — so you can tell "genuinely empty" apart from "auth silently rejected, API returned 200 + []",

    • the full response body, pretty-printed (truncated past 4000 chars),

    • the generated source code in your configured language.

Code generation is powered by quicktype-core, which infers types (including nested objects, arrays, optional/nullable fields) from the JSON shape.


Related MCP server: MCP Swagger Server

Project structure

json-to-model/
├── package.json          Dependencies & npm scripts (build/start/dev)
├── tsconfig.json          TypeScript compiler config
├── .gitignore
├── README.md
├── .claude/
│   └── commands/
│       └── json-to-model.md   Claude Code slash command — `/json-to-model`
│                              walks you through setup or a generate call
└── src/
    ├── index.ts           MCP server entrypoint — registers the tools
    │                      (setup_auth, generate_model_from_api,
    │                      list_supported_languages), the `json-to-model`
    │                      MCP prompt, and wires request building, error
    │                      handling, and responses
    ├── types.ts           Shared types: AuthConfig, SessionState, ToolTextResult
    ├── store.ts           Reads/writes config.json and session.json under
    │                      ./.json-to-model/ in the current project root
    │                      (per-project, not shared globally)
    ├── auth.ts            Token resolution chain: explicit token → cached
    │                      token → refresh → login → unauthenticated.
    │                      Handles rotating refresh tokens.
    ├── language.ts        Supported language enum, case-insensitive
    │                      normalization, and aliases (c# → csharp, ts →
    │                      typescript, py → python, etc.)
    └── codegen.ts          Wraps quicktype-core: JSON string → generated
                            source code for the configured language, with
                            per-language serializer/framework choices

How a request flows through the code

generate_model_from_api tool call
        │
        ▼
  index.ts: check setup exists (store.ts) ──► no? return setup error
        │ yes
        ▼
  auth.ts: resolveToken()
    1. explicit `token` param?          → use it
    2. cached access token still valid? → use it
    3. refresh token + endpoint?        → refresh, cache, use it
    4. login endpoint configured?       → login, cache, use it
    5. none of the above                → proceed unauthenticated
        │
        ▼
  index.ts: resolve `url` (or join `path` onto configured baseUrl),
            build headers + body (json or form), fetch(url)
        │
        ▼
  codegen.ts: quicktype-core turns the JSON response into
              source code in the configured language (using that
              language's configured serializer — see table below)
        │
        ▼
  Status/shape summary + full response body + generated class
  returned to Claude / you

Prerequisites

  • Node.js v18 or later (the code uses the built-in fetch API)

  • Claude Code, or OpenAI's Codex CLI — anything that can spawn a stdio MCP server. Instructions below cover Claude Code first, Codex CLI in its own section further down.


Dependencies

Runtime:

Package

Purpose

@modelcontextprotocol/sdk

MCP server framework — tools, prompts, stdio transport

quicktype-core

JSON → model code generation engine

zod

Schema validation for tool parameters

Dev-only (not shipped, used to build/run from source):

Package

Purpose

@types/node

Node.js type definitions

tsx

Runs TypeScript directly for npm run dev

typescript

Compiler (tsc) for npm run build

Everything else is Node.js built-ins (fs, path, fetch) — no other third-party libraries.


Setup process

1. Install and build

cd json-to-model
npm install
npm run build

This compiles src/*.tsdist/*.js. dist/index.js is what actually runs.

2. Register the server with Claude Code

claude mcp add json-to-model -- node /absolute/path/to/json-to-model/dist/index.js

Use an absolute path — Claude Code spawns this as a subprocess on demand (stdio transport), so there's nothing to host or deploy for local/personal use.

3. Run first-time setup (in a Claude Code conversation)

Easiest: type the slash command.

/json-to-model

This is defined in .claude/commands/json-to-model.md. If no setup exists yet, Claude interviews you one question at a time — language (offering to call list_supported_languages if you're unsure), optional baseUrl, login endpoint + body + token field, refresh endpoint + fields — then calls setup_auth with your answers. If setup already exists, it shows a summary and asks whether to reconfigure or go straight to generating a model.

The same interview flow is also exposed as an MCP prompt named json-to-model (works from any MCP client, not just the slash command).

Or ask directly / call setup_auth yourself. Fields:

Field

Required?

Notes

language

Yes

java, kotlin, typescript, python, csharp, go, swift, dart, rust. Fixed at setup — not chosen per call. Call list_supported_languages if unsure.

baseUrl

No

Host to join with a relative path on later generate_model_from_api calls, so you don't have to repeat the full host every time.

loginEndpoint

No

POST endpoint that returns an access token. Skip this if you'll always pass a token manually.

loginBody

No

JSON body sent to the login endpoint (credentials, API key, etc.)

loginTokenField

No

Field in the login response holding the token. Default: access_token

refreshEndpoint

No

POST endpoint that exchanges a refresh token for a new access token

refreshTokenField

No

Field holding the refresh token. Default: refresh_token

expiryField

No

Field holding token lifetime in seconds. Default: expires_in

Example:

"Set up json-to-model. Language: Kotlin. Login endpoint: https://api.example.com/auth/login with body { "apiKey": "..." }."

Config is saved to <project-root>/.json-to-model/config.jsonscoped to whichever project directory Claude Code/Codex was running in when the MCP server was spawned, not shared globally. Different projects get their own language, baseUrl, login/refresh endpoints, etc. Session tokens are cached separately in <project-root>/.json-to-model/session.json (file permissions 600, never logged, never echoed back in any tool response).

Add .json-to-model/ to that project's .gitignoresession.json holds live tokens and shouldn't be committed.

4. Use it

GET request (full URL):

"Generate a model from https://api.example.com/users/1 called User"

GET request (relative path, requires baseUrl configured):

"Generate a model from /users/1 called User"

POST with JSON body:

"POST https://api.example.com/clients with body { "name": "Acme" } as JSON, call the model Client"

POST with form data:

"POST https://api.example.com/clients as form data with name=Acme, call the model Client"

One-off call with a manual token (bypasses stored login/refresh):

"Generate a model from https://api.example.com/orders/5 using token eyJhbGciOi..." — the Bearer prefix is optional, it's stripped and re-added automatically either way.

Every successful call returns three things, in order: a status/shape summary line, the full pretty-printed response body, then the generated model code. The generated code also carries the same response JSON baked in as a comment header (plus a "Generated by json-to-model MCP server" line), so the pairing between response and model survives even if the code is saved to its own file or the chat reply gets trimmed/summarized.


Tool reference

setup_auth

Run once (or again to reconfigure). See the setup table above for fields.

generate_model_from_api

Param

Required?

Default

Notes

url

One of url/path

Full endpoint URL

path

One of url/path

Relative path, joined onto the configured baseUrl. Errors clearly if baseUrl isn't set.

method

No

GET

Any HTTP method

token

No

Per-call override; falls back to configured login/refresh flow

className

No

Model

Name for the generated class/type

headers

No

Extra headers to send

body

No

Request body/params for POST/PUT/PATCH/DELETE

bodyType

No

json

jsonapplication/json, formapplication/x-www-form-urlencoded

GET/HEAD requests reject a body with a clear error, since those methods don't carry one.

list_supported_languages

No params. Returns the current list of valid language values for setup_auth — use this if you're not sure what's supported.

Supported HTTP methods

method accepts any HTTP verb — it's passed straight through to fetch().

Method

Body allowed?

Notes

GET

No

Rejected with an error if body is passed

HEAD

No

Rejected with an error if body is passed

POST

Yes

Use body + bodyType (json or form)

PUT

Yes

Full resource replacement — same body handling as POST

PATCH

Yes

Partial update — same body handling as POST

DELETE

Yes (permissive)

Body is allowed but not required — some APIs expect the resource ID in the URL instead, others (e.g. bulk-delete-by-filter) expect a body. Since a body on DELETE is unusual, the response is prefixed with a note (Note: DELETE request included a body — unusual, verify the API expects this.) so it's never silently ambiguous.

Examples:

"PATCH https://api.example.com/clients/5 with body { "status": "active" }, call the model Client"

"DELETE https://api.example.com/clients/5"


Generated code: serializer per language

codegen.ts picks a serialization approach per language before handing off to quicktype-core. Most languages only have one sensible option upstream; Kotlin and C# support multiple frameworks — this project pins the one below as the default.

Language

Serializer / framework used

Notes

Kotlin

kotlinx.serialization (@Serializable, @SerialName)

Explicitly pinned via rendererOptions.framework = "kotlinx" in codegen.ts. quicktype's own default is Klaxon — if you see import com.beust.klaxon.* you're on an older build; kotlinx was chosen instead since it's the JetBrains-maintained, dependency-light option. Needs the org.jetbrains.kotlinx:kotlinx-serialization-json Gradle dependency. Package name is pinned to models via rendererOptions.package (quicktype-core's own default is quicktype, which isn't meaningful in a real project) — edit codegen.ts if you want a different package.

Java

Jackson (@JsonProperty)

quicktype's only Java renderer. Needs jackson-databind on the classpath.

C#

Newtonsoft.Json / Json.NET

quicktype-core's default C# renderer; System.Text.Json is available upstream but not wired up here. Needs the Newtonsoft.Json NuGet package.

TypeScript

Plain interfaces, no library

quicktype emits interface declarations plus optional runtime type-guard helpers; no external dependency.

Python

dataclasses (stdlib)

quicktype emits @dataclass-based models with hand-rolled from_dict/to_dict — no third-party serializer needed.

Go

encoding/json struct tags (stdlib)

Plain structs with `json:"field"` tags; no external module required.

Swift

Codable (stdlib protocol)

Structs conform to Codable; no external dependency.

Dart

Hand-written fromJson/toJson, no library

Works directly in Flutter projects — no json_serializable/build_runner step required, the generated code is usable as-is.

Rust

serde (#[derive(Serialize, Deserialize)])

The de-facto standard for Rust; needs the serde + serde_json crates.

To change Kotlin's or C#'s framework, edit the rendererOptions block in src/codegen.ts (valid Kotlin values: klaxon, kotlinx, jackson; valid C# values: newtonsoft, systemtextjson), then npm run build.


Using with Codex CLI

The server itself is plain MCP over stdio, so it works with OpenAI's Codex CLI too — same build, same tools. Two things differ from the Claude Code setup above:

  • No /json-to-model slash command. That file lives under .claude/commands/, which is Claude-Code-specific — Codex doesn't read it. Codex has its own custom-prompt mechanism instead: drop a markdown file under ~/.codex/prompts/<name>.md and it becomes /<name> inside Codex. You can copy the interview instructions out of .claude/commands/json-to-model.md into a file there if you want the same guided flow in Codex; it's plain markdown, no Claude-specific syntax.

  • The MCP prompt primitive may not surface. Codex's MCP client support has historically focused on toolssetup_auth, generate_model_from_api, list_supported_languages all work normally, but the json-to-model prompt registered in index.ts might not appear in Codex's UI even though it's a spec-compliant MCP prompt. Check your installed Codex version if you're relying on it; the tools work regardless.

1. Build

Same as Claude Code — see Install and build above.

2. Register the server with Codex

Add an entry to Codex's config (~/.codex/config.toml):

[mcp_servers.json-to-model]
command = "node"
args = ["/absolute/path/to/json-to-model/dist/index.js"]

Use an absolute path, same reasoning as the Claude Code setup — Codex spawns this as a subprocess on demand. Restart Codex (or reload MCP servers) to pick up the config change.

3. Use it

Without the slash command or prompt, just ask Codex directly and it calls the tools for you:

"Set up json-to-model. Language: Kotlin. Login endpoint: https://api.example.com/auth/login with body { "apiKey": "..." }."

"Generate a model from https://api.example.com/users/1 called User"

Everything else — baseUrl/path support, the status/shape summary line, full response body display, per-language serializers — behaves identically to Claude Code, since it's all server-side logic in index.ts/codegen.ts, not client-specific.


Design notes

  • No profiles within a project — one auth config per project directory, by design (kept intentionally simple; a profile system would be needed only if you're juggling multiple unrelated APIs with different auth from the same project). Across projects, config is already isolated since it's stored per-project under .json-to-model/ in each project root, not globally.

  • Language is fixed at setup, not selectable per call — this removes the need for any "which language?" fallback logic in the main tool.

  • Symbolic endpoint references (e.g. a constant like ApiEndpoints.GET_CLIENT in your codebase) aren't resolved by this MCP server itself — it only ever sees the literal URL string it's given. In practice this still works conversationally because Claude Code uses its own separate file-reading tools to resolve the constant to a real URL before calling this tool.

  • Rotating refresh tokens are supported — if a refresh response includes a new refresh token, it overwrites the stored one; if not, the old one is kept.

  • Errors are returned with isError: true per the MCP convention, with a distinct message for: no setup found, incomplete config, auth failure, network failure, non-2xx response, and JSON parse/codegen failure. Tokens are never included in error text.

  • Response body is always shown, not just the generated code — this was added after an empty-array response turned out to be ambiguous (genuinely empty data vs. auth silently rejected + API returning 200 []). It's truncated past 4000 characters to avoid flooding the terminal on huge payloads.

  • Response body is also embedded in the generated code as a comment header (withHeaderComment() in codegen.ts), along with a "Generated by json-to-model MCP server" line — so if only the code gets saved/copied out of the chat, the exact response it was modeled from isn't lost.

  • /json-to-model and the MCP prompt are two separate mechanisms that do the same interview: the slash command (.claude/commands/json-to-model.md) is Claude-Code-specific and needs to ship alongside this server if used from another project directory; the MCP prompt (registered in index.ts) works from any MCP client that supports prompts.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A basic MCP server to operate on the Postman API.

  • An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform

  • MCP server for interacting with the Supabase platform

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Ramzanelayodath/mcp-json-to-model'

If you have feedback or need assistance with the MCP directory API, please join our Discord server