Custom Agents
Use the payload-markdown agent operations in your own chat, dashboard or automation without MCP.
Custom Agents
The MCP tools are thin wrappers around plain server functions. Use the functions directly to build an in-admin chat, a scheduled content job, or an agent on any LLM SDK, with the same validation, draft and access behavior.
The Operations
1import {2 getMarkdownGuide,3 publishMarkdown,4 readMarkdownDocuments,5 validateMarkdown,6 writeMarkdown,7} from '@valkyrianlabs/payload-markdown/mcp'
| Function | MCP tool | Returns |
|---|---|---|
getMarkdownGuide({ payload, collection? }) | markdownGuide | Guide Markdown string. |
readMarkdownDocuments({ req, collection, id | search | where }) | markdownRead | { docs, totalDocs } |
validateMarkdown(markdown, { payload, collection?, scope? }) | markdownValidate | { ok, counts, diagnostics, errors, headings } |
writeMarkdown({ req, collection, id, edits, … }) | markdownWrite | { saved, status, edits, adminUrl, … } |
publishMarkdown({ req, collection, id }) | markdownPublish | { saved, status, … } |
The document operations take a PayloadRequest with a user and always run with overrideAccess: false, so they act exactly as that user could in the admin. They throw MarkdownAgentError with a code (see error codes).
Example: A Server Endpoint
A Payload endpoint that applies an agent's edits for the logged-in user:
1import type { Endpoint } from 'payload'2 3import { MarkdownAgentError, writeMarkdown } from '@valkyrianlabs/payload-markdown/mcp'4 5export const applyAgentEdits: Endpoint = {6 path: '/agent/markdown',7 method: 'post',8 handler: async (req) => {9 const { collection, edits, id, ifUpdatedAt } = await req.json?.()10 11 try {12 const result = await writeMarkdown({ collection, edits, id, ifUpdatedAt, req })13 return Response.json(result)14 } catch (error) {15 if (error instanceof MarkdownAgentError)16 return Response.json({ code: error.code, details: error.details, message: error.message }, { status: 400 })17 throw error18 }19 },20}
Example: Tools For An LLM
Give your model the guide as context and expose read, validate and write as tools. A minimal loop with any SDK:
1const guide = getMarkdownGuide({ collection: 'pages', payload: req.payload })2 3const tools = {4 read: (args) => readMarkdownDocuments({ ...args, req }),5 validate: (args) => validateMarkdown(args.markdown, { collection: 'pages', payload: req.payload, scope: args.scope }),6 write: (args) => writeMarkdown({ ...args, req }),7}
Keep publish out of the model's tools and publish from your UI after review, or call publishMarkdown only on an explicit user action.
Building Blocks
For lower-level work the export also includes:
collectMarkdownTargets(fields, data, payload): markdown targets and blocks outlines of any document data.describeMarkdownLocations(fields, payload): where markdown can live in a collection or global config.isMarkdownField(field): detects fields created bymarkdownField().MARKDOWN_GUIDE_EXAMPLES: the guide's examples, each validated in the package tests.