Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .agents/skills/hyperterse-docs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: hyperterse-docs
description: Hyperterse LLM integration docs. Use when building tools, adapters, or MCP integrations with Hyperterse.
---

This entire project is built with Hyperterse - the declarative and performant MCP framework.

You are an expert at building tools, adapters, and MCP integrations with Hyperterse. You are well versed with

# Hyperterse

When working with Hyperterse tools, adapters, or MCP integrations, read the latest documentation from:

**https://docs.hyperterse.com/llms.txt**

Fetch and use this content for accurate schema, configuration, and API reference.
9 changes: 9 additions & 0 deletions mcp-hyperterse/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Bridge API port (the internal HTTP server Hyperterse handlers call)
BRIDGE_PORT=8100

# NeuroStack reads these via its own config.toml / env — set here if needed
# NEUROSTACK_VAULT_ROOT=~/brain
# NEUROSTACK_EMBED_URL=http://localhost:11435
# NEUROSTACK_EMBED_MODEL=nomic-embed-text
# NEUROSTACK_LLM_URL=http://localhost:11434
# NEUROSTACK_LLM_MODEL=phi3.5
11 changes: 11 additions & 0 deletions mcp-hyperterse/.hyperterse
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: neurostack

server:
port: 8080
log_level: 3

root: app

tools:
directory: tools

161 changes: 161 additions & 0 deletions mcp-hyperterse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# NeuroStack Hyperterse MCP

A [Hyperterse](https://docs.hyperterse.com) MCP server that exposes all 21 NeuroStack vault tools. This is a drop-in replacement for the Python FastMCP server — same tools, same behavior, powered by the Hyperterse framework.

## Architecture

```
Claude / Cursor ──► Hyperterse MCP Server (port 8080)
│ fetch() from TypeScript handlers
Python Bridge API (port 8100)
│ direct imports
neurostack internals
```

- **Hyperterse** is the MCP server that clients connect to. It provides tool discovery, input validation, auth, and the MCP protocol surface.
- **The bridge** is an internal HTTP API (not an MCP server) that Hyperterse handlers call via `fetch()`. It imports NeuroStack's Python modules directly, so there is zero logic duplication.
- **One start command** launches both processes together.

## Prerequisites

- [Hyperterse CLI](https://docs.hyperterse.com/installation) installed
- NeuroStack installed and indexed (`neurostack doctor` passes)
- Python 3.10+ with `fastapi` and `uvicorn` (or `pip install neurostack[api]`)
- Ollama running (for search, ask, and community tools)

## Quick Start

```bash
cd mcp-hyperterse

# Copy and edit environment variables (optional — defaults work if neurostack is configured)
cp .env.example .env

# Start everything
./start.sh
```

The start script launches the Python bridge on port 8100, waits for it to be healthy, then starts Hyperterse on port 8080.

## Connecting to Claude Desktop / Cursor

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
"mcpServers": {
"neurostack": {
"url": "http://localhost:8080/mcp"
}
}
}
```

### Cursor

Add to your MCP settings:

```json
{
"mcpServers": {
"neurostack": {
"url": "http://localhost:8080/mcp"
}
}
}
```

## Tools (21)

### Search & Retrieval
| Tool | Description |
|------|-------------|
| `vault-search` | Hybrid search with tiered depth (triples/summaries/full/auto) |
| `vault-ask` | RAG Q&A with inline `[[citations]]` |
| `vault-summary` | Pre-computed note summary by path or search query |
| `vault-graph` | Wiki-link neighborhood with PageRank |
| `vault-related` | Semantically similar notes by embedding distance |
| `vault-triples` | Search knowledge graph triples (SPO facts) |
| `vault-communities` | GraphRAG global queries across topic clusters |
| `vault-context` | Task-scoped context assembly for session recovery |

### Context & Insights
| Tool | Description |
|------|-------------|
| `session-brief` | Compact session briefing (~500 tokens) |
| `vault-stats` | Index health (notes, embeddings, graph, triples, memories) |
| `vault-record-usage` | Record note usage for hotness scoring |
| `vault-prediction-errors` | Notes flagged as stale or miscategorised |

### Memories
| Tool | Description |
|------|-------------|
| `vault-remember` | Save a memory (observation, decision, convention, etc.) |
| `vault-forget` | Delete a memory by ID |
| `vault-update-memory` | Update an existing memory |
| `vault-merge` | Merge two memories (dedup) |
| `vault-memories` | Search or list memories |

### Sessions
| Tool | Description |
|------|-------------|
| `vault-session-start` | Begin a memory session |
| `vault-session-end` | End session with optional summary and harvest |
| `vault-capture` | Quick-capture a thought to the vault inbox |
| `vault-harvest` | Extract insights from AI session transcripts |

## Environment Variables

Set in `.env` or export before running:

| Variable | Default | Description |
|----------|---------|-------------|
| `BRIDGE_PORT` | `8100` | Port for the internal Python bridge API |

Standard NeuroStack variables (`NEUROSTACK_VAULT_ROOT`, `NEUROSTACK_EMBED_URL`, etc.) are read by the bridge through NeuroStack's own config system.

## Development

Use `--watch` for automatic restarts on file changes:

```bash
# Start bridge manually
BRIDGE_PORT=8100 python3 bridge/api.py &

# Start Hyperterse with hot reload
hyperterse start --watch
```

Validate the project without starting:

```bash
hyperterse validate
```

## Project Structure

```
mcp-hyperterse/
├── .hyperterse Root config (service name, port, log level)
├── .env.example Environment variable template
├── start.sh Launches bridge + Hyperterse together
├── bridge/
│ ├── api.py FastAPI bridge — all 21 tool endpoints
│ └── requirements.txt Python deps (fastapi, uvicorn)
├── app/
│ └── tools/
│ ├── vault-search/ config.terse + handler.ts
│ ├── vault-ask/ ...
│ └── ... (21 tool directories)
└── README.md
```

Each tool directory contains:
- `config.terse` — Hyperterse tool definition (name, description, inputs, auth)
- `handler.ts` — TypeScript handler that calls the bridge via `fetch()`
12 changes: 12 additions & 0 deletions mcp-hyperterse/app/tools/session-brief/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
description: |
Get a compact ~500 token session brief.
Includes recent vault changes with summaries, git commits,
recent memories, top connected notes, and time-of-day context.
handler: "./handler.ts"
inputs:
workspace:
type: string
description: "Optional vault subdirectory prefix to restrict results"
optional: true
auth:
plugin: allow_all
13 changes: 13 additions & 0 deletions mcp-hyperterse/app/tools/session-brief/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const BRIDGE = "http://127.0.0.1:8100";

export default async function handler(payload: {
inputs: Record<string, unknown>;
tool: string;
}) {
const res = await fetch(`${BRIDGE}/tools/session-brief`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload.inputs),
});
return await res.json();
}
20 changes: 20 additions & 0 deletions mcp-hyperterse/app/tools/vault-ask/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: |
Ask a natural language question and get an answer with citations from vault content.
Uses RAG to search the vault for relevant content, then synthesizes an answer
with inline [[note-title]] citations.
handler: "./handler.ts"
inputs:
question:
type: string
description: "Natural language question to answer"
top_k:
type: int
description: "Number of chunks to retrieve for context (default 8)"
optional: true
default: "8"
workspace:
type: string
description: "Optional vault subdirectory prefix to restrict results"
optional: true
auth:
plugin: allow_all
13 changes: 13 additions & 0 deletions mcp-hyperterse/app/tools/vault-ask/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const BRIDGE = "http://127.0.0.1:8100";

export default async function handler(payload: {
inputs: Record<string, unknown>;
tool: string;
}) {
const res = await fetch(`${BRIDGE}/tools/vault-ask`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload.inputs),
});
return await res.json();
}
15 changes: 15 additions & 0 deletions mcp-hyperterse/app/tools/vault-capture/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
description: |
Quick-capture a thought into the vault inbox.
Zero-friction way to dump a thought without creating a full note.
Creates a timestamped markdown file in the vault's inbox/ folder.
handler: "./handler.ts"
inputs:
content:
type: string
description: "The thought or idea to capture"
tags:
type: string
description: 'Optional comma-separated tags for the capture (e.g. "idea,research")'
optional: true
auth:
plugin: allow_all
13 changes: 13 additions & 0 deletions mcp-hyperterse/app/tools/vault-capture/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const BRIDGE = "http://127.0.0.1:8100";

export default async function handler(payload: {
inputs: Record<string, unknown>;
tool: string;
}) {
const res = await fetch(`${BRIDGE}/tools/vault-capture`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload.inputs),
});
return await res.json();
}
31 changes: 31 additions & 0 deletions mcp-hyperterse/app/tools/vault-communities/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
description: |
Answer global queries using GraphRAG community summaries.
Unlike vault-search (which retrieves specific chunks), this answers thematic
questions like "what topics dominate my vault?" by running Leiden community
detection summaries through a map-reduce synthesis.
handler: "./handler.ts"
inputs:
query:
type: string
description: "Natural language question about vault themes/topics"
top_k:
type: int
description: "Number of communities to retrieve (default 6)"
optional: true
default: "6"
level:
type: int
description: "Community hierarchy level — 0=coarse themes, 1=fine sub-themes"
optional: true
default: "0"
map_reduce:
type: boolean
description: "Use LLM map-reduce synthesis (true) or raw hits (false)"
optional: true
default: "true"
workspace:
type: string
description: "Optional vault subdirectory prefix to restrict results"
optional: true
auth:
plugin: allow_all
13 changes: 13 additions & 0 deletions mcp-hyperterse/app/tools/vault-communities/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const BRIDGE = "http://127.0.0.1:8100";

export default async function handler(payload: {
inputs: Record<string, unknown>;
tool: string;
}) {
const res = await fetch(`${BRIDGE}/tools/vault-communities`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload.inputs),
});
return await res.json();
}
31 changes: 31 additions & 0 deletions mcp-hyperterse/app/tools/vault-context/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
description: |
Assemble task-scoped context for session recovery after /clear or new conversation.
Unlike session-brief (time-anchored status snapshot), this is task-anchored:
it retrieves memories, triples, summaries, and session history relevant to
a specific task description, respecting a token budget.
handler: "./handler.ts"
inputs:
task:
type: string
description: "Description of the current task or goal"
token_budget:
type: int
description: "Maximum approximate tokens in response (default 2000)"
optional: true
default: "2000"
workspace:
type: string
description: "Optional vault subdirectory to scope"
optional: true
include_memories:
type: boolean
description: "Include relevant memories (default true)"
optional: true
default: "true"
include_triples:
type: boolean
description: "Include relevant triples (default true)"
optional: true
default: "true"
auth:
plugin: allow_all
13 changes: 13 additions & 0 deletions mcp-hyperterse/app/tools/vault-context/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const BRIDGE = "http://127.0.0.1:8100";

export default async function handler(payload: {
inputs: Record<string, unknown>;
tool: string;
}) {
const res = await fetch(`${BRIDGE}/tools/vault-context`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload.inputs),
});
return await res.json();
}
8 changes: 8 additions & 0 deletions mcp-hyperterse/app/tools/vault-forget/config.terse
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description: "Delete a specific memory by ID."
handler: "./handler.ts"
inputs:
memory_id:
type: int
description: "The ID of the memory to delete (from vault-remember or vault-memories)"
auth:
plugin: allow_all
Loading