colab_read_file refuses a file whose content is over 1 MiB with "file exceeds 1 MiB; use Python to read a slice". a model that gets this has no size, no call to make, and no hint that base64 lowers the limit, so it has to work the slicing out on its own. one agent hit it reading a 3 MB file in 786432-byte chunks: each chunk's base64 came to exactly 1 MiB, every read failed, and its loop took the error text for file data. this pull request has two commits.
say how to read a file over 1 MiB. the error now gives the file's size and the limit for the format, and the tool description and readme say how to read a bigger file. the phrase "exceeds 1 MiB" is kept.
offset and length.colab_read_file takes offset and length, in bytes, and returns a slice:
{ path, format, size, offset, length, next_offset, content }
next_offset is where the next slice starts and is null at the end of the file, so a client reads a file with a loop and does not need to run python for it. a base64 slice holds at most 786432 bytes, since 1 MiB of base64 is that many file bytes, and a text slice at most 1 MiB. a text slice is never cut inside a multi-byte character: it stops before one and next_offset says where to go on. an offset inside a character, past the end of the file, or a length over the limit is an error that says so. with neither argument the tool behaves as before, and the oversize error now points at offset and length.
a file over about 6 MB still cannot be fetched this way, because jupyter sends it in one response and colab.js cuts responses off at 8 MiB. that error used to say only "colab response exceeded the 8 MiB limit"; it now says why and gives a colab_execute call that reads a slice from the kernel:
import base64; f = open(PATH, "rb"); f.seek(OFFSET); print(base64.b64encode(f.read(600000)).decode())
tests: the over-1-MiB test checks the size and the hint, a file that fits as text but not as base64 is covered, and there are new cases for slices of a 1,000,000-byte binary file that add up to the file, text slices on character boundaries, the bad ranges, the 8 MiB message and the new argument checks. npm test (85 tests), npm run check and prettier --check . pass.
@okami.mompushed 2 commits to ⎇ read-file-oversize-hintv0+204−53 files
58 unmodified lines
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
58 unmodified lines
all tools advertise `readOnlyHint: true` by convention, but they can execute code,
modify files, and allocate paid compute. stop runtimes when you're done; closing
the mcp client doesn't stop them.
## large files
`colab_read_file` returns at most 1 MiB of content per call, and base64 grows by a third, so a
binary file comes back at most 786432 bytes at a time. pass `offset` and `length` (in bytes) to
read a bigger file in slices; each answer has `size`, `length` and `next_offset`, which is where
the next slice starts and `null` at the end of the file. a text slice is never cut inside a
multi-byte character, so it can be shorter than `length`.
jupyter sends a file in one response and colab-mcp caps responses at 8 MiB, so a file over about
6 MB cannot be fetched this way. read slices of it with `colab_execute`:
```python
import base64
f = open(path, 'rb')
f.seek(offset)
print(base64.b64encode(f.read(600000)).decode())
```
advance `offset` by 600000 for each call and decode the base64 on your side. the errors for an
oversized file say all of this, with the file's size.
'Read a runtime file, up to 1 MiB of returned content. Use base64 for binary files. Use Python for larger files.',
'Read a runtime file, up to 1 MiB of returned content. Use base64 for binary files; it grows by a third, so one call returns at most 786432 file bytes. For a larger file pass offset and length (bytes) to read it in slices; next_offset says where the next slice starts. A file over about 6 MB cannot be fetched this way: the error says how to read it with colab_execute.',
{
id,
path,
format,
offset: z
.number()
.int()
.min(0)
.optional()
.describe('byte offset to start at; with or without length, reads a slice of the file'),
length: z
.number()
.int()
.min(1)
.max(MIB)
.optional()
.describe('bytes to read; at most 1048576 as text and 786432 as base64'),
},
async (args, signal) => {
const data = await colab.files(args, signal);
async ({ offset, length, ...args }, signal) => {
const data = await colab.files(args, signal).catch(tooLarge);
if (data.type !== 'file')
throw new Error('path is not a regular file; use colab_execute for notebooks');
if (typeof data.content !== 'string')
throw new Error('file response did not contain text or base64');
if (Buffer.byteLength(data.content) > MIB)
throw new Error('file exceeds 1 MiB; use Python to read a slice');