mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
@@ -34,3 +34,8 @@ ASK262_EMBEDDING_PROVIDER=ollama
|
|||||||
|
|
||||||
# Port for the HTTP MCP server (optional, defaults to 8081)
|
# Port for the HTTP MCP server (optional, defaults to 8081)
|
||||||
# ASK262_PORT=8081
|
# ASK262_PORT=8081
|
||||||
|
|
||||||
|
# Public URL for the MCP server (used by MCP Inspector to auto-connect)
|
||||||
|
# Required when running behind a reverse proxy or in production
|
||||||
|
# Example: https://ask262.bendtherules.in or https://your-server.com
|
||||||
|
# MCP_PUBLIC_URL=http://localhost:8081
|
||||||
|
|||||||
@@ -2,216 +2,77 @@
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
**Ask262** is a RAG-based AI chat agent for exploring the ECMAScript specification and its implementation in [engine262](https://github.com/bendtherules/engine262) (a JavaScript engine written in JavaScript).
|
**Ask262** is a RAG-based MCP server for exploring the ECMAScript specification via [engine262](https://github.com/bendtherules/engine262). Users ask questions like *"How does array.map work?"* and get answers grounded in the actual spec and implementation.
|
||||||
|
|
||||||
The agent combines:
|
**Stack:** Vector search (LanceDB + Ollama/Fireworks embeddings) → Knowledge graph → LLM reasoning. Runs as MCP server (stdio or HTTP) for Claude Desktop, OpenCode, etc.
|
||||||
- **Vector search** (via LanceDB + Ollama embeddings) to find relevant spec sections
|
|
||||||
- **Knowledge graph** (via Graphology) mapping spec sections to implementation functions
|
|
||||||
- **LLM reasoning** (via OpenAI-compatible API) to answer questions about JavaScript internals
|
|
||||||
|
|
||||||
Users ask questions like: *"How does the if statement work?"* or *"Which function implements sec-if-statement?"*
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- **Node.js** 18+ with Bun runtime (packageManager: bun@1.2.8)
|
|
||||||
- **Ollama** installed locally with embedding model (e.g., `qwen3-embedding:0.6b`)
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
ask262/
|
|
||||||
├── src/
|
|
||||||
│ ├── agent.ts # Main ReAct agent - answers user queries
|
|
||||||
│ ├── constants.ts # Directory paths and model configs
|
|
||||||
│ ├── agent-tools/ # Tool implementations (spec retriever, graph explorer)
|
|
||||||
│ │ ├── index.ts # Tool exports
|
|
||||||
│ │ ├── searchSpecSections.ts # Vector search tool
|
|
||||||
│ │ ├── getSectionContent.ts # Section chunk retrieval tool
|
|
||||||
│ │ ├── graphExplorer.ts # Knowledge graph navigation tool
|
|
||||||
│ │ ├── evaluateInEngine262.ts # Execute JS and capture spec marks
|
|
||||||
│ │ └── reranker.ts # Document reranking utility
|
|
||||||
│ └── setup/ # Data ingestion and graph building
|
|
||||||
│ ├── ingest.ts # Ingests spec HTML into vector index
|
|
||||||
│ ├── buildGraph.ts # Builds knowledge graph
|
|
||||||
│ ├── stripSpecContainer.ts # Cleans spec HTML files
|
|
||||||
│ ├── htmlAddInternalMethodLink.ts # Adds internal method links
|
|
||||||
│ ├── text-splitters/ # Text chunking utilities
|
|
||||||
│ └── utils/ # Formatting utilities
|
|
||||||
│ ├── mcp-server-stdio.ts # MCP server (stdio transport)
|
|
||||||
│ └── test/ # Manual verification tests
|
|
||||||
│ └── manual/
|
|
||||||
│ ├── verify-db.ts # Verify database contents
|
|
||||||
│ ├── test-search-spec-sections.ts # Test vector search tool
|
|
||||||
│ └── test-evaluate-in-engine262.ts # Test evaluate tool
|
|
||||||
├── spec-built/multipage/ # ECMAScript spec HTML files
|
|
||||||
├── engine262/src/ # JavaScript engine implementation
|
|
||||||
├── storage/ # Vector index persistence (LanceDB)
|
|
||||||
├── graphology/ # Knowledge graph JSON file
|
|
||||||
├── biome.json # Biome formatter config
|
|
||||||
├── tsconfig.json # TypeScript strict config
|
|
||||||
└── package.json # Bun-based dependencies
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun run ingest # Ingest spec HTML into vector index
|
bun run ingest # Ingest spec HTML into vector DB
|
||||||
bun run build # Build knowledge graph (spec → code mappings)
|
bun run build # Build knowledge graph
|
||||||
bun run lint # Check code with Biome
|
bun run lint # Biome check
|
||||||
bun run lint:fix # Fix auto-fixable issues
|
bun run type-check # TypeScript strict check
|
||||||
bun run format:fix # Format code with Biome
|
bun test # Run all Bun tests
|
||||||
bun run type-check # TypeScript check (no emit)
|
bun run ask262-stdio # Stdio transport
|
||||||
bun test # Run all tests
|
bun run ask262-http # HTTP transport (port 8081)
|
||||||
bun run test-evaluate # Test evaluate in engine262 tool
|
|
||||||
bun run test-search-spec-sections "query" # Test vector search tool with query
|
|
||||||
bun run agent "Query" # Run agent with question
|
|
||||||
bun run ask262-stdio # Start MCP server (stdio transport)
|
|
||||||
bun run test-mcp-server # Test MCP server with all tools
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## MCP Server
|
## Project Structure
|
||||||
|
|
||||||
Ask262 can run as an MCP (Model Context Protocol) server, making its tools available to any MCP-compatible client (Claude Desktop, OpenCode, etc.).
|
**Core:**
|
||||||
|
`src/agent-tools/` - MCP tool implementations
|
||||||
|
`src/mcp-server-stdio.ts` - Stdio server entry
|
||||||
|
`src/mcp-server-http.ts` - HTTP server entry
|
||||||
|
|
||||||
### Available MCP Tools
|
**Data:**
|
||||||
|
`storage/` - LanceDB vector index
|
||||||
|
`spec-built/multipage/` - ECMAScript spec HTML
|
||||||
|
`engine262/` - JS engine implementation (git submodule, ignored)
|
||||||
|
`graphology/` - Knowledge graph JSON
|
||||||
|
|
||||||
| Tool | Description |
|
**Setup:**
|
||||||
|------|-------------|
|
`src/setup/ingest.ts` - Creates vector DB from spec
|
||||||
| `ask262_search_spec_sections` | Vector search ECMAScript spec for relevant sections |
|
`src/setup/buildGraph.ts` - Maps spec sections to code
|
||||||
| `ask262_get_section_content` | Retrieve full content from a spec section |
|
|
||||||
| `ask262_evaluate_in_engine262` | Execute JS in engine262 and capture spec sections |
|
|
||||||
|
|
||||||
### Configuration
|
## Code Style
|
||||||
|
|
||||||
Add to your MCP client configuration:
|
**Imports:** ES modules only. Node built-ins use `node:` prefix. Never CommonJS.
|
||||||
|
|
||||||
**Claude Desktop (`claude_desktop_config.json`):**
|
**Formatting (Biome):** 2 spaces, 80 char width, LF endings. Excludes: `spec-built/`, `engine262/`, `graphology/`.
|
||||||
```json
|
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"ask262": {
|
|
||||||
"command": "bun",
|
|
||||||
"args": ["run", "/path/to/ask262/src/mcp-server-stdio.ts"],
|
|
||||||
"cwd": "/path/to/ask262"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**OpenCode (`.opencode/mcp.json` or `~/.config/opencode/opencode.json`):**
|
**TypeScript:** Strict mode enabled. Explicit return types. Avoid `any`. Target: ES2022.
|
||||||
|
|
||||||
*stdio (local process):*
|
**Naming:** Folders kebab-case (`agent-tools`). Files camelCase (`buildGraph.ts`). Functions camelCase (`createTool`). Constants UPPER_SNAKE_CASE. Types PascalCase.
|
||||||
```json
|
|
||||||
{
|
|
||||||
"$schema": "https://opencode.ai/config.json",
|
|
||||||
"mcp": {
|
|
||||||
"ask262": {
|
|
||||||
"type": "local",
|
|
||||||
"command": ["bun", "run", "src/mcp-server-stdio.ts"],
|
|
||||||
"enabled": true,
|
|
||||||
"environment": {
|
|
||||||
"OLLAMA_HOST": "http://localhost:11434"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
*http (stateless JSON server):*
|
**Error Handling:** Try/catch with meaningful messages. Validate env vars. Log warnings for missing config.
|
||||||
```json
|
|
||||||
{
|
|
||||||
"$schema": "https://opencode.ai/config.json",
|
|
||||||
"mcp": {
|
|
||||||
"ask262": {
|
|
||||||
"type": "remote",
|
|
||||||
"url": "http://localhost:8081/mcp",
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Start the HTTP server first:
|
**Comments & Documentation:**
|
||||||
```bash
|
- JSDoc for public functions: purpose, params, return values, examples
|
||||||
bun run ask262-http # Development
|
|
||||||
ask262-http # After npm install -g
|
|
||||||
```
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
Test the MCP server before configuring your client:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run automated tests for all MCP tools
|
|
||||||
bun run test-mcp-server
|
|
||||||
```
|
|
||||||
|
|
||||||
This tests:
|
|
||||||
- Tool listing
|
|
||||||
- Vector search (`ask262_search_spec_sections`)
|
|
||||||
- Section content retrieval (`ask262_get_section_content`)
|
|
||||||
- Code evaluation with console capture (`ask262_evaluate_in_engine262`)
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
Before running the MCP server:
|
|
||||||
1. Ensure `storage/` directory exists with ingested spec vectors (`bun run ingest`)
|
|
||||||
2. Ensure Ollama is running with `qwen3-embedding:0.6b` model
|
|
||||||
|
|
||||||
## Code Style Guidelines
|
|
||||||
|
|
||||||
### Imports & Modules
|
|
||||||
- Use ES modules (`import/export`), never CommonJS
|
|
||||||
- Node.js built-ins: `import fs from "node:fs"` (with `node:` prefix)
|
|
||||||
- Third-party: `import * as cheerio from "cheerio"`
|
|
||||||
- Package type: `"type": "module"` in package.json
|
|
||||||
|
|
||||||
### Formatting (Biome)
|
|
||||||
- **Indent**: 2 spaces (not tabs)
|
|
||||||
- **Line width**: 80 characters
|
|
||||||
- **Line ending**: LF
|
|
||||||
- **Excluded directories**: `spec-built/`, `engine262/`, `graphology/` (external/vendor)
|
|
||||||
|
|
||||||
### TypeScript
|
|
||||||
- **Target**: ES2022
|
|
||||||
- **Strict mode**: Enabled with `strict: true`
|
|
||||||
- **Module resolution**: Node
|
|
||||||
- Explicit types for function parameters and return values
|
|
||||||
- Use `as const` for literal arrays
|
|
||||||
- Avoid `any` - use proper types or `unknown`
|
|
||||||
- JSON imports: `resolveJsonModule: true`
|
|
||||||
|
|
||||||
### Naming Conventions
|
|
||||||
- **Folders**: kebab-case (e.g., `agent-tools`, `text-splitters`)
|
|
||||||
- **Files**: camelCase (e.g., `buildGraph.ts`, `specRetriever.ts`)
|
|
||||||
- **Functions**: camelCase (e.g., `createGraphExplorerTool`)
|
|
||||||
- **Constants**: UPPER_SNAKE_CASE or camelCase for exported constants
|
|
||||||
- **Types/Interfaces**: PascalCase with descriptive names
|
|
||||||
|
|
||||||
### Comments & Documentation
|
|
||||||
- JSDoc for public functions explaining purpose, params, return values
|
|
||||||
- Use `/** */` for documentation blocks
|
- Use `/** */` for documentation blocks
|
||||||
- Use `//` for inline implementation notes
|
- Use `//` for inline implementation notes
|
||||||
- Document complex logic or non-obvious decisions
|
- Document complex logic or non-obvious decisions
|
||||||
|
|
||||||
### Error Handling
|
## Environment
|
||||||
- Use `try/catch` for async operations with meaningful error messages
|
|
||||||
- Validate environment variables
|
Copy `.env.example` to `.env`:
|
||||||
- Check file existence before reading
|
- `ASK262_EMBEDDING_PROVIDER` - `ollama` or `fireworks`
|
||||||
- Log warnings for missing configuration rather than failing silently
|
- `FIREWORKS_API_KEY` - Required for Fireworks
|
||||||
|
- `OLLAMA_HOST` - Ollama URL (default: http://localhost:11434)
|
||||||
|
- `ASK262_PORT` - HTTP server port (default: 8081)
|
||||||
|
- `MCP_PUBLIC_URL` - Public URL for inspector
|
||||||
|
|
||||||
## Key Dependencies
|
## Key Dependencies
|
||||||
|
|
||||||
- **LangChain**: Agent framework and LLM integration (`langchain`, `@langchain/*`)
|
- **LanceDB** - Vector storage
|
||||||
- **LanceDB**: Vector storage for embeddings (`@lancedb/lancedb`)
|
- **Ollama** / **Fireworks** - Embeddings
|
||||||
- **Ollama**: Local embeddings (`@langchain/ollama`)
|
- **LangChain** - LLM framework
|
||||||
- **Graphology**: Knowledge graph library (`graphology`)
|
- **Hono** - HTTP server
|
||||||
- **Cheerio**: HTML parsing (`cheerio`)
|
- **Biome** - Lint/format
|
||||||
- **Biome**: Linting and formatting (`@biomejs/biome`)
|
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
1. Always use TypeScript for implementation - no plain JavaScript
|
- TypeScript only - no plain JS
|
||||||
2. Run type-check before committing: `bun run type-check`
|
- Run `bun run type-check` before committing
|
||||||
3. Ingest and build commands can take significant time due to local embedding generation
|
- Ingest/build are slow (local embedding generation)
|
||||||
4. External directories (`spec-built/`, `engine262/`, `graphology/`) should not be modified by linting/formatting
|
- Don't lint/format external dirs (`engine262/`, `spec-built/`, `graphology/`)
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ Use the hosted MCP server without any local setup:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Experiment with the Inspector:**
|
||||||
|
|
||||||
|
Visit `https://ask262.bendtherules.in/` to access the MCP Inspector UI. This provides an interactive interface to test all available tools with custom inputs.
|
||||||
|
|
||||||
## Local Installation
|
## Local Installation
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
@@ -157,6 +161,16 @@ bun run ask262-http # start HTTP server
|
|||||||
bun run ask262-http # start HTTP server
|
bun run ask262-http # start HTTP server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**HTTP Server Endpoints:**
|
||||||
|
|
||||||
|
| Endpoint | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `GET /health` | Health check |
|
||||||
|
| `GET/POST /mcp` | MCP protocol endpoint |
|
||||||
|
| `GET /` | MCP Inspector UI (auto-connects to /mcp) |
|
||||||
|
|
||||||
|
*Note: `/mcp` is defined before the inspector's catch-all `/` route to ensure proper request handling.*
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
"@langchain/core": "^0.2.0",
|
"@langchain/core": "^0.2.0",
|
||||||
"@langchain/ollama": "^0.1.0",
|
"@langchain/ollama": "^0.1.0",
|
||||||
"@langchain/openai": "^0.1.0",
|
"@langchain/openai": "^0.1.0",
|
||||||
|
"@mcp-use/inspector": "^2.1.0",
|
||||||
"@modelcontextprotocol/sdk": "^1.0.4",
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
||||||
"acorn": "^8.16.0",
|
"acorn": "^8.16.0",
|
||||||
"cheerio": "^1.2.0",
|
"cheerio": "^1.2.0",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import path from "node:path";
|
|||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { serve } from "@hono/node-server";
|
import { serve } from "@hono/node-server";
|
||||||
import * as lancedbSdk from "@lancedb/lancedb";
|
import * as lancedbSdk from "@lancedb/lancedb";
|
||||||
|
import { mountInspector } from "@mcp-use/inspector";
|
||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
@@ -252,6 +253,7 @@ export async function main() {
|
|||||||
app.get("/health", (c) => c.json({ status: "ok" }));
|
app.get("/health", (c) => c.json({ status: "ok" }));
|
||||||
|
|
||||||
// MCP endpoint - handles both GET and POST
|
// MCP endpoint - handles both GET and POST
|
||||||
|
// Must be defined BEFORE inspector (which mounts at /) for proper route matching
|
||||||
app.all("/mcp", async (c) => {
|
app.all("/mcp", async (c) => {
|
||||||
// Get parsed body from Hono (automatic JSON parsing)
|
// Get parsed body from Hono (automatic JSON parsing)
|
||||||
let parsedBody: unknown;
|
let parsedBody: unknown;
|
||||||
@@ -280,6 +282,14 @@ export async function main() {
|
|||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// MCP Inspector at root path - auto-connects to /mcp
|
||||||
|
// Mounted AFTER /mcp so specific routes take precedence
|
||||||
|
const mcpPublicUrl = process.env.COOLIFY_URL || process.env.MCP_PUBLIC_URL || `http://localhost:${PORT}`;
|
||||||
|
mountInspector(app, {
|
||||||
|
autoConnectUrl: `${mcpPublicUrl}/mcp`,
|
||||||
|
devMode: process.env.NODE_ENV !== "production",
|
||||||
|
});
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
console.log(`Ask262 MCP HTTP Server running on http://0.0.0.0:${PORT}`);
|
console.log(`Ask262 MCP HTTP Server running on http://0.0.0.0:${PORT}`);
|
||||||
console.log(`MCP endpoint: POST http://0.0.0.0:${PORT}/mcp`);
|
console.log(`MCP endpoint: POST http://0.0.0.0:${PORT}/mcp`);
|
||||||
|
|||||||
Reference in New Issue
Block a user