Skip to main content
Glama

Ink answer paper

A dialog-embedded blank sheet. The student handwrites an answer with a finger, stylus, or mouse. The host agent asks the question in the normal chat. The paper has pen, eraser, undo, clear, and submit. It has no question bank.

Submit exports a PNG replayed from the stored strokes, plus the stroke JSON. If STUDYWAM_GRADE_URL is set, the server POSTs that payload for later studywam grading. The request sends no credentials.

What was borrowed

The server shell follows excalidraw/excalidraw-mcp (MIT): src/main.ts (stateless Streamable HTTP on /mcp, plus --stdio) and src/server.ts (registerAppTool / registerAppResource, widget calls an app-only tool through callServerTool). scripts/build.mjs follows that repo's build (typecheck, one HTML file, one server bundle). The answer surface is not Excalidraw. That repo pins @modelcontextprotocol/sdk 1.25.2 and @modelcontextprotocol/ext-apps 0.4; this one uses the current split SDK 2 (@modelcontextprotocol/server, client, node, express) and @modelcontextprotocol/ext-apps 2.x, which speak the same MCP Apps ui:// resource.

Ink marks follow Bin-H-17/passpaper (MIT): each stroke is { points, width, eraser }, eraser marks paint white and stay in the list, and the PNG is a replay capped at a 1568px long edge. surfndev/petroglyphs-mcp (MIT) is the handoff shape: a base64 PNG in image plus stroke metadata, returned to the agent as an image.

openninoor/noteful-mcp (MIT) is the reason the agent receives a page image of the handwriting. This repo does not read or write Noteful notebooks, does not use the .noteful container, and does not connect to the Noteful iOS or Mac app.

aimengwang11-collab/studywam src/mcp-widgets/ was the intended grade bridge. That repository returned 404 here, so src/mcp-widgets/grade-client.ts is a placeholder POST in the PassPaper + Petroglyphs shape. Point STUDYWAM_GRADE_URL at studywam when that hook exists.

Related MCP server: claude-draw

Product rules

  • Questions stay in chat.

  • The paper is answers only.

  • open_answer_paper opens a blank sheet and takes no question text.

  • submit_ink_answer is called by the sheet. It returns the PNG and, when configured, forwards the ink.

Run locally

Node.js 20 or newer.

npm i
npm run dev

The MCP endpoint is http://localhost:3001/mcp. http://localhost:3001/preview opens the sheet without a host (submit needs the host). npm run build writes dist/index.js and dist/mcp-app.html. npm start runs the built HTTP server. npm run start:stdio is the desktop stdio entry.

PORT defaults to 3001.

Public HTTPS

Claude web and ChatGPT connect to the Cloudflare Worker. excalidraw-mcp deploys to Vercel and has no Workers config, so this uses the same workers.dev account as foldscape and studywam. Express stays the local Node process. The Worker (src/worker.ts) is a fetch handler around the SDK's web-standard Streamable HTTP transport and the same tools, ui:// resource, and ink sheet.

Route

URL

MCP

https://answer-paper-mcp.aimengwang11.workers.dev/mcp

Preview

https://answer-paper-mcp.aimengwang11.workers.dev/preview

Health

https://answer-paper-mcp.aimengwang11.workers.dev/health

npm run deploy

npm run dev:worker serves the Worker locally after a build. npm run build still writes the Node bundle. The stdio entry is unchanged.

The grade URL is optional. Leave it unset and submit still succeeds. To forward ink, set a Worker secret (the value is not committed):

npx wrangler secret put STUDYWAM_GRADE_URL

Local Worker dev reads that name from .dev.vars, which is gitignored.

Connect a host

Do not put credentials in these snippets.

Claude Desktop, after npm run build:

{
  "mcpServers": {
    "ink-answer-paper": {
      "command": "node",
      "args": ["ABSOLUTE_PATH/dist/index.js", "--stdio"],
      "env": {
        "STUDYWAM_GRADE_URL": "https://YOUR_STUDYWAM_HOST/grade"
      }
    }
  }
}

Claude web, Claude Desktop remote, and ChatGPT (Apps / developer mode) use the public Worker. Paste the URL, or use this connector JSON:

{
  "mcpServers": {
    "ink-answer-paper": {
      "type": "http",
      "url": "https://answer-paper-mcp.aimengwang11.workers.dev/mcp"
    }
  }
}

Hosts that only accept a URL field can drop type:

{
  "mcpServers": {
    "ink-answer-paper": {
      "url": "https://answer-paper-mcp.aimengwang11.workers.dev/mcp"
    }
  }
}

There is no OAuth on this endpoint. The sheet is the same MCP App as the local server: questions stay in chat, the paper is answers only, and hosts that support MCP Apps render ui://ink-answer-paper/mcp-app.html. Grok Bot can keep using npm run start:stdio.

Layout

  • src/main.ts — local HTTP and stdio entry, from the Excalidraw MCP App server.

  • src/worker.ts — Cloudflare Workers fetch entry for the public /mcp and /preview routes.

  • src/http.ts — Streamable HTTP fetch handler shared with the Worker.

  • src/server.ts — tool and UI resource registration.

  • src/mcp-app.html / src/mcp-app.ts — the ink pad. The build inlines the script into dist/mcp-app.html and src/generated/paper-html.ts (gitignored).

  • src/mcp-widgets/grade-client.ts — studywam POST placeholder.

  • wrangler.jsonc — Workers config. STUDYWAM_GRADE_URL is a secret, not a var in this file.

Grade payload

STUDYWAM_GRADE_URL=https://YOUR_STUDYWAM_HOST/grade npm run dev

Unset URL: submit still succeeds and says grading is not configured. Set URL: one JSON POST, http or https, no userinfo, no Authorization header, redirects refused, 10 second timeout. A grading failure keeps the captured ink.

{
  "source": "ink-answer-paper",
  "widget": "ink-answer-paper",
  "action": "grade",
  "submittedAt": "2026-01-01T00:00:00.000Z",
  "mimeType": "image/png",
  "image": "<base64 PNG>",
  "width": 800,
  "height": 600,
  "strokeCount": 1,
  "strokes": [
    { "points": [{ "x": 10, "y": 12 }], "width": 3, "eraser": false }
  ]
}

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    D
    maintenance
    Enables collecting contextual user input through a dedicated Electron window interface. Supports drawable image input and other input types, allowing MCP clients to request interactive user submissions.
    1
    7 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude Code to request and read hand-drawn sketches or annotations on a persistent canvas displayed on local or networked devices.
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables non-multimodal AI models to play Pictionary by turning drawings into structured SVG paths and ASCII grids instead of images. Exposes tools to start a round with an answer and strokes, view the current drawing without spoiling the answer, and submit guesses.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables LLM clients to create hand-drawn study-notes style graphics, including charts, concept maps, mind maps, timelines, sketch notes, and 2×2 matrices, as PNG images via MCP.
    1
    MIT