@granoflow/mcp-server 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 +21 -0
- package/README.md +203 -0
- package/dist/api.d.ts +26 -0
- package/dist/api.js +98 -0
- package/dist/api.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.js +148 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata.d.ts +2 -0
- package/dist/metadata.js +3 -0
- package/dist/metadata.js.map +1 -0
- package/dist/setup.d.ts +126 -0
- package/dist/setup.js +363 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools.d.ts +11 -0
- package/dist/tools.js +268 -0
- package/dist/tools.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Granoflow
|
|
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,203 @@
|
|
|
1
|
+
# Granoflow MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for Granoflow: exposes the Granoflow Local HTTP API as tools for AI
|
|
4
|
+
agents, IDEs, and automation.
|
|
5
|
+
|
|
6
|
+
This server is intentionally thin. It does not own Granoflow business logic,
|
|
7
|
+
database access, app orchestration, or release workflows. It resolves a local API
|
|
8
|
+
endpoint, forwards structured requests to the running Granoflow app, and returns
|
|
9
|
+
predictable MCP tool results.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- Node.js 20 or newer.
|
|
14
|
+
- A running Granoflow app with the Local HTTP API enabled.
|
|
15
|
+
|
|
16
|
+
The default Granoflow API URL is:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
http://127.0.0.1:56789
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can override it with:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export GRANOFLOW_API_BASE_URL="http://127.0.0.1:56789"
|
|
26
|
+
export GRANOFLOW_API_TOKEN="..."
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The MCP server can keep non-secret local connection defaults in:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
~/.config/granoflow-mcp/config.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Set `GRANOFLOW_MCP_CONFIG_PATH` to use a different config path for tests,
|
|
36
|
+
temporary setups, or advanced local installs. API tokens are not stored in this
|
|
37
|
+
file; keep `GRANOFLOW_API_TOKEN` in the MCP client environment.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @granoflow/mcp-server
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For local development:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install
|
|
49
|
+
npm run build
|
|
50
|
+
node dist/index.js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Verify an installed package without starting an MCP stdio session:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx -y @granoflow/mcp-server --version
|
|
57
|
+
npx -y @granoflow/mcp-server --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Before publishing a release, verify the package contents:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm run check
|
|
64
|
+
npm pack --dry-run
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Tools
|
|
68
|
+
|
|
69
|
+
Initial tools:
|
|
70
|
+
|
|
71
|
+
- `granoflow_setup_status`
|
|
72
|
+
- `granoflow_setup_detect_local_api`
|
|
73
|
+
- `granoflow_setup_write_config`
|
|
74
|
+
- `granoflow_setup_open_config`
|
|
75
|
+
- `granoflow_setup_open_app`
|
|
76
|
+
- `granoflow_health`
|
|
77
|
+
- `granoflow_version`
|
|
78
|
+
- `granoflow_capabilities`
|
|
79
|
+
- `granoflow_ai_agent_tools`
|
|
80
|
+
- `granoflow_task_list`
|
|
81
|
+
- `granoflow_task_export`
|
|
82
|
+
- `granoflow_task_validate`
|
|
83
|
+
- `granoflow_task_import`
|
|
84
|
+
- `granoflow_task_create`
|
|
85
|
+
- `granoflow_task_create_structured`
|
|
86
|
+
- `granoflow_task_update`
|
|
87
|
+
- `granoflow_task_update_structured`
|
|
88
|
+
- `granoflow_task_complete`
|
|
89
|
+
- `granoflow_project_list`
|
|
90
|
+
- `granoflow_project_create`
|
|
91
|
+
- `granoflow_project_update`
|
|
92
|
+
- `granoflow_milestone_list`
|
|
93
|
+
- `granoflow_milestone_create`
|
|
94
|
+
- `granoflow_milestone_update`
|
|
95
|
+
- `granoflow_review_day_show`
|
|
96
|
+
- `granoflow_api_request`
|
|
97
|
+
|
|
98
|
+
Prefer the structured task, project, and milestone tools for common resource
|
|
99
|
+
operations. The JSON payload tools remain available as escape hatches when the
|
|
100
|
+
running app exposes newer fields before this package has first-class schemas.
|
|
101
|
+
|
|
102
|
+
Write tools default to dry-run behavior. Ask the tool to write only after you
|
|
103
|
+
have reviewed the preview or the user has explicitly requested a write.
|
|
104
|
+
|
|
105
|
+
## Setup Diagnostics
|
|
106
|
+
|
|
107
|
+
Use the setup tools when an agent or MCP client needs to connect to a local
|
|
108
|
+
Granoflow app without hand-editing every setting first:
|
|
109
|
+
|
|
110
|
+
- `granoflow_setup_status` reports config path, env/config precedence, token
|
|
111
|
+
presence, Local HTTP API health, version metadata, and local Granoflow process
|
|
112
|
+
evidence without printing secrets.
|
|
113
|
+
- `granoflow_setup_detect_local_api` probes a small bounded localhost port list
|
|
114
|
+
only.
|
|
115
|
+
- `granoflow_setup_write_config` previews or writes non-secret config. It
|
|
116
|
+
defaults to dry-run.
|
|
117
|
+
- `granoflow_setup_open_config` creates and optionally opens the config file for
|
|
118
|
+
manual editing.
|
|
119
|
+
- `granoflow_setup_open_app` previews or opens the installed Granoflow app after
|
|
120
|
+
user approval. On macOS it tries the formal `/Applications/granoflow.app`
|
|
121
|
+
path before app-name fallbacks. It defaults to dry-run.
|
|
122
|
+
|
|
123
|
+
When setup status sees a configured localhost API URL that is unreachable, it
|
|
124
|
+
checks whether a local Granoflow process appears to be running. If not, it
|
|
125
|
+
returns a warning and asks the agent to confirm before opening the app.
|
|
126
|
+
|
|
127
|
+
## Client Support
|
|
128
|
+
|
|
129
|
+
This package implements a standard MCP stdio server. The primary compatibility
|
|
130
|
+
contract is the MCP protocol plus the npm executable:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx -y @granoflow/mcp-server
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Cursor and Codex are the verified client targets for this repository. Other
|
|
137
|
+
MCP-compatible clients can use the same stdio command shape, but are not part of
|
|
138
|
+
the routine verification matrix.
|
|
139
|
+
|
|
140
|
+
## Cursor
|
|
141
|
+
|
|
142
|
+
Add this to `.cursor/mcp.json` in a project or `~/.cursor/mcp.json` globally:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"mcpServers": {
|
|
147
|
+
"granoflow": {
|
|
148
|
+
"command": "npx",
|
|
149
|
+
"args": ["-y", "@granoflow/mcp-server"],
|
|
150
|
+
"env": {
|
|
151
|
+
"GRANOFLOW_API_BASE_URL": "http://127.0.0.1:56789"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Codex
|
|
159
|
+
|
|
160
|
+
Add this to `~/.codex/config.toml`:
|
|
161
|
+
|
|
162
|
+
```toml
|
|
163
|
+
[mcp_servers.granoflow]
|
|
164
|
+
command = "npx"
|
|
165
|
+
args = ["-y", "@granoflow/mcp-server"]
|
|
166
|
+
|
|
167
|
+
[mcp_servers.granoflow.env]
|
|
168
|
+
GRANOFLOW_API_BASE_URL = "http://127.0.0.1:56789"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Restart Codex after changing MCP configuration.
|
|
172
|
+
|
|
173
|
+
## Other MCP-Compatible Clients
|
|
174
|
+
|
|
175
|
+
For clients that support local stdio MCP servers, configure the server with:
|
|
176
|
+
|
|
177
|
+
```jsonc
|
|
178
|
+
{
|
|
179
|
+
"type": "stdio",
|
|
180
|
+
"command": "npx",
|
|
181
|
+
"args": ["-y", "@granoflow/mcp-server"],
|
|
182
|
+
"env": {
|
|
183
|
+
"GRANOFLOW_API_BASE_URL": "http://127.0.0.1:56789",
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm install
|
|
192
|
+
npm run check
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`npm run check` runs Prettier, ESLint, TypeScript, and Vitest.
|
|
196
|
+
|
|
197
|
+
## Security
|
|
198
|
+
|
|
199
|
+
- This server does not read or write Granoflow's SQLite/Drift database.
|
|
200
|
+
- This server does not run Granoflow app builds, screenshots, release jobs, or
|
|
201
|
+
scenario orchestration.
|
|
202
|
+
- Core operations go through the running app's Local HTTP API.
|
|
203
|
+
- API tokens are passed through environment variables and must not be logged.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RuntimeResolution } from "./config.js";
|
|
2
|
+
export interface ApiRequestOptions {
|
|
3
|
+
method?: "GET" | "POST" | "PATCH" | "DELETE";
|
|
4
|
+
path: string;
|
|
5
|
+
body?: unknown;
|
|
6
|
+
dryRun?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiResult {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
code: string;
|
|
11
|
+
data?: unknown;
|
|
12
|
+
error?: {
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
httpStatus?: number;
|
|
16
|
+
runtime: {
|
|
17
|
+
apiBaseUrl: string;
|
|
18
|
+
apiBaseUrlSource: RuntimeResolution["apiBaseUrlSource"];
|
|
19
|
+
apiToken: {
|
|
20
|
+
present: boolean;
|
|
21
|
+
source: RuntimeResolution["apiTokenSource"];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function buildApiUrl(apiBaseUrl: string, path: string): URL;
|
|
26
|
+
export declare function requestGranoflowApi(options: ApiRequestOptions, env?: NodeJS.ProcessEnv): Promise<ApiResult>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { resolveMcpRuntime } from "./config.js";
|
|
2
|
+
function runtimeSummary(runtime) {
|
|
3
|
+
return {
|
|
4
|
+
apiBaseUrl: runtime.apiBaseUrl,
|
|
5
|
+
apiBaseUrlSource: runtime.apiBaseUrlSource,
|
|
6
|
+
apiToken: {
|
|
7
|
+
present: runtime.hasApiToken,
|
|
8
|
+
source: runtime.apiTokenSource,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function pathWithLeadingSlash(path) {
|
|
13
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
14
|
+
}
|
|
15
|
+
export function buildApiUrl(apiBaseUrl, path) {
|
|
16
|
+
return new URL(pathWithLeadingSlash(path), apiBaseUrl.endsWith("/") ? apiBaseUrl : `${apiBaseUrl}/`);
|
|
17
|
+
}
|
|
18
|
+
async function parseResponseBody(response) {
|
|
19
|
+
const text = await response.text();
|
|
20
|
+
if (!text.trim()) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(text);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function requestGranoflowApi(options, env = process.env) {
|
|
31
|
+
const runtime = await resolveMcpRuntime(env);
|
|
32
|
+
const method = options.method ?? "GET";
|
|
33
|
+
const path = pathWithLeadingSlash(options.path);
|
|
34
|
+
if (options.dryRun) {
|
|
35
|
+
return {
|
|
36
|
+
ok: true,
|
|
37
|
+
code: "dry_run",
|
|
38
|
+
data: {
|
|
39
|
+
method,
|
|
40
|
+
path,
|
|
41
|
+
body: options.body ?? null,
|
|
42
|
+
previewMode: "local_request_only",
|
|
43
|
+
},
|
|
44
|
+
runtime: runtimeSummary(runtime),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const headers = new Headers();
|
|
48
|
+
headers.set("accept", "application/json");
|
|
49
|
+
if (options.body !== undefined) {
|
|
50
|
+
headers.set("content-type", "application/json");
|
|
51
|
+
}
|
|
52
|
+
if (runtime.apiToken) {
|
|
53
|
+
headers.set("authorization", `Bearer ${runtime.apiToken}`);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(buildApiUrl(runtime.apiBaseUrl, path), {
|
|
57
|
+
method,
|
|
58
|
+
headers,
|
|
59
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
60
|
+
});
|
|
61
|
+
const body = await parseResponseBody(response);
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
code: `http_${response.status}`,
|
|
66
|
+
data: body,
|
|
67
|
+
error: { message: `Granoflow Local HTTP API returned HTTP ${response.status}.` },
|
|
68
|
+
httpStatus: response.status,
|
|
69
|
+
runtime: runtimeSummary(runtime),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (typeof body === "object" && body !== null && "ok" in body && "code" in body) {
|
|
73
|
+
return {
|
|
74
|
+
...body,
|
|
75
|
+
httpStatus: response.status,
|
|
76
|
+
runtime: runtimeSummary(runtime),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
ok: true,
|
|
81
|
+
code: "ok",
|
|
82
|
+
data: body,
|
|
83
|
+
httpStatus: response.status,
|
|
84
|
+
runtime: runtimeSummary(runtime),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
code: "network_error",
|
|
91
|
+
error: {
|
|
92
|
+
message: error instanceof Error ? error.message : String(error),
|
|
93
|
+
},
|
|
94
|
+
runtime: runtimeSummary(runtime),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface GranoflowMcpConfig {
|
|
2
|
+
apiBaseUrl?: string;
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface ConfigReadResult {
|
|
6
|
+
configPath: string;
|
|
7
|
+
exists: boolean;
|
|
8
|
+
config: GranoflowMcpConfig;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RuntimeResolution {
|
|
12
|
+
configPath: string;
|
|
13
|
+
configExists: boolean;
|
|
14
|
+
configError?: string;
|
|
15
|
+
apiBaseUrl: string;
|
|
16
|
+
apiBaseUrlSource: "env" | "config" | "default";
|
|
17
|
+
hasApiToken: boolean;
|
|
18
|
+
apiTokenSource: "env" | "none";
|
|
19
|
+
apiToken?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface WriteConfigInput {
|
|
22
|
+
apiBaseUrl?: string;
|
|
23
|
+
dryRun?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface WriteConfigResult {
|
|
26
|
+
configPath: string;
|
|
27
|
+
dryRun: boolean;
|
|
28
|
+
written: boolean;
|
|
29
|
+
backupPath: string | null;
|
|
30
|
+
previousConfig: Record<string, unknown>;
|
|
31
|
+
nextConfig: Record<string, unknown>;
|
|
32
|
+
changedKeys: string[];
|
|
33
|
+
nextActions: string[];
|
|
34
|
+
}
|
|
35
|
+
export declare function getMcpConfigPath(env?: NodeJS.ProcessEnv): string;
|
|
36
|
+
export declare function redactConfig(config: GranoflowMcpConfig): Record<string, unknown>;
|
|
37
|
+
export declare function readMcpConfig(env?: NodeJS.ProcessEnv): Promise<ConfigReadResult>;
|
|
38
|
+
export declare function resolveMcpRuntime(env?: NodeJS.ProcessEnv): Promise<RuntimeResolution>;
|
|
39
|
+
export declare function writeMcpConfig(input: WriteConfigInput, env?: NodeJS.ProcessEnv): Promise<WriteConfigResult>;
|
|
40
|
+
export declare function configFileExists(configPath: string): Promise<boolean>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { mkdir, open, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
const SECRET_KEY_PATTERN = /(token|secret|password|credential|key)/i;
|
|
5
|
+
const DEFAULT_API_BASE_URL = "http://127.0.0.1:56789";
|
|
6
|
+
function isObject(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function validateApiBaseUrl(apiBaseUrl) {
|
|
10
|
+
const url = new URL(apiBaseUrl);
|
|
11
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
12
|
+
throw new Error("apiBaseUrl must use http or https.");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function stableJson(value) {
|
|
16
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
17
|
+
}
|
|
18
|
+
export function getMcpConfigPath(env = process.env) {
|
|
19
|
+
if (env.GRANOFLOW_MCP_CONFIG_PATH) {
|
|
20
|
+
return env.GRANOFLOW_MCP_CONFIG_PATH;
|
|
21
|
+
}
|
|
22
|
+
if (env.XDG_CONFIG_HOME) {
|
|
23
|
+
return join(env.XDG_CONFIG_HOME, "granoflow-mcp", "config.json");
|
|
24
|
+
}
|
|
25
|
+
return join(homedir(), ".config", "granoflow-mcp", "config.json");
|
|
26
|
+
}
|
|
27
|
+
export function redactConfig(config) {
|
|
28
|
+
const redacted = {};
|
|
29
|
+
for (const [key, value] of Object.entries(config)) {
|
|
30
|
+
redacted[key] = SECRET_KEY_PATTERN.test(key) && value !== undefined ? "[REDACTED]" : value;
|
|
31
|
+
}
|
|
32
|
+
return redacted;
|
|
33
|
+
}
|
|
34
|
+
export async function readMcpConfig(env = process.env) {
|
|
35
|
+
const configPath = getMcpConfigPath(env);
|
|
36
|
+
try {
|
|
37
|
+
const text = await readFile(configPath, "utf8");
|
|
38
|
+
const parsed = JSON.parse(text);
|
|
39
|
+
if (!isObject(parsed)) {
|
|
40
|
+
return {
|
|
41
|
+
configPath,
|
|
42
|
+
exists: true,
|
|
43
|
+
config: {},
|
|
44
|
+
error: "Config file must contain a JSON object.",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { configPath, exists: true, config: parsed };
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (isObject(error) && "code" in error && error.code === "ENOENT") {
|
|
51
|
+
return { configPath, exists: false, config: {} };
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
configPath,
|
|
55
|
+
exists: false,
|
|
56
|
+
config: {},
|
|
57
|
+
error: error instanceof Error ? error.message : String(error),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function resolveMcpRuntime(env = process.env) {
|
|
62
|
+
const configResult = await readMcpConfig(env);
|
|
63
|
+
const config = configResult.config;
|
|
64
|
+
const apiBaseUrl = env.GRANOFLOW_API_BASE_URL ??
|
|
65
|
+
(typeof config.apiBaseUrl === "string" ? config.apiBaseUrl : undefined) ??
|
|
66
|
+
DEFAULT_API_BASE_URL;
|
|
67
|
+
return {
|
|
68
|
+
configPath: configResult.configPath,
|
|
69
|
+
configExists: configResult.exists,
|
|
70
|
+
configError: configResult.error,
|
|
71
|
+
apiBaseUrl,
|
|
72
|
+
apiBaseUrlSource: env.GRANOFLOW_API_BASE_URL
|
|
73
|
+
? "env"
|
|
74
|
+
: typeof config.apiBaseUrl === "string"
|
|
75
|
+
? "config"
|
|
76
|
+
: "default",
|
|
77
|
+
hasApiToken: Boolean(env.GRANOFLOW_API_TOKEN),
|
|
78
|
+
apiTokenSource: env.GRANOFLOW_API_TOKEN ? "env" : "none",
|
|
79
|
+
apiToken: env.GRANOFLOW_API_TOKEN,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export async function writeMcpConfig(input, env = process.env) {
|
|
83
|
+
if (input.apiBaseUrl !== undefined) {
|
|
84
|
+
validateApiBaseUrl(input.apiBaseUrl);
|
|
85
|
+
}
|
|
86
|
+
const readResult = await readMcpConfig(env);
|
|
87
|
+
const nextConfig = { ...readResult.config };
|
|
88
|
+
if (input.apiBaseUrl !== undefined) {
|
|
89
|
+
nextConfig.apiBaseUrl = input.apiBaseUrl;
|
|
90
|
+
}
|
|
91
|
+
const previousConfig = redactConfig(readResult.config);
|
|
92
|
+
const redactedNextConfig = redactConfig(nextConfig);
|
|
93
|
+
const changedKeys = Object.keys(redactedNextConfig).filter((key) => previousConfig[key] !== redactedNextConfig[key]);
|
|
94
|
+
const dryRun = input.dryRun !== false;
|
|
95
|
+
if (dryRun) {
|
|
96
|
+
return {
|
|
97
|
+
configPath: readResult.configPath,
|
|
98
|
+
dryRun,
|
|
99
|
+
written: false,
|
|
100
|
+
backupPath: null,
|
|
101
|
+
previousConfig,
|
|
102
|
+
nextConfig: redactedNextConfig,
|
|
103
|
+
changedKeys,
|
|
104
|
+
nextActions: [
|
|
105
|
+
"Review the config preview.",
|
|
106
|
+
"Call this tool again with dryRun=false to write.",
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
await mkdir(dirname(readResult.configPath), { recursive: true });
|
|
111
|
+
let backupPath = null;
|
|
112
|
+
if (readResult.exists) {
|
|
113
|
+
backupPath = `${readResult.configPath}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
114
|
+
await writeFile(backupPath, stableJson(readResult.config), { mode: 0o600 });
|
|
115
|
+
}
|
|
116
|
+
const tempPath = `${readResult.configPath}.tmp-${process.pid}`;
|
|
117
|
+
await writeFile(tempPath, stableJson(nextConfig), { mode: 0o600 });
|
|
118
|
+
await rename(tempPath, readResult.configPath);
|
|
119
|
+
const handle = await open(readResult.configPath, "r+");
|
|
120
|
+
await handle.chmod(0o600);
|
|
121
|
+
await handle.close();
|
|
122
|
+
return {
|
|
123
|
+
configPath: readResult.configPath,
|
|
124
|
+
dryRun,
|
|
125
|
+
written: true,
|
|
126
|
+
backupPath,
|
|
127
|
+
previousConfig,
|
|
128
|
+
nextConfig: redactedNextConfig,
|
|
129
|
+
changedKeys,
|
|
130
|
+
nextActions: [
|
|
131
|
+
"Restart or reload the MCP client if it keeps a long-running server process.",
|
|
132
|
+
"Call granoflow_setup_status to verify the resolved configuration.",
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export async function configFileExists(configPath) {
|
|
137
|
+
try {
|
|
138
|
+
await stat(configPath);
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (isObject(error) && "code" in error && error.code === "ENOENT") {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { SERVER_NAME, SERVER_VERSION } from "./metadata.js";
|
|
5
|
+
import { registerGranoflowTools } from "./tools.js";
|
|
6
|
+
function printHelp() {
|
|
7
|
+
process.stdout.write(`${SERVER_NAME} ${SERVER_VERSION}
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
granoflow-mcp-server
|
|
11
|
+
granoflow-mcp-server --help
|
|
12
|
+
granoflow-mcp-server --version
|
|
13
|
+
|
|
14
|
+
Starts the Granoflow MCP server over stdio.
|
|
15
|
+
|
|
16
|
+
Environment:
|
|
17
|
+
GRANOFLOW_API_BASE_URL Optional Granoflow Local HTTP API base URL.
|
|
18
|
+
GRANOFLOW_API_TOKEN Optional Granoflow Local HTTP API token.
|
|
19
|
+
GRANOFLOW_MCP_CONFIG_PATH Optional path for MCP-owned non-secret config.
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
23
|
+
process.stdout.write(`${SERVER_VERSION}\n`);
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
27
|
+
printHelp();
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
const server = new McpServer({
|
|
31
|
+
name: SERVER_NAME,
|
|
32
|
+
version: SERVER_VERSION,
|
|
33
|
+
});
|
|
34
|
+
registerGranoflowTools(server);
|
|
35
|
+
const transport = new StdioServerTransport();
|
|
36
|
+
await server.connect(transport);
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,SAAS,SAAS;IAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,IAAI,cAAc;;;;;;;;;;;;;CAatD,CAAC,CAAC;AACH,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,cAAc,IAAI,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACnE,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;CACxB,CAAC,CAAC;AAEH,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAE/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC"}
|