Managing content over MCP
MCP is a standard way for AI agents to use tools. Every njin site has an MCP endpoint at /mcp, through which an agent such as Claude can read and edit your content. The agent works through tools, and every tool follows the same permissions as the REST API, so an agent can do only what you allow.
For example, once connected you can ask an agent to "write three draft posts about our new product and attach the images I uploaded", or to "change the footer text".
Connecting an agent
The address is your site's address followed by /mcp:
https://example.com/mcp
http://localhost:3000/mcpAdd that address as a remote MCP server in your agent or client. With Claude Code, for example:
claude mcp add --transport http mysite https://example.com/mcpMost clients then handle sign-in themselves:
- The client calls
/mcpand is told it needs to sign in. njin answers401and points to its sign-in details. - The client registers itself with njin and opens the njin sign-in page in your browser.
- You sign in with your normal njin account and choose what the client may do.
- The client receives its own token, limited to what you chose. Nobody pastes a token anywhere.
You can see and revoke each connection at any time. See Connected apps.
A site on your own computer
http://localhost:3000/mcp can be reached only by clients running on the same computer. An agent that runs in the cloud cannot reach localhost. To use one, give your site a public HTTPS address.
Setting the public address
njin publishes its sign-in details with the address a client used to reach it. When the site sits behind a proxy that changes the host, set publicUrl in config.ts so the address is exact:
export default defineConfig({
publicUrl: "https://example.com",
});Which clients are accepted
Sign-in needs a callback address that njin trusts, so that no unknown program can receive a sign-in. These are accepted out of the box:
- Claude (
claude.aiandclaude.com) - ChatGPT
- Cursor
- VS Code
- Any program on your own computer that uses a loopback address (
localhostor127.0.0.1), which covers command-line clients
For another client, add its callback address to config.ts. An entry that ends in * matches any path below it:
export default defineConfig({
mcp: {
redirectUris: ["https://agent.example.com/oauth/callback", "https://app.example.com/oauth/*"],
},
});Add only the clients you trust: the callback is where the sign-in result is sent.
With a personal token
A client that lets you set a request header can skip the sign-in and use a personal token. Create one in the admin panel or with POST /api/token, and send it as Authorization: Bearer <token>. See Users and tokens. /mcp accepts personal and OAuth tokens, not a signed-in session.
The built-in tools
An agent is told to start with list_models, which returns every model and settings group with its schema, so it knows what it can work with.
| Tools | What they do |
|---|---|
list_models |
List the models and vars groups, with their schemas |
read_records, get_record |
List records with search, filters, sorting and pagination. Get one record with its relations expanded |
create_record, update_record, delete_record |
Create, change and delete records. An update changes only the fields it sends |
publish_record, unpublish_record, discard_changes |
The draft workflow, for models with draftable |
remove_locale |
Delete one language of a record, for models with i18n |
get_vars, update_vars |
Read and change a settings group |
publish_vars, unpublish_vars, discard_vars |
The draft workflow, for vars groups with draftable |
create_upload_url, check_upload |
Add files to the site. See below |
list_files, get_file, delete_file |
Look at and delete uploaded files |
You can add your own. See Custom MCP tools.
How fields are written
The tools follow the same rules as the API:
- A relation or file field takes the id of the related record, as a plain string. Never an object.
update_recordandupdate_varschange only the fields they send.- A localized field is an object keyed by language:
{ "en": "About", "id": "Tentang" }. - A validation error names the field, and the agent can fix it and try again.
Permissions
Every agent sees the same list of tools, but each call is checked against the permissions of the token. Without permission, the call returns a Forbidden error, which the agent can read. A token that was approved only for post:read and post:create can create posts, but publishing or deleting one fails.
See Tokens and scopes.
Uploading files
A file cannot be sent through a tool call, since the bytes would flood the conversation. Instead, create_upload_url returns a short-lived address, and the file travels outside the conversation:
- The agent calls
create_upload_url. - The agent uploads the file to that address, for example with
curl -F [email protected] <url>. If it cannot reach the address, it gives the address to you, and you open it in a browser and drop the file on it. - The agent calls
check_uploadand gets the ids of the files that arrived. - The agent writes those ids into a
file()field.
An upload address works for 10 minutes, accepts up to 10 files, and each file can be up to 10 MB. Only these file types are accepted:
jpg, jpeg, png, gif, webp, avif, bmp, ico, pdf, txt, csv, md, doc, docx, xls, xlsx, ppt, pptx, zip, mp3, wav, ogg, mp4, webm, mov, woff and woff2.
This list is stricter than the one for POST /api/file. Web pages and scripts (html, js, xml, svg) are not accepted over MCP.
What gets logged
Every tool call is written to the log at info level with the name of the token, the tool, the model or group and the record id. Use it to see what an agent has done.
Errors
An error inside a tool is returned to the agent as an error result with a message, not as a failure of the connection. A tool call with arguments of the wrong type is rejected before it runs, with a message that names the argument.