ark
by ruizrica
README.md
<p align="center">
<img src="./public/ark.png" width="320" height="160" alt="ark logo" />
</p>
<p align="center">
<strong>ark</strong> (from Arkenstone) — a self-hosted research vault on Cloudflare Workers with a native MCP server, so AI agents can search and (soon) maintain your knowledge base from anywhere.
</p>
<p align="center">
<a href="./CONTRIBUTING.md">Contributing</a> ·
<a href="./LICENSE">LGPL-3.0-only</a> ·
<a href="https://github.com/shuaiplus/inkstone">Upstream: Inkstone</a>
</p>
## About
ark is a fork of [Inkstone](https://github.com/shuaiplus/inkstone), a browser-based Markdown notebook that runs entirely on Cloudflare Workers (D1, R2, Durable Objects). ark keeps everything Inkstone does — editor, wiki links, backlinks, graph, FTS5 search, versions, sync, backups — and adds a **stateless MCP surface** so LLM agents become first-class users of the vault.
The goal is the Karpathy-style LLM-Wiki pattern in the cloud: raw sources are ingested, compiled by agents into wiki pages with indexes and cross-links, then queried during research — with the vault reachable from any machine, not just where the files live.
## The MCP surface
ark mounts an MCP endpoint at `/mcp`, implementing spec revision **2026-07-28** (fully stateless: no initialize handshake, no session ids) plus a dual-era shim that answers the legacy `initialize` handshake so current MCP clients connect today.
- **Auth**: personal access tokens (`ak_…`), minted by the owner, stored as SHA-256 hashes in D1 with per-token scopes and optional expiry.
- **Transport**: single JSON-RPC POST endpoint; validates `MCP-Protocol-Version`, `Mcp-Method`, and `Mcp-Name` headers against the body (spec error `-32020`), negotiates versions (`-32022`), answers `server/discover`, and serves cacheable `tools/list` results (`ttlMs`/`cacheScope`).
- **Tools** (walking skeleton): `search_wiki` — ranked FTS5 snippets scoped to the token's user. The query string supports `tag:name`, `folder:name`, `is:starred`, `is:archived`, `in:trash`, and `"quoted phrases"`. Read tools, write tools with MRTR, lint, and semantic search are planned.
## Authentication
ark signs users in with **Google OAuth only**. Password login and registration are disabled everywhere except local development.
### Enable Google sign-in (production)
1. In [Google Cloud Console](https://console.cloud.google.com/apis/credentials), create an **OAuth client ID** of type **Web application** with the authorized redirect URI `https://YOUR-WORKER/api/auth/google/callback`.
2. Configure the Worker:
```bash
npx wrangler secret put GOOGLE_CLIENT_SECRET
```
And in `wrangler.toml` under `[vars]`:
```toml
GOOGLE_CLIENT_ID = "…apps.googleusercontent.com"
GOOGLE_ALLOWED_EMAILS = "you@example.com"
```
Only the Google accounts in `GOOGLE_ALLOWED_EMAILS` (comma-separated, case-insensitive) can sign in; everyone signs into the owner's vault. If no owner account exists yet, the first allowed Google sign-in creates it.
### Local dev mode (password auth, local only)
Create a `.dev.vars` file (gitignored, read only by `wrangler dev` / vite — never deployed):
```ini
AUTH_DEV_MODE=1
```
With it, classic username/password register/login work locally for testing. Without it — i.e. in every deployment — password endpoints return `403 password_auth_disabled`.
### Mint an MCP token
In production: sign in with Google in the browser, then run this in the devtools console:
```js
await fetch('/api/mcp-tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Ark-Client': '1' },
body: JSON.stringify({ label: 'my-agent', ttlDays: 365 }),
}).then((r) => r.json())
```
In local dev mode the same endpoint works with a password session:
```bash
curl -s -c jar http://localhost:8787/api/auth/login \
-H 'Content-Type: application/json' -H 'X-Ark-Client: 1' \
-d '{"username":"you","password":"…"}'
curl -s -b jar http://localhost:8787/api/mcp-tokens -X POST \
-H 'Content-Type: application/json' -H 'X-Ark-Client: 1' \
-d '{"label":"my-agent"}'
```
The plaintext token is returned exactly once.
### Connect Claude Code
```bash
claude mcp add --transport http ark https://YOUR-WORKER/mcp \
--header "Authorization: Bearer ak_…"
```
### Call it raw (2026-07-28 strict mode)
```bash
curl -s https://YOUR-WORKER/mcp \
-H "Authorization: Bearer ak_…" -H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2026-07-28' -H 'Mcp-Method: tools/call' -H 'Mcp-Name: search_wiki' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_wiki","arguments":{"query":"tag:research \"exact phrase\""},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
```
## Inherited features
| Area | Included |
| --- | --- |
| Writing | CodeMirror 6 editor, **live preview**, editor/split/preview layouts, synchronized scrolling, outline, **focus mode**, **typewriter mode**, **autosave**, and **version history** |
| Markdown | Tables, task lists, footnotes, definition lists, callouts, tabs, **details blocks**, **math**, **Mermaid diagrams**, **syntax highlighting**, **Front Matter**, and Pandoc-style attributes |
| Organization | Nested folders, inline tags, favorites, pinning, archive, trash, **wiki links**, backlinks, block references, note embeds, and a relationship graph |
| Search | D1 FTS5 **full-text search** with Chinese indexing, filters, recent notes, and command-palette navigation |
| Reliability | Installable PWA, offline app launch, browser-side cache, **offline write queue, optimistic concurrency control**, conflict copies, realtime notifications, and polling fallback |
| Sharing | Public note links with optional access passwords and expiration dates |
| Portability | JSON and ZIP exports, directly readable **Markdown**, attachment export, and **manual or scheduled WebDAV/S3 backups** |
| Interface | **Desktop and mobile layouts**, **dark/light themes**, accent colors, English by default |
## Data storage
| Component | Purpose |
| --- | --- |
| Cloudflare D1 | Accounts, notes, folders, tags, settings, versions, shares, search indexes, and MCP tokens |
| Cloudflare R2 or Workers KV | Attachment and uploaded-avatar binaries through the `FILES` or `FILES_KV` binding |
| Browser IndexedDB | Local cache and pending offline writes |
| `SyncHub` Durable Object | Realtime change notifications between active clients (the MCP path never touches it) |
| `CredentialVault` Durable Object | Isolated storage for the key used to encrypt backup credentials |
| WebDAV or S3 storage | User-configured off-site backups |
## Deployment
1. Fork this repository to your GitHub account.
2. Open [Cloudflare Workers & Pages](https://dash.cloudflare.com/?to=/:account/workers-and-pages/create) and connect the fork, or run `npm run deploy` locally with wrangler authenticated.
3. Configure Google sign-in (see Authentication) and open the deployed URL.
4. Mint an MCP token and connect your agent.
Note: the schema initializer asserts the final schema and does not run migrations. If you upgrade an existing deployment across a schema change, apply the new DDL manually with `wrangler d1 execute` (see `src/worker/db/schema.ts`).
## Development and verification
Requires Node `^24.15.0`.
| Command | Purpose |
| --- | --- |
| `npm run dev` | Start the local Worker and client |
| `npm run typecheck` | Run TypeScript project checks |
| `npm run test:unit` | Run the Vitest suite, including worker tests on real workerd D1 (`*.workers.test.ts`) |
| `npm run i18n:check` | Verify parity between the bundled locale resources |
| `npm run comments:check` | Enforce the source-comment policy (new files register their header in `scripts/check-comments.mjs`) |
| `npm run build` | Type-check and create a production build |
| `npm run deploy` | Build and deploy with wrangler |
| `npm run test:e2e` | Exercise the API against a running disposable local instance |
## Repository layout
```text
src/
├── client/ React interface, editor, preview, and local state
├── shared/ Shared types, limits, locale resources, and Markdown utilities
└── worker/ Hono API, authentication, D1 access, sync, sharing, backups,
and the MCP surface (src/worker/mcp/)
public/ Static assets
scripts/ Repository checks and end-to-end verification scripts
tests/ Cross-module regression tests
```
## Security and contributions
Read [`SECURITY.md`](./SECURITY.md) before reporting a vulnerability. Development setup and contribution requirements are documented in [`CONTRIBUTING.md`](./CONTRIBUTING.md).
## Credits and license
ark is created and maintained by **Ricardo Ruiz** ([@ruizrica](https://github.com/ruizrica)).
It is a derivative work of [Inkstone](https://github.com/shuaiplus/inkstone) by [shuaiplus](https://github.com/shuaiplus), distributed under the [GNU Lesser General Public License v3.0 only](./LICENSE) (`LGPL-3.0-only`). ark keeps the same license.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing