ashlr-stack-mcp 0.2.2 → 0.3.1
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 +26 -7
- package/dist/server.js +121 -31
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# ashlr-stack-mcp
|
|
2
2
|
|
|
3
|
-
> MCP server for [Ashlr Stack](https://stack.ashlr.ai). Exposes 19 tools and up to 3 resources
|
|
3
|
+
> MCP server for [Ashlr Stack](https://stack.ashlr.ai). Exposes 19 tools and up to 3 resources for inspecting and configuring supported services from MCP clients.
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
`stack` is a CLI. `ashlr-stack-mcp` is the same capabilities as MCP tools so your coding agent can drive Stack directly.
|
|
7
|
+
`stack` is a CLI. `ashlr-stack-mcp` is the same capabilities as MCP tools so your coding agent can drive Stack directly. An agent can request `stack_add` for a supported provider; authentication, resource setup and configuration changes depend on the adapter and authorization. Inspect the result and any changes.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -26,7 +26,25 @@ bun add -g ashlr-stack-mcp @ashlr/stack
|
|
|
26
26
|
npm i -g ashlr-stack-mcp @ashlr/stack
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Every tool runs the `stack` CLI
|
|
29
|
+
Every tool runs the `stack` CLI. The server resolves it in this order: the executable specified by `STACK_BIN`, the installed `@ashlr/stack` dependency's bin, then `stack` on PATH. If none is available, the server can still start and list tools, but calls fail with a CLI error. The npm CLI and MCP packages in this release declare Node.js >= 20 and use Node entrypoints. Check your installed package manifests; source development uses Bun.
|
|
30
|
+
|
|
31
|
+
## Run from a local clone
|
|
32
|
+
|
|
33
|
+
Install Bun and Node.js 20 or later, then install the workspace dependencies and build the CLI from the repository root:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bun install --frozen-lockfile
|
|
37
|
+
(cd packages/cli && bun run build)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The source server runs with Bun; the CLI build provides the workspace dependency's `dist/index.js`. Start the server from the project you want it to inspect, replacing the paths with absolute paths on your machine:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cd /absolute/path/to/my-project
|
|
44
|
+
bun run /absolute/path/to/ashlr-stack/packages/mcp/src/server.ts
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The server speaks MCP over stdin and stdout, so connect it to an MCP client rather than expecting an interactive prompt. Keep stdout reserved for the protocol. Provider operations may need Phantom and provider credentials configured separately.
|
|
30
48
|
|
|
31
49
|
## Wire it into your agent
|
|
32
50
|
|
|
@@ -42,23 +60,24 @@ Drop this into your project's `.mcp.json` (Claude Code, Cursor and Windsurf read
|
|
|
42
60
|
}
|
|
43
61
|
```
|
|
44
62
|
|
|
45
|
-
|
|
63
|
+
For a local clone, after the installation and CLI build above, point the client at the source entry directly (with `bun` available on its PATH):
|
|
46
64
|
|
|
47
65
|
```json
|
|
48
66
|
{
|
|
49
67
|
"mcpServers": {
|
|
50
68
|
"ashlr-stack": {
|
|
51
69
|
"command": "bun",
|
|
52
|
-
"args": ["run", "/absolute/path/to/ashlr-stack/packages/mcp/src/server.ts"]
|
|
53
|
-
"env": { "STACK_BIN": "/absolute/path/to/ashlr-stack/packages/cli/src/index.ts" }
|
|
70
|
+
"args": ["run", "/absolute/path/to/ashlr-stack/packages/mcp/src/server.ts"]
|
|
54
71
|
}
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
74
|
```
|
|
58
75
|
|
|
76
|
+
The client chooses the server's working directory; the absolute entry path does not set it. Configure the client to start the server in your project if supported, or pass `cwd` to project-scoped tool calls as described below.
|
|
77
|
+
|
|
59
78
|
## Targeting a project (`cwd`)
|
|
60
79
|
|
|
61
|
-
Every tool runs `stack` in the server's working directory
|
|
80
|
+
Every tool runs `stack` in the server's working directory by default. When your client starts the server outside the project (Claude Desktop, a global Cursor or Windsurf config), pass the project's absolute path to a project-scoped tool:
|
|
62
81
|
|
|
63
82
|
```json
|
|
64
83
|
{ "name": "stack_list", "arguments": { "json": true, "cwd": "/home/me/code/my-app" } }
|
package/dist/server.js
CHANGED
|
@@ -6508,7 +6508,7 @@ var require_dist = __commonJS(function(exports, module) {
|
|
|
6508
6508
|
|
|
6509
6509
|
// src/server.ts
|
|
6510
6510
|
import { spawn } from "child_process";
|
|
6511
|
-
import { existsSync
|
|
6511
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
6512
6512
|
import { join } from "path";
|
|
6513
6513
|
|
|
6514
6514
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/core.js
|
|
@@ -14197,8 +14197,8 @@ var ServerResultSchema2 = union([
|
|
|
14197
14197
|
]);
|
|
14198
14198
|
|
|
14199
14199
|
// src/cwd.ts
|
|
14200
|
-
import { realpathSync, statSync } from "node:fs";
|
|
14201
|
-
import { isAbsolute } from "node:path";
|
|
14200
|
+
import { lstatSync, realpathSync, statSync } from "node:fs";
|
|
14201
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
14202
14202
|
|
|
14203
14203
|
// src/tools.ts
|
|
14204
14204
|
function validateToolInput(tool, input) {
|
|
@@ -14274,13 +14274,97 @@ function planToolCall(tool, input) {
|
|
|
14274
14274
|
const resolved = resolveToolCwd(tool, input);
|
|
14275
14275
|
if (resolved.error !== undefined)
|
|
14276
14276
|
return { ok: false, error: resolved.error };
|
|
14277
|
+
const pathKey = tool.name === "stack_scan" ? "path" : tool.name === "stack_import" ? "from" : null;
|
|
14278
|
+
const project = resolved.cwd ?? process.cwd();
|
|
14279
|
+
if (pathKey) {
|
|
14280
|
+
const value = input[pathKey] ?? (pathKey === "path" ? "." : ".env");
|
|
14281
|
+
const error = validateProjectPath(tool, pathKey, String(value), project);
|
|
14282
|
+
if (error)
|
|
14283
|
+
return { ok: false, error };
|
|
14284
|
+
}
|
|
14285
|
+
if (tool.name === "stack_apply" && typeof input.recipe_id === "string") {
|
|
14286
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(input.recipe_id)) {
|
|
14287
|
+
return {
|
|
14288
|
+
ok: false,
|
|
14289
|
+
error: `${tool.name}: argument "recipe_id" must be a filename stem using letters, numbers, underscores or hyphens.`
|
|
14290
|
+
};
|
|
14291
|
+
}
|
|
14292
|
+
const error = validateProjectPath(tool, "recipe_id", `.stack/recipes/${input.recipe_id}.toml`, project);
|
|
14293
|
+
if (error)
|
|
14294
|
+
return { ok: false, error };
|
|
14295
|
+
}
|
|
14277
14296
|
return { ok: true, args: tool.cliArgs(input), cwd: resolved.cwd };
|
|
14278
14297
|
}
|
|
14298
|
+
function canonicalPath(path) {
|
|
14299
|
+
try {
|
|
14300
|
+
return realpathSync(path);
|
|
14301
|
+
} catch (error) {
|
|
14302
|
+
if (error.code !== "ENOENT")
|
|
14303
|
+
throw error;
|
|
14304
|
+
try {
|
|
14305
|
+
if (lstatSync(path).isSymbolicLink())
|
|
14306
|
+
throw error;
|
|
14307
|
+
} catch (statError) {
|
|
14308
|
+
if (statError === error || statError.code !== "ENOENT") {
|
|
14309
|
+
throw statError;
|
|
14310
|
+
}
|
|
14311
|
+
}
|
|
14312
|
+
const parent = dirname(path);
|
|
14313
|
+
if (parent === path)
|
|
14314
|
+
throw error;
|
|
14315
|
+
return resolve(canonicalPath(parent), relative(parent, path));
|
|
14316
|
+
}
|
|
14317
|
+
}
|
|
14318
|
+
function validateProjectPath(tool, key, value, project) {
|
|
14319
|
+
try {
|
|
14320
|
+
const root = realpathSync(project);
|
|
14321
|
+
const target = canonicalPath(isAbsolute(value) ? value : `${root}${sep}${value}`);
|
|
14322
|
+
const suffix = relative(root, target);
|
|
14323
|
+
if (suffix !== ".." && !suffix.startsWith(`..${sep}`) && !isAbsolute(suffix))
|
|
14324
|
+
return null;
|
|
14325
|
+
} catch {
|
|
14326
|
+
return `${tool.name}: argument "${key}" cannot be resolved; use a valid path inside the project directory.`;
|
|
14327
|
+
}
|
|
14328
|
+
return `${tool.name}: argument "${key}" must stay inside the project directory (got ${JSON.stringify(value)}); use a path relative to cwd within the project.`;
|
|
14329
|
+
}
|
|
14330
|
+
|
|
14331
|
+
// src/output.ts
|
|
14332
|
+
function compactJsonOutput(stdout, args) {
|
|
14333
|
+
const text = stdout.trim();
|
|
14334
|
+
if (!args.includes("--json"))
|
|
14335
|
+
return text;
|
|
14336
|
+
try {
|
|
14337
|
+
JSON.parse(text);
|
|
14338
|
+
} catch {
|
|
14339
|
+
return text;
|
|
14340
|
+
}
|
|
14341
|
+
let quoted = false;
|
|
14342
|
+
let escaped = false;
|
|
14343
|
+
let result = "";
|
|
14344
|
+
for (const char of text) {
|
|
14345
|
+
if (quoted) {
|
|
14346
|
+
result += char;
|
|
14347
|
+
if (escaped)
|
|
14348
|
+
escaped = false;
|
|
14349
|
+
else if (char === "\\")
|
|
14350
|
+
escaped = true;
|
|
14351
|
+
else if (char === '"')
|
|
14352
|
+
quoted = false;
|
|
14353
|
+
} else if (char === '"') {
|
|
14354
|
+
quoted = true;
|
|
14355
|
+
result += char;
|
|
14356
|
+
} else if (!`
|
|
14357
|
+
\r `.includes(char)) {
|
|
14358
|
+
result += char;
|
|
14359
|
+
}
|
|
14360
|
+
}
|
|
14361
|
+
return result;
|
|
14362
|
+
}
|
|
14279
14363
|
|
|
14280
14364
|
// src/stack-bin.ts
|
|
14281
|
-
import {
|
|
14365
|
+
import { readFileSync, statSync as statSync2 } from "node:fs";
|
|
14282
14366
|
import { createRequire } from "node:module";
|
|
14283
|
-
import { dirname, resolve } from "node:path";
|
|
14367
|
+
import { dirname as dirname2, resolve as resolve2 } from "node:path";
|
|
14284
14368
|
import { fileURLToPath } from "node:url";
|
|
14285
14369
|
var CLI_PACKAGE_JSON = ["@ashlr", "stack", "package.json"].join("/");
|
|
14286
14370
|
function resolveCliPackageJson() {
|
|
@@ -14296,8 +14380,8 @@ function cliBinFromPackageJson(pkgJsonPath) {
|
|
|
14296
14380
|
const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.stack;
|
|
14297
14381
|
if (!rel)
|
|
14298
14382
|
return;
|
|
14299
|
-
const abs =
|
|
14300
|
-
return
|
|
14383
|
+
const abs = resolve2(dirname2(pkgJsonPath), rel);
|
|
14384
|
+
return statSync2(abs).isFile() ? abs : undefined;
|
|
14301
14385
|
} catch {
|
|
14302
14386
|
return;
|
|
14303
14387
|
}
|
|
@@ -14314,7 +14398,7 @@ function resolveStackCommand(env = process.env, findPackageJson = resolveCliPack
|
|
|
14314
14398
|
}
|
|
14315
14399
|
function readServerVersion(moduleUrl = import.meta.url) {
|
|
14316
14400
|
try {
|
|
14317
|
-
const pkgPath =
|
|
14401
|
+
const pkgPath = resolve2(dirname2(fileURLToPath(moduleUrl)), "..", "package.json");
|
|
14318
14402
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
14319
14403
|
if (pkg.name === "ashlr-stack-mcp" && pkg.version)
|
|
14320
14404
|
return pkg.version;
|
|
@@ -14325,7 +14409,7 @@ function readServerVersion(moduleUrl = import.meta.url) {
|
|
|
14325
14409
|
// src/tools.ts
|
|
14326
14410
|
var CWD_INPUT = {
|
|
14327
14411
|
type: "string",
|
|
14328
|
-
description: "
|
|
14412
|
+
description: "Existing absolute project directory; defaults to server cwd."
|
|
14329
14413
|
};
|
|
14330
14414
|
var TOOLS = [
|
|
14331
14415
|
{
|
|
@@ -14334,7 +14418,7 @@ var TOOLS = [
|
|
|
14334
14418
|
inputSchema: {
|
|
14335
14419
|
type: "object",
|
|
14336
14420
|
properties: {
|
|
14337
|
-
template: { type: "string", description: "
|
|
14421
|
+
template: { type: "string", description: "Starter template name." },
|
|
14338
14422
|
force: { type: "boolean", description: "Overwrite an existing .stack.toml." },
|
|
14339
14423
|
cwd: CWD_INPUT
|
|
14340
14424
|
}
|
|
@@ -14354,7 +14438,10 @@ var TOOLS = [
|
|
|
14354
14438
|
inputSchema: {
|
|
14355
14439
|
type: "object",
|
|
14356
14440
|
properties: {
|
|
14357
|
-
from: {
|
|
14441
|
+
from: {
|
|
14442
|
+
type: "string",
|
|
14443
|
+
description: "Path to the .env file inside the project (default: .env)."
|
|
14444
|
+
},
|
|
14358
14445
|
dryRun: { type: "boolean", description: "Preview without writing." },
|
|
14359
14446
|
cwd: CWD_INPUT
|
|
14360
14447
|
}
|
|
@@ -14374,7 +14461,10 @@ var TOOLS = [
|
|
|
14374
14461
|
inputSchema: {
|
|
14375
14462
|
type: "object",
|
|
14376
14463
|
properties: {
|
|
14377
|
-
path: {
|
|
14464
|
+
path: {
|
|
14465
|
+
type: "string",
|
|
14466
|
+
description: "Directory to scan inside the project (default: cwd)."
|
|
14467
|
+
},
|
|
14378
14468
|
confidence: {
|
|
14379
14469
|
type: "string",
|
|
14380
14470
|
description: "Minimum confidence: low, medium, or high (default: medium)."
|
|
@@ -14437,7 +14527,7 @@ var TOOLS = [
|
|
|
14437
14527
|
properties: {
|
|
14438
14528
|
json: {
|
|
14439
14529
|
type: "boolean",
|
|
14440
|
-
description: "
|
|
14530
|
+
description: "JSON: ashlr.stack.list/v1."
|
|
14441
14531
|
},
|
|
14442
14532
|
cwd: CWD_INPUT
|
|
14443
14533
|
}
|
|
@@ -14453,7 +14543,7 @@ var TOOLS = [
|
|
|
14453
14543
|
service: { type: "string" },
|
|
14454
14544
|
json: {
|
|
14455
14545
|
type: "boolean",
|
|
14456
|
-
description: "
|
|
14546
|
+
description: "JSON: ashlr.stack.info/v1."
|
|
14457
14547
|
},
|
|
14458
14548
|
cwd: CWD_INPUT
|
|
14459
14549
|
},
|
|
@@ -14474,7 +14564,7 @@ var TOOLS = [
|
|
|
14474
14564
|
properties: {
|
|
14475
14565
|
json: {
|
|
14476
14566
|
type: "boolean",
|
|
14477
|
-
description: "
|
|
14567
|
+
description: "JSON: ashlr.stack.status/v1."
|
|
14478
14568
|
},
|
|
14479
14569
|
cwd: CWD_INPUT
|
|
14480
14570
|
}
|
|
@@ -14489,7 +14579,7 @@ var TOOLS = [
|
|
|
14489
14579
|
properties: {
|
|
14490
14580
|
json: {
|
|
14491
14581
|
type: "boolean",
|
|
14492
|
-
description: "
|
|
14582
|
+
description: "JSON: ashlr.stack.env/v1; names only."
|
|
14493
14583
|
},
|
|
14494
14584
|
cwd: CWD_INPUT
|
|
14495
14585
|
}
|
|
@@ -14504,7 +14594,7 @@ var TOOLS = [
|
|
|
14504
14594
|
properties: {
|
|
14505
14595
|
json: {
|
|
14506
14596
|
type: "boolean",
|
|
14507
|
-
description: "
|
|
14597
|
+
description: "JSON: ashlr.stack.env-diff/v1; names and service only. Missing secrets remain an error."
|
|
14508
14598
|
},
|
|
14509
14599
|
cwd: CWD_INPUT
|
|
14510
14600
|
}
|
|
@@ -14519,7 +14609,7 @@ var TOOLS = [
|
|
|
14519
14609
|
properties: {
|
|
14520
14610
|
fix: { type: "boolean", description: "Attempt auto-remediation." },
|
|
14521
14611
|
all: { type: "boolean", description: "Run across every registered project." },
|
|
14522
|
-
json: { type: "boolean", description: "
|
|
14612
|
+
json: { type: "boolean", description: "JSON output." },
|
|
14523
14613
|
cwd: CWD_INPUT
|
|
14524
14614
|
}
|
|
14525
14615
|
},
|
|
@@ -14559,7 +14649,7 @@ var TOOLS = [
|
|
|
14559
14649
|
},
|
|
14560
14650
|
json: {
|
|
14561
14651
|
type: "boolean",
|
|
14562
|
-
description: "
|
|
14652
|
+
description: "JSON: ashlr.stack.providers/v1."
|
|
14563
14653
|
}
|
|
14564
14654
|
}
|
|
14565
14655
|
},
|
|
@@ -14577,7 +14667,7 @@ var TOOLS = [
|
|
|
14577
14667
|
properties: {
|
|
14578
14668
|
json: {
|
|
14579
14669
|
type: "boolean",
|
|
14580
|
-
description: "
|
|
14670
|
+
description: "JSON: ashlr.stack.projects/v1."
|
|
14581
14671
|
}
|
|
14582
14672
|
}
|
|
14583
14673
|
},
|
|
@@ -14591,7 +14681,7 @@ var TOOLS = [
|
|
|
14591
14681
|
properties: {
|
|
14592
14682
|
json: {
|
|
14593
14683
|
type: "boolean",
|
|
14594
|
-
description: "
|
|
14684
|
+
description: "JSON: ashlr.stack.deps/v1."
|
|
14595
14685
|
},
|
|
14596
14686
|
cwd: CWD_INPUT
|
|
14597
14687
|
}
|
|
@@ -14606,7 +14696,7 @@ var TOOLS = [
|
|
|
14606
14696
|
properties: {
|
|
14607
14697
|
json: {
|
|
14608
14698
|
type: "boolean",
|
|
14609
|
-
description: "
|
|
14699
|
+
description: "JSON: ashlr.stack.templates/v1; services, providers and secret names."
|
|
14610
14700
|
}
|
|
14611
14701
|
}
|
|
14612
14702
|
},
|
|
@@ -14620,7 +14710,7 @@ var TOOLS = [
|
|
|
14620
14710
|
},
|
|
14621
14711
|
{
|
|
14622
14712
|
name: "stack_recommend",
|
|
14623
|
-
description: "
|
|
14713
|
+
description: "Rank curated providers by query, returning JSON as text without LLM inference. save:true writes a Recipe for stack_apply.",
|
|
14624
14714
|
inputSchema: {
|
|
14625
14715
|
type: "object",
|
|
14626
14716
|
properties: {
|
|
@@ -14634,11 +14724,11 @@ var TOOLS = [
|
|
|
14634
14724
|
},
|
|
14635
14725
|
category: {
|
|
14636
14726
|
type: "string",
|
|
14637
|
-
description: "
|
|
14727
|
+
description: "Category (case-insensitive): Database, Deploy, Cloud, AI, Analytics, Observability, Errors, Payments, Code, Tickets, Email, Auth, FeatureFlags. Unknown values error."
|
|
14638
14728
|
},
|
|
14639
14729
|
save: {
|
|
14640
14730
|
type: "boolean",
|
|
14641
|
-
description: "
|
|
14731
|
+
description: "Save .stack/recipes/<id>.toml for stack_apply; returns recipe id."
|
|
14642
14732
|
},
|
|
14643
14733
|
cwd: CWD_INPUT
|
|
14644
14734
|
},
|
|
@@ -14663,7 +14753,7 @@ var TOOLS = [
|
|
|
14663
14753
|
properties: {
|
|
14664
14754
|
recipe_id: {
|
|
14665
14755
|
type: "string",
|
|
14666
|
-
description: "Recipe id (filename stem in .stack/recipes
|
|
14756
|
+
description: "Recipe id (filename stem in .stack/recipes/, letters, numbers, underscores or hyphens)."
|
|
14667
14757
|
},
|
|
14668
14758
|
no_wire: {
|
|
14669
14759
|
type: "boolean",
|
|
@@ -14726,7 +14816,7 @@ server.setRequestHandler(CallToolRequestSchema2, async (request) => {
|
|
|
14726
14816
|
}
|
|
14727
14817
|
const { args, cwd } = plan;
|
|
14728
14818
|
const { stdout, stderr, code } = await runStack(args, cwd);
|
|
14729
|
-
const body = stdout
|
|
14819
|
+
const body = compactJsonOutput(stdout, args) + (stderr.trim() ? `
|
|
14730
14820
|
|
|
14731
14821
|
[stderr]
|
|
14732
14822
|
${stderr.trim()}` : "");
|
|
@@ -14738,7 +14828,7 @@ ${stderr.trim()}` : "");
|
|
|
14738
14828
|
server.setRequestHandler(ListResourcesRequestSchema2, async () => {
|
|
14739
14829
|
const resources = [];
|
|
14740
14830
|
const cwd = process.cwd();
|
|
14741
|
-
if (
|
|
14831
|
+
if (existsSync(join(cwd, ".stack.toml"))) {
|
|
14742
14832
|
resources.push({
|
|
14743
14833
|
uri: "stack://current/.stack.toml",
|
|
14744
14834
|
name: ".stack.toml (this project)",
|
|
@@ -14746,7 +14836,7 @@ server.setRequestHandler(ListResourcesRequestSchema2, async () => {
|
|
|
14746
14836
|
mimeType: "application/toml"
|
|
14747
14837
|
});
|
|
14748
14838
|
}
|
|
14749
|
-
if (
|
|
14839
|
+
if (existsSync(join(cwd, ".stack.local.toml"))) {
|
|
14750
14840
|
resources.push({
|
|
14751
14841
|
uri: "stack://current/.stack.local.toml",
|
|
14752
14842
|
name: ".stack.local.toml (local instance)",
|
|
@@ -14754,7 +14844,7 @@ server.setRequestHandler(ListResourcesRequestSchema2, async () => {
|
|
|
14754
14844
|
mimeType: "application/toml"
|
|
14755
14845
|
});
|
|
14756
14846
|
}
|
|
14757
|
-
if (
|
|
14847
|
+
if (existsSync(join(cwd, ".mcp.json"))) {
|
|
14758
14848
|
resources.push({
|
|
14759
14849
|
uri: "stack://current/.mcp.json",
|
|
14760
14850
|
name: ".mcp.json (MCP wiring)",
|
|
@@ -14775,7 +14865,7 @@ server.setRequestHandler(ReadResourceRequestSchema2, async (request) => {
|
|
|
14775
14865
|
throw new Error(`Refusing to read: ${rel}`);
|
|
14776
14866
|
}
|
|
14777
14867
|
const path = join(process.cwd(), rel);
|
|
14778
|
-
if (!
|
|
14868
|
+
if (!existsSync(path))
|
|
14779
14869
|
throw new Error(`${rel} does not exist in cwd.`);
|
|
14780
14870
|
const text = readFileSync2(path, "utf-8");
|
|
14781
14871
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ashlr-stack-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"mcpName": "io.github.ashlrai/ashlr-stack",
|
|
5
5
|
"description": "MCP server for Ashlr Stack. Exposes 19 tools and 3 resources so Claude Code / Cursor / Windsurf / Codex can provision every third-party service in a project with one call.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"typecheck": "bunx tsc --noEmit"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@ashlr/stack": "^0.
|
|
54
|
+
"@ashlr/stack": "^0.3.1",
|
|
55
55
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|