self-inspect

self-inspect

Enables agents to reflect on their own thinking by returning a metathought question based on a deterministic selection from curated cognitive lenses.

Category
Visit Server

README

<p align="center"> <img src="assets/banner.png" alt="Self-Inspect by Ejentum: a question your agent would not think to ask itself. Thought in, metathought out. Keyless, deterministic, no LLM, open CSV, REST + MCP." width="100%"> </p>

Self-Inspect

A question your agent would not think to ask itself.

An agent sends a thought, or a description of the task it is working on. It gets back one metathought: a short, abstract question that turns the agent's attention back onto its own task and assumptions before it continues. Not advice, not an answer. A question.

Keyless, free, deterministic. No LLM, no embeddings, no semantic similarity. Selection is a small heuristic over an open CSV you can read in five minutes, and the code that answers api.ejentum.com/self-inspect is the code in this repo. A test proves the two cannot drift.

Why an agent needs this

Agents move forward. That is the whole problem. Left to itself, an agent:

  • commits to its first interpretation and never reopens it,
  • piles up assumptions it never names,
  • drifts from the original goal over a long chain of steps,
  • stops at the first answer that looks plausible,
  • grows more confident without growing more evidence,
  • agrees with the user because agreeing is the easy path.

None of these are knowledge failures. The model already knows better. They are attention failures: the agent never stops to ask the one question that would have caught it.

And it cannot reliably ask that question itself. Whatever picks what to reflect on is the same process that is already committed, so an agent that "double-checks" tends to re-run its own bias and call it confidence. Acknowledging a trap is not escaping it.

Self-Inspect is the external question. It returns a metathought the agent would not have produced on its own: What is assumed? What is fixed? What does not follow? What is missing? When would this not hold? What confidence is warranted? The agent still does the thinking. The tool just makes it look.

When to call it

Put it in the loop at the moments an agent would otherwise barrel through:

  • after forming a hypothesis, before acting on it,
  • before committing to a plan or a final answer,
  • at each step of a long chain, to catch drift,
  • when the agent notices it is agreeing, or feeling certain.

Send a thought, get a metathought, answer it to yourself, continue with more awareness. It always returns a question (there is no "no result" case), one call, no model in the loop, no key.

Quickstart

Send a thought, get a metathought. No key.

REST (any language):

curl -s -X POST https://api.ejentum.com/self-inspect \
  -H "Content-Type: application/json" \
  -d '{"thought":"I am committing to this architecture and treating it as fixed"}'
# -> [{ "label": "commitment", "metathought": "What is fixed?" }]

MCP, Claude Code:

claude mcp add --transport http self-inspect https://api.ejentum.com/self-inspect-mcp

MCP, Claude Desktop / Cursor / any HTTP-MCP client:

{
  "mcpServers": {
    "self-inspect": {
      "type": "http",
      "url": "https://api.ejentum.com/self-inspect-mcp"
    }
  }
}

The MCP server exposes one tool, self_inspect, that takes a thought and returns the metathought. No install, no key.

Endpoints

Surface Endpoint Auth Returns
REST POST https://api.ejentum.com/self-inspect keyless, per-IP rate limit (120/min) [{ label, metathought }]
MCP over HTTP https://api.ejentum.com/self-inspect-mcp (Streamable HTTP) keyless, per-IP rate limit (60/min) tool self_inspect -> metathought text
MCP stdio / offline the mcp/ package; SELF_INSPECT_LOCAL=1 runs the selector locally keyless tool self_inspect (npm publish pending)

Both hosted endpoints are keyless and protected by per-IP rate limiting plus standard security headers (HSTS, nosniff, frame-deny).

How selection works

select(thought, rows) (src/selector.js) routes in two levels, deterministically, over the data in selfinspect.csv:

  1. Normalize the thought: lowercase, Unicode NFKC, non-alphanumerics to spaces, collapse whitespace, tokenize (src/normalize.js).
  2. Score each lens (input_type): 3 x (type-name tokens present in the thought) + 1 x (distinct content tokens from that lens's questions present). Content tokens are the meta_thought words minus a small visible stopword list. Evidence aggregates across all of a lens's questions, so a lens can win on signal spread across several of its rows.
  3. Pick the highest-scoring lens; ties prefer strict over booster, then lexicographic lens name.
  4. Within the chosen lens, return the question with the most local content matches; tiebreak by lowest operator_rank (the canonical question). matched: true.
  5. If no lens has any signal, return a universal self-inspection question (about task and assumptions) chosen deterministically from a small default set by a stable hash of the input, so different inputs get different nudges. matched: false.

Self-Inspect always returns a metathought. There is always a worthwhile question an agent can ask about its own task and assumptions, so the tool never returns null. The matched flag distinguishes a routed lens (true) from a universal default (false); the metathought is never empty. Deterministic: the same input always returns the same metathought. (To make more inputs route to a specific lens, add wording to the CSV, or a future triggers column, never a model.)

The CSV is the source of truth

selfinspect.csv (~50 lenses, 137 questions):

column role shipped to caller
input_type the cognitive lens; its name tokens are routing keys, weighted x3 as part of id
operator_rank order within the lens (1 = canonical); tiebreak as part of id
runtime_tier strict (core) or booster (perceptual); strict preferred on ties no
meta_thought the returned text (verbatim) AND a source of content routing tokens yes

The returned id is input_type-operator_rank (e.g. confidence-4). To add or change a metathought, edit the CSV. Do not edit dist/code-node.js, dist/backend.cjs, or the deployed copies by hand.

Published == deployed (enforced, not promised)

npm run build regenerates dist/code-node.js from selfinspect.csv + src/normalize.js + src/selector.js (build/generate.mjs). That file is the literal body of the n8n Code node behind the hosted endpoint.

test/drift.test.mjs fails if dist/code-node.js is not byte-identical to the generator output. So a committed code node that drifts from the CSV/selector cannot pass CI. Anyone can clone this repo, run the fixtures locally and against the live endpoint, and confirm identical selection.

Verify

npm test          # selector fixtures + drift test
npm run build     # regenerate dist/code-node.js
git diff --exit-code dist/code-node.js   # clean == no drift

Response contract

REST returns an array of one object with exactly two fields: label (the lens, from input_type) and metathought (the question). Unroutable input still returns a universal default (a different lens, same shape):

{"thought":"How much confidence is warranted in this result?"} -> [{ "label": "confidence", "metathought": "What confidence is warranted?" }]
{"thought":"order a pizza"}                                     -> [{ "label": "sequence",   "metathought": "What order is active?" }]

The MCP surfaces (self_inspect) return the metathought text only.

Deploying the engine (operator)

The hosted side runs dist/backend.cjs (the CommonJS build of the same CSV + selector) inside an Express route, mounted keyless and isolated from any auth/tier. dist/backend.cjs is regenerated by npm run build and is drift-tested against the source like every other artifact. To update: edit selfinspect.csv, run npm run build, redeploy the build. Never edit the deployed copy by hand.

dist/code-node.js is an alternative deployment target for anyone who would rather run the engine as a single n8n Code node behind a webhook; it is generated from the same source and is not the canonical host.

MCP

mcp/ is a standalone MCP server (self-inspect-mcp) exposing one tool, self_inspect. By default it calls the hosted endpoint; set SELF_INSPECT_LOCAL=1 to run this exact selector offline against a vendored copy of the CSV. See mcp/README.md.

Troubleshooting

CRYPT_E_NO_REVOCATION_CHECK or a TLS revocation error on connect. The certificate is valid (Let's Encrypt, full chain, verify ok). TLS uses Let's Encrypt, which is CRL-based now: OCSP was retired by the CA in 2026, so there is no OCSP responder to query. Strict clients that hard-fail revocation when OCSP is unavailable (some Windows/schannel setups) can report this even though the cert is fine. Most clients (Node, Python TLS) soft-fail and connect normally. If yours hard-fails, set revocation checking to soft-fail; the certificate is valid.

License

MIT.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured