plsreadme_share_file
Transform a local markdown file into a shareable web link. Uploads the file, returns a permanent URL, and updates any existing link for the same file.
Instructions
Share a local markdown file as a clean, readable web link on plsreadme.com.
Reads the file, uploads it, and returns a permanent shareable URL. If the file was previously shared, updates the existing link instead of creating a new one.
Tracks links in a local .plsreadme file for future edits and deletes.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Path to the markdown file to share (relative or absolute). |
Implementation Reference
- packages/mcp/src/index.ts:315-365 (handler)The main handler function for the 'plsreadme_share_file' tool. It reads a local markdown file, checks for existing records to update, otherwise creates a new share, and saves the record locally.
async ({ file_path }) => { const absolutePath = resolve(process.cwd(), file_path); let markdown: string; try { markdown = readFileSync(absolutePath, 'utf-8'); } catch (err) { const code = (err as NodeJS.ErrnoException).code; if (code === 'ENOENT') return formatError(`File not found: ${file_path}\nTried: ${absolutePath}`); if (code === 'EACCES') return formatError(`Permission denied: ${file_path}`); return formatError(`Could not read file: ${(err as Error).message}`); } if (markdown.length > MAX_FILE_SIZE) return formatError(`File too large (${Math.round(markdown.length / 1024)}KB). Max ${MAX_FILE_SIZE / 1024}KB.`); if (markdown.trim().length === 0) return formatError(`File is empty: ${file_path}`); try { // Check if already shared — update instead of creating new const existing = getRecordBySource(file_path) || getRecordBySource(absolutePath); if (existing) { await apiUpdate(existing.id, existing.admin_token, markdown); const title = extractTitle(markdown) || basename(file_path, '.md'); existing.title = title; saveRecord(existing); return formatSuccess(title, existing.url, existing.raw_url, '♻️ Updated existing link (same URL).'); } const result = await apiCreate(markdown); const title = extractTitle(markdown) || basename(file_path, '.md'); saveRecord({ id: result.id, url: result.url, raw_url: result.raw_url, admin_token: result.admin_token, title, source: file_path, created_at: new Date().toISOString(), }); const gitWarn = checkGitignore(); return formatSuccess( title, result.url, result.raw_url, gitWarn || undefined ); } catch (err) { return formatError((err as Error).message); } } - packages/mcp/src/index.ts:297-366 (registration)Registration of the 'plsreadme_share_file' tool on the MCP server via server.tool(), including description, schema (file_path parameter), and metadata (title, hints).
// Tool: Share a file server.tool( 'plsreadme_share_file', `Share a local markdown file as a clean, readable web link on plsreadme.com. Reads the file, uploads it, and returns a permanent shareable URL. If the file was previously shared, updates the existing link instead of creating a new one. Tracks links in a local .plsreadme file for future edits and deletes.`, { file_path: z.string().describe('Path to the markdown file to share (relative or absolute).'), }, { title: 'Share Markdown File', readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, async ({ file_path }) => { const absolutePath = resolve(process.cwd(), file_path); let markdown: string; try { markdown = readFileSync(absolutePath, 'utf-8'); } catch (err) { const code = (err as NodeJS.ErrnoException).code; if (code === 'ENOENT') return formatError(`File not found: ${file_path}\nTried: ${absolutePath}`); if (code === 'EACCES') return formatError(`Permission denied: ${file_path}`); return formatError(`Could not read file: ${(err as Error).message}`); } if (markdown.length > MAX_FILE_SIZE) return formatError(`File too large (${Math.round(markdown.length / 1024)}KB). Max ${MAX_FILE_SIZE / 1024}KB.`); if (markdown.trim().length === 0) return formatError(`File is empty: ${file_path}`); try { // Check if already shared — update instead of creating new const existing = getRecordBySource(file_path) || getRecordBySource(absolutePath); if (existing) { await apiUpdate(existing.id, existing.admin_token, markdown); const title = extractTitle(markdown) || basename(file_path, '.md'); existing.title = title; saveRecord(existing); return formatSuccess(title, existing.url, existing.raw_url, '♻️ Updated existing link (same URL).'); } const result = await apiCreate(markdown); const title = extractTitle(markdown) || basename(file_path, '.md'); saveRecord({ id: result.id, url: result.url, raw_url: result.raw_url, admin_token: result.admin_token, title, source: file_path, created_at: new Date().toISOString(), }); const gitWarn = checkGitignore(); return formatSuccess( title, result.url, result.raw_url, gitWarn || undefined ); } catch (err) { return formatError((err as Error).message); } } ); - packages/mcp/src/index.ts:305-307 (schema)Input schema for the tool: file_path (string) describing the path to the markdown file to share.
{ file_path: z.string().describe('Path to the markdown file to share (relative or absolute).'), }, - packages/mcp/src/index.ts:104-109 (helper)getRecordBySource() - finds an existing record by source file path, used to determine if we should update instead of create.
function getRecordBySource(source: string): DocRecord | undefined { const abs = resolve(process.cwd(), source); return loadRecords(findRecordFile()).find( (r) => r.source === source || r.source === abs ); } - packages/mcp/src/index.ts:173-215 (helper)API helpers: apiCreate() and apiUpdate() - functions that call the plsreadme.com API to create or update shared documents.
async function apiCreate(markdown: string): Promise<CreateResponse> { const auth = getLocalAuthState(); if (auth.mode === 'missing') { throw new Error(auth.summary); } const response = await fetch(PLSREADME_API, { method: 'POST', headers: { 'Content-Type': 'application/json', ...(auth.apiKey ? { Authorization: `Bearer ${auth.apiKey}` } : {}), }, body: JSON.stringify({ markdown }), }); if (!response.ok) { const body = await response.text().catch(() => response.statusText); if (response.status === 401 && auth.mode === 'api_key') { throw new Error(`Personal API key rejected (HTTP 401). Rotate the key from your plsreadme account page and update ${PLSREADME_API_KEY_ENV}.`); } if (response.status === 413) throw new Error(`Content too large (max ~200KB). ${body}`); if (response.status >= 500) throw new Error(`plsreadme.com unavailable (HTTP ${response.status}). Try again.`); throw new Error(`Upload failed (HTTP ${response.status}): ${body}`); } return (await response.json()) as CreateResponse; } async function apiUpdate(id: string, token: string, markdown: string): Promise<void> { const response = await fetch(`${PLSREADME_VIEW}/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ markdown }), }); if (!response.ok) { const body = await response.text().catch(() => response.statusText); throw new Error(`Update failed (HTTP ${response.status}): ${body}`); } }