Skip to main content
Glama
Lxvi101
by Lxvi101

Math Circuit Studio

A small, self-hosted MCP App for ChatGPT/Codex that can:

  • draw interactive 2D function plots, 3D surfaces, and parametric 3D curves;

  • embed a pinned CircuitJS1 editor for explanatory circuits;

  • render short Manim MP4s from a constrained slide/equation schema.

It has no database, queue, S3 bucket, CDN, or external simulation API. One Docker container runs the MCP server, hosts every browser asset, and invokes Manim locally. Generated videos and CircuitJS export files live in a named Docker volume and expire automatically.

CircuitJS is used as an interactive teaching canvas. This project intentionally does not expose SPICE, arbitrary Manim Python, or electrical design verification.

Architecture

flowchart LR
  C["ChatGPT or an MCP client"] -->|"Streamable HTTP /mcp"| A["Node MCP server"]
  A --> W["Unified in-chat widget"]
  W --> P["Plotly + mathjs lazy-loaded for graphs"]
  W --> J["Bundled CircuitJS iframe"]
  A --> M["Constrained Manim templates"]
  M --> V["Local artifacts volume"]
  W --> V

Related MCP server: scicompute-mcp

Tools

Tool

Intended input

Result

plot_math

mathjs expressions and finite ranges

interactive 2D/3D Plotly view

show_circuit

CircuitJS Export as Text content

embedded CircuitJS canvas

render_manim_explanation

1–8 text/LaTeX slides

locally rendered MP4 player

All three tools use the same MCP App resource at ui://math-circuit-studio/viewer-v2.html. Every structured tool result has a matching output schema. The resource declares only the deployed origin in its CSP; there are no public CDN dependencies.

Run locally with Docker

Requirements: Docker Compose v2 and roughly 4 GB RAM for building CircuitJS and rendering Manim.

cp .env.example .env
# For local use, set PUBLIC_ORIGIN=http://localhost:3000 in .env
docker compose -f compose.yaml -f compose.local.yaml up --build

Check http://localhost:3000/readyz (dependency readiness) or /healthz (process liveness). The MCP endpoint is http://localhost:3000/mcp and the bundled CircuitJS page is http://localhost:3000/circuitjs/circuitjs.html.

The first image build compiles the pinned CircuitJS GWT application, so it is much slower than subsequent cached builds.

Deploy with Dokploy

  1. Create a Docker Compose application from this repository and select compose.yaml.

  2. In Dokploy's Environment tab, set at least:

    PUBLIC_ORIGIN=https://visuals.your-domain.example
    WIDGET_DOMAIN=https://visuals.your-domain.example
    MEMORY_LIMIT=4G
    CPU_LIMIT=2.0
  3. In Domains, add the public hostname to service app, container port 3000, and enable HTTPS. Do not add Traefik labels to the Compose file; Dokploy manages them from this domain configuration.

  4. Deploy, then verify https://visuals.your-domain.example/readyz and https://visuals.your-domain.example/circuitjs/circuitjs.html.

  5. Add https://visuals.your-domain.example/mcp as the remote MCP server in ChatGPT developer mode.

Dokploy writes dashboard environment values to .env; this Compose file references them explicitly with ${VARIABLE} interpolation. It uses only a named volume, never an absolute host bind mount, so redeploys remain portable on a single Dokploy node.

Do not run multiple replicas: the render-concurrency guard is process-local and the artifact volume is local. This is intentionally a simple single-instance service.

Configuration

Variable

Default

Purpose

PUBLIC_ORIGIN

http://localhost:3000

Exact external origin used in iframe/video URLs and widget CSP

WIDGET_DOMAIN

PUBLIC_ORIGIN

Dedicated HTTPS origin declared to the ChatGPT widget host

MANIM_ENABLED

true

Enables the Manim tool

MANIM_TIMEOUT_MS

75000

Hard timeout for one render

MANIM_MAX_CONCURRENT

1

Simultaneous render limit

ARTIFACT_TTL_HOURS

72

Local MP4 and CircuitJS export retention

MCP_BEARER_TOKEN

empty

Optional static bearer protection for clients that can send it

MEMORY_LIMIT

4G

Runtime Compose memory limit

CPU_LIMIT

2.0

Runtime Compose CPU limit

CIRCUITJS_REF

pinned SHA

Reproducible CircuitJS source revision

PUBLIC_ORIGIN must be the external HTTPS origin in ChatGPT. Set WIDGET_DOMAIN to that same dedicated origin for plugin submission. A localhost value in a remote deployment will make nested CircuitJS frames and video URLs point at the wrong machine.

ChatGPT integration notes

The server uses Streamable HTTP at /mcp, serves an MCP App HTML resource with the text/html;profile=mcp-app MIME type, and returns structured content for the widget. The CircuitJS editor is a nested same-origin frame, so the resource CSP includes the configured origin in frameDomains. Circuit export text is loaded from a short, content-addressed /circuit-files/... URL instead of being placed in a potentially oversized query string.

The default deployment has no authentication to keep first-time self-hosting simple. That means anyone who can reach /mcp can request renders. For an internet-facing production deployment, put the endpoint behind an OAuth-capable gateway compatible with your MCP client, or use MCP_BEARER_TOKEN with a client that can attach a static Authorization header. Keep the video and CircuitJS routes publicly readable so the sandboxed widget can load them.

Local development

Node 22+ is required.

npm ci
npm run check
npm test
MANIM_ENABLED=false PUBLIC_ORIGIN=http://localhost:3000 npm start

The host build does not install Manim or compile CircuitJS; those are supplied by the Docker image. The normal test suite disables Manim and verifies MCP schemas, metadata, input rejection, graph results, concurrent circuit storage, and widget resources. The container test additionally exercises a real Manim/LaTeX render and cache hit.

The included .mcp.json points Codex at http://localhost:3000/mcp, so start the Compose application before using the repo-local plugin configuration. For a remote instance, change that URL to the deployed HTTPS endpoint.

Operational and safety boundaries

  • Manim source is generated only by server-owned templates. User/model content is inserted as escaped string literals; arbitrary Python is not accepted. LaTeX is restricted to a math-oriented command and environment allowlist before TeX runs.

  • Graph expressions are parsed and restricted to numeric operators, selected math functions, constants, and the variables expected by each graph mode. Assignment, object access, imports, and function definitions are rejected.

  • The container runs as manimuser, drops Linux capabilities, uses a read-only root filesystem, and writes only to /tmp plus the artifact volume.

  • Manim jobs are synchronous, cached, timeout-bound, and deliberately limited. On timeout or shutdown, the complete Manim/ffmpeg/LaTeX process group is terminated. This avoids Redis and a worker queue, but it is intended for short explanations rather than production video jobs.

  • CircuitJS browser behavior is useful for intuition and demos, not component sizing, compliance, safety analysis, or sign-off.

CircuitJS license

CircuitJS1 is GPL-2.0 licensed. The Docker image exposes the exact license at /licenses/circuitjs1-GPL-2.0.txt and the complete pinned source used to build it at /licenses/circuitjs1-source.tar.gz. Review THIRD_PARTY_NOTICES.md before redistributing an image, especially if you modify CircuitJS.

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

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/Lxvi101/math-circuit-studio'

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