testchimp-mcp-client 0.0.1 → 0.0.3

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.
Files changed (3) hide show
  1. package/README.md +22 -2
  2. package/dist/index.js +95 -15
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -13,11 +13,28 @@ MCP (Model Context Protocol) server for [TestChimp](https://testchimp.io). Expos
13
13
 
14
14
  - **`get_requirement_coverage`** — POST `/api/mcp/list_requirement_coverage` (scenario / requirement coverage scoped by platform-rooted `scope.folderPath` under **`tests/...`** or **`plans/...`**).
15
15
  - **`get_execution_history`** — POST `/api/mcp/list_execution_history`.
16
- - **`get_test_advice`** — POST `/api/mcp/get_test_advice` (stub until PR analysis ships).
16
+ - **`create_user_story`** — POST `/api/mcp/create_user_story` (`platformFilePath` under `plans/stories/...`, `title`).
17
+ - **`create_test_scenario`** — POST `/api/mcp/create_test_scenario` (`platformFilePath` under `plans/scenarios/...`, `title`, `userStoryOrdinalId`).
18
+ - **`update_user_story`** — POST `/api/mcp/update_user_story` (full markdown `content` with `id: US-...` in frontmatter).
19
+ - **`update_test_scenario`** — POST `/api/mcp/update_test_scenario` (full markdown `content` with `id: TS-...` and `story: US-...` in frontmatter).
20
+ - **`get_eaas_config`** — POST `/api/mcp/get_eaas_config` (BunnyShell YAML path and project name; token excluded; `{}` when unconfigured).
21
+ - **`provision_ephemeral_environment`** — POST `/api/mcp/provision_ephemeral_environment` (optional `branchName`).
22
+ - **`get_ephemeral_environment_status`** — POST `/api/mcp/get_ephemeral_environment_status` (`bnsEnvironmentId`).
23
+ - **`destroy_ephemeral_environment`** — POST `/api/mcp/destroy_ephemeral_environment` (`bnsEnvironmentId`).
17
24
 
18
25
  ## Cursor
19
26
 
20
- Add to MCP config (e.g. `~/.cursor/mcp.json`):
27
+ **Install only at project level.** TestChimp API keys are **scoped to a TestChimp project**; the MCP server must use the key for **the repo you have open**. Do **not** add this server to **IDE-wide** MCP config (`~/.cursor/mcp.json` or global Cursor MCP settings): you risk using the wrong key when switching workspaces, and agents may target the wrong backend project.
28
+
29
+ **For humans and AI agents:** create or edit **`<project-root>/.cursor/mcp.json`** in the repository you are working in (the folder Cursor has open as the workspace root). That path is **`.cursor/mcp.json` relative to the project root**, not under your home directory.
30
+
31
+ The MCP server reads **`TESTCHIMP_API_KEY`** and **`TESTCHIMP_BACKEND_URL`** from **`process.env`** — it does not read `mcp.json` directly. Cursor starts the server as a **child process**; variables must be present in **that** process’s environment.
32
+
33
+ **Why `mcp.json` uses an `env` block:** If you open Cursor from the Dock, Spotlight, or similar, it usually does **not** load your shell profile (`.zshrc`, etc.), so values you only `export` in a terminal may **not** reach the MCP server. The `env` object next to `command` / `args` is the reliable way Cursor injects variables into the MCP process. (Cursor’s `mcp.json` does **not** expand `$VAR` / `${VAR}` from your shell; use literal values in `env`, or a wrapper that loads a `.env` file before starting the server.)
34
+
35
+ ### Project `mcp.json` example
36
+
37
+ `<project-root>/.cursor/mcp.json`:
21
38
 
22
39
  ```json
23
40
  {
@@ -34,6 +51,9 @@ Add to MCP config (e.g. `~/.cursor/mcp.json`):
34
51
  }
35
52
  ```
36
53
 
54
+ - **Do not commit secrets:** Add `.cursor/mcp.json` to **`.gitignore`** if it contains real keys, or keep only a committed `.cursor/mcp.json.example` with placeholders and document that each developer maintains a local ignored file.
55
+ - **After changing env or config:** Restart the MCP server or reload MCP / restart Cursor so the new environment is picked up.
56
+
37
57
  For a published npm package name, adjust `args` to your scope (e.g. `@testchimp/mcp-client`) after publish.
38
58
 
39
59
  ## Scope path format
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ function getBackendUrl() {
16
16
  function requireApiKey() {
17
17
  const k = process.env.TESTCHIMP_API_KEY?.trim();
18
18
  if (!k) {
19
- throw new Error("TESTCHIMP_API_KEY is required. Set it in the MCP server env (e.g. Cursor mcp.json).");
19
+ throw new Error("TESTCHIMP_API_KEY is required. Set it in <project>/.cursor/mcp.json env (project-level MCP config), not IDE-wide config.");
20
20
  }
21
21
  return k;
22
22
  }
@@ -59,11 +59,29 @@ const listExecutionInput = z.object({
59
59
  scope: scopeSchema,
60
60
  branchName: z.string().optional(),
61
61
  });
62
- const testAdviceInput = z.object({
62
+ /** Platform path to the new markdown file, e.g. plans/stories/auth/login-flow.md */
63
+ const createUserStoryInput = z.object({
64
+ platformFilePath: z.string().min(1),
65
+ title: z.string().min(1),
66
+ });
67
+ const createTestScenarioInput = z.object({
68
+ platformFilePath: z.string().min(1),
69
+ title: z.string().min(1),
70
+ /** Parent story ordinal (the number n in US-n). */
71
+ userStoryOrdinalId: z.coerce.number().int().positive(),
72
+ });
73
+ const updatePlanMarkdownInput = z.object({
74
+ /** Full markdown including YAML frontmatter and body (as written under the repo plans root). */
75
+ content: z.string().min(1),
76
+ });
77
+ const emptyInput = z.object({});
78
+ const provisionEphemeralInput = z.object({
79
+ /** Git branch to deploy; omit to use the repo default branch. */
63
80
  branchName: z.string().optional(),
64
- prUrl: z.string().optional(),
65
- baseSha: z.string().optional(),
66
- headSha: z.string().optional(),
81
+ });
82
+ const bnsEnvironmentIdInput = z.object({
83
+ /** BunnyShell environment id returned from provision_ephemeral_environment. */
84
+ bnsEnvironmentId: z.string().min(1),
67
85
  });
68
86
  function textResult(json) {
69
87
  return {
@@ -133,21 +151,83 @@ async function main() {
133
151
  const json = await postMcp("/api/mcp/list_execution_history", body);
134
152
  return textResult(json);
135
153
  });
136
- server.registerTool("get_test_advice", {
137
- description: "Placeholder for PR-scoped test advice. Returns not_implemented until the backend provides analysis.",
138
- inputSchema: testAdviceInput,
154
+ server.registerTool("create_user_story", {
155
+ description: "Create a user story on the TestChimp project and its plan file stub. " +
156
+ "Always call this before writing a new story markdown file; use the returned ordinalId as US-<ordinalId> in frontmatter. " +
157
+ "platformFilePath must be under plans/stories/ and end with .md.",
158
+ inputSchema: createUserStoryInput,
159
+ }, async (args) => {
160
+ const json = await postMcp("/api/mcp/create_user_story", {
161
+ platformFilePath: args.platformFilePath,
162
+ title: args.title,
163
+ });
164
+ return textResult(json);
165
+ });
166
+ server.registerTool("create_test_scenario", {
167
+ description: "Create a test scenario linked to a user story. Call after the parent story exists. " +
168
+ "platformFilePath must be under plans/scenarios/ and end with .md. " +
169
+ "userStoryOrdinalId is the numeric part of the parent US-<n> id.",
170
+ inputSchema: createTestScenarioInput,
171
+ }, async (args) => {
172
+ const json = await postMcp("/api/mcp/create_test_scenario", {
173
+ platformFilePath: args.platformFilePath,
174
+ title: args.title,
175
+ userStoryOrdinalId: args.userStoryOrdinalId,
176
+ });
177
+ return textResult(json);
178
+ });
179
+ server.registerTool("update_user_story", {
180
+ description: "Sync a user story markdown file to the platform after local edits. " +
181
+ "Parses frontmatter (id: US-..., title, priority, status) and updates the linked support file and entity.",
182
+ inputSchema: updatePlanMarkdownInput,
183
+ }, async (args) => {
184
+ const json = await postMcp("/api/mcp/update_user_story", { content: args.content });
185
+ return textResult(json);
186
+ });
187
+ server.registerTool("update_test_scenario", {
188
+ description: "Sync a test scenario markdown file to the platform after local edits. " +
189
+ "Parses frontmatter (id: TS-..., story: US-..., title, priority, status) and updates linking if story changes.",
190
+ inputSchema: updatePlanMarkdownInput,
191
+ }, async (args) => {
192
+ const json = await postMcp("/api/mcp/update_test_scenario", { content: args.content });
193
+ return textResult(json);
194
+ });
195
+ server.registerTool("get_eaas_config", {
196
+ description: "Return the project's BunnyShell (Environment-as-a-Service) settings: ymlRepoPath and bunnyshellProjectName. " +
197
+ "Secrets (API token) are never returned. Response is {} when EaaS is not configured or has no public fields.",
198
+ inputSchema: emptyInput,
199
+ }, async () => {
200
+ const json = await postMcp("/api/mcp/get_eaas_config", {});
201
+ return textResult(json);
202
+ });
203
+ server.registerTool("provision_ephemeral_environment", {
204
+ description: "Create a BunnyShell ephemeral environment for the TestChimp project from the configured Git repo + YAML path. " +
205
+ "Requires BunnyShell + GitHub integration in project settings. Poll with get_ephemeral_environment_status using bnsEnvironmentId.",
206
+ inputSchema: provisionEphemeralInput,
139
207
  }, async (args) => {
140
208
  const body = {};
141
209
  if (args.branchName != null && args.branchName.trim() !== "") {
142
210
  body.branchName = args.branchName.trim();
143
211
  }
144
- if (args.prUrl != null)
145
- body.pr_url = args.prUrl;
146
- if (args.baseSha != null)
147
- body.base_sha = args.baseSha;
148
- if (args.headSha != null)
149
- body.head_sha = args.headSha;
150
- const json = await postMcp("/api/mcp/get_test_advice", body);
212
+ const json = await postMcp("/api/mcp/provision_ephemeral_environment", body);
213
+ return textResult(json);
214
+ });
215
+ server.registerTool("get_ephemeral_environment_status", {
216
+ description: "Poll BunnyShell for environment status and definition. When deployed, environmentSpec may contain URLs/components JSON.",
217
+ inputSchema: bnsEnvironmentIdInput,
218
+ }, async (args) => {
219
+ const json = await postMcp("/api/mcp/get_ephemeral_environment_status", {
220
+ bnsEnvironmentId: args.bnsEnvironmentId,
221
+ });
222
+ return textResult(json);
223
+ });
224
+ server.registerTool("destroy_ephemeral_environment", {
225
+ description: "Delete a BunnyShell environment created for this project (bnsEnvironmentId from provision).",
226
+ inputSchema: bnsEnvironmentIdInput,
227
+ }, async (args) => {
228
+ const json = await postMcp("/api/mcp/destroy_ephemeral_environment", {
229
+ bnsEnvironmentId: args.bnsEnvironmentId,
230
+ });
151
231
  return textResult(json);
152
232
  });
153
233
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testchimp-mcp-client",
3
- "version": "0.0.1",
4
- "description": "MCP server for TestChimp — requirement coverage, execution history, and test advice (stub)",
3
+ "version": "0.0.3",
4
+ "description": "MCP server for TestChimp — coverage, execution history, and plan authoring",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",