discourse_read_post
Retrieve content from a specific post in Discourse forums using its unique post ID to access and display discussion details.
Instructions
Read a specific post.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes |
Implementation Reference
- src/tools/builtin/read_post.ts:16-34 (handler)The async handler function that reads a Discourse post by ID using the site client, formats it with username, date, truncated content, and link, or returns an error.async ({ post_id }, _extra: any) => { try { const { base, client } = ctx.siteState.ensureSelectedSite(); // Prefer raw by asking API for include_raw const data = (await client.getCached(`/posts/${post_id}.json?include_raw=true`, 10000)) as any; const username = data?.username || data?.user_id || "user"; const created = data?.created_at || ""; const raw: string = data?.raw || data?.cooked || ""; const limit = Number.isFinite(ctx.maxReadLength) ? ctx.maxReadLength : 50000; const content = raw.slice(0, limit); const url = data?.topic_slug && data?.topic_id ? `${base}/t/${data.topic_slug}/${data.topic_id}/${data.post_number}` : `${base}/posts/${post_id}`; const text = `Post by @${username} (${created})\n\n${content}${raw.length > content.length ? `\n… (+${raw.length - content.length} more)` : ""}\n\nLink: ${url}`; return { content: [{ type: "text", text }] }; } catch (e: any) { return { content: [{ type: "text", text: `Failed to read post ${post_id}: ${e?.message || String(e)}` }], isError: true }; } }
- src/tools/builtin/read_post.ts:5-7 (schema)Zod input schema requiring a positive integer post_id.const schema = z.object({ post_id: z.number().int().positive(), });
- src/tools/builtin/read_post.ts:4-36 (registration)The registration module that defines and registers the discourse_read_post tool with its schema and handler.export const registerReadPost: RegisterFn = (server, ctx) => { const schema = z.object({ post_id: z.number().int().positive(), }); server.registerTool( "discourse_read_post", { title: "Read Post", description: "Read a specific post.", inputSchema: schema.shape, }, async ({ post_id }, _extra: any) => { try { const { base, client } = ctx.siteState.ensureSelectedSite(); // Prefer raw by asking API for include_raw const data = (await client.getCached(`/posts/${post_id}.json?include_raw=true`, 10000)) as any; const username = data?.username || data?.user_id || "user"; const created = data?.created_at || ""; const raw: string = data?.raw || data?.cooked || ""; const limit = Number.isFinite(ctx.maxReadLength) ? ctx.maxReadLength : 50000; const content = raw.slice(0, limit); const url = data?.topic_slug && data?.topic_id ? `${base}/t/${data.topic_slug}/${data.topic_id}/${data.post_number}` : `${base}/posts/${post_id}`; const text = `Post by @${username} (${created})\n\n${content}${raw.length > content.length ? `\n… (+${raw.length - content.length} more)` : ""}\n\nLink: ${url}`; return { content: [{ type: "text", text }] }; } catch (e: any) { return { content: [{ type: "text", text: `Failed to read post ${post_id}: ${e?.message || String(e)}` }], isError: true }; } } ); };
- src/tools/registry.ts:43-43 (registration)Invocation of the registerReadPost function in the main tools registry.registerReadPost(server, ctx, { allowWrites: false });