Back to blog
Headless CMS 11 min read 12 views

Build a solid blogging platform

Create blog articles with Garchi CMS data items three ways: in the dashboard, through an AI agent over MCP, or both. Then render them in Next.js.

Aditya Kadam Garchi CMS

Your site is live, and now someone wants to publish articles on it without touching the code. You need a blog, and you don't want to build one into your codebase post by post.

In Garchi CMS, a blog article is a data item: one record in a collection where every record has the same shape. Title, slug, body, author, date, cover image. You write the article in Garchi, and your site fetches it from the API.

This guide takes you from creating an article in Garchi CMS to rendering it for your reader. 

You'll create it three ways: by hand in the dashboard, through an AI agent over MCP, and with the agent drafting while you edit and publish. Then you'll render it in your app using our Node or PHP SDK or our REST APIs. The blog you're reading runs on this setup. 

Why a blog post is a data item

Garchi stores content in two ways. Pages hold one-off designed screens, like a home page or a pricing page, built from reusable sections. Data items hold collections of similar records: articles, products, documents. A blog is a collection, so each post becomes a data item.

Every article is made of five parts:

Part What it is For example
Space The workspace that holds your content. Every API call targets one. Website, Project A, etc.
Category

A label every data item needs at least one of. Your app filters by it.

You can have multiple categories for a data item.

Blog, Article, AI, Technology, etc.
Base fields The fields every data item comes with

Name, slug, one-line description, rich text body.

The rich text body can be used to insert inline images,
videos, legit iframes, scripts.

Extra details Your own key-value fields, each with a type such as text, date or URL author, published_date
Images Item images, or featured image/s for your article. Cover image

You'll also see price, stock and SKU on every item. Skip them for a blog. Product catalogues use the same data items, so those fields come along.

One rule shapes the rest of this guide: the API serves published items only. In the dashboard, you choose to publish now, save a draft or schedule a time. An AI agent working over MCP can only save drafts, and a person decides when they go live.

The human way: write it in the dashboard

Pick this route when you want to see every field and own every word. You need no code and no AI client.

  1. Sign in and open your space. If you don't have one, create it from the dashboard first. Everything else lives inside it.
  2. Create a category called Blog. Your app uses this category's ID to fetch articles, so every post needs it. You can also create multiple categories to attach to your blog article.
  3. Go to Content, then Data Items, and click Add New Item.
  4. Fill in the base fields. Name is the article title. Slug becomes the URL, so keep it short, for example writing-my-first-blog. The one-line description works as your meta description and the summary on blog cards. The detailed description is the article body, written in the rich text editor.
  5. Paste or drag images into the body. Garchi accepts JPEG, PNG and WebP up to 10 MB, uploads each one to your space assets, saves it as WebP scaled to fit 2000 × 2000 pixels, and links it from the body.
  6. Click Add extra details under the item name. Add author as text and published_date as a date, using Add New for each, then save. You can add additional details as well under extra details.
  7. Add a cover image through Manage, then Add Images.
  8. Publish now, save a draft, or schedule it. 

Your frontend reads the step 6 keys by name. Write publish_date on one post and published_date on the rest, and that one post shows up on your site with no date. Pick the keys once and reuse them on every article.

Doing it by hand gives you full control. It also gets slow when you publish often, and that's the work an agent can take off you.

The agent way: let an AI agent create it over MCP

Garchi has a built-in MCP server. MCP is the open standard that lets AI tools such as Claude, ChatGPT, Cursor and Claude Code use other software through a fixed set of actions. Once you connect it, you describe the article and the agent creates the data item, fills in the extra details and hands it back to you as a draft.

Connect once

The server URL is https://garchi.co.uk/mcp-oauth. You sign in with OAuth and approve the connection in your browser, so you never paste an API key into your AI client.

 

You can visit this link to see how you can install the MCP connector for several AI clients

If you'd rather skip the setup, give your agent garchi.co.uk/ai-agent-mcp-use and ask it to set Garchi up. We wrote that page for agents. It covers connecting, installing the Garchi skills and the content model, so you don't have to explain any of it.

Ask for the article

Name the space, the category and the fields you use:

In my Website space, create a blog article in the Blog category titled "My first article". Use the slug my-first-article. Write a one-line description under 160 characters. Add extra details: author = your name, published_date = today. Generate a cover image.

What the agent can't do

No MCP tool publishes on the spot. The agent finishes by telling you which item it created and that the draft is waiting in your dashboard. It also can't create a space or delete a data item. Those stay with you.

There is one exception to the draft rule. If you ask the agent to set a scheduled publish time, Garchi publishes the item at that time. Only ask for a schedule once you've read the content.

The mixed approach: the agent drafts, you decide

I recommend this setup for most teams. The agent handles the repetitive work and you keep the judgement calls.

Task Who does it Why
First draft of the body Agent It's fast and follows your field conventions
One-liner and extra details Agent Tedious by hand, easy for an agent to keep consistent
Cover image Agent first, then you if needed An agent can generate an image but can't upload your own photo
Facts and voice You, in the dashboard The agent doesn't know what you'd never say
Slug and category You A wrong slug turns into a broken link later
Publish or schedule You It's best you keep control of publishing it live

In practice: you ask the agent for a draft, open it in the dashboard, refine it so that it sounds like your creativity, swap the cover through Manage, then Add Images if you have a better one, and publish.

You can run it the other way round. Write rough notes into a draft yourself, then ask the agent to tighten the body, write the one-liner and add the missing details. The agent sends only the fields you ask it to change, so your title and slug stay as you left them.

Garchi keeps a restore point for every change for 30 days, labelled with who made it, so you can roll back an agent's edit in one click. 

Render the articles on your site

Whoever wrote the article, your app reads it the same way: from the server, over the REST API. The example below uses the Next.js App Router and the Garchi Node SDK. Starting from an empty folder? Run npx @lumenharbor/garchi-starter-kit -k next to scaffold a project with the SDK and client already set up. Laravel projects can use the PHP SDK, and any other stack can call the REST API.

1. Install the SDK and add your keys

Garchi CMS starter kits already contain the Garchi SDK and required packages to get started with your project. But in case you are starting from scratch or integrating it into your own project, then it's best to install the respective Garchi CMS SDK (Node or PHP).

Below is an example of installing a Node SDK and the sanitize-html package to avoid XSS attacks.

npm install @garchicms/garchi-node-sdk sanitize-html

Then add three values to .env.local:

GARCHI_API_KEY=
GARCHI_SPACE_UID=
GARCHI_BLOG_CATEGORY_ID=

Generate the API key from your Garchi dashboard: click your profile icon in the top right and open API keys. The key belongs to your account and covers every space you own. Keep it on the server. Never give it a NEXT_PUBLIC_ prefix, and never call the Garchi API from the browser.

2. Create one Garchi client

// lib/garchi.ts
import "server-only";
import GarchiCMS, { GarchiItem, GarchiItemAPIResponse } from "@garchicms/garchi-node-sdk";

export const garchi = new GarchiCMS({ api_key: process.env.GARCHI_API_KEY });

const BLOG_CATEGORY_ID = Number(process.env.GARCHI_BLOG_CATEGORY_ID);

export async function getPosts(page = 1) { return (await garchi.compoundQuery.query( { dataset: "items", fields: ["categories"], conditions: ["eq"], values: [BLOG_CATEGORY_ID] }, { page, size: 9, order_key: "meta.published_date", order_by: "desc" } )) as GarchiItemAPIResponse; }

export async function getPost(slug: string) { try { return await garchi.dataItem.get({ item: slug }); } catch { return null; } }

// item_meta arrives as an array of { key, value, type }. Flatten it once. export function meta(item: GarchiItem): Record<string, string> { return Object.fromEntries((item.item_meta ?? []).map((m) => [m.key, m.value])); }

Look at order_key: "meta.published_date". You can sort articles by any extra detail key, which is another reason to keep those keys identical across posts.

3. The blog index

// app/blog/page.tsx
import Link from "next/link";
import { getPosts, meta } from "@/lib/garchi";

export const revalidate = 600;

export default async function BlogPage() { const posts = await getPosts();

return ( <main> <h1>Blog</h1> {posts.data.map((post) => { const m = meta(post); return ( <article key={post.item_id}> <Link href={/blog/${post.slug}}> <h2>{post.name}</h2> </Link> <p>{post.one_liner}</p> <small>{m.author} · {m.published_date}</small> </article> ); })} </main> ); }

4. The article page

// app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import sanitizeHtml from "sanitize-html";
import { getPost, meta } from "@/lib/garchi";

export const revalidate = 3600;

type Props = { params: Promise<{ slug: string }> };

export async function generateMetadata({ params }: Props): Promise<Metadata> { const post = await getPost((await params).slug); if (!post) return {}; return { title: post.name, description: post.one_liner, openGraph: { images: post.main_image ? [post.main_image] : [] }, }; }

export default async function PostPage({ params }: Props) { const post = await getPost((await params).slug); if (!post?.item_id) notFound();

const m = meta(post); const body = sanitizeHtml(post.description ?? "", { allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]), });

return ( <article> {post.main_image && <img src={post.main_image} alt={post.name} />} <h1>{post.name}</h1> <p>By {m.author} · {m.published_date}</p> <div dangerouslySetInnerHTML={{ __html: body }} /> </article> ); }

The body comes back as HTML. Sanitise it before you render it, whether a person or an agent wrote it.

If an article doesn't appear

Check that you published it before you debug any code. The API returns published items only, so your site can't see a fresh agent draft. Publish it in the dashboard, wait for the revalidate window to pass, and reload.

Or let the agent write this code too

The agent that drafts your articles can also set up the rendering. Install the Garchi skills with npx skills add lumenharbor/garchi-cms-skills, then ask it to add a blog to your app. The rendering skill already knows the patterns above, including server-only keys and HTML sanitising, so you review its changes instead of writing them.

Outro

The main advantage of creativity is that there is no limit. Personally, I like the AI agent and Human method. Agents can write a draft, scaffold all the content in Garchi CMS and write the code, and humans can be the decision maker before it goes live.
The article ends up as the same data item, your site reads it the same way, and nothing reaches your readers until someone on your team publishes it.

Enjoyed this article?

Get the next one in your inbox, with new Garchi features and practical ideas for running content operations with your team and AI agents. No spam, and you can unsubscribe at any time.

We only use your email to send the newsletter. Read our Privacy Policy.