---
title: "API · tabnas"
description: "Every endpoint tabnas.dev serves to machines: an OpenAPI 3.1 document, JSON catalogues for versions, packages and error codes, and markdown on any page."
source: "https://tabnas.dev/api/"
---

# The tabnas API

Everything `tabnas.dev` serves to a program, described by an OpenAPI 3.1 document at [`/openapi.json`](https://tabnas.dev/openapi.json) (or [`/openapi.yaml`](https://tabnas.dev/openapi.yaml)). Every operation is a `GET`, none of them needs a key, and none of them is rate limited.

**What this is not:** tabnas does not parse your documents over HTTP. The engine runs in your own process — that is the point of it — and this site publishes the catalogue around it: which versions the documentation describes, what the packages are, every error code the engine can raise, and how to connect an agent over MCP. The one endpoint that executes anything is the hosted MCP server below, and running it locally is still the recommendation.

## Endpoints

| Endpoint | Operation | What it returns |
| --- | --- | --- |
| `GET /llms.txt` | `getLlmsIndex` | The llms.txt site index Start here |
| `GET /llms-full.txt` | `getLlmsFull` | Every documentation page in one file Start here |
| `GET /openapi.json` | `getOpenApiJson` | This document, as JSON Start here |
| `GET /openapi.yaml` | `getOpenApiYaml` | This document, as YAML Start here |
| `GET /versions.json` | `getVersions` | The package versions this documentation describes Catalogues |
| `GET /packages.json` | `getPackages` | The package catalogue Catalogues |
| `GET /errors.json` | `getErrorRegistry` | Every error code the engine and its plugins raise Catalogues |
| `GET /errors/{code}.json` | `getErrorCode` | One error code Catalogues |
| `GET /.well-known/mcp` | `getMcpManifest` | How to connect an agent over MCP MCP |
| `GET /{page}.md` | `getPageMarkdown` | Any documentation page, as markdown Content |

Each operation carries a unique `operationId`, typed parameters and a response schema in [`/openapi.json`](https://tabnas.dev/openapi.json), so a tool that turns an OpenAPI document into callable functions can do so without further description.

## Any page, as markdown

Every page on this site is content-negotiated. Ask for markdown and the same URL answers with markdown instead of HTML — no navigation, no styling, no scripts — and the response carries `Vary: Accept` so a cache keeps the two apart ([acceptmarkdown.com](https://acceptmarkdown.com)).

```
curl -H "Accept: text/markdown" https://tabnas.dev/docs/quickstart
```

The same bytes are at the path plus `.md`, for callers that would rather not set a header — `https://tabnas.dev/docs/quickstart.md`, and `https://tabnas.dev/index.md` for the home page. Each twin opens with a small YAML frontmatter block carrying the page's title, description and canonical URL.

If you want the whole documentation set in one request instead, that is [`/llms-full.txt`](https://tabnas.dev/llms-full.txt); the index of what is here is [`/llms.txt`](https://tabnas.dev/llms.txt).

## When something is wrong

A path that does not exist returns a real `404` — never a 200 with an application shell. What is in the body depends on what you asked for: `application/json`, any path under `/api/`, and any path ending `.json` or `.yaml` get an error object; a browser gets the [404 page](https://tabnas.dev/404); anything else gets markdown carrying the same links.

```
{
  "error": {
    "status": 404,
    "code": "not_found",
    "message": "Not Found",
    "hint": "Nothing is published at /api/v1/parse. This site is documentation for the tabnas parsing engine; start from /llms.txt for the machine-readable index, or /openapi.json for the endpoints that return JSON.",
    "documentation": "https://tabnas.dev/api",
    "openapi": "https://tabnas.dev/openapi.json",
    "resources": {
      "llms.txt": "https://tabnas.dev/llms.txt"
    }
  }
}
```

`code` is stable and safe to branch on: it is one of `not_found`, `method_not_allowed` (the site is read-only, so anything other than `GET`, `HEAD` or `OPTIONS` gets one) and `not_acceptable` (you asked for a representation that does not exist for that URL). `hint` is written to tell you what to do next, and `resources` lists the site's entry points so one failed request is enough to recover.

Errors _from the engine_ are a different thing entirely: a parse failure carries a diagnostic whose `code` is the contract across both runtimes. All 46 of them are at [`/errors.json`](https://tabnas.dev/errors.json), one at a time at `/errors/<code>.json`, and with prose at [/errors](https://tabnas.dev/errors/).

## The MCP endpoint

7 tools that actually run the engine — parse, validate a grammar, explain a failure, run fixtures, read the plugin catalogue, compare two grammar versions — are served over the Model Context Protocol from a separate service at `https://mcp.tabnas.dev`, deployed from the `tabnas/mcp` repository. Start from [`/.well-known/mcp`](https://tabnas.dev/.well-known/mcp) on this domain, which names both transports; [/mcp](https://tabnas.dev/mcp/) has each tool's contract.

| Endpoint | Operation | What it does |
| --- | --- | --- |
| `GET https://mcp.tabnas.dev/health` | `getMcpHealth` | Hosted MCP endpoint liveness |
| `POST https://mcp.tabnas.dev/mcp` | `callMcpTool` | Call the hosted MCP server |

Local stdio stays the recommended path: `npx --yes @tabnas/mcp mcp` is the same code, unbounded and private. The hosted endpoint is bounded by a body cap and a per-IP rate limit, both reported by its own `/.well-known/mcp`.
