mathpix-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4b82c966d9f5d395fd034f4c76fde15fe299dbf5a7f181e4134e23b7791b43fd
4
+ data.tar.gz: 7d83ad2772cc8f35c8e0ff522a5079fdbf633f3154194e5b942ebff026cfac3a
5
+ SHA512:
6
+ metadata.gz: 8ecbcc1d334fe67f92964cbe85228af711d018a31ab459d43383f23d0215c70f5e642a80a68d1f281a4b674b2f1bf8fd6e3354b7eb7e8bece97b81312d4c17c9
7
+ data.tar.gz: 33b669c9f84353b892a9293c2875bf7317e836b3382a80c5b742f70df9105f6f2c81763ea0505ef22c05adaa6a742af47de5f9495dff1dfc91b6d308821c1510
data/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.0.0] - 2026-06-29
11
+
12
+ First release: a Model Context Protocol server for Mathpix OCR over **stdio** and
13
+ **Streamable HTTP**, with every tool verified end-to-end against the live Mathpix
14
+ API.
15
+
16
+ ### Added
17
+ - Nine MCP tools: `convert_document`, `convert_image`, `convert_strokes`,
18
+ `batch_convert`, `check_document_status`, `search_results`, `get_usage`,
19
+ `get_account_info`, `list_formats`.
20
+ - Document conversion (PDF/DOCX/PPTX) via `/v3/pdf` for remote URLs and local
21
+ files (multipart upload), returning Markdown/HTML.
22
+ - Image OCR via `/v3/text`, handwritten strokes via `/v3/strokes`, and recent
23
+ captures via `/v3/ocr-results`; usage/account identifiers via `/v3/ocr-usage`.
24
+ - File-routed output: OCR results (LaTeX/text/MathML/HTML/bounding-box data) are
25
+ always written to files and returned as a path + short preview + metadata, so
26
+ results never overflow the model context. Destination follows the tool's
27
+ `output_path`/`output_dir`, else `MATHPIX_OUTPUT_DIR`, else the system temp dir.
28
+ - Descriptive API errors that surface Mathpix's `error_info.message` (status and
29
+ details included).
30
+ - Concurrent `batch_convert` (bounded thread pool) and polling that tolerates all
31
+ intermediate Mathpix states.
32
+ - stdio transport (`mathpix-mcp`) and Streamable HTTP transport
33
+ (`mathpix-mcp-http` / `config.ru`) with required bearer-token auth
34
+ (`MATHPIX_MCP_TOKEN`).
35
+ - Configuration via environment variables (documented in the README and
36
+ `.env.example`), including `MATHPIX_OUTPUT_DIR` for the output directory.
37
+ - Docs: README with an env-var reference and per-agent client setup,
38
+ `docs/DEPLOYMENT.md` for HTTP deployment, `MAINTAINING.md` for release/admin,
39
+ and a `Dockerfile`.
40
+ - Tooling/CI: RuboCop + RSpec (`rake`), GitHub Actions CI (rubocop, rspec,
41
+ bundler-audit), Dependabot, and a trusted-publishing release workflow.
42
+
43
+ ### Dependencies
44
+ - Runtime: `base64`, `mcp` (>= 0.9.2), `rack`, `puma` (>= 8.0.2).
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Barton Rhodes
4
+ Copyright (c) 2026 Georgios Douzas
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,403 @@
1
+ # mathpix-mcp
2
+
3
+ A **Model Context Protocol server** for [Mathpix](https://mathpix.com) OCR, over
4
+ **stdio** or **Streamable HTTP** (bearer-token auth). It exposes Mathpix
5
+ conversion as MCP tools so an LLM/agent can turn images and PDF/DOCX/PPTX
6
+ documents into LaTeX and Markdown.
7
+
8
+ ## Tools
9
+
10
+ | Tool | Purpose |
11
+ |------|---------|
12
+ | `convert_document_tool` | PDF/DOCX/PPTX → Markdown/LaTeX/HTML (URL or local path). Saves output to a file and returns a path + preview so it doesn't overflow the model context. |
13
+ | `convert_image_tool` | Image → LaTeX/text/MathML/etc. Result is written to a file (path + preview returned). |
14
+ | `convert_strokes_tool` | Handwritten strokes → LaTeX/text. |
15
+ | `batch_convert_tool` | Multiple images, optionally concurrent (`parallel`, `max_parallel`). |
16
+ | `check_document_status_tool` | Poll an async document conversion. |
17
+ | `search_results_tool` | Search recent captures; full content (when requested) is written to files. |
18
+ | `get_usage_tool` / `get_account_info_tool` | Usage statistics and account identifiers. |
19
+ | `list_formats_tool` | List supported output formats. |
20
+
21
+ > OCR results (LaTeX/text/MathML/etc.) are always written to files rather than
22
+ > returned inline; tools return a file path, a short preview, and metadata. The
23
+ > destination follows the tool's `output_path`/`output_dir` argument, else
24
+ > `MATHPIX_OUTPUT_DIR`, else the system temp dir.
25
+
26
+ ## Requirements
27
+
28
+ - Ruby >= 3.2 (CI runs 3.3 and 3.4)
29
+ - Mathpix API credentials (`MATHPIX_APP_ID`, `MATHPIX_APP_KEY`)
30
+
31
+ ## Install
32
+
33
+ From RubyGems (provides the `mathpix-mcp` / `mathpix-mcp-http` executables):
34
+
35
+ ```bash
36
+ gem install mathpix-mcp
37
+ ```
38
+
39
+ Or straight from GitHub (in a Gemfile):
40
+
41
+ ```ruby
42
+ gem 'mathpix-mcp', git: 'https://github.com/georgedouzas/mathpix-mcp'
43
+ ```
44
+
45
+ Or build locally from a clone:
46
+
47
+ ```bash
48
+ gem build mathpix-mcp.gemspec
49
+ gem install ./mathpix-mcp-*.gem
50
+ ```
51
+
52
+ Or run from a clone with Bundler:
53
+
54
+ ```bash
55
+ bundle install
56
+ cp .env.example .env # add your MATHPIX_APP_ID / MATHPIX_APP_KEY
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ All configuration is via environment variables (loaded from `.env` when launched
62
+ from the project directory, or from the process environment). Copy
63
+ [`.env.example`](.env.example) to `.env` as a starting point.
64
+
65
+ | Variable | Required | Default | Description |
66
+ |----------|----------|---------|-------------|
67
+ | `MATHPIX_APP_ID` | **yes** | — | Mathpix application id. |
68
+ | `MATHPIX_APP_KEY` | **yes** | — | Mathpix application key. |
69
+ | `MATHPIX_OUTPUT_DIR` | no | system temp dir | Where OCR results are written when a tool isn't given an explicit `output_path`/`output_dir`. |
70
+ | `MATHPIX_MAX_FILE_SIZE_MB` | no | `10` | Maximum local file size accepted for upload. |
71
+ | `MATHPIX_HTTPS_ONLY` | no | `true` | Upgrade/enforce HTTPS for remote sources. |
72
+ | `MATHPIX_API_URL` | no | `https://api.mathpix.com/v3` | Mathpix API base URL. |
73
+ | `MATHPIX_TIMEOUT` | no | `30` | Per-request timeout in seconds (1–300). |
74
+ | `MATHPIX_LOG_LEVEL` | no | _(off)_ | Log verbosity to stderr: `DEBUG`/`INFO`/`WARN`/`ERROR`. |
75
+ | `MATHPIX_MCP_TOKEN` | HTTP only | — | Bearer token required by the HTTP transport. |
76
+ | `MATHPIX_MCP_HOST` | no | `127.0.0.1` | HTTP bind host. |
77
+ | `MATHPIX_MCP_PORT` | no | `3000` | HTTP bind port. |
78
+
79
+ ## Run (stdio)
80
+
81
+ ```bash
82
+ mathpix-mcp # if installed as a gem
83
+ # or
84
+ bundle exec mathpix-mcp
85
+ ```
86
+
87
+ It speaks MCP over stdio. Credentials are read from `.env` (when launched from
88
+ the project directory) or the process environment.
89
+
90
+ ## Run (HTTP / Streamable HTTP)
91
+
92
+ The HTTP transport requires a bearer token (`MATHPIX_MCP_TOKEN`) — every request
93
+ must send `Authorization: Bearer <token>`. It binds to `127.0.0.1:3000` by
94
+ default (`MATHPIX_MCP_HOST` / `MATHPIX_MCP_PORT`).
95
+
96
+ ```bash
97
+ export MATHPIX_MCP_TOKEN=$(openssl rand -hex 32)
98
+ mathpix-mcp-http # if installed as a gem
99
+ # or
100
+ bundle exec mathpix-mcp-http
101
+ # or, with a Rack server of your choice:
102
+ bundle exec puma config.ru -b tcp://127.0.0.1:3000
103
+ ```
104
+
105
+ Example request:
106
+
107
+ ```bash
108
+ curl -s http://127.0.0.1:3000/ \
109
+ -H "Authorization: Bearer $MATHPIX_MCP_TOKEN" \
110
+ -H 'Content-Type: application/json' \
111
+ -H 'Accept: application/json, text/event-stream' \
112
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
113
+ ```
114
+
115
+ Don't expose it on a public interface without a TLS-terminating reverse proxy.
116
+
117
+ ## Connect an agent
118
+
119
+ This server speaks MCP over **stdio** (`mathpix-mcp`) and **Streamable HTTP**
120
+ (`mathpix-mcp-http`, bearer-token auth). Replace credentials with your own and
121
+ prefer a real secret for `MATHPIX_MCP_TOKEN` (e.g. `openssl rand -hex 32`).
122
+ Config schemas vary slightly between client versions — check your client's docs
123
+ if a key is rejected. Examples assume the gem is installed (`mathpix-mcp` on
124
+ `PATH`); to run from a clone, use `bundle` as the command with
125
+ `args: ["exec", "mathpix-mcp"]` and set `BUNDLE_GEMFILE` to the project's
126
+ `Gemfile`.
127
+
128
+ ### Claude Code (CLI)
129
+
130
+ **stdio** — keep secrets in the project `.env` and let the launcher `cd` in:
131
+
132
+ ```bash
133
+ claude mcp add mathpix -- \
134
+ bash -lc 'cd /path/to/mathpix-mcp && exec bundle exec mathpix-mcp'
135
+ ```
136
+
137
+ or, if installed as a gem, pass creds inline:
138
+
139
+ ```bash
140
+ claude mcp add mathpix -e MATHPIX_APP_ID=... -e MATHPIX_APP_KEY=... -- mathpix-mcp
141
+ ```
142
+
143
+ **HTTP** — point at a running `mathpix-mcp-http`:
144
+
145
+ ```bash
146
+ claude mcp add --transport http mathpix http://127.0.0.1:3000/ \
147
+ --header "Authorization: Bearer $MATHPIX_MCP_TOKEN"
148
+ ```
149
+
150
+ List/verify: `claude mcp list`.
151
+
152
+ <details>
153
+ <summary><b>Claude Desktop</b></summary>
154
+
155
+ Edit the config file (macOS:
156
+ `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows:
157
+ `%APPDATA%\Claude\claude_desktop_config.json`):
158
+
159
+ ```json
160
+ {
161
+ "mcpServers": {
162
+ "mathpix": {
163
+ "command": "mathpix-mcp",
164
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
165
+ }
166
+ }
167
+ }
168
+ ```
169
+
170
+ Claude Desktop talks to local servers over stdio, so for HTTP bridge with
171
+ [`mcp-remote`](https://www.npmjs.com/package/mcp-remote):
172
+
173
+ ```json
174
+ {
175
+ "mcpServers": {
176
+ "mathpix": {
177
+ "command": "npx",
178
+ "args": ["-y", "mcp-remote", "http://127.0.0.1:3000/",
179
+ "--header", "Authorization: Bearer YOUR_TOKEN"]
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
185
+ Restart Claude Desktop after editing.
186
+ </details>
187
+
188
+ <details>
189
+ <summary><b>Codex (OpenAI Codex CLI)</b></summary>
190
+
191
+ Edit `~/.codex/config.toml`:
192
+
193
+ ```toml
194
+ [mcp_servers.mathpix]
195
+ command = "mathpix-mcp"
196
+ env = { MATHPIX_APP_ID = "your_app_id", MATHPIX_APP_KEY = "your_app_key" }
197
+ ```
198
+
199
+ For HTTP, bridge with `mcp-remote`:
200
+
201
+ ```toml
202
+ [mcp_servers.mathpix]
203
+ command = "npx"
204
+ args = ["-y", "mcp-remote", "http://127.0.0.1:3000/", "--header", "Authorization: Bearer YOUR_TOKEN"]
205
+ ```
206
+ </details>
207
+
208
+ <details>
209
+ <summary><b>Cursor</b></summary>
210
+
211
+ Edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project).
212
+
213
+ ```json
214
+ {
215
+ "mcpServers": {
216
+ "mathpix": {
217
+ "command": "mathpix-mcp",
218
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
219
+ }
220
+ }
221
+ }
222
+ ```
223
+
224
+ HTTP (Cursor supports remote URLs with headers):
225
+
226
+ ```json
227
+ {
228
+ "mcpServers": {
229
+ "mathpix": {
230
+ "url": "http://127.0.0.1:3000/",
231
+ "headers": { "Authorization": "Bearer YOUR_TOKEN" }
232
+ }
233
+ }
234
+ }
235
+ ```
236
+ </details>
237
+
238
+ <details>
239
+ <summary><b>Gemini CLI</b></summary>
240
+
241
+ Edit `~/.gemini/settings.json`:
242
+
243
+ ```json
244
+ {
245
+ "mcpServers": {
246
+ "mathpix": {
247
+ "command": "mathpix-mcp",
248
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
249
+ }
250
+ }
251
+ }
252
+ ```
253
+
254
+ HTTP (Gemini CLI uses `httpUrl` for Streamable HTTP; `url` for SSE):
255
+
256
+ ```json
257
+ {
258
+ "mcpServers": {
259
+ "mathpix": {
260
+ "httpUrl": "http://127.0.0.1:3000/",
261
+ "headers": { "Authorization": "Bearer YOUR_TOKEN" }
262
+ }
263
+ }
264
+ }
265
+ ```
266
+ </details>
267
+
268
+ <details>
269
+ <summary><b>VS Code (GitHub Copilot, agent mode)</b></summary>
270
+
271
+ Create `.vscode/mcp.json` in the workspace (top-level key is `servers`):
272
+
273
+ ```json
274
+ {
275
+ "servers": {
276
+ "mathpix": {
277
+ "type": "stdio",
278
+ "command": "mathpix-mcp",
279
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
280
+ }
281
+ }
282
+ }
283
+ ```
284
+
285
+ HTTP — use `"type": "http"`, `"url": "http://127.0.0.1:3000/"`, and a `headers`
286
+ object with the bearer token.
287
+ </details>
288
+
289
+ <details>
290
+ <summary><b>Windsurf</b></summary>
291
+
292
+ Edit `~/.codeium/windsurf/mcp_config.json`:
293
+
294
+ ```json
295
+ {
296
+ "mcpServers": {
297
+ "mathpix": {
298
+ "command": "mathpix-mcp",
299
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
300
+ }
301
+ }
302
+ }
303
+ ```
304
+
305
+ HTTP uses `serverUrl`:
306
+ `{ "mcpServers": { "mathpix": { "serverUrl": "http://127.0.0.1:3000/" } } }`. If
307
+ your version can't attach the bearer header, use the `mcp-remote` bridge as the
308
+ `command`.
309
+ </details>
310
+
311
+ <details>
312
+ <summary><b>Zed</b></summary>
313
+
314
+ Edit `settings.json` (`Cmd/Ctrl+,`) under `context_servers`:
315
+
316
+ ```json
317
+ {
318
+ "context_servers": {
319
+ "mathpix": {
320
+ "command": {
321
+ "path": "mathpix-mcp",
322
+ "args": [],
323
+ "env": { "MATHPIX_APP_ID": "your_app_id", "MATHPIX_APP_KEY": "your_app_key" }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ ```
329
+ </details>
330
+
331
+ <details>
332
+ <summary><b>Continue, Cline, Goose</b></summary>
333
+
334
+ **Continue** (`~/.continue/config.yaml`):
335
+
336
+ ```yaml
337
+ mcpServers:
338
+ - name: Mathpix
339
+ command: mathpix-mcp
340
+ env:
341
+ MATHPIX_APP_ID: your_app_id
342
+ MATHPIX_APP_KEY: your_app_key
343
+ ```
344
+
345
+ **Cline** (MCP Servers panel → "Configure MCP Servers" →
346
+ `cline_mcp_settings.json`): same `mcpServers` JSON shape as Cursor.
347
+
348
+ **Goose** (`~/.config/goose/config.yaml`):
349
+
350
+ ```yaml
351
+ extensions:
352
+ mathpix:
353
+ enabled: true
354
+ type: stdio
355
+ cmd: mathpix-mcp
356
+ args: []
357
+ envs:
358
+ MATHPIX_APP_ID: your_app_id
359
+ MATHPIX_APP_KEY: your_app_key
360
+ ```
361
+ </details>
362
+
363
+ <details>
364
+ <summary><b>Programmatic (agent SDKs) &amp; any other client</b></summary>
365
+
366
+ For HTTP, point any MCP-capable SDK at `http://<host>:3000/` with an
367
+ `Authorization: Bearer <token>` header — e.g. the Anthropic Claude Agent SDK MCP
368
+ connector, the OpenAI Agents SDK (`MCPServerStreamableHttp`), or LangChain's MCP
369
+ adapters. For stdio, spawn `mathpix-mcp` with `MATHPIX_APP_ID` /
370
+ `MATHPIX_APP_KEY` in its environment.
371
+
372
+ Most clients use one of two shapes: **stdio** (`command` + `args` + `env`) or
373
+ **HTTP** (a URL field — `url`/`httpUrl`/`serverUrl`, name varies — plus
374
+ `headers`). If a stdio-only client can't reach the HTTP server, bridge with
375
+ [`mcp-remote`](https://www.npmjs.com/package/mcp-remote):
376
+
377
+ ```bash
378
+ npx -y mcp-remote http://127.0.0.1:3000/ --header "Authorization: Bearer YOUR_TOKEN"
379
+ ```
380
+ </details>
381
+
382
+ ## Deploy (HTTP)
383
+
384
+ Production deployment — TLS reverse proxy (Caddy/nginx), systemd, Docker /
385
+ docker-compose, and the security checklist — is in
386
+ **[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)**. A `Dockerfile` is included:
387
+
388
+ ```bash
389
+ docker build -t mathpix-mcp .
390
+ docker run --rm -p 3000:3000 \
391
+ -e MATHPIX_APP_ID=... -e MATHPIX_APP_KEY=... \
392
+ -e MATHPIX_MCP_TOKEN=$(openssl rand -hex 32) mathpix-mcp
393
+ ```
394
+
395
+ ## Notes
396
+
397
+ - If Mathpix's backend rejects a malformed PDF (e.g. a `pdftoppm` crash), the
398
+ tool returns a descriptive error; repairing the PDF first
399
+ (`gs -o fixed.pdf -sDEVICE=pdfwrite in.pdf`) usually resolves it.
400
+
401
+ ## License
402
+
403
+ MIT — see [LICENSE](LICENSE).
data/bin/mathpix-mcp ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+
6
+ # Load environment variables from a .env file if one is present (no-op if the
7
+ # dotenv gem or file is missing). Done before configuring Mathpix so MATHPIX_*
8
+ # from .env are available.
9
+ begin
10
+ require 'dotenv/load'
11
+ rescue LoadError
12
+ # dotenv not installed — rely on the process environment
13
+ end
14
+
15
+ require 'mathpix'
16
+ require 'mathpix/mcp'
17
+
18
+ # Configure Mathpix from environment
19
+ Mathpix.configure do |config|
20
+ config.app_id = ENV.fetch('MATHPIX_APP_ID', nil)
21
+ config.app_key = ENV.fetch('MATHPIX_APP_KEY', nil)
22
+
23
+ # Optional configuration
24
+ config.max_file_size_mb = ENV['MATHPIX_MAX_FILE_SIZE_MB']&.to_i || 10
25
+ config.enforce_https = ENV['MATHPIX_HTTPS_ONLY'] != 'false'
26
+
27
+ # Logging
28
+ if ENV['MATHPIX_LOG_LEVEL']
29
+ require 'logger'
30
+ config.logger = Logger.new($stderr)
31
+ config.logger.level = Logger.const_get(ENV['MATHPIX_LOG_LEVEL'].upcase)
32
+ end
33
+ end
34
+
35
+ # Start MCP server on stdio.
36
+ #
37
+ # The Server constructor wires up all 9 tools internally
38
+ # (see Mathpix::MCP::Server#tool_classes), so we just
39
+ # build it and run the stdio transport.
40
+ begin
41
+ Mathpix::MCP::Server.run
42
+ rescue StandardError => e
43
+ warn "Error starting Mathpix MCP server: #{e.message}"
44
+ warn e.backtrace.join("\n")
45
+ exit 1
46
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+
6
+ # Load environment (incl. MATHPIX_* and MATHPIX_MCP_TOKEN) from .env if present.
7
+ begin
8
+ require 'dotenv/load'
9
+ rescue LoadError
10
+ # dotenv not installed — rely on the process environment
11
+ end
12
+
13
+ require 'mathpix'
14
+ require 'mathpix/mcp'
15
+ require 'mathpix/mcp/http_app'
16
+
17
+ Mathpix.configure do |config|
18
+ config.app_id = ENV.fetch('MATHPIX_APP_ID', nil)
19
+ config.app_key = ENV.fetch('MATHPIX_APP_KEY', nil)
20
+ config.max_file_size_mb = ENV['MATHPIX_MAX_FILE_SIZE_MB']&.to_i || 10
21
+ config.enforce_https = ENV['MATHPIX_HTTPS_ONLY'] != 'false'
22
+ end
23
+
24
+ app = Mathpix::MCP::HttpApp.build
25
+ host = ENV.fetch('MATHPIX_MCP_HOST', '127.0.0.1')
26
+ port = Integer(ENV.fetch('MATHPIX_MCP_PORT', '3000'))
27
+
28
+ require 'puma'
29
+ require 'puma/configuration'
30
+ require 'puma/launcher'
31
+
32
+ configuration = Puma::Configuration.new do |c|
33
+ c.app(app)
34
+ c.bind("tcp://#{host}:#{port}")
35
+ c.log_requests(false)
36
+ end
37
+
38
+ warn "Mathpix MCP (Streamable HTTP) listening on http://#{host}:#{port}"
39
+ Puma::Launcher.new(configuration).run
data/config.ru ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rack entrypoint for the Mathpix MCP Streamable HTTP transport.
4
+ # Run with: bundle exec puma config.ru -b tcp://127.0.0.1:3000
5
+ #
6
+ # Requires MATHPIX_APP_ID, MATHPIX_APP_KEY and MATHPIX_MCP_TOKEN in the
7
+ # environment (or a local .env).
8
+
9
+ begin
10
+ require 'dotenv/load'
11
+ rescue LoadError
12
+ nil
13
+ end
14
+
15
+ require 'mathpix'
16
+ require 'mathpix/mcp'
17
+ require 'mathpix/mcp/http_app'
18
+
19
+ Mathpix.configure do |config|
20
+ config.app_id = ENV.fetch('MATHPIX_APP_ID', nil)
21
+ config.app_key = ENV.fetch('MATHPIX_APP_KEY', nil)
22
+ end
23
+
24
+ run Mathpix::MCP::HttpApp.build