@nesso-how/mcp 0.1.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +22 -0
- package/dist/lib/starlight-docs.d.ts +7 -0
- package/dist/lib/starlight-docs.js +14 -0
- package/dist/starlight-docs.pages.json +46 -0
- package/dist/tools/get-docs.d.ts +2 -0
- package/dist/tools/get-docs.js +31 -0
- package/dist/tools/get-relation-types.d.ts +2 -0
- package/dist/tools/get-relation-types.js +25 -0
- package/package.json +34 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/server';
|
|
5
|
+
import { registerGetRelationTypes } from './tools/get-relation-types.js';
|
|
6
|
+
import { registerGetDocs } from './tools/get-docs.js';
|
|
7
|
+
const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: 'nesso',
|
|
10
|
+
version,
|
|
11
|
+
});
|
|
12
|
+
registerGetRelationTypes(server);
|
|
13
|
+
registerGetDocs(server);
|
|
14
|
+
async function main() {
|
|
15
|
+
const transport = new StdioServerTransport();
|
|
16
|
+
await server.connect(transport);
|
|
17
|
+
console.error('Nesso MCP server running on stdio');
|
|
18
|
+
}
|
|
19
|
+
main().catch((err) => {
|
|
20
|
+
console.error(err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const DIST_DIR = fileURLToPath(new URL('..', import.meta.url));
|
|
6
|
+
export function loadStarlightDocPages() {
|
|
7
|
+
try {
|
|
8
|
+
const raw = readFileSync(join(DIST_DIR, 'starlight-docs.pages.json'), 'utf8');
|
|
9
|
+
return JSON.parse(raw).pages;
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
throw new Error('Missing starlight-docs.pages.json. Run `pnpm build` in packages/mcp.', { cause: err });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pages": [
|
|
3
|
+
{
|
|
4
|
+
"slug": "guides/ai-mentor",
|
|
5
|
+
"title": "AI mentor (Socrates)",
|
|
6
|
+
"description": "How the Socratic mentor works, local vs remote, persona, and graph-aware context.",
|
|
7
|
+
"markdown": "Click the **Socrates** bubble in the bottom-right of the canvas to start a dialogue. The mentor reads your current graph and selection, and replies with **questions rather than explanations**. The goal is to surface what you understand and where the gaps are.\n\n## How it works\n\nEvery send rebuilds a system prompt from the live store: a snapshot of up to ~60 concept nodes, sorted weakest-first via **`nodeStrength()`** ([`context.ts`](https://github.com/cedoor/nesso/blob/main/src/llm/context.ts))—**FSRS stability** dominates ordering, **Again/Hard** nudge weaker items up, overdue is only a slight tie-break. Each node line lists stability (`s=` days), days since last review, last FSRS rating, and `DUE` when the scheduler says so, plus typed edges (~2× the node allowance), current selection when any, and focal-neighbour context when a node is selected (`Focus:` / `Related:` lines). The conversation history stays in the mentor card and is reset when you switch graphs or click **New chat**.\n\nChat history is **not persisted**. It lives only for the current panel session.\n\n## Local vs remote\n\nConfigure under **Settings -> AI**:\n\n- **Local model (default):** Qwen2.5 1.5B (~1.1 GB, q4f16 quantised) runs entirely in the browser via WebGPU using [WebLLM](https://github.com/mlc-ai/web-llm). First run prompts a one-off download; subsequent loads use the cached weights in IndexedDB. Nothing leaves your device.\n- **Remote API:** any OpenAI-compatible `chat/completions` endpoint. Set base URL, model, and (optionally) API key. Defaults work with a local [Ollama](https://ollama.com/) instance at `http://localhost:11434/v1`.\n\nThe toggle is live: switching modes takes effect on the next message.\n\n### When local mode is unavailable\n\nIf your browser does not support WebGPU, or the weights haven't been downloaded yet, the chat input stays disabled and the mentor card shows a short status line. Click **Download & use** in **Settings -> AI** to fetch the model, or switch to Remote API mode.\n\n## The Socratic persona\n\nThe system prompt (`getMentorBase` in [`MentorBubble.tsx`](https://github.com/cedoor/nesso/blob/main/src/components/MentorBubble.tsx)) shapes Socrates:\n\n- One short question per turn by default; explain only enough to frame the question.\n- Replies are soft-capped at ~200 words (hard cap via output tokens).\n- No graph edits proposed in dialogue. Socrates probes; the user edits.\n- No emojis, flattery, JSON, or pseudo-graph markup. Sparse `*asterisks*` on key terms.\n- Replies in the active UI language (English or Italian). Snapshot tokens stay **English-shaped** (`s=…d`, `…d since review`, etc.), with the same spelling in the legend for every locale.\n\nIf you want a more permissive coach, fork the persona. It is plain text in the component and easy to swap.\n\n## Opening message\n\nWhen the panel opens, the mentor sends itself a short synthetic **user** turn so its first message reflects what's selected:\n\n- **A concept node selected:** opens on that concept and one of its relations.\n- **An edge selected (no node):** opens on the typed relation between its endpoints.\n- **Nothing selected:** opens on a weak spot in the graph (low stability plus weak **last reviews** — Again/Hard or a long gap; **DUE** is extra scheduler context).\n\nClick **New chat** in the header to reset history and request a fresh opener.\n\n## Context size\n\nLarge graphs are summarised, not truncated abruptly. The weakest-reviewed nodes appear first (`nodeStrength`), so the verbatim slice emphasises instability and risky last ratings; tail nodes are omitted with a short count only. Edges have a ~2x allowance over node count. These limits live in [`MentorBubble.tsx`](https://github.com/cedoor/nesso/blob/main/src/components/MentorBubble.tsx) as `MAX_SNAPSHOT_NODES` and `MAX_SNAPSHOT_EDGES`.\n\n## Privacy\n\n- **Local mode:** every byte stays in the browser. Graph data, prompts, responses, and model weights are all client-side.\n- **Remote mode:** the system prompt (graph snapshot) and chat history are sent to whichever endpoint you configured, each turn. If that is a hosted provider, the usual provider-side logging applies."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"slug": "guides/concepts-and-inspector",
|
|
11
|
+
"title": "Concepts & Inspector",
|
|
12
|
+
"description": "Adding concepts, drawing typed relations, and using the Inspector to enrich nodes with definitions, examples, notes, and images.",
|
|
13
|
+
"markdown": "The canvas is the centre of Nesso. **Concepts** are nodes; **typed relations** are edges. The **Inspector** is the right-hand panel where you enrich whatever you've got selected.\n\n## Adding concepts\n\n- **Bottom dock -> +** adds a new concept near the centre of the viewport.\n- The new node opens in edit mode. Type the label and press `Enter` to commit, `Esc` to cancel.\n\nConcepts you add are stored locally in IndexedDB. Switch graphs from the sidebar; create new graphs from the **Graphs** list.\n\n## Drawing relations\n\nDrag from a node's right edge (`out` handle) to another node's left edge (`in` handle). On release, a **relation picker** opens, grouped by category. Pick the relation type and the edge is created.\n\n- Drag-to-self is ignored, so you can't accidentally create self-loops.\n- The connection line previews with the same quadratic geometry the final edge uses.\n- Edge type can be changed any time from the Inspector when an edge is selected.\n\nSee the [relation types reference](../../reference/relation-types/) for the full list and what each one encodes visually.\n\n## Selecting and editing\n\n- **Click** a node or edge to select it. The Inspector reflects the selection.\n- **Hold `⌘` / `Ctrl` and click** to toggle additional items into the selection.\n- **Drag on empty canvas** to marquee-select multiple items.\n- **`Del`** or **`Backspace`** deletes everything in the selection. Edges attached to a deleted node go with it.\n- **`⌘Z` / `Ctrl+Z`** undoes structural edits; **`⌘⇧Z` / `Ctrl+Shift+Z`** redoes. History has 50 steps and resets when you switch or import a graph.\n\n## The Inspector\n\nWhen a concept is selected, the Inspector shows two tabs.\n\n### Overview\n\n- **Title:** edit inline. Pressing `Enter` commits; `Esc` reverts.\n- **FSRS stats:** when due, stability (in days), and last self-rating. Surfaced read-only.\n- **Relations:** outgoing and incoming edges grouped by category. Click a relation chip to jump to the connected node; click the type to swap relation in place.\n\n### Notes\n\nThree free-text fields that travel with the concept and feed both the AI mentor and Review:\n\n- **Definition:** a one-sentence-ish explanation in your own words.\n- **Examples:** one per line. Press `Shift+Enter` or use the `+` button to add a new line.\n- **Notes:** anything else: caveats, sources, mnemonics.\n\nThese power the [Review](./review-mode/) recall question. The model is told to *aim* at the topic suggested by your notes without paraphrasing the definition, so active recall still works.\n\n### Concept image\n\nPress the picture icon to open the **Wikimedia Commons search**. The query auto-fills from the concept title and runs immediately; pick any result to attach a 200-px thumbnail to the concept. The image shows in the Inspector, in Review mode, and is included as context for the AI mentor.\n\nThe image link and Commons description URL are persisted with the graph, so attribution is preserved on export.\n\n## When an edge is selected\n\nThe Inspector shows the relation as a chip with its category colour and a dropdown of every relation type. Picking a new type updates the edge in place; the graph keeps its endpoints and identity.\n\n## Stats and search\n\n- **Sidebar -> Stats** shows concept count, link count, and current zoom (a handy gut-check for graph size).\n- **`⌘K` / `Ctrl+K`** opens a fuzzy search palette over concept titles. `Enter` selects and recenters the viewport; `Esc` closes.\n\n## Edge encoding density\n\nEdges carry three visual channels: colour (category), line style, and glyph. Crank this down for large or printed graphs from **Settings -> Appearance -> Edge encoding**:\n\n- **Full:** colour + style + glyph (default).\n- **Category:** colour only.\n- **Minimal:** plain line, no encoding.\n\nSymmetric relations (similarity, opposition) never render an arrowhead regardless of encoding."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"slug": "guides/getting-started",
|
|
17
|
+
"title": "Getting started",
|
|
18
|
+
"description": "How to run Nesso locally or on the web.",
|
|
19
|
+
"markdown": "Nesso is available as a hosted web app, a macOS desktop app, and as open-source code you can run locally. All data is stored in your browser or on your machine; nothing is sent to external servers unless you configure a remote AI endpoint.\n\n## Web app\n\nOpen [app.nesso.how](https://app.nesso.how) in your browser. The app works offline after the first load. Use Chrome, Edge, Arc, or any other browser with **WebGPU** if you want to run the AI mentor locally; for the remote API mode any modern browser is fine.\n\n## Desktop app (macOS)\n\nPre-built alpha installers for Apple silicon and Intel are published on [GitHub Releases](https://github.com/cedoor/nesso/releases). Download the `.dmg` for your architecture and open it.\n\n## Run from source\n\nRequires [Node.js](https://nodejs.org/) and [pnpm](https://pnpm.io/).\n\n```sh\ngit clone https://github.com/cedoor/nesso.git\ncd nesso\npnpm install\npnpm dev\n```\n\nFor a desktop build, [Rust](https://rustup.rs/) is required as well:\n\n```sh\npnpm build:desktop\n```\n\n## Picking an AI backend\n\nThe Socratic mentor uses an LLM. Choose under **Settings -> AI**:\n\n- **Local model (default):** Qwen2.5 1.5B runs entirely in the browser via WebGPU (powered by [WebLLM](https://github.com/mlc-ai/web-llm)). The first run downloads ~1.1 GB and caches it; subsequent loads are instant. Nothing leaves your machine.\n- **Remote API:** any OpenAI-compatible `chat/completions` endpoint: local [Ollama](https://ollama.com/) at `http://localhost:11434/v1`, an OpenAI-compatible proxy, or a hosted provider. Set base URL, model, and API key if needed.\n\nEither mode can be switched at any time from **Settings** (`⌘,` / `Ctrl+,`).\n\n> API keys are stored client-side in `localStorage`. Do not self-host the web app publicly with secrets baked in.\n\n### Local mode tips\n\n- WebGPU is required. On macOS, recent Chrome / Edge / Arc work out of the box; Safari support is improving but currently limited.\n- The first download streams progress into the Settings panel. Closing the panel does not cancel the download.\n- **Settings -> Data -> Delete** clears graphs and preferences but leaves the cached model untouched. Clearing browser site data removes everything, including the model weights.\n\n### Remote mode with Ollama\n\nRun Ollama locally, then pull a small instruction-tuned model:\n\n```sh\nollama pull gemma3:4b\n```\n\nIn **Settings -> AI**, choose **Remote API** and set:\n\n- Base URL: `http://localhost:11434/v1`\n- Model: `gemma3:4b` (or `llama3.2:3b`, `qwen2.5:7b`; presets are shown in Settings)\n- API key: leave empty\n\nSettings auto-probes the endpoint and offers a **Pull** button if the model is missing.\n\n## Keyboard shortcuts\n\n| Shortcut | Action |\n| --- | --- |\n| `?` | Show shortcuts dialog |\n| `⌘,` / `Ctrl+,` | Settings |\n| `⌘K` / `Ctrl+K` | Search concepts |\n| `R` | Open review mode |\n| `⌘Z` / `Ctrl+Z` | Undo |\n| `⌘⇧Z` / `Ctrl+Shift+Z` | Redo |\n| `Del` / `Backspace` | Delete selection |\n| `Esc` | Close dialog |\n\nHold `⌘` / `Ctrl` to add to a selection; drag on empty canvas to marquee-select."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"slug": "guides/mcp-integration",
|
|
23
|
+
"title": "MCP",
|
|
24
|
+
"description": "Connect Nesso to Claude, Cursor, or any MCP-compatible AI client.",
|
|
25
|
+
"markdown": "The `@nesso-how/mcp` package is a [Model Context Protocol](https://modelcontextprotocol.io/) server that gives AI clients access to Nesso documentation and the full relation-type vocabulary. Once connected, models can answer questions about how Nesso works and use the correct relation names when you build graphs yourself in the app or in JSON.\n\n## Setup\n\n### Claude Desktop\n\nOpen `claude_desktop_config.json`. On macOS it lives at `~/Library/Application Support/Claude/claude_desktop_config.json`; on Windows at `%APPDATA%\\Claude\\claude_desktop_config.json`.\n\nAdd a `nesso` entry under `mcpServers`:\n\n```json\n{\n \"mcpServers\": {\n \"nesso\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@nesso-how/mcp\"]\n }\n }\n}\n```\n\nSave the file and restart Claude Desktop. The Nesso tools will be available to the model automatically.\n\n### Cursor\n\nOpen **Settings -> MCP** and add a new server with command `npx` and args `[\"-y\", \"@nesso-how/mcp\"]`.\n\n### Other MCP clients\n\nAny client that speaks the stdio MCP transport works. Run `npx -y @nesso-how/mcp` as the server command. No other configuration is required.\n\n## What it can do\n\nOnce connected, you can ask your AI client things like:\n\n- \"What relation types does Nesso support?\" (uses `get_relation_types`)\n- \"Show me the Nesso getting started guide\" (uses `get_nesso_docs`)\n\nYou can build graphs in [app.nesso.how](https://app.nesso.how) yourself, or paste graph JSON from the model via **Graph menu → Import JSON** when it follows the shape below.\n\n## Tools reference\n\n### `get_nesso_docs`\n\nFetches documentation pages from this site. Call it without a `slug` to get a table of contents, or with a slug (e.g. `\"guides/getting-started\"`) to get the full page content.\n\n### `get_relation_types`\n\nReturns the complete list of relation types with their category, line style, and symmetry. Use this whenever you need valid type names for graph JSON or explanations for the learner.\n\n### Graph JSON (Import JSON)\n\nPaste this JSON shape into **Graph menu → Import JSON** in the web or desktop app (or construct it elsewhere and import the file):\n\n```json\n{\n \"name\": \"Graph title\",\n \"nodes\": [\n {\n \"id\": \"n1\",\n \"type\": \"concept\",\n \"position\": { \"x\": 0, \"y\": 0 },\n \"data\": {\n \"text\": \"Concept label\",\n \"stability\": 0,\n \"difficulty\": 0,\n \"reps\": 0,\n \"lapses\": 0,\n \"fsrsState\": 0,\n \"due\": 0,\n \"lastReview\": 0,\n \"lastRating\": 0\n }\n }\n ],\n \"edges\": [\n {\n \"id\": \"e1\",\n \"type\": \"nesso\",\n \"source\": \"n1\",\n \"target\": \"n2\",\n \"sourceHandle\": \"out\",\n \"targetHandle\": \"in\",\n \"data\": { \"type\": \"causes\" }\n }\n ]\n}\n```\n\nCall `get_relation_types` before inventing **`data.type`** values so they match Nesso."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"slug": "guides/review-mode",
|
|
29
|
+
"title": "Review mode",
|
|
30
|
+
"description": "Spaced-repetition review of your concepts with FSRS, how it queues cards, asks AI recall questions, and reschedules.",
|
|
31
|
+
"markdown": "Press `R` (or open the **Review** pill in the top bar) to start a focused study session. Review surfaces concepts whose **FSRS** state says they are due, asks you a recall question, and reschedules them based on how you self-rate.\n\nNesso uses [FSRS](https://github.com/open-spaced-repetition/ts-fsrs), a modern open-source successor to the SM-2 / Anki algorithm.\n\n## What gets reviewed\n\nEach concept node carries its own FSRS state: `stability`, `difficulty`, `due`, `lastReview`, `lastRating`, and friends. A node is **due** when `due <= now`. New, unrated concepts default to `due = 0`, which means they show up immediately the first time you open Review.\n\nThe session queue is built fresh every time you open the overlay: all due nodes, sorted by urgency, in random order within the same due bucket.\n\n## Flow\n\nFor each due concept, Review:\n\n1. **Asks a recall question** generated by the AI mentor (local or remote; the same backend you configured in [AI mentor](./ai-mentor/)). The question uses the concept's title, its relations, and the elaboration fields (definition, examples, notes). It is prompted to **not paraphrase the definition** so active recall still works.\n2. **Waits for you to think**, then click **Reveal** (or press `Space`).\n3. **Reveals** the concept's typed relations, examples, and image (the same panel you see in the Inspector).\n4. **You rate** how it felt: `Again`, `Hard`, `Good`, `Easy`. Each button shows the **predicted next interval** under it (e.g. `< 1d`, `4d`, `2mo`).\n\nFSRS then updates `stability` and `difficulty`, schedules the next `due` date, and Review advances to the next card. Done with the queue, the overlay closes; you're caught up.\n\nIf the AI backend is unavailable (no WebGPU, model not downloaded, remote endpoint unreachable), Review still works. It falls back to showing the concept title without a generated question.\n\n## Tuning FSRS\n\nUnder **Settings -> Review**:\n\n| Setting | What it does | Range |\n| --- | --- | --- |\n| **Target retention** | Probability of correctly recalling a concept at its next review. Higher means more frequent reviews. | 70% to 97% |\n| **Max interval** | Longest interval FSRS can schedule, in days. Caps how far into the future a card can be pushed. | 1 to 36,500 |\n\nThe defaults (90% retention, 100-year cap) match the FSRS reference defaults. Lower the retention if you're comfortable forgetting more in exchange for fewer reviews; raise the max interval if you want long-term cards to keep stretching out.\n\n## Keyboard shortcuts\n\n| Key | Action |\n| --- | --- |\n| `Space` / `Enter` | Reveal |\n| `1` | Again |\n| `2` | Hard |\n| `3` | Good |\n| `4` | Easy |\n| `Esc` | Close review |\n\nNumeric keys only fire after the answer is revealed.\n\n## Tips\n\n- Add a **definition** in the Inspector's Notes tab. Even one short sentence per concept dramatically improves AI question quality, since the model can aim at a specific facet (pitfall, application, contrast) instead of asking something generic.\n- Pair concepts with **at least one typed edge** before reviewing them. Review questions lean on the relation graph for context; isolated nodes get vaguer questions.\n- The session count in the top bar reflects the original queue size. Cards rated `Again` that come back later increase the count past 100%; that is expected."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"slug": "introduction",
|
|
35
|
+
"title": "Introduction",
|
|
36
|
+
"description": "What Nesso is, why it exists, and the principles it is built on.",
|
|
37
|
+
"markdown": "Nesso is an open-source, AI-assisted knowledge graph for active learning. It is built on a specific claim about how understanding works and a specific critique of how most current tools approach it.\n\n## The problem with passive learning tools\n\nThe dominant pattern AI is settling into is passive: hand over a source, receive a summary; ask a question, receive an answer; describe what you want to learn, receive a pre-built map. This is convenient, and pedagogically counterproductive. Decades of cognitive science converge on the same conclusion: deep understanding is not received; it is constructed. When the work of deciding how concepts relate is offloaded to a system, the process that produces comprehension is bypassed.\n\nAlongside this, most learning platforms treat user data as a resource. In the context of learning, this data is uniquely sensitive: it reveals not just what someone has read, but how they reason, where they struggle, and how their understanding evolves over time. Capturing it passively, and often opaquely, is at odds with the interests of the people the tools claim to serve.\n\nFinally, most platforms are proprietary silos: closed standards, locked formats, no way to inspect or extend them. Educators, developers, and learners themselves have no meaningful recourse when a platform makes choices they disagree with or stops serving their needs.\n\n## What Nesso does instead\n\nNesso inverts the flow. The learner constructs their own knowledge structure: a typed concept graph that reflects how *they* understand, not just what they have consumed. The act of deciding which relation holds between two concepts (does X *cause* Y, or merely *enable* it? is A an *instance of* B, or a *subtype of* it?) is where elaborative processing happens. The decision is the learning.\n\nAlgorithms work on what the learner has built, not on a generic curriculum. Spaced repetition is driven by graph structure: concepts with low stability or untested connections surface before well-reinforced ones. The review queue is always a function of the learner's own map.\n\nAI is present, but with a constrained role. The AI mentor, Socrates, does not deliver pre-packaged answers. It asks questions calibrated to the learner's current graph, probing understanding, surfacing gaps, and leaving the work of constructing answers to the learner. It is designed to accelerate active thinking, not to replace it.\n\n## Principles\n\n**Constructivist by design.** Every feature is oriented around the learner doing cognitive work: drawing edges, labelling relations, writing definitions in their own words, self-rating recall. The system does not do this work for them.\n\n**Private by architecture.** Graphs are stored locally in the browser (IndexedDB). The local AI mode runs entirely in-browser via WebGPU; no data leaves the device. Privacy is an implementation detail, not a policy promise.\n\n**Open by default.** The code is MIT-licensed. Data formats are documented and importable/exportable as plain JSON. The MCP server makes the graph vocabulary available to any compatible client. Technical work done here is intended to be useful beyond this application.\n\n**Provider-agnostic AI.** Nesso talks to any OpenAI-compatible `chat/completions` endpoint. Users choose whether to run a model locally or connect a remote provider; no vendor is privileged by the architecture.\n\n## What Nesso is not\n\nNesso is not a note-taking app. It does not replace a text editor, a spaced-repetition deck manager, or a general-purpose LLM interface. It is specifically a tool for the phase of learning where understanding a domain means deciding how its concepts relate to each other, and testing whether you can hold that structure under questioning.\n\nIt is also not a finished product. It is an alpha-stage open-source project. Some features are rough, some planned items are not yet built, and the codebase is publicly available for inspection and contribution.\n\n---\n\nThe remainder of this documentation covers how to use the app and how to integrate with it programmatically. If you want to start immediately, [Getting started](./guides/getting-started/) has everything you need."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"slug": "reference/relation-types",
|
|
41
|
+
"title": "Relation types",
|
|
42
|
+
"description": "The 21 semantic relation types across 7 categories in Nesso.",
|
|
43
|
+
"markdown": "Edges in Nesso carry a **semantic type**: a named relation that describes how two concepts are connected. There are 21 types grouped into 7 categories. Each category has a distinct colour; each type has a line style and a glyph.\n\n## Taxonomic\n\n*What kind of thing is it?*\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `is-a` | is a | solid | triangle-up |\n| `instance-of` | instance of | solid | circle-dot |\n| `subtype-of` | subtype of | double | triangle-up |\n\n## Structural\n\n*What is it made of or composed from?*\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `part-of` | part of | solid | diamond |\n| `made-of` | made of | dashed | hash |\n| `contains` | contains | solid | diamond-open |\n\n## Causal\n\n*What does it do or prevent?*\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `causes` | causes | solid | arrow-right |\n| `produces` | produces | solid | asterisk |\n| `enables` | enables | dotted | key |\n| `prevents` | prevents | dotted | block |\n| `triggers` | triggers | solid | spark |\n| `inhibits` | inhibits | dotted | minus |\n\n## Dependency\n\n*What does it need or serve?*\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `requires` | requires | solid | anchor |\n| `uses` | uses | dashed | tool |\n| `used-for` | used for | dashed | flag |\n\n## Temporal\n\n*When or where does it happen?*\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `precedes` | precedes | solid | chevron-r |\n| `occurs-in` | occurs in | dotted | ring |\n\n## Opposition\n\n*What does it contrast with?* Symmetric.\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `contrasts-with` | contrasts with | wavy | tilde |\n| `opposite-of` | opposite of | double | x |\n\n## Similarity\n\n*What is it like?* Symmetric.\n\n| Type | Label | Line | Glyph |\n|------|-------|------|-------|\n| `similar-to` | similar to | dashed | approx |\n| `analogous-to` | analogous to | dotted | arrows-lr |\n\n---\n\n**Symmetric** relations (opposition and similarity) carry the same meaning in both directions; the edge has no arrowhead.\n\n**Edge encoding** is controlled per-graph via Settings -> Appearance -> Edge encoding:\n- `full`: glyph and line style\n- `category`: colour only\n- `minimal`: plain line"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { loadStarlightDocPages } from '../lib/starlight-docs.js';
|
|
3
|
+
function toc() {
|
|
4
|
+
const pages = loadStarlightDocPages();
|
|
5
|
+
const rows = pages.map((p) => `- \`${p.slug}\` — **${p.title}**: ${p.description}`);
|
|
6
|
+
return ['# Nesso documentation — available pages', '', ...rows, '', 'Call get_nesso_docs with a slug to read a page.'].join('\n');
|
|
7
|
+
}
|
|
8
|
+
export function registerGetDocs(server) {
|
|
9
|
+
server.registerTool('get_nesso_docs', {
|
|
10
|
+
description: 'Nesso docs. Without a slug returns a table of contents (page slugs + descriptions). With a slug returns that page\'s full Markdown.',
|
|
11
|
+
inputSchema: z.object({
|
|
12
|
+
slug: z.string().optional().describe('Page slug to retrieve (e.g. "guides/getting-started"). Omit to list available pages.'),
|
|
13
|
+
}),
|
|
14
|
+
}, async ({ slug }) => {
|
|
15
|
+
if (!slug) {
|
|
16
|
+
return { content: [{ type: 'text', text: toc() }] };
|
|
17
|
+
}
|
|
18
|
+
const pages = loadStarlightDocPages();
|
|
19
|
+
const page = pages.find((p) => p.slug === slug);
|
|
20
|
+
if (!page) {
|
|
21
|
+
const available = pages.map((p) => p.slug).join(', ');
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: 'text', text: `Unknown slug "${slug}". Available: ${available}` }],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: [`# ${page.title}`, '', page.markdown].join('\n') }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { RELATION_TYPES, RELATION_CATEGORY_META } from '@nesso-how/relation-types';
|
|
3
|
+
export function registerGetRelationTypes(server) {
|
|
4
|
+
server.registerTool('get_relation_types', {
|
|
5
|
+
description: 'Returns all 21 semantic relation types supported by Nesso, grouped by category. ' +
|
|
6
|
+
'Use this when you need valid relation type names for graph JSON or explanations for the user.',
|
|
7
|
+
inputSchema: z.object({}),
|
|
8
|
+
}, async () => {
|
|
9
|
+
const result = Object.entries(RELATION_CATEGORY_META).map(([cat, catDef]) => ({
|
|
10
|
+
category: catDef.label,
|
|
11
|
+
question: catDef.subtitle,
|
|
12
|
+
types: Object.entries(RELATION_TYPES)
|
|
13
|
+
.filter(([, def]) => def.cat === cat)
|
|
14
|
+
.map(([name, def]) => ({
|
|
15
|
+
type: name,
|
|
16
|
+
label: def.label,
|
|
17
|
+
line: def.line,
|
|
18
|
+
symmetric: def.symmetric,
|
|
19
|
+
})),
|
|
20
|
+
}));
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nesso-how/mcp",
|
|
3
|
+
"version": "0.1.0-alpha.16",
|
|
4
|
+
"description": "MCP server exposing Nesso knowledge graph tools to LLM clients",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"bin": {
|
|
12
|
+
"nesso-mcp": "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"bundle-docs": "node scripts/bundle-starlight-docs.mjs",
|
|
19
|
+
"build": "tsc && node scripts/bundle-starlight-docs.mjs",
|
|
20
|
+
"prepublishOnly": "pnpm build",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"start": "node dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@cfworker/json-schema": "^4.1.1",
|
|
26
|
+
"@modelcontextprotocol/server": "latest",
|
|
27
|
+
"@nesso-how/relation-types": "workspace:*",
|
|
28
|
+
"zod": "latest"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^22.0.0",
|
|
32
|
+
"typescript": "~5.8.3"
|
|
33
|
+
}
|
|
34
|
+
}
|