overleaf-forge 2.7.1 → 2.7.3

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.
package/README.md CHANGED
@@ -10,6 +10,27 @@ A [Model Context Protocol](https://modelcontextprotocol.io) server that lets an
10
10
 
11
11
  Editing a LaTeX project through an AI normally means one of two bad options: paste files back and forth by hand, or let the model overwrite whole files and hope it didn't clobber an edit you made in the browser. This server removes both. It treats Overleaf's git remote as the source of truth and gives the model **anchored edits** (replace an exact string, refuse if it moved), a **conflict gate** (a stale or concurrent change is detected, never silently overwritten), and a **build verdict** (compile from scratch, PASS only on zero errors and zero undefined references), so an editing session is safe to run unattended and provable when it's done.
12
12
 
13
+ ## Token economy
14
+
15
+ Safety is one motivation; keeping a large document out of the model's context window is the other, and it drove most of the tool design. A 50 KB chapter is about 12K to 13K tokens, so the cost of a naive workflow is dominated by moving that whole file in and out.
16
+
17
+ Rough token cost per operation on such a chapter, and the cut each tool buys:
18
+
19
+ | Operation (on a ~50 KB chapter) | Whole-file workflow | overleaf-forge | Reduction |
20
+ | --- | --- | --- | --- |
21
+ | One surgical edit | ~25K (read + write the file) | ~0.15K (`edit_file`) | ~99% |
22
+ | A dozen edits (one revision pass) | ~170K | ~3K | ~98% |
23
+ | One compile check | ~1.5K (raw `latexmk` log) | ~0.02K (`verify_build` verdict) | ~99% |
24
+ | Locating a passage | ~13K (read the whole file) | ~2K (`get_section_content` / `search_text`) | ~85% |
25
+
26
+ Figures are order-of-magnitude, for a chapter this size; the absolute numbers scale with file size, the percentages roughly hold.
27
+
28
+ - **Anchored edits instead of whole-file rewrites.** Changing one phrase by reading the whole file and writing it back costs roughly 25K tokens per edit: the file into context, then the file back out as the write payload. `edit_file` sends only the old and new strings and returns a one-line confirmation, on the order of 100 tokens. Across a dozen edits to a single chapter that is the difference between roughly 170K tokens and 3K.
29
+ - **A one-line build verdict instead of a raw log.** `verify_build` returns `✓ PASS — 24 pages` rather than the `latexmk` output. A raw log runs to hundreds or thousands of tokens per compile, and a multi-pass log buries the true final state under transient undefined-reference warnings from early passes (the exact trap `verify_build` classifies away by reading the final log). Over a session of repeated compiles that is a few thousand tokens against a few dozen.
30
+ - **Section and grep reads instead of the whole file.** `get_section_content` returns one section and `search_text` returns the matching lines, so locating something costs 1K to 3K tokens rather than the full 13K.
31
+
32
+ For an iterative edit, build, and review loop on a large document the tool traffic runs about an order of magnitude lighter than a read-and-rewrite-the-whole-file approach. The gain is workflow-dependent: a single full-file rewrite is a wash, since `write_file` moves the same bytes either way. It is the repeated, surgical work that compounds, which is exactly the shape of writing and revising a paper.
33
+
13
34
  ## Features
14
35
 
15
36
  - **Surgical, conflict-safe edits**: `edit_file` replaces an exact anchor and refuses if the region changed on Overleaf; non-overlapping concurrent edits auto-merge via git.
@@ -33,14 +54,17 @@ Editing a LaTeX project through an AI normally means one of two bad options: pas
33
54
 
34
55
  ## Install
35
56
 
36
- For most clients the whole install is a few lines of JSON: point the client at the published npm package via `npx`, which fetches and runs it on demand with nothing to clone or update by hand.
57
+ **Recommended: npx.** Nothing to clone, nothing to keep updated by hand. The whole install is a few lines of JSON in your MCP client, plus two values from Overleaf.
58
+
59
+ 1. Get your two values: an Overleaf **git token** (Account Settings → Git Integration → create token) and your **project id** (the `<ID>` in `https://www.overleaf.com/project/<ID>`).
60
+ 2. Add this block to your client's config file (locations in the table below):
37
61
 
38
62
  ```json
39
63
  {
40
64
  "mcpServers": {
41
65
  "overleaf": {
42
66
  "command": "npx",
43
- "args": ["-y", "overleaf-forge"],
67
+ "args": ["-y", "overleaf-forge@latest"],
44
68
  "env": {
45
69
  "OVERLEAF_GIT_TOKEN": "olp_xxxxxxxxxxxxxxxxxxxxxxxx",
46
70
  "OVERLEAF_PROJECT_ID": "0123456789abcdef01234567"
@@ -50,7 +74,17 @@ For most clients the whole install is a few lines of JSON: point the client at t
50
74
  }
51
75
  ```
52
76
 
53
- A token and a project id in that `env` block are the entire setup for a single project, with no config file. This is **env-only mode** (see Configuration for the multi-project path).
77
+ 3. Restart the client (or reload its MCP servers). That's it.
78
+
79
+ `npx` fetches and runs the published package on demand. The token and project id are the entire setup for a single project, with no config file (this is **env-only mode**). `@latest` means each client restart picks up the newest published version automatically; pin `overleaf-forge@2.7.1` instead to freeze a version. For multiple projects, per-project contexts, or the SSA bootstrap, see [Configuration](#configuration).
80
+
81
+ An MCP server is not an app you launch yourself: the client starts it as a subprocess, so "installing" it just means making its command available to the client. The `npx` form above needs no install step. If you would rather have a real command on your `PATH`, install it globally:
82
+
83
+ ```bash
84
+ npm install -g overleaf-forge
85
+ ```
86
+
87
+ and set `"command": "overleaf-forge"` with no `args` (keep the same `env` block). A global install does not auto-update: refresh it yourself with `npm update -g overleaf-forge`. `npx` is recommended precisely because it skips that step.
54
88
 
55
89
  To hack on the server instead, run it from source:
56
90
 
@@ -75,6 +109,20 @@ The `mcpServers` schema is identical across clients; only the file location diff
75
109
 
76
110
  Restart the client (or reload its MCP servers) after editing, so it spawns the server with the new config.
77
111
 
112
+ ## Updating
113
+
114
+ **As a user.** With `overleaf-forge@latest` in your config (the recommended form), restart the client or reload its MCP servers and it fetches the newest published version. If you pinned a version (`overleaf-forge@2.7.1`), change the number. If `npx` seems to keep running an old version, clear its cache with `npx clear-npx-cache` and restart. If you installed globally instead, update with `npm update -g overleaf-forge`.
115
+
116
+ **As the maintainer (publishing a new release).** From the repository:
117
+
118
+ ```bash
119
+ npm version patch # or minor / major; bumps package.json and tags
120
+ npm publish # enter your npm 2FA one-time code when prompted
121
+ git push --follow-tags # push the commit and the version tag
122
+ ```
123
+
124
+ Anyone on `@latest` picks the new version up on their next client restart.
125
+
78
126
  ## Configuration
79
127
 
80
128
  Two modes, smallest first.
@@ -7,7 +7,7 @@ import {
7
7
  ListToolsRequestSchema,
8
8
  } from '@modelcontextprotocol/sdk/types.js';
9
9
  import { readFile, writeFile, access, mkdir, readdir, stat, rm, rename, copyFile } from 'fs/promises';
10
- import { existsSync, realpathSync } from 'fs';
10
+ import { existsSync, realpathSync, readFileSync } from 'fs';
11
11
  import { promisify } from 'util';
12
12
  import { execFile as execFileCallback } from 'child_process';
13
13
  import path from 'path';
@@ -30,6 +30,12 @@ const execFile = promisify(execFileCallback);
30
30
  // cache. Anything a user edits resolves user-copy-first, bundled-default-last.
31
31
  const PACKAGE_DIR = __dirname;
32
32
 
33
+ // Single source of truth for the version: read it from the shipped package.json
34
+ // so `npm version` is the only place a release number changes. Fall back to '0.0.0'
35
+ // if package.json is somehow unreadable (never fatal).
36
+ let PKG_VERSION = '0.0.0';
37
+ try { PKG_VERSION = JSON.parse(readFileSync(path.join(PACKAGE_DIR, 'package.json'), 'utf-8')).version || PKG_VERSION; } catch { /* keep fallback */ }
38
+
33
39
  // Expand a leading ~ to the user's home. Plain join elsewhere assumes absolute.
34
40
  function expandHome(p) {
35
41
  if (!p) return p;
@@ -927,7 +933,7 @@ async function readContext(projectKey, project) {
927
933
 
928
934
  // MCP server
929
935
  const server = new Server(
930
- { name: 'overleaf-forge', version: '2.7.1' },
936
+ { name: 'overleaf-forge', version: PKG_VERSION },
931
937
  { capabilities: { tools: {} } }
932
938
  );
933
939
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "overleaf-forge",
3
- "version": "2.7.1",
3
+ "version": "2.7.3",
4
4
  "description": "MCP server to read, edit, compile, and verify Overleaf/LaTeX projects over git: conflict-safe edits, figure upload, clean-build verification, citation and voice linting.",
5
5
  "type": "module",
6
6
  "main": "overleaf-mcp-server.js",
7
7
  "bin": {
8
- "overleaf-forge": "./overleaf-mcp-server.js"
8
+ "overleaf-forge": "overleaf-mcp-server.js"
9
9
  },
10
10
  "files": [
11
11
  "overleaf-mcp-server.js",