Streamable HTTP

    Standard MCP transport. Add the URL to any MCP client.

    Public & Free

    No API key, no signup. Every call is public and stateless.

    REST Fallback

    Invoke tools directly over plain HTTP with curl or fetch.

    Overview

    This app exposes its name generators as an MCP (Model Context Protocol) server so AI agents can call them as tools. It speaks the standard Streamable HTTP transport, and also offers a plain REST dispatcher for quick scripting and testing.

    All generation is public and stateless — no accounts, no personal data, no API key. The same logic powers our REST name API.

    MCP endpoint:

    https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp

    Connect via MCP

    Add the server to any MCP-capable client (Claude Desktop, Cursor, and similar) using its Streamable HTTP URL. A typical client config looks like this:

    {
      "mcpServers": {
        "star-wars-name-generator": {
          "url": "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp",
          "transport": "http"
        }
      }
    }

    Once connected, the agent can discover all 5 tools automatically and call them by name. No authentication step is required.

    REST Access

    Prefer plain HTTP? Two endpoints let you list and invoke tools without an MCP client:

    • GET /.mcp/list-tools — discover every tool and its input schema.
    • POST /.mcp/invoke-tool/<tool> — call a tool, sending its arguments as a JSON body.

    List all tools:

    curl "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp/.mcp/list-tools"

    Every response has the shape { content: [...], structuredContent: {...} }. Read structuredContent for machine-friendly output.

    OpenAPI Spec & Typed Clients

    A machine-readable OpenAPI 3.1 spec describes the request and response shape of every /.mcp/invoke-tool/<tool> endpoint — including enums, defaults, and the structuredContent payload. Point any OpenAPI codegen tool at it to generate typed clients automatically — no manual JSON wiring.

    Canonical spec URL — copy-paste this exact path into any codegen tool:

    https://starwarsnamegenerator.com/mcp-openapi.json

    Environment variables — both tools read the same vars. Save this as .env.example, then cp .env.example .env (MCP_AUTH_TOKEN is only needed behind an OAuth-protected server):

    # .env.example — env vars for openapi-typescript + orval.
    # Copy to .env:  cp .env.example .env
    
    # URL of the OpenAPI 3.1 spec (codegen input for BOTH tools).
    MCP_OPENAPI_URL=https://starwarsnamegenerator.com/mcp-openapi.json
    
    # Base URL of the live MCP endpoint (orval output.baseUrl + runtime client).
    MCP_BASE_URL=https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp
    
    # OAuth 2.1 Bearer token — OPTIONAL. Empty for the public server; set only when
    # the spec is hosted behind an OAuth-protected server. Sent as:
    #   Authorization: Bearer ${MCP_AUTH_TOKEN}
    MCP_AUTH_TOKEN=

    Wire scripts, orval.config.ts, and the runtime client to those vars so nothing is hard-coded:

    # ── package.json scripts (read $MCP_OPENAPI_URL) ─────────────────
    # "mcp:types":  "openapi-typescript $MCP_OPENAPI_URL -o src/mcp-types.ts --enum"
    # "mcp:client": "orval --config ./orval.config.ts"
    
    # ── orval.config.ts (reads env, nothing hard-coded) ──────────────
    # input:  { target: process.env.MCP_OPENAPI_URL! }
    # output: { baseUrl: process.env.MCP_BASE_URL! }
    
    # ── generated client at runtime (auth only if protected) ─────────
    # fetch(`${process.env.MCP_BASE_URL}/.mcp/invoke-tool/${tool}`, {
    #   method: "POST",
    #   headers: {
    #     "Content-Type": "application/json",
    #     ...(process.env.MCP_AUTH_TOKEN
    #       ? { Authorization: `Bearer ${process.env.MCP_AUTH_TOKEN}` }
    #       : {}),
    #   },
    #   body: JSON.stringify(body),
    # });

    openapi-typescript — typed models:

    # openapi-typescript — emit a single .d.ts of typed request/response models.
    npm i -D openapi-typescript
    
    # Straight from the hosted spec:
    npx openapi-typescript https://starwarsnamegenerator.com/mcp-openapi.json -o src/mcp-types.ts
    
    # Use a generated type, e.g. the generate_star_wars_name request body:
    #   import type { components } from "./mcp-types";
    #   type GenerateStarWarsNameRequest =
    #     components["schemas"]["GenerateStarWarsNameRequest"];

    orval — typed fetch client + models. Save this as orval.config.ts:

    // orval.config.ts — typed client + models from the OpenAPI 3.1 spec.
    import { defineConfig } from "orval";
    
    export default defineConfig({
      mcp: {
        input: {
          target: "https://starwarsnamegenerator.com/mcp-openapi.json",
        },
        output: {
          mode: "tags-split",       // one folder per tag (Discovery, Tools)
          target: "src/mcp/client.ts",
          schemas: "src/mcp/model", // request/response models land here
          client: "fetch",          // dependency-free fetch client
          baseUrl: "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp",
          clean: true,
          prettier: true,
        },
      },
    });
    # orval — typed fetch client + models from the same spec.
    npm i -D orval
    
    # Reads orval.config.ts above:
    npx orval --config ./orval.config.ts
    
    # Or one-off without a config file:
    npx orval --input https://starwarsnamegenerator.com/mcp-openapi.json \
      --output src/mcp/client.ts --client fetch

    openapi-generator — clients for other languages:

    # openapi-generator — typed client for any language.
    npx @openapitools/openapi-generator-cli generate \
      -i https://starwarsnamegenerator.com/mcp-openapi.json \
      -g typescript-fetch \
      -o ./mcp-client

    Typed invoke-tool call — use the generated types for full request/response typing:

    // mcp-client.ts — fully typed invoke-tool call using openapi-typescript output.
    // Generated first with:
    //   npx openapi-typescript https://starwarsnamegenerator.com/mcp-openapi.json -o src/mcp-types.ts
    import type { components } from "./mcp-types";
    
    type Schemas = components["schemas"];
    type GenerateStarWarsNameRequest = Schemas["GenerateStarWarsNameRequest"];
    type GenerateStarWarsNameResponse = Schemas["GenerateStarWarsNameResponse"];
    type ToolError = Schemas["ToolError"];
    
    const MCP_BASE = "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp";
    
    async function invokeTool<TReq, TRes>(tool: string, body: TReq): Promise<TRes> {
      const res = await fetch(`${MCP_BASE}/.mcp/invoke-tool/${tool}`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      if (!res.ok) {
        const err = (await res.json()) as ToolError;
        throw new Error(err.error ?? `invoke-tool failed: ${res.status}`);
      }
      return (await res.json()) as TRes;
    }
    
    // Request body is checked against the generated schema — wrong fields won't compile.
    const result = await invokeTool<GenerateStarWarsNameRequest, GenerateStarWarsNameResponse>(
      "generate_star_wars_name",
      { species: "twilek", gender: "female", count: 5 },
    );
    
    // Response is typed too: structuredContent.names is string[].
    console.log(result.structuredContent?.names);

    End-to-end (openapi-typescript) — typed invokeTool wired to MCP_BASE_URL with the correct Authorization: Bearer header:

    // mcp/openapi-client.ts — END-TO-END with openapi-typescript output.
    // 1) Generate types:  openapi-typescript $MCP_OPENAPI_URL -o src/mcp-types.ts --enum
    // 2) Env (see .env.example): MCP_BASE_URL, MCP_AUTH_TOKEN (optional)
    import type { components } from "./mcp-types";
    
    type Schemas = components["schemas"];
    type GenerateStarWarsNameRequest = Schemas["GenerateStarWarsNameRequest"];
    type GenerateStarWarsNameResponse = Schemas["GenerateStarWarsNameResponse"];
    type ToolError = Schemas["ToolError"];
    
    const MCP_BASE_URL = process.env.MCP_BASE_URL!;      // e.g. https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp
    const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;    // undefined on the public server
    
    /** Build headers once — the ONLY correct auth format is Authorization: Bearer <token>. */
    function authHeaders(): Record<string, string> {
      return {
        "Content-Type": "application/json",
        // Omit entirely when public; add the Bearer prefix when protected.
        ...(MCP_AUTH_TOKEN ? { Authorization: `Bearer ${MCP_AUTH_TOKEN}` } : {}),
      };
    }
    
    async function invokeTool<TReq, TRes>(tool: string, body: TReq): Promise<TRes> {
      const res = await fetch(`${MCP_BASE_URL}/.mcp/invoke-tool/${tool}`, {
        method: "POST",
        headers: authHeaders(),
        body: JSON.stringify(body),
      });
      if (!res.ok) {
        const err = (await res.json()) as ToolError;
        throw new Error(err.error ?? `invoke-tool failed: ${res.status}`);
      }
      return (await res.json()) as TRes;
    }
    
    // Fully typed call — request body AND response are checked at compile time.
    const result = await invokeTool<GenerateStarWarsNameRequest, GenerateStarWarsNameResponse>(
      "generate_star_wars_name",
      { species: "twilek", gender: "female", count: 5 },
    );
    console.log(result.structuredContent?.names); // string[]

    End-to-end (orval) — a customFetch mutator injects the same Bearer header, then call the generated typed operation:

    // mcp/fetcher.ts — END-TO-END with orval output (custom fetch mutator).
    // orval.config.ts:
    //   output: {
    //     baseUrl: process.env.MCP_BASE_URL!,
    //     override: { mutator: { path: "src/mcp/fetcher.ts", name: "customFetch" } },
    //   }
    // Env (see .env.example): MCP_BASE_URL, MCP_AUTH_TOKEN (optional)
    
    const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN; // undefined on the public server
    
    /** orval calls this for every request; inject the correct Bearer header here. */
    export const customFetch = async <T>(url: string, init?: RequestInit): Promise<T> => {
      const res = await fetch(url, {
        ...init,
        headers: {
          "Content-Type": "application/json",
          ...init?.headers,
          // The server only reads Authorization: Bearer <token>; skip when public.
          ...(MCP_AUTH_TOKEN ? { Authorization: `Bearer ${MCP_AUTH_TOKEN}` } : {}),
        },
      });
      if (!res.ok) throw new Error(`invoke-tool failed: ${res.status}`);
      return (await res.json()) as T;
    };
    
    // ── Usage (mcp/usage.ts) — import the generated, typed operation ──
    // The function name mirrors the spec's operationId; params/response are typed.
    import { postMcpInvokeToolGenerateStarWarsName } from "./client";
    
    const result = await postMcpInvokeToolGenerateStarWarsName({
      species: "twilek",
      gender: "female",
      count: 5,
    });
    console.log(result.structuredContent?.names); // string[]

    Concrete request / response JSON — the exact payloads these typed calls send and receive, matching GenerateStarWarsNameRequest/Response for both openapi-typescript & orval:

    // ── REQUEST — POST https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp/.mcp/invoke-tool/generate_star_wars_name
    // Matches GenerateStarWarsNameRequest (openapi-typescript) and the generated
    // body type for postMcpInvokeToolGenerateStarWarsName (orval). Both accept THIS
    // exact JSON — species is required; gender/era/count are optional (count 1–50).
    {
      "species": "twilek",
      "gender": "female",
      "era": "imperial",
      "count": 5
    }
    
    // ── RESPONSE (200) — matches GenerateStarWarsNameResponse
    // content[] is required; structuredContent + isError are optional.
    {
      "content": [
        {
          "type": "text",
          "text": "Aayla Secura\nNuala Deenan\nXiaan Amersu\nDrelliad Vao\nHera'toth Nal"
        }
      ],
      "structuredContent": {
        "species": "twilek",
        "gender": "female",
        "era": "imperial",
        "names": [
          "Aayla Secura",
          "Nuala Deenan",
          "Xiaan Amersu",
          "Drelliad Vao",
          "Hera'toth Nal"
        ]
      }
    }
    
    // ── ERROR RESPONSE (400/413/429) — matches ToolError
    {
      "error": "species must be one of the supported ids"
    }

    Each tool has a matching <Tool>Request and <Tool>Response schema under components/schemas.

    Troubleshooting — exact config tweaks for common openapi-typescript & orval issues (requestBody naming, baseURL, auth headers):

    # ── openapi-typescript ──────────────────────────────────────────
    # Types nested oddly / can't find a schema? Reference by component name:
    #   type Req = components["schemas"]["GenerateStarWarsNameRequest"];
    # requestBody is inline, not a named type — pull it off the operation:
    #   type Body = paths["/.mcp/invoke-tool/generate_star_wars_name"]
    #     ["post"]["requestBody"]["content"]["application/json"];
    # Enums missing? add --enum so unions become real TS enums:
    npx openapi-typescript https://starwarsnamegenerator.com/mcp-openapi.json -o src/mcp-types.ts --enum
    # ── orval ───────────────────────────────────────────────────────
    # 1) Wrong request/response names? The spec's operationId drives them.
    #    Force clean names with an override:
    #      output: { override: { operationName: (op) => op.operationId } }
    # 2) Calls hit the wrong host? orval uses the spec's servers[] by default.
    #    Pin it explicitly so it never points at localhost:
    #      output: { baseUrl: "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp" }
    # 3) Need auth headers (only if you protect the server)? Use a mutator:
    #      output: { override: { mutator: {
    #        path: "src/mcp/fetcher.ts", name: "customFetch" } } }
    #    // src/mcp/fetcher.ts
    #    export const customFetch = (url: string, init?: RequestInit) =>
    #      fetch(url, { ...init, headers: {
    #        ...init?.headers, Authorization: `Bearer ${token}` } });
    # 4) Stale output after a spec change? add clean: true to regenerate fresh.

    Auth headers — before / after — common Bearer vs API-key mistakes for openapi-typescript & orval (only relevant behind an OAuth-protected server):

    # This MCP server is public — no auth header is needed. These before/after
    # examples are for when you put the SAME spec behind an OAuth-protected server.
    
    # ── openapi-typescript (you write the fetch yourself) ────────────
    # ❌ Before — API-key style header the server never reads:
    fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json", "x-api-key": token },
      body: JSON.stringify(body),
    });
    # ✅ After — OAuth 2.1 Bearer token in the Authorization header:
    fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${token}`,   // note the "Bearer " prefix
      },
      body: JSON.stringify(body),
    });
    # Common gotchas: no "Bearer " prefix -> 401; header named "Authentication"
    # instead of "Authorization" -> ignored; raw token in the URL -> leaks + 401.
    
    # ── orval (mutator supplies the header) ──────────────────────────
    # ❌ Before — wrong header name AND missing prefix:
    export const customFetch = (url: string, init?: RequestInit) =>
      fetch(url, { ...init, headers: {
        ...init?.headers, "api-key": token } });          // server ignores this
    # ✅ After — Authorization: Bearer <token>:
    export const customFetch = (url: string, init?: RequestInit) =>
      fetch(url, { ...init, headers: {
        ...init?.headers, Authorization: `Bearer ${token}` } });
    # Wire it in orval.config.ts:
    #   output: { override: { mutator: {
    #     path: "src/mcp/fetcher.ts", name: "customFetch" } } }

    Verify with curl — before/after requests proving the server only accepts Authorization: Bearer <token>, so you can confirm the format before wiring it into openapi-typescript or orval:

    # Quick sanity check with curl — confirm the header format the server accepts
    # BEFORE you wire it into openapi-typescript or orval. Same result for both:
    # the endpoint only reads "Authorization: Bearer <token>".
    
    # ── ❌ Before — wrong header, request is rejected (401) ───────────
    curl -i -X POST "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp/.mcp/invoke-tool/generate_star_wars_name" \
      -H "Content-Type: application/json" \
      -H "x-api-key: $TOKEN" \
      -d '{"species":"human"}'
    # -> HTTP/1.1 401 Unauthorized  (server never reads x-api-key)
    
    # ── ✅ After — Authorization: Bearer <token>, request succeeds ────
    curl -i -X POST "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp/.mcp/invoke-tool/generate_star_wars_name" \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{"species":"human"}'
    # -> HTTP/1.1 200 OK  (note the "Bearer " prefix + exact "Authorization" name)
    
    # openapi-typescript: mirror the ✅ header in your fetch() call.
    # orval: mirror the ✅ header in the customFetch mutator.

    Error → fix FAQ — maps 401/403, invalid token, and missing-API-key errors to the exact openapi-typescript & orval config tweak:

    # Mini FAQ — map the error you see to the exact config tweak.
    # ("ot" = openapi-typescript, "orval" = orval.config.ts + mutator)
    
    # Q: 401 Unauthorized on every invoke-tool call.
    #    Cause: no token, or the header the server reads is missing.
    #  ot   -> add the Bearer header to your fetch():
    #            headers: { Authorization: `Bearer ${process.env.MCP_AUTH_TOKEN}` }
    #  orval-> set the mutator + baseUrl so every request carries it:
    #            output: { baseUrl: process.env.MCP_BASE_URL!,
    #              override: { mutator: { path: "src/mcp/fetcher.ts", name: "customFetch" } } }
    
    # Q: 403 Forbidden (token is present but rejected).
    #    Cause: valid header shape, wrong/expired token or wrong audience.
    #  ot   -> read a FRESH token at call time, don't cache a build-time literal:
    #            const token = process.env.MCP_AUTH_TOKEN; // re-read per run
    #  orval-> refresh inside the mutator so each call gets a live token:
    #            headers: { Authorization: `Bearer ${await getToken()}` }
    
    # Q: "invalid token" / malformed Authorization.
    #    Cause: missing "Bearer " prefix, extra quotes, or a newline in the value.
    #  ot   -> use a template literal, no quotes around the value:
    #            Authorization: `Bearer ${token.trim()}`   // NOT "Bearer '${token}'"
    #  orval-> same, inside customFetch: `Bearer ${token.trim()}`
    
    # Q: "missing API key" from a client that expects x-api-key.
    #    Cause: this server is OAuth-only; x-api-key is never read.
    #  ot   -> delete the x-api-key header, send Authorization: Bearer instead.
    #  orval-> in the mutator, replace { "api-key": key } with
    #            { Authorization: `Bearer ${token}` }
    
    # Q: Requests hit localhost / the wrong host (then 401/404).
    #    Cause: tool used the spec's servers[] instead of your endpoint.
    #  ot   -> you build the URL yourself: `${process.env.MCP_BASE_URL}/.mcp/invoke-tool/${tool}`
    #  orval-> pin it: output: { baseUrl: process.env.MCP_BASE_URL! }
    
    # Q: Header edits don't take effect after regenerating.
    #    Cause: stale generated output.
    #  orval-> add clean: true to output so it regenerates fresh.
    #  ot   -> re-run: openapi-typescript $MCP_OPENAPI_URL -o src/mcp-types.ts --enum

    Network issues — timeouts, CORS-like Failed to fetch, and wrong base URL mapped to concrete openapi-typescript & orval config tweaks:

    # Network failures — connection times out, "Failed to fetch" / CORS-like
    # errors, or requests land on the wrong host. Map the symptom to the fix.
    # ("ot" = openapi-typescript, "orval" = orval.config.ts + mutator)
    
    # ── Symptom: request hangs then times out ────────────────────────
    #    Cause: no timeout set, so a stalled connection blocks forever.
    #  ot   -> abort with AbortSignal.timeout (build the fetch yourself):
    fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(15000),   // 15s cap -> throws TimeoutError
    });
    #  orval-> add the same signal inside the customFetch mutator so EVERY
    #          generated call is bounded:
    export const customFetch = (url: string, init?: RequestInit) =>
      fetch(url, { ...init, signal: AbortSignal.timeout(15000) });
    # ── Symptom: "Failed to fetch" / blocked by CORS in the browser ──
    #    Cause: calling the API directly from browser code against an origin
    #    that doesn't return the right CORS headers for your site.
    #  ot   -> don't call cross-origin from the browser; route through your
    #          own server/edge function, or use a same-origin proxy path:
    #            const base = "/api/mcp";   // your proxy forwards to https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp
    #  orval-> pin baseUrl to that same-origin proxy so generated code never
    #          hits the cross-origin host directly:
    #            output: { baseUrl: "/api/mcp" }
    #    // NOTE: this server DOES send permissive CORS headers, so a real
    #    // "Failed to fetch" here almost always means the wrong URL (below)
    #    // or an offline/blocked network — not a missing CORS header.
    
    # ── Symptom: 404 / connection refused / hits localhost ───────────
    #    Cause: wrong base URL — trailing slash, http vs https, or the spec's
    #    servers[] pointing at a dev host.
    #  ot   -> build the URL from ONE source of truth, no trailing slash:
    #            const base = process.env.MCP_BASE_URL!;   // "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"
    #            fetch(`${base}/.mcp/invoke-tool/${tool}`, ...)
    #  orval-> override the spec's servers[] explicitly:
    #            output: { baseUrl: "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp" }   // never trust servers[0]
    
    # ── Symptom: works with curl, fails from the app ─────────────────
    #    Cause: env var missing at runtime, so base URL is undefined and the
    #    request goes to "undefined/.mcp/...".
    #  ot   -> fail fast so you see the real problem, not a silent bad URL:
    #            if (!base) throw new Error("MCP_BASE_URL is not set");
    #  orval-> require it in the config: output: { baseUrl: process.env.MCP_BASE_URL! }
    
    # ── Verify reachability with curl before blaming your code ───────
    curl -i --max-time 15 -X POST "https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp/.mcp/invoke-tool/generate_star_wars_name" \
      -H "Content-Type: application/json" \
      -d '{"species":"human"}'
    # -> HTTP/1.1 200 OK confirms the host + path are correct and reachable.
    # curl: (28) after --max-time -> network/timeout, not a code bug.

    Auth config linter — paste your fetch headers, orval customFetch mutator, or .env to catch a missing MCP_AUTH_TOKEN, the wrong header name, or the wrong Authorization scheme — with the exact openapi-typescript & orval fix:

    Token format validator — paste the token you plan to send to confirm it looks like a Bearer token (or API-key format) and catch stray whitespace, a pasted Bearer prefix, or a truncated value before you hit a 401/403:

    Accepted token formats

    server defaultJWT Bearer
    Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.sig

    OAuth 2.1 access token — three base64url segments split by dots. The only scheme this server accepts.

    target-specificx-api-key header
    x-api-key: sk_live_51H8xConcreteApiKeyValue0000

    Raw key in its own header, no scheme prefix. Used by servers that document x-api-key auth.

    target-specificAuthorization: ApiKey
    Authorization: ApiKey sk_live_51H8xConcreteApiKeyValue0000

    Key sent with the ApiKey scheme instead of Bearer. Only for servers that document this scheme.

    target-specificapi-key header
    api-key: 9f8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d

    Opaque key variant (also seen as apikey). Same rule — only if the target server documents it.

    This MCP server accepts Authorization: Bearer <JWT> only. The x-api-key and Authorization: ApiKey shapes are shown for target servers that document API-key auth.

    Live request tester — paste a spec URL, pick your client, add a token if the server is protected, and send a sample invoke-tool request to confirm you get a 200:

    The invoke base is read from the spec's servers[0].url.

    {
      "species": "twilek",
      "gender": "female",
      "era": "imperial",
      "count": 5
    }

    Per-Tool JSON Schemas

    Prefer plain JSON Schema over OpenAPI? Every tool ships two self-contained schema files (draft 2020-12) you can feed straight to json-schema-to-typescript, quicktype, or ajv — no OpenAPI toolchain required. Each has a stable $id for $ref resolution.

    Browse mcp-schemas/index.json

    Generate types:

    # Generate types from a single tool's JSON Schema — no OpenAPI needed.
    # TypeScript (json-schema-to-typescript):
    npx json-schema-to-typescript \
      https://starwarsnamegenerator.com/mcp-schemas/generate_star_wars_name.request.json \
      -o GenerateStarWarsNameRequest.d.ts
    
    # Any language (quicktype):
    npx quicktype https://starwarsnamegenerator.com/mcp-schemas/generate_star_wars_name.response.json \
      -o GenerateStarWarsNameResponse.ts
    
    # Validate a payload at runtime (ajv):
    npx ajv validate \
      -s https://starwarsnamegenerator.com/mcp-schemas/generate_star_wars_name.request.json \
      -d payload.json

    Rate Limits

    The endpoint applies best-effort per-IP limits to keep it healthy under load: roughly 120 requests/minute with a short-window burst guard. Exceeding them returns HTTP 429 with a Retry-After header — honor it and retry after the given number of seconds. Requests over 256 KB are rejected with 413.

    list_star_wars_species

    List the species ids supported by generate_star_wars_name, with their display names. Call this first to discover valid species ids.

    This tool takes no parameters.

    // npm i @modelcontextprotocol/sdk
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
    
    // Connect once, reuse the client for every tool call. No API key required.
    const client = new Client({ name: "my-agent", version: "1.0.0" });
    await client.connect(
      new StreamableHTTPClientTransport(new URL("https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"))
    );
    
    const result = await client.callTool({
      name: "list_star_wars_species",
      arguments: {},
    });
    
    // Typed, structured output — no manual JSON wiring.
    console.log(result.structuredContent);

    generate_star_wars_name

    Generate authentic-sounding Star Wars character names for a given species, gender, and era. Use list_star_wars_species first to see valid species ids.

    ParameterTypeRequiredDescription
    speciesstring (enum)requiredSpecies id, e.g. human, jedi, sith, mandalorian, twilek, wookiee.
    genderstring (enum)optionalmale, female, or neutral. Applies to human, jedi, mandalorian. Default neutral.
    erastring (enum)optionalold-republic, clone-wars, imperial, or new-republic. Default imperial.
    countintegeroptionalHow many names to generate (1–50). Default 6.
    // npm i @modelcontextprotocol/sdk
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
    
    // Connect once, reuse the client for every tool call. No API key required.
    const client = new Client({ name: "my-agent", version: "1.0.0" });
    await client.connect(
      new StreamableHTTPClientTransport(new URL("https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"))
    );
    
    const result = await client.callTool({
      name: "generate_star_wars_name",
      arguments: {
          "species": "sith",
          "gender": "neutral",
          "era": "imperial",
          "count": 5
        },
    });
    
    // Typed, structured output — no manual JSON wiring.
    console.log(result.structuredContent);

    generate_droid_name

    Generate Star Wars droid designations by class: astromech (R2-D2 / BB-8 serials), protocol (C-3PO / K-2SO blocks), or battle (OOM-9 / IG-88 / HK-47 series).

    ParameterTypeRequiredDescription
    droidClassstring (enum)requiredastromech, protocol, or battle.
    countintegeroptionalHow many designations to generate (1–50). Default 6.
    // npm i @modelcontextprotocol/sdk
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
    
    // Connect once, reuse the client for every tool call. No API key required.
    const client = new Client({ name: "my-agent", version: "1.0.0" });
    await client.connect(
      new StreamableHTTPClientTransport(new URL("https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"))
    );
    
    const result = await client.callTool({
      name: "generate_droid_name",
      arguments: {
          "droidClass": "astromech",
          "count": 5
        },
    });
    
    // Typed, structured output — no manual JSON wiring.
    console.log(result.structuredContent);

    generate_ship_name

    Generate Star Wars starship names — from smuggler freighters to Imperial capital ships.

    ParameterTypeRequiredDescription
    countintegeroptionalHow many ship names to generate (1–50). Default 6.
    // npm i @modelcontextprotocol/sdk
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
    
    // Connect once, reuse the client for every tool call. No API key required.
    const client = new Client({ name: "my-agent", version: "1.0.0" });
    await client.connect(
      new StreamableHTTPClientTransport(new URL("https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"))
    );
    
    const result = await client.callTool({
      name: "generate_ship_name",
      arguments: {
          "count": 5
        },
    });
    
    // Typed, structured output — no manual JSON wiring.
    console.log(result.structuredContent);

    generate_planet_name

    Generate Star Wars planet and world names in the style of Coruscant, Tatooine, and Naboo.

    ParameterTypeRequiredDescription
    countintegeroptionalHow many planet names to generate (1–50). Default 6.
    // npm i @modelcontextprotocol/sdk
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
    
    // Connect once, reuse the client for every tool call. No API key required.
    const client = new Client({ name: "my-agent", version: "1.0.0" });
    await client.connect(
      new StreamableHTTPClientTransport(new URL("https://vqcjvexnwxnwvaoeofka.supabase.co/functions/v1/mcp"))
    );
    
    const result = await client.callTool({
      name: "generate_planet_name",
      arguments: {
          "count": 5
        },
    });
    
    // Typed, structured output — no manual JSON wiring.
    console.log(result.structuredContent);