opencontext-mcp 1.0.0 → 1.2.0

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/README.md CHANGED
@@ -1,47 +1,39 @@
1
- # OpenContext MCP
1
+ <p align="center">
2
+ <a href="https://opencntx.dev">
3
+ <img src="https://github.com/slxca/opencontext/blob/master/apps/web/public/opencontext.png?raw=true" alt="OpenContext logo" width="500">
4
+ </a>
5
+ </p>
2
6
 
3
- [![MCP](https://img.shields.io/badge/MCP-compatible-2563eb)](https://modelcontextprotocol.io/)
4
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6)](https://www.typescriptlang.org/)
5
- [![Node.js](https://img.shields.io/badge/Node.js-20%2B-339933)](https://nodejs.org/)
6
- [![Website](https://img.shields.io/badge/URL-opencntx.dev-c42f52?link=https%3A%2F%2Fopencntx.dev)](https://opencntx.dev/)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+ <p align="center"><b>Persistent, project-local memory for AI coding agents.</b></p>
8
8
 
9
- OpenContext MCP gives AI agents persistent, project-local memory.
9
+ <p align="center">
10
+ <a href="https://opencntx.dev"><img alt="Website" src="https://img.shields.io/badge/website-opencntx.dev-191919?style=flat-square" /></a>
11
+ <a href="https://www.npmjs.com/package/opencontext-mcp"><img alt="npm version" src="https://img.shields.io/npm/v/opencontext-mcp?style=flat-square" /></a>
12
+ <a href="https://github.com/slxca/opencontext/actions"><img alt="CI status" src="https://img.shields.io/github/actions/workflow/status/slxca/opencontext/ci.yml?style=flat-square&branch=master" /></a>
13
+ </p>
10
14
 
11
- Most coding agents lose important decisions between sessions: architecture rules, naming conventions, API contracts, migration notes, and hard-won debugging context. OpenContext MCP solves that by exposing a tiny Model Context Protocol server that lets agents save and read markdown files in a local `.opencontext/` directory inside each project.
15
+ ---
12
16
 
13
- The result is simple and transparent: your agent gets memory, and you keep full control because the memory is plain markdown committed or ignored however you choose.
17
+ Most coding agents lose critical decisions between sessions: architecture invariants, API contracts, rejected patterns, and setup quirks. OpenContext solves context loss through a lightweight Model Context Protocol (MCP) server that lets agents read and mutate durable markdown files inside `.opencontext/`.
14
18
 
15
- ## Features
19
+ No vector databases, no cloud subscriptions, and no hidden state. Memory is plain markdown tracked directly in Git.
16
20
 
17
- - `save_context`: save markdown context to `.opencontext/<topic>.md`
18
- - `read_context`: read one saved topic or list all available topics
19
- - Project-specific storage based on the client's current working directory
20
- - No database, account, cloud sync, or hidden state
21
- - Works with MCP-compatible clients over stdio
22
- - Built with strict TypeScript and the official `@modelcontextprotocol/sdk`
21
+ ---
23
22
 
24
- ## Installation
23
+ ### Quickstart
25
24
 
26
- You normally do not need to install OpenContext MCP manually. Configure your MCP client to run it with `npx`:
25
+ Run directly without installation via `npx`:
27
26
 
28
27
  ```bash
29
28
  npx -y opencontext-mcp
30
- ```
31
-
32
- For local development in this repository:
33
29
 
34
- ```bash
35
- pnpm install
36
- pnpm build
37
- pnpm start
38
30
  ```
39
31
 
40
- ## MCP Client Setup
32
+ ### Client Setup
41
33
 
42
- ### OpenCode
34
+ #### OpenCode
43
35
 
44
- Add OpenContext MCP to your OpenCode MCP configuration:
36
+ Add OpenContext to your project MCP configuration (`opencode.json`):
45
37
 
46
38
  ```json
47
39
  {
@@ -53,11 +45,12 @@ Add OpenContext MCP to your OpenCode MCP configuration:
53
45
  }
54
46
  }
55
47
  }
48
+
56
49
  ```
57
50
 
58
- ### Cursor / Claude Desktop
51
+ #### Cursor / Claude Desktop / Windsurf
59
52
 
60
- Cursor and Claude Desktop use the same MCP server configuration:
53
+ Add OpenContext to your MCP settings file (`claude_desktop_config.json` or Cursor MCP settings):
61
54
 
62
55
  ```json
63
56
  {
@@ -68,128 +61,116 @@ Cursor and Claude Desktop use the same MCP server configuration:
68
61
  }
69
62
  }
70
63
  }
64
+
71
65
  ```
72
66
 
73
- Restart your MCP client after updating the configuration.
67
+ ---
74
68
 
75
- ## How It Works
69
+ ### Core Tools
76
70
 
77
- OpenContext MCP stores files relative to the process working directory used by your MCP client:
71
+ | Tool | Parameters | Description |
72
+ | --- | --- | --- |
73
+ | `read_context` | `topic?` *(optional string)* | Reads a specific context topic, or returns the lightweight topic index (~100 tokens) if omitted. |
74
+ | `save_context` | `topic` *(string)*, `content` *(string)* | Writes or mutates markdown memory inside `.opencontext/<topic>.md` with built-in write guards and symlink protections. |
75
+ | `delete_context` | `topic` *(string)* | Removes an obsolete topic file and automatically rebuilds the topic index. |
78
76
 
79
- ```text
80
- your-project/
81
- .opencontext/
82
- architecture.md
83
- api-contracts.md
84
- coding_rules.md
85
- ```
77
+ ---
86
78
 
87
- Topics must be lowercase snake_case or kebab-case, such as `architecture`, `api-contracts`, or `coding_rules`.
79
+ ### ADR Lifecycle & Frontmatter
88
80
 
89
- ## Available Tools
81
+ Topics support optional YAML frontmatter to track lifecycle status — useful when architectural decisions evolve and old context should be visible but clearly flagged as outdated.
90
82
 
91
- ### `save_context`
83
+ ````markdown
84
+ ---
85
+ description: OAuth2 + PKCE authentication flow
86
+ status: active
87
+ supersedes: auth_v1
88
+ ---
92
89
 
93
- Saves markdown content to `.opencontext/<topic>.md`. Existing files are overwritten.
90
+ # Authentication v2
94
91
 
95
- Arguments:
92
+ Migrated from JWT to OAuth2 with PKCE.
93
+ ````
96
94
 
97
- | Name | Type | Required | Description |
98
- | --------- | ------ | -------- | --------------------------------------------- |
99
- | `topic` | string | yes | Lowercase snake_case or kebab-case topic name |
100
- | `content` | string | yes | Markdown content to save |
95
+ **Supported frontmatter keys:**
101
96
 
102
- Example use:
97
+ | Key | Values | Description |
98
+ | --- | --- | --- |
99
+ | `description` | string | Short summary used in the auto-generated index. |
100
+ | `status` | `active` \| `deprecated` \| `superseded` | Lifecycle status. Defaults to `active` when omitted. |
101
+ | `supersedes` | string | Topic name this topic replaces *(set on the newer topic)*. |
102
+ | `superseded_by` | string | Topic name that replaced this one *(set on the older topic)*. |
103
103
 
104
- ```text
105
- Save our API conventions under topic api-contracts.
106
- ```
104
+ Non-active topics automatically receive `[DEPRECATED]` or `[SUPERSEDED]` badges in the auto-generated `index.md`, along with cross-references showing which topic replaced or was replaced.
107
105
 
108
- ### `read_context`
106
+ ---
109
107
 
110
- Reads one saved topic, or lists all topics when no topic is provided.
108
+ ### Agent Workflows
111
109
 
112
- Arguments:
110
+ Instruct your agents to automatically leverage project context. Add this snippet to your `.cursorrules`, `CLAUDE.md`, or system prompt:
113
111
 
114
- | Name | Type | Required | Description |
115
- | ------- | ------ | -------- | ------------- |
116
- | `topic` | string | no | Topic to read |
112
+ ```markdown
113
+ Before making structural code changes, run `read_context` to inspect existing project topics and architectural decisions.
117
114
 
118
- Example use:
115
+ Whenever a new architectural convention, database schema, or API rule is established or refactored, call `save_context` with a concise, topic-scoped markdown summary. Use YAML frontmatter (status, supersedes) when updating conventions to track lifecycle changes.
119
116
 
120
- ```text
121
- Read the architecture context before changing the routing layer.
117
+ When a topic becomes obsolete, call `delete_context` to remove it. For deprecated topics that should remain visible, set status: deprecated or status: superseded in the frontmatter instead of deleting.
122
118
  ```
123
119
 
124
- ## How To Instruct Agents
125
-
126
- MCP tools are most useful when your agent is explicitly told when to use them. Add instructions like these to your system prompt or project rules:
120
+ ---
127
121
 
128
- ```text
129
- Always use read_context before making code changes. First list available topics, then read any topic relevant to the task.
122
+ ### Configuration
130
123
 
131
- Use save_context whenever you learn a durable project rule, architectural decision, convention, API contract, or debugging note that future agents should know.
124
+ Customize storage paths and security boundaries with an optional `.opencontext.jsonc` file in your repository root:
132
125
 
133
- Prefer small, focused context topics in snake_case or kebab-case. Keep the content concise, factual, and written in markdown.
134
- ```
126
+ ```jsonc
127
+ {
128
+ // Storage location (default: ".opencontext")
129
+ "path": ".opencontext",
135
130
 
136
- Recommended workflow:
131
+ // Prevent agents from writing or updating files
132
+ "readOnly": false,
137
133
 
138
- 1. Ask an architect or planning agent to analyze the project and save durable decisions with `save_context`.
139
- 2. Ask build agents to call `read_context` before coding.
140
- 3. Let agents update context when they discover something that should survive the current chat.
141
- 4. Review `.opencontext/` files like normal project documentation.
134
+ // Auto-generate index.md with topic descriptions
135
+ "autoIndex": true,
142
136
 
143
- Copy-ready agent prompts:
137
+ // Write guard & prompt injection defenses
138
+ "guard": {
139
+ "enabled": true,
140
+ "maxFileSizeKb": 50,
141
+ "strictPatternCheck": true
142
+ }
143
+ }
144
144
 
145
- - [`examples/plan-agent.md`](examples/plan-agent.md) -- architect that analyzes requirements and saves context
146
- - [`examples/build-agent.md`](examples/build-agent.md) -- developer that reads context before coding
145
+ ```
147
146
 
148
- ## Version Control
147
+ ---
149
148
 
150
- You can commit `.opencontext/` when it contains team-wide knowledge:
149
+ ### Local Development
151
150
 
152
151
  ```bash
153
- git add .opencontext
154
- ```
152
+ # Clone and install dependencies
153
+ git clone [https://github.com/slxca/opencontext.git](https://github.com/slxca/opencontext.git)
154
+ cd opencontext
155
+ pnpm install
155
156
 
156
- Or ignore it when context should stay local:
157
+ # Build & run tests
158
+ pnpm build
159
+ pnpm test
157
160
 
158
- ```gitignore
159
- .opencontext/
160
161
  ```
161
162
 
162
- Because files are plain markdown, both approaches are safe and easy to audit.
163
+ ---
163
164
 
164
- ## Development
165
+ ### Documentation
165
166
 
166
- ```bash
167
- pnpm install
168
- pnpm build # compile TypeScript
169
- pnpm typecheck # type-check without emitting
170
- pnpm test # run vitest suite
171
- pnpm start # start the MCP server
172
- ```
167
+ For advanced setup guides, guard parameters, and agent prompt templates, visit **[opencntx.dev/docs](https://www.google.com/search?q=https://opencntx.dev/docs)**.
173
168
 
174
- Project structure:
175
-
176
- ```text
177
- src/
178
- index.ts CLI entrypoint (stdio transport, startup error handling)
179
- server.ts McpServer factory and tool registration
180
- context-store.ts Filesystem operations for .opencontext/
181
- validation.ts Topic validation and input rules
182
- types.ts Shared constants, error classes, and result helpers
183
- test/
184
- validation.test.ts Unit tests for topic validation
185
- context-store.test.ts Unit tests for read/write/list operations
186
- examples/
187
- plan-agent.md Architect system prompt
188
- build-agent.md Developer system prompt
189
- README.md User documentation
190
- LICENSE MIT license
191
- ```
169
+ ### Contributing
192
170
 
193
- ## License
171
+ Contributions are welcome. Please ensure all unit tests and typechecks pass before submitting a pull request:
194
172
 
195
- MIT
173
+ ```bash
174
+ pnpm typecheck && pnpm test
175
+
176
+ ```
@@ -0,0 +1,24 @@
1
+ export interface OpenContextConfig {
2
+ $schema?: string;
3
+ path?: string;
4
+ readOnly?: boolean;
5
+ disabled?: boolean;
6
+ autoIndex?: boolean;
7
+ history?: {
8
+ enabled?: boolean;
9
+ maxBackupsPerTopic?: number;
10
+ retentionDays?: number;
11
+ };
12
+ guard?: {
13
+ enabled?: boolean;
14
+ maxFileSizeKb?: number;
15
+ strictPatternCheck?: boolean;
16
+ };
17
+ }
18
+ export type ResolvedConfig = Required<Omit<OpenContextConfig, "$schema">>;
19
+ export declare const DEFAULT_CONFIG: ResolvedConfig;
20
+ /**
21
+ * Loads configuration from .opencontext.jsonc or .opencontext.json in the given directory.
22
+ * Falls back to DEFAULT_CONFIG if no file exists or parsing fails.
23
+ */
24
+ export declare function loadConfig(cwd?: string): Promise<ResolvedConfig>;
package/dist/config.js ADDED
@@ -0,0 +1,145 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ export const DEFAULT_CONFIG = {
4
+ path: ".opencontext",
5
+ readOnly: false,
6
+ disabled: false,
7
+ autoIndex: true,
8
+ history: {
9
+ enabled: false,
10
+ maxBackupsPerTopic: 5,
11
+ retentionDays: 7,
12
+ },
13
+ guard: {
14
+ enabled: true,
15
+ maxFileSizeKb: 50,
16
+ strictPatternCheck: true,
17
+ },
18
+ };
19
+ const CONFIG_CANDIDATES = [".opencontext.jsonc", ".opencontext.json"];
20
+ /**
21
+ * Strips JSONC content into parseable JSON by removing comments and trailing commas.
22
+ * Handles single-line (//), multi-line (/* * /), and trailing commas.
23
+ * Trailing comma removal is token-aware to avoid modifying string literals.
24
+ */
25
+ function stripJsonComments(raw) {
26
+ let result = "";
27
+ let i = 0;
28
+ const len = raw.length;
29
+ while (i < len) {
30
+ const ch = raw[i];
31
+ // Strings: copy verbatim (including escaped characters)
32
+ if (ch === '"') {
33
+ result += ch;
34
+ i++;
35
+ while (i < len && raw[i] !== '"') {
36
+ if (raw[i] === "\\") {
37
+ result += raw[i];
38
+ i++;
39
+ }
40
+ if (i < len) {
41
+ result += raw[i];
42
+ i++;
43
+ }
44
+ }
45
+ if (i < len) {
46
+ result += raw[i]; // closing quote
47
+ i++;
48
+ }
49
+ continue;
50
+ }
51
+ // Single-line comment: skip until newline
52
+ if (ch === "/" && i + 1 < len && raw[i + 1] === "/") {
53
+ while (i < len && raw[i] !== "\n") {
54
+ i++;
55
+ }
56
+ continue;
57
+ }
58
+ // Multi-line comment: skip until */
59
+ if (ch === "/" && i + 1 < len && raw[i + 1] === "*") {
60
+ i += 2;
61
+ while (i < len - 1 && !(raw[i] === "*" && raw[i + 1] === "/")) {
62
+ i++;
63
+ }
64
+ i += 2; // skip */
65
+ continue;
66
+ }
67
+ // Trailing comma: skip comma if followed by optional whitespace/comments then } or ]
68
+ if (ch === ",") {
69
+ let j = i + 1;
70
+ // Skip whitespace and comments to find the next meaningful token
71
+ while (j < len) {
72
+ if (raw[j] === " " || raw[j] === "\t" || raw[j] === "\n" || raw[j] === "\r") {
73
+ j++;
74
+ }
75
+ else if (raw[j] === "/" && j + 1 < len && raw[j + 1] === "/") {
76
+ while (j < len && raw[j] !== "\n")
77
+ j++;
78
+ }
79
+ else if (raw[j] === "/" && j + 1 < len && raw[j + 1] === "*") {
80
+ j += 2;
81
+ while (j < len - 1 && !(raw[j] === "*" && raw[j + 1] === "/"))
82
+ j++;
83
+ j += 2;
84
+ }
85
+ else {
86
+ break;
87
+ }
88
+ }
89
+ if (j < len && (raw[j] === "}" || raw[j] === "]")) {
90
+ i = j; // skip comma and whitespace/comments, continue from closing bracket
91
+ continue;
92
+ }
93
+ // Not a trailing comma — keep it
94
+ result += ch;
95
+ i++;
96
+ continue;
97
+ }
98
+ result += ch;
99
+ i++;
100
+ }
101
+ return result;
102
+ }
103
+ function deepMerge(target, source) {
104
+ const result = { ...target };
105
+ for (const key of Object.keys(source)) {
106
+ const sourceVal = source[key];
107
+ const targetVal = result[key];
108
+ if (sourceVal !== null &&
109
+ typeof sourceVal === "object" &&
110
+ !Array.isArray(sourceVal) &&
111
+ targetVal !== null &&
112
+ typeof targetVal === "object" &&
113
+ !Array.isArray(targetVal)) {
114
+ result[key] = deepMerge(targetVal, sourceVal);
115
+ }
116
+ else if (sourceVal !== undefined) {
117
+ result[key] = sourceVal;
118
+ }
119
+ }
120
+ return result;
121
+ }
122
+ /**
123
+ * Loads configuration from .opencontext.jsonc or .opencontext.json in the given directory.
124
+ * Falls back to DEFAULT_CONFIG if no file exists or parsing fails.
125
+ */
126
+ export async function loadConfig(cwd = process.cwd()) {
127
+ for (const filename of CONFIG_CANDIDATES) {
128
+ const filePath = path.join(cwd, filename);
129
+ try {
130
+ const raw = await readFile(filePath, "utf8");
131
+ const cleaned = stripJsonComments(raw);
132
+ const parsed = JSON.parse(cleaned);
133
+ return deepMerge(DEFAULT_CONFIG, parsed);
134
+ }
135
+ catch (error) {
136
+ if (error.code === "ENOENT") {
137
+ continue; // file doesn't exist, try next candidate
138
+ }
139
+ console.error(`OpenContext: failed to parse ${filename}: ${error.message}`);
140
+ return DEFAULT_CONFIG;
141
+ }
142
+ }
143
+ return DEFAULT_CONFIG;
144
+ }
145
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,63 @@
1
+ import { type ResolvedConfig } from "./config.js";
2
+ /**
3
+ * Manages context file storage operations.
4
+ * Handles reading, writing, and listing context files in the configured directory.
5
+ */
1
6
  export declare class ContextStore {
2
7
  private readonly basePath;
3
- constructor(basePath?: string);
8
+ private readonly config;
9
+ private readonly contextDir;
10
+ constructor(basePath?: string, config?: ResolvedConfig);
11
+ /** Returns the absolute path to the context directory. */
4
12
  getContextDirectory(): string;
13
+ /** Returns the absolute path to a topic file. */
5
14
  getTopicFilePath(topic: string): string;
15
+ /**
16
+ * Saves context content to a topic file.
17
+ * Validates payload using WriteGuard before writing.
18
+ * @param topicInput - Topic name (will be validated and trimmed)
19
+ * @param content - Markdown content to save
20
+ * @returns Success message with file location
21
+ * @throws UserInputError if validation fails
22
+ */
6
23
  saveContext(topicInput: string, content: string): Promise<string>;
24
+ /**
25
+ * Reads context content from a topic file, or lists all topics if none specified.
26
+ * @param topicInput - Optional topic name to read
27
+ * @returns Topic content or list of available topics
28
+ * @throws UserInputError if topic doesn't exist or is invalid
29
+ */
7
30
  readContext(topicInput?: string): Promise<string>;
31
+ /**
32
+ * Deletes a context topic file from the context directory.
33
+ * @param topicInput - Topic name to delete
34
+ * @returns Success message with confirmation
35
+ * @throws UserInputError if topic doesn't exist or is invalid
36
+ */
37
+ deleteContext(topicInput: string): Promise<string>;
38
+ /**
39
+ * Lists all available context topics.
40
+ * Scans the context directory for .md files and returns sorted topic names.
41
+ * @returns Sorted array of topic names
42
+ */
8
43
  listTopics(): Promise<string[]>;
44
+ /**
45
+ * Parses YAML frontmatter from markdown content.
46
+ * Returns extracted fields or empty object if no frontmatter found.
47
+ * Uses simple line-by-line parsing — no external YAML dependency.
48
+ */
49
+ private parseFrontmatter;
50
+ /**
51
+ * Extracts a short description from markdown content.
52
+ * Strategy: frontmatter description → first heading → first paragraph → fallback.
53
+ * @param content - Raw markdown content
54
+ * @returns Truncated description (max 120 chars)
55
+ */
56
+ private extractDescription;
57
+ /**
58
+ * Rebuilds the auto-generated index.md file in the context directory.
59
+ * Scans all topic files, extracts metadata, and writes a compact index.
60
+ * @returns The generated index markdown content
61
+ */
62
+ rebuildContextIndex(): Promise<string>;
9
63
  }