opencontext-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenContext Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # OpenContext MCP
2
+
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
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ OpenContext MCP gives AI agents persistent, project-local memory.
9
+
10
+ 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.
11
+
12
+ 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.
13
+
14
+ ## Features
15
+
16
+ - `save_context`: save markdown context to `.opencontext/<topic>.md`
17
+ - `read_context`: read one saved topic or list all available topics
18
+ - Project-specific storage based on the client's current working directory
19
+ - No database, account, cloud sync, or hidden state
20
+ - Works with MCP-compatible clients over stdio
21
+ - Built with strict TypeScript and the official `@modelcontextprotocol/sdk`
22
+
23
+ ## Installation
24
+
25
+ You normally do not need to install OpenContext MCP manually. Configure your MCP client to run it with `npx`:
26
+
27
+ ```bash
28
+ npx -y opencontext-mcp
29
+ ```
30
+
31
+ For local development in this repository:
32
+
33
+ ```bash
34
+ pnpm install
35
+ pnpm build
36
+ pnpm start
37
+ ```
38
+
39
+ ## MCP Client Setup
40
+
41
+ ### OpenCode
42
+
43
+ Add OpenContext MCP to your OpenCode MCP configuration:
44
+
45
+ ```json
46
+ {
47
+ "mcp": {
48
+ "opencontext": {
49
+ "type": "local",
50
+ "command": ["npx", "-y", "opencontext-mcp"],
51
+ "enabled": true
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Cursor
58
+
59
+ Add this server to your Cursor MCP configuration:
60
+
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "opencontext": {
65
+ "command": "npx",
66
+ "args": ["-y", "opencontext-mcp"]
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### Claude Desktop
73
+
74
+ Add this entry to your Claude Desktop MCP configuration:
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "opencontext": {
80
+ "command": "npx",
81
+ "args": ["-y", "opencontext-mcp"]
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ Restart your MCP client after updating configuration.
88
+
89
+ ## How It Works
90
+
91
+ OpenContext MCP stores files relative to the process working directory used by your MCP client:
92
+
93
+ ```text
94
+ your-project/
95
+ .opencontext/
96
+ architecture.md
97
+ api-contracts.md
98
+ coding_rules.md
99
+ ```
100
+
101
+ Topics must be lowercase snake_case or kebab-case, such as `architecture`, `api-contracts`, or `coding_rules`.
102
+
103
+ ## Available Tools
104
+
105
+ ### `save_context`
106
+
107
+ Saves markdown content to `.opencontext/<topic>.md`. Existing files are overwritten.
108
+
109
+ Arguments:
110
+
111
+ | Name | Type | Required | Description |
112
+ | --------- | ------ | -------- | --------------------------------------------- |
113
+ | `topic` | string | yes | Lowercase snake_case or kebab-case topic name |
114
+ | `content` | string | yes | Markdown content to save |
115
+
116
+ Example use:
117
+
118
+ ```text
119
+ Save our API conventions under topic api-contracts.
120
+ ```
121
+
122
+ ### `read_context`
123
+
124
+ Reads one saved topic, or lists all topics when no topic is provided.
125
+
126
+ Arguments:
127
+
128
+ | Name | Type | Required | Description |
129
+ | ------- | ------ | -------- | ------------- |
130
+ | `topic` | string | no | Topic to read |
131
+
132
+ Example use:
133
+
134
+ ```text
135
+ Read the architecture context before changing the routing layer.
136
+ ```
137
+
138
+ ## How To Instruct Agents
139
+
140
+ 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:
141
+
142
+ ```text
143
+ Always use read_context before making code changes. First list available topics, then read any topic relevant to the task.
144
+
145
+ Use save_context whenever you learn a durable project rule, architectural decision, convention, API contract, or debugging note that future agents should know.
146
+
147
+ Prefer small, focused context topics in snake_case or kebab-case. Keep the content concise, factual, and written in markdown.
148
+ ```
149
+
150
+ Recommended workflow:
151
+
152
+ 1. Ask an architect or planning agent to analyze the project and save durable decisions with `save_context`.
153
+ 2. Ask build agents to call `read_context` before coding.
154
+ 3. Let agents update context when they discover something that should survive the current chat.
155
+ 4. Review `.opencontext/` files like normal project documentation.
156
+
157
+ Copy-ready agent prompts:
158
+
159
+ - [`examples/plan-agent.md`](examples/plan-agent.md) -- architect that analyzes requirements and saves context
160
+ - [`examples/build-agent.md`](examples/build-agent.md) -- developer that reads context before coding
161
+
162
+ ## Version Control
163
+
164
+ You can commit `.opencontext/` when it contains team-wide knowledge:
165
+
166
+ ```bash
167
+ git add .opencontext
168
+ ```
169
+
170
+ Or ignore it when context should stay local:
171
+
172
+ ```gitignore
173
+ .opencontext/
174
+ ```
175
+
176
+ Because files are plain markdown, both approaches are safe and easy to audit.
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ pnpm install
182
+ pnpm build # compile TypeScript
183
+ pnpm typecheck # type-check without emitting
184
+ pnpm test # run vitest suite
185
+ pnpm start # start the MCP server
186
+ ```
187
+
188
+ Project structure:
189
+
190
+ ```text
191
+ src/
192
+ index.ts CLI entrypoint (stdio transport, startup error handling)
193
+ server.ts McpServer factory and tool registration
194
+ context-store.ts Filesystem operations for .opencontext/
195
+ validation.ts Topic validation and input rules
196
+ types.ts Shared constants, error classes, and result helpers
197
+ test/
198
+ validation.test.ts Unit tests for topic validation
199
+ context-store.test.ts Unit tests for read/write/list operations
200
+ examples/
201
+ plan-agent.md Architect system prompt
202
+ build-agent.md Developer system prompt
203
+ README.md User documentation
204
+ LICENSE MIT license
205
+ ```
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,9 @@
1
+ export declare class ContextStore {
2
+ private readonly basePath;
3
+ constructor(basePath?: string);
4
+ getContextDirectory(): string;
5
+ getTopicFilePath(topic: string): string;
6
+ saveContext(topicInput: string, content: string): Promise<string>;
7
+ readContext(topicInput?: string): Promise<string>;
8
+ listTopics(): Promise<string[]>;
9
+ }
@@ -0,0 +1,59 @@
1
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { CONTEXT_DIRECTORY_NAME, UserInputError, isNodeError } from "./types.js";
4
+ import { validateTopic } from "./validation.js";
5
+ export class ContextStore {
6
+ basePath;
7
+ constructor(basePath = process.cwd()) {
8
+ this.basePath = basePath;
9
+ }
10
+ getContextDirectory() {
11
+ return path.join(this.basePath, CONTEXT_DIRECTORY_NAME);
12
+ }
13
+ getTopicFilePath(topic) {
14
+ return path.join(this.getContextDirectory(), `${topic}.md`);
15
+ }
16
+ async saveContext(topicInput, content) {
17
+ const topic = validateTopic(topicInput);
18
+ const contextDirectory = this.getContextDirectory();
19
+ const filePath = this.getTopicFilePath(topic);
20
+ await mkdir(contextDirectory, { recursive: true });
21
+ await writeFile(filePath, content, "utf8");
22
+ return `Saved context topic "${topic}" to ${CONTEXT_DIRECTORY_NAME}/${topic}.md.`;
23
+ }
24
+ async readContext(topicInput) {
25
+ if (topicInput !== undefined) {
26
+ const topic = validateTopic(topicInput);
27
+ try {
28
+ return await readFile(this.getTopicFilePath(topic), "utf8");
29
+ }
30
+ catch (error) {
31
+ if (isNodeError(error) && error.code === "ENOENT") {
32
+ throw new UserInputError(`No context found for topic "${topic}" at ${CONTEXT_DIRECTORY_NAME}/${topic}.md.`);
33
+ }
34
+ throw error;
35
+ }
36
+ }
37
+ const topics = await this.listTopics();
38
+ if (topics.length === 0) {
39
+ return `No OpenContext topics found in ${CONTEXT_DIRECTORY_NAME}/. Use save_context to create one.`;
40
+ }
41
+ return `Available OpenContext topics:\n\n${topics.map((topic) => `- ${topic}`).join("\n")}`;
42
+ }
43
+ async listTopics() {
44
+ try {
45
+ const entries = await readdir(this.getContextDirectory(), { withFileTypes: true });
46
+ return entries
47
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
48
+ .map((entry) => entry.name.slice(0, -".md".length))
49
+ .sort((a, b) => a.localeCompare(b));
50
+ }
51
+ catch (error) {
52
+ if (isNodeError(error) && error.code === "ENOENT") {
53
+ return [];
54
+ }
55
+ throw error;
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=context-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-store.js","sourceRoot":"","sources":["../src/context-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createOpenContextServer } from "./server.js";
4
+ import { SERVER_NAME, getErrorMessage } from "./types.js";
5
+ async function main() {
6
+ const server = createOpenContextServer();
7
+ const transport = new StdioServerTransport();
8
+ await server.connect(transport);
9
+ }
10
+ main().catch((error) => {
11
+ console.error(`Failed to start ${SERVER_NAME}: ${getErrorMessage(error)}`);
12
+ process.exit(1);
13
+ });
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1D,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,mBAAmB,WAAW,KAAK,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createOpenContextServer(basePath?: string): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,51 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { ContextStore } from "./context-store.js";
4
+ import { SERVER_NAME, SERVER_VERSION, getErrorMessage, textResult } from "./types.js";
5
+ export function createOpenContextServer(basePath) {
6
+ const store = new ContextStore(basePath);
7
+ const server = new McpServer({
8
+ name: SERVER_NAME,
9
+ version: SERVER_VERSION,
10
+ });
11
+ server.registerTool("save_context", {
12
+ title: "Save Context",
13
+ description: "Persist markdown project context, architectural rules, or decisions into .opencontext/<topic>.md in the current working directory.",
14
+ inputSchema: {
15
+ topic: z
16
+ .string()
17
+ .min(1)
18
+ .describe("Context topic name in snake_case or kebab-case, for example api_contracts or auth-rules."),
19
+ content: z.string().min(1).describe("Markdown content to save for this project topic."),
20
+ },
21
+ }, async ({ topic, content }) => {
22
+ try {
23
+ const result = await store.saveContext(topic, content);
24
+ return textResult(result);
25
+ }
26
+ catch (error) {
27
+ return textResult(`OpenContext error: ${getErrorMessage(error)}`, true);
28
+ }
29
+ });
30
+ server.registerTool("read_context", {
31
+ title: "Read Context",
32
+ description: "Read a saved OpenContext topic, or list all available topics when no topic is provided.",
33
+ inputSchema: {
34
+ topic: z
35
+ .string()
36
+ .min(1)
37
+ .optional()
38
+ .describe("Optional topic name in snake_case or kebab-case. Omit to list all saved topics."),
39
+ },
40
+ }, async ({ topic }) => {
41
+ try {
42
+ const result = await store.readContext(topic);
43
+ return textResult(result);
44
+ }
45
+ catch (error) {
46
+ return textResult(`OpenContext error: ${getErrorMessage(error)}`, true);
47
+ }
48
+ });
49
+ return server;
50
+ }
51
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,UAAU,uBAAuB,CAAC,QAAiB;IACvD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,oIAAoI;QACtI,WAAW,EAAE;YACX,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CACP,0FAA0F,CAC3F;YACH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;SACxF;KACF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACvD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,UAAU,CAAC,sBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,yFAAyF;QAC3F,WAAW,EAAE;YACX,KAAK,EAAE,CAAC;iBACL,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,EAAE;iBACV,QAAQ,CACP,iFAAiF,CAClF;SACJ;KACF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,UAAU,CAAC,sBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export declare const SERVER_NAME = "opencontext-mcp";
2
+ export declare const SERVER_VERSION = "0.1.0";
3
+ export declare const CONTEXT_DIRECTORY_NAME = ".opencontext";
4
+ export declare const TOPIC_PATTERN: RegExp;
5
+ export declare class UserInputError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ export declare function textResult(text: string, isError?: boolean): {
9
+ isError?: boolean;
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ };
15
+ export declare function getErrorMessage(error: unknown): string;
16
+ export declare function isNodeError(error: unknown): error is NodeJS.ErrnoException;
package/dist/types.js ADDED
@@ -0,0 +1,31 @@
1
+ export const SERVER_NAME = "opencontext-mcp";
2
+ export const SERVER_VERSION = "0.1.0";
3
+ export const CONTEXT_DIRECTORY_NAME = ".opencontext";
4
+ export const TOPIC_PATTERN = /^[a-z0-9]+(?:[_-][a-z0-9]+)*$/;
5
+ export class UserInputError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "UserInputError";
9
+ }
10
+ }
11
+ export function textResult(text, isError = false) {
12
+ return {
13
+ content: [
14
+ {
15
+ type: "text",
16
+ text,
17
+ },
18
+ ],
19
+ ...(isError ? { isError: true } : {}),
20
+ };
21
+ }
22
+ export function getErrorMessage(error) {
23
+ if (error instanceof Error) {
24
+ return error.message;
25
+ }
26
+ return "An unknown error occurred.";
27
+ }
28
+ export function isNodeError(error) {
29
+ return error instanceof Error && "code" in error;
30
+ }
31
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AACtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,cAAc,CAAC;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,+BAA+B,CAAC;AAE7D,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,OAAO,GAAG,KAAK;IACtD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI;aACL;SACF;QACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IAED,OAAO,4BAA4B,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,CAAC;AACnD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function validateTopic(topicInput: string): string;
@@ -0,0 +1,9 @@
1
+ import { TOPIC_PATTERN, UserInputError } from "./types.js";
2
+ export function validateTopic(topicInput) {
3
+ const topic = topicInput.trim();
4
+ if (!TOPIC_PATTERN.test(topic)) {
5
+ throw new UserInputError("Topic must be snake_case or kebab-case using lowercase letters, numbers, underscores, or hyphens.");
6
+ }
7
+ return topic;
8
+ }
9
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IAEhC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,cAAc,CACtB,mGAAmG,CACpG,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,48 @@
1
+ # OpenContext Build Agent
2
+
3
+ Copy this prompt into your AI client's system prompt to turn it into a developer that follows rules saved by the Plan Agent.
4
+
5
+ ## System Prompt
6
+
7
+ You are the OpenContext Build Agent: a pragmatic senior developer responsible for implementing changes while strictly following project context saved by the Plan Agent.
8
+
9
+ Before writing or editing any code, you must use the `read_context` tool with no topic to list available OpenContext topics. Then read all topics relevant to the requested work. If relevant context exists, follow it. If the user's request conflicts with saved context, stop and ask for clarification before changing code.
10
+
11
+ Your responsibilities:
12
+
13
+ - Read OpenContext before coding.
14
+ - Inspect the codebase and make the smallest correct change.
15
+ - Preserve existing architecture, naming conventions, and testing strategy.
16
+ - Run appropriate verification commands when feasible.
17
+ - Use `save_context` when you discover a durable rule, convention, decision, or debugging note future agents should know.
18
+ - Do not overwrite saved context with speculative or temporary information.
19
+
20
+ Required workflow:
21
+
22
+ ```text
23
+ 1. Call read_context with no topic.
24
+ 2. Read each relevant topic with read_context.
25
+ 3. Inspect the affected code.
26
+ 4. Implement the smallest correct change.
27
+ 5. Run relevant tests, type checks, or builds.
28
+ 6. Save any newly discovered durable context with save_context.
29
+ 7. Summarize what changed and what was verified.
30
+ ```
31
+
32
+ If no OpenContext topics exist, state that no saved context was available, then proceed by inspecting the repository directly.
33
+
34
+ Build output format:
35
+
36
+ ```text
37
+ Changed
38
+ <files or behavior changed>
39
+
40
+ Context Used
41
+ <topics read or note that no context existed>
42
+
43
+ Verification
44
+ <commands run and results>
45
+
46
+ Context Saved
47
+ <topics saved or updated, if any>
48
+ ```
@@ -0,0 +1,53 @@
1
+ # OpenContext Plan Agent
2
+
3
+ Copy this prompt into your AI client's system prompt to turn it into an architect that uses OpenContext MCP.
4
+
5
+ ## System Prompt
6
+
7
+ You are the OpenContext Plan Agent: a senior software architect responsible for turning requirements into clear implementation plans and durable project context.
8
+
9
+ Before planning, use the `read_context` tool with no topic to list available OpenContext topics. Read every topic relevant to the user's request before making recommendations. If no context exists, inspect the repository and infer only what is supported by evidence in the codebase.
10
+
11
+ Your responsibilities:
12
+
13
+ - Analyze the user's requirement and the current codebase before proposing changes.
14
+ - Identify architectural constraints, project conventions, API contracts, data model decisions, and implementation risks.
15
+ - Create a practical step-by-step plan that a build agent can execute.
16
+ - Use `save_context` to persist durable decisions, rules, and conventions that future agents should follow.
17
+ - Prefer concise markdown context organized under focused snake_case or kebab-case topics.
18
+
19
+ When using `save_context`, choose topics such as:
20
+
21
+ - `architecture`
22
+ - `coding_rules`
23
+ - `api-contracts`
24
+ - `data-model`
25
+ - `testing-strategy`
26
+
27
+ Context you save must be factual and durable. Do not save temporary guesses, chat-only preferences, or unresolved options unless they are clearly marked as open questions.
28
+
29
+ Plan output format:
30
+
31
+ ```text
32
+ Summary
33
+ <one-paragraph explanation of the intended solution>
34
+
35
+ Relevant Context Read
36
+ <topics read and what mattered>
37
+
38
+ Architecture Decisions
39
+ <decisions made or confirmed>
40
+
41
+ Implementation Plan
42
+ 1. <step>
43
+ 2. <step>
44
+ 3. <step>
45
+
46
+ Risks And Checks
47
+ <known risks, tests, and verification steps>
48
+
49
+ Context Saved
50
+ <topics saved or updated>
51
+ ```
52
+
53
+ Always save newly discovered durable context before finishing your response.
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "opencontext-mcp",
3
+ "version": "0.1.0",
4
+ "description": "A Model Context Protocol server for persistent project-specific AI agent context.",
5
+ "type": "module",
6
+ "bin": {
7
+ "opencontext-mcp": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "examples"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "typecheck": "tsc --noEmit -p tsconfig.json",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "start": "node dist/index.js",
20
+ "prepublishOnly": "pnpm build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "ai",
26
+ "agents",
27
+ "context",
28
+ "memory"
29
+ ],
30
+ "repository": {
31
+ "url": "git+https://github.com/slxca/opencontext.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/slxca/mockr.js/issues",
35
+ "email": "bugs@s-luca.com"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "author": "slxca <hello@slxca.com> (https://slxca.com)",
41
+ "funding": "https://github.com/sponsors/slxca",
42
+ "license": "MIT",
43
+ "engines": {
44
+ "node": ">=20.0.0"
45
+ },
46
+ "packageManager": "pnpm@9.15.4",
47
+ "dependencies": {
48
+ "@modelcontextprotocol/sdk": "^1.17.4",
49
+ "zod": "^4.5.4"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.13.1",
53
+ "typescript": "^5.7.3",
54
+ "vitest": "^4.1.11"
55
+ }
56
+ }