@studiometa/forge-mcp 0.0.1 → 0.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 +152 -0
- package/dist/auth.d.ts +15 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +18 -0
- package/dist/auth.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/formatters.d.ts +187 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/handlers/backups.d.ts +2 -0
- package/dist/handlers/backups.d.ts.map +1 -0
- package/dist/handlers/certificates.d.ts +2 -0
- package/dist/handlers/certificates.d.ts.map +1 -0
- package/dist/handlers/commands.d.ts +2 -0
- package/dist/handlers/commands.d.ts.map +1 -0
- package/dist/handlers/daemons.d.ts +2 -0
- package/dist/handlers/daemons.d.ts.map +1 -0
- package/dist/handlers/database-users.d.ts +2 -0
- package/dist/handlers/database-users.d.ts.map +1 -0
- package/dist/handlers/databases.d.ts +2 -0
- package/dist/handlers/databases.d.ts.map +1 -0
- package/dist/handlers/deployments.d.ts +9 -0
- package/dist/handlers/deployments.d.ts.map +1 -0
- package/dist/handlers/env.d.ts +2 -0
- package/dist/handlers/env.d.ts.map +1 -0
- package/dist/handlers/factory.d.ts +71 -0
- package/dist/handlers/factory.d.ts.map +1 -0
- package/dist/handlers/firewall-rules.d.ts +2 -0
- package/dist/handlers/firewall-rules.d.ts.map +1 -0
- package/dist/handlers/help.d.ts +16 -0
- package/dist/handlers/help.d.ts.map +1 -0
- package/dist/handlers/index.d.ts +20 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/monitors.d.ts +2 -0
- package/dist/handlers/monitors.d.ts.map +1 -0
- package/dist/handlers/nginx-config.d.ts +2 -0
- package/dist/handlers/nginx-config.d.ts.map +1 -0
- package/dist/handlers/nginx-templates.d.ts +2 -0
- package/dist/handlers/nginx-templates.d.ts.map +1 -0
- package/dist/handlers/recipes.d.ts +2 -0
- package/dist/handlers/recipes.d.ts.map +1 -0
- package/dist/handlers/redirect-rules.d.ts +2 -0
- package/dist/handlers/redirect-rules.d.ts.map +1 -0
- package/dist/handlers/scheduled-jobs.d.ts +2 -0
- package/dist/handlers/scheduled-jobs.d.ts.map +1 -0
- package/dist/handlers/schema.d.ts +16 -0
- package/dist/handlers/schema.d.ts.map +1 -0
- package/dist/handlers/security-rules.d.ts +2 -0
- package/dist/handlers/security-rules.d.ts.map +1 -0
- package/dist/handlers/servers.d.ts +2 -0
- package/dist/handlers/servers.d.ts.map +1 -0
- package/dist/handlers/sites.d.ts +2 -0
- package/dist/handlers/sites.d.ts.map +1 -0
- package/dist/handlers/ssh-keys.d.ts +2 -0
- package/dist/handlers/ssh-keys.d.ts.map +1 -0
- package/dist/handlers/types.d.ts +38 -0
- package/dist/handlers/types.d.ts.map +1 -0
- package/dist/handlers/user.d.ts +2 -0
- package/dist/handlers/user.d.ts.map +1 -0
- package/dist/handlers/utils.d.ts +29 -0
- package/dist/handlers/utils.d.ts.map +1 -0
- package/dist/hints.d.ts +60 -0
- package/dist/hints.d.ts.map +1 -0
- package/dist/http-CfjqK_e4.js +277 -0
- package/dist/http-CfjqK_e4.js.map +1 -0
- package/dist/http.d.ts +55 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +3 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/instructions.d.ts +11 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +76 -0
- package/dist/server.js.map +1 -0
- package/dist/sessions.d.ts +64 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/src-BdwavqrN.js +189 -0
- package/dist/src-BdwavqrN.js.map +1 -0
- package/dist/stdio.d.ts +36 -0
- package/dist/stdio.d.ts.map +1 -0
- package/dist/tools.d.ts +47 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/version-DaD5zvGh.js +3470 -0
- package/dist/version-DaD5zvGh.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +53 -1
- package/skills/SKILL.md +219 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Forge MCP Server — Stdio Transport
|
|
4
|
+
*
|
|
5
|
+
* This is the local execution mode using stdio transport.
|
|
6
|
+
* For remote HTTP deployment, use server.ts instead.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @studiometa/forge-mcp
|
|
10
|
+
* npx @studiometa/forge-mcp --read-only
|
|
11
|
+
* FORGE_READ_ONLY=true npx @studiometa/forge-mcp
|
|
12
|
+
*
|
|
13
|
+
* Or in Claude Desktop config:
|
|
14
|
+
* {
|
|
15
|
+
* "mcpServers": {
|
|
16
|
+
* "forge": {
|
|
17
|
+
* "command": "forge-mcp",
|
|
18
|
+
* "args": ["--read-only"],
|
|
19
|
+
* "env": { "FORGE_API_TOKEN": "your-token" }
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
25
|
+
/**
|
|
26
|
+
* Options for the stdio MCP server.
|
|
27
|
+
*/
|
|
28
|
+
export interface StdioServerOptions {
|
|
29
|
+
/** When true, forge_write tool is not registered and write operations are rejected. */
|
|
30
|
+
readOnly?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse read-only flag from process.argv and environment.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseReadOnlyFlag(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Create and configure the MCP server.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createStdioServer(options?: StdioServerOptions): Server;
|
|
40
|
+
/**
|
|
41
|
+
* Start the stdio server.
|
|
42
|
+
*/
|
|
43
|
+
export declare function startStdioServer(options?: StdioServerOptions): Promise<void>;
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAuCtE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Instructions
|
|
3
|
+
*
|
|
4
|
+
* These instructions are sent to MCP clients during initialization
|
|
5
|
+
* and used as context/hints for the LLM. Ensures the AI agent
|
|
6
|
+
* knows how to properly use the Forge MCP server.
|
|
7
|
+
*
|
|
8
|
+
* The content is derived from skills/SKILL.md (without YAML frontmatter).
|
|
9
|
+
*/
|
|
10
|
+
export declare const INSTRUCTIONS: string;
|
|
11
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2BH,eAAO,MAAM,YAAY,QAAqB,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Forge MCP Server - HTTP Transport (Streamable HTTP)
|
|
4
|
+
*
|
|
5
|
+
* Implements the official MCP Streamable HTTP transport specification.
|
|
6
|
+
* Credentials are passed via Bearer token in the Authorization header.
|
|
7
|
+
*
|
|
8
|
+
* Token format: raw Forge API token
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* forge-mcp-server
|
|
12
|
+
* forge-mcp-server --read-only
|
|
13
|
+
* FORGE_READ_ONLY=true forge-mcp-server
|
|
14
|
+
* PORT=3000 forge-mcp-server
|
|
15
|
+
*
|
|
16
|
+
* Endpoints:
|
|
17
|
+
* POST /mcp - MCP Streamable HTTP (JSON-RPC messages)
|
|
18
|
+
* GET /mcp - MCP Streamable HTTP (SSE stream for server notifications)
|
|
19
|
+
* DELETE /mcp - MCP Streamable HTTP (session termination)
|
|
20
|
+
* GET / - Service info
|
|
21
|
+
* GET /health - Health check
|
|
22
|
+
*/
|
|
23
|
+
import { type Server } from "node:http";
|
|
24
|
+
/**
|
|
25
|
+
* Options for the HTTP server.
|
|
26
|
+
*/
|
|
27
|
+
export interface HttpStartOptions {
|
|
28
|
+
/** When true, forge_write tool is not registered. */
|
|
29
|
+
readOnly?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Start the HTTP server with Streamable HTTP transport.
|
|
33
|
+
*/
|
|
34
|
+
export declare function startHttpServer(port?: number, host?: string, options?: HttpStartOptions): Promise<Server>;
|
|
35
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAUtD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,GAAE,MAAqB,EAC3B,IAAI,GAAE,MAAqB,EAC3B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as VERSION } from "./version-DaD5zvGh.js";
|
|
3
|
+
import { n as parseReadOnlyFlag } from "./src-BdwavqrN.js";
|
|
4
|
+
import { a as SessionManager, n as createMcpRequestHandler, t as createHealthApp } from "./http-CfjqK_e4.js";
|
|
5
|
+
import { toNodeHandler } from "h3/node";
|
|
6
|
+
import { createServer } from "node:http";
|
|
7
|
+
/**
|
|
8
|
+
* Forge MCP Server - HTTP Transport (Streamable HTTP)
|
|
9
|
+
*
|
|
10
|
+
* Implements the official MCP Streamable HTTP transport specification.
|
|
11
|
+
* Credentials are passed via Bearer token in the Authorization header.
|
|
12
|
+
*
|
|
13
|
+
* Token format: raw Forge API token
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* forge-mcp-server
|
|
17
|
+
* forge-mcp-server --read-only
|
|
18
|
+
* FORGE_READ_ONLY=true forge-mcp-server
|
|
19
|
+
* PORT=3000 forge-mcp-server
|
|
20
|
+
*
|
|
21
|
+
* Endpoints:
|
|
22
|
+
* POST /mcp - MCP Streamable HTTP (JSON-RPC messages)
|
|
23
|
+
* GET /mcp - MCP Streamable HTTP (SSE stream for server notifications)
|
|
24
|
+
* DELETE /mcp - MCP Streamable HTTP (session termination)
|
|
25
|
+
* GET / - Service info
|
|
26
|
+
* GET /health - Health check
|
|
27
|
+
*/
|
|
28
|
+
var DEFAULT_PORT = 3e3;
|
|
29
|
+
var DEFAULT_HOST = "0.0.0.0";
|
|
30
|
+
/**
|
|
31
|
+
* Start the HTTP server with Streamable HTTP transport.
|
|
32
|
+
*/
|
|
33
|
+
function startHttpServer(port = DEFAULT_PORT, host = DEFAULT_HOST, options) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const readOnly = options?.readOnly ?? false;
|
|
36
|
+
const handleMcp = createMcpRequestHandler(new SessionManager(), { readOnly });
|
|
37
|
+
const healthHandler = toNodeHandler(createHealthApp());
|
|
38
|
+
const server = createServer(async (req, res) => {
|
|
39
|
+
const url = req.url ?? "/";
|
|
40
|
+
if (url === "/mcp" || url.startsWith("/mcp?")) {
|
|
41
|
+
await handleMcp(req, res);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
healthHandler(req, res);
|
|
45
|
+
});
|
|
46
|
+
server.listen(port, host, () => {
|
|
47
|
+
const displayHost = host === "0.0.0.0" ? "localhost" : host;
|
|
48
|
+
const mode = readOnly ? " (read-only)" : "";
|
|
49
|
+
console.log(`Forge MCP server v${VERSION}${mode}`);
|
|
50
|
+
console.log(`Node.js ${process.version}`);
|
|
51
|
+
console.log("");
|
|
52
|
+
console.log(`Running at http://${displayHost}:${port}`);
|
|
53
|
+
console.log("");
|
|
54
|
+
console.log("Endpoints:");
|
|
55
|
+
console.log(` POST/GET/DELETE http://${displayHost}:${port}/mcp - MCP Streamable HTTP endpoint`);
|
|
56
|
+
console.log(` GET http://${displayHost}:${port}/health - Health check`);
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log("Authentication:");
|
|
59
|
+
console.log(" Bearer token in Authorization header");
|
|
60
|
+
console.log(" Token format: your raw Forge API token");
|
|
61
|
+
if (readOnly) {
|
|
62
|
+
console.log("");
|
|
63
|
+
console.log("Mode: READ-ONLY (write operations disabled)");
|
|
64
|
+
}
|
|
65
|
+
console.log("");
|
|
66
|
+
resolve(server);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/forge-mcp-server") || process.argv[1]?.endsWith("\\forge-mcp-server")) startHttpServer(Number.parseInt(process.env.PORT || String(DEFAULT_PORT), 10), process.env.HOST || DEFAULT_HOST, { readOnly: parseReadOnlyFlag() }).catch((error) => {
|
|
71
|
+
console.error("Fatal error:", error);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
export { startHttpServer };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Forge MCP Server - HTTP Transport (Streamable HTTP)\n *\n * Implements the official MCP Streamable HTTP transport specification.\n * Credentials are passed via Bearer token in the Authorization header.\n *\n * Token format: raw Forge API token\n *\n * Usage:\n * forge-mcp-server\n * forge-mcp-server --read-only\n * FORGE_READ_ONLY=true forge-mcp-server\n * PORT=3000 forge-mcp-server\n *\n * Endpoints:\n * POST /mcp - MCP Streamable HTTP (JSON-RPC messages)\n * GET /mcp - MCP Streamable HTTP (SSE stream for server notifications)\n * DELETE /mcp - MCP Streamable HTTP (session termination)\n * GET / - Service info\n * GET /health - Health check\n */\n\nimport { toNodeHandler } from \"h3/node\";\nimport { createServer, type Server } from \"node:http\";\n\nimport { createHealthApp, createMcpRequestHandler } from \"./http.ts\";\nimport { parseReadOnlyFlag } from \"./index.ts\";\nimport { SessionManager } from \"./sessions.ts\";\nimport { VERSION } from \"./version.ts\";\n\nconst DEFAULT_PORT = 3000;\nconst DEFAULT_HOST = \"0.0.0.0\";\n\n/**\n * Options for the HTTP server.\n */\nexport interface HttpStartOptions {\n /** When true, forge_write tool is not registered. */\n readOnly?: boolean;\n}\n\n/**\n * Start the HTTP server with Streamable HTTP transport.\n */\nexport function startHttpServer(\n port: number = DEFAULT_PORT,\n host: string = DEFAULT_HOST,\n options?: HttpStartOptions,\n): Promise<Server> {\n return new Promise((resolve) => {\n const readOnly = options?.readOnly ?? false;\n const sessions = new SessionManager();\n const handleMcp = createMcpRequestHandler(sessions, { readOnly });\n const healthApp = createHealthApp();\n const healthHandler = toNodeHandler(healthApp);\n\n const server = createServer(async (req, res) => {\n const url = req.url ?? \"/\";\n\n // Route /mcp to MCP Streamable HTTP transport\n if (url === \"/mcp\" || url.startsWith(\"/mcp?\")) {\n await handleMcp(req, res);\n return;\n }\n\n // Everything else goes to h3 (health checks, service info)\n healthHandler(req, res);\n });\n\n server.listen(port, host, () => {\n const displayHost = host === \"0.0.0.0\" ? \"localhost\" : host;\n const mode = readOnly ? \" (read-only)\" : \"\";\n console.log(`Forge MCP server v${VERSION}${mode}`);\n console.log(`Node.js ${process.version}`);\n console.log(\"\");\n console.log(`Running at http://${displayHost}:${port}`);\n console.log(\"\");\n console.log(\"Endpoints:\");\n console.log(\n ` POST/GET/DELETE http://${displayHost}:${port}/mcp - MCP Streamable HTTP endpoint`,\n );\n console.log(` GET http://${displayHost}:${port}/health - Health check`);\n console.log(\"\");\n console.log(\"Authentication:\");\n console.log(\" Bearer token in Authorization header\");\n console.log(\" Token format: your raw Forge API token\");\n if (readOnly) {\n console.log(\"\");\n console.log(\"Mode: READ-ONLY (write operations disabled)\");\n }\n console.log(\"\");\n resolve(server);\n });\n });\n}\n\n// Start server when run directly\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"/forge-mcp-server\") ||\n process.argv[1]?.endsWith(\"\\\\forge-mcp-server\");\n\nif (isMainModule) {\n const port = Number.parseInt(process.env.PORT || String(DEFAULT_PORT), 10);\n const host = process.env.HOST || DEFAULT_HOST;\n const readOnly = parseReadOnlyFlag();\n\n startHttpServer(port, host, { readOnly }).catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAM,eAAe;AACrB,IAAM,eAAe;;;;AAarB,SAAgB,gBACd,OAAe,cACf,OAAe,cACf,SACiB;AACjB,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,WAAW,SAAS,YAAY;EAEtC,MAAM,YAAY,wBADD,IAAI,gBAAgB,EACe,EAAE,UAAU,CAAC;EAEjE,MAAM,gBAAgB,cADJ,iBAAiB,CACW;EAE9C,MAAM,SAAS,aAAa,OAAO,KAAK,QAAQ;GAC9C,MAAM,MAAM,IAAI,OAAO;AAGvB,OAAI,QAAQ,UAAU,IAAI,WAAW,QAAQ,EAAE;AAC7C,UAAM,UAAU,KAAK,IAAI;AACzB;;AAIF,iBAAc,KAAK,IAAI;IACvB;AAEF,SAAO,OAAO,MAAM,YAAY;GAC9B,MAAM,cAAc,SAAS,YAAY,cAAc;GACvD,MAAM,OAAO,WAAW,iBAAiB;AACzC,WAAQ,IAAI,qBAAqB,UAAU,OAAO;AAClD,WAAQ,IAAI,WAAW,QAAQ,UAAU;AACzC,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,qBAAqB,YAAY,GAAG,OAAO;AACvD,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,aAAa;AACzB,WAAQ,IACN,4BAA4B,YAAY,GAAG,KAAK,qCACjD;AACD,WAAQ,IAAI,iBAAiB,YAAY,GAAG,KAAK,wBAAwB;AACzE,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,kBAAkB;AAC9B,WAAQ,IAAI,yCAAyC;AACrD,WAAQ,IAAI,2CAA2C;AACvD,OAAI,UAAU;AACZ,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,8CAA8C;;AAE5D,WAAQ,IAAI,GAAG;AACf,WAAQ,OAAO;IACf;GACF;;AASJ,IAJE,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,QAC3C,QAAQ,KAAK,IAAI,SAAS,oBAAoB,IAC9C,QAAQ,KAAK,IAAI,SAAS,qBAAqB,CAO/C,iBAJa,OAAO,SAAS,QAAQ,IAAI,QAAQ,OAAO,aAAa,EAAE,GAAG,EAC7D,QAAQ,IAAI,QAAQ,cAGL,EAAE,UAFb,mBAAmB,EAEI,CAAC,CAAC,OAAO,UAAU;AACzD,SAAQ,MAAM,gBAAgB,MAAM;AACpC,SAAQ,KAAK,EAAE;EACf"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for multi-tenant Streamable HTTP transport.
|
|
3
|
+
*
|
|
4
|
+
* Each MCP client session gets its own transport + server pair.
|
|
5
|
+
* Sessions are identified by UUID and tracked in a Map.
|
|
6
|
+
*
|
|
7
|
+
* Supports automatic TTL-based cleanup of idle sessions to prevent
|
|
8
|
+
* memory leaks from abandoned clients.
|
|
9
|
+
*/
|
|
10
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import type { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
12
|
+
/**
|
|
13
|
+
* A managed session: transport + MCP server pair.
|
|
14
|
+
*/
|
|
15
|
+
export interface ManagedSession {
|
|
16
|
+
transport: StreamableHTTPServerTransport;
|
|
17
|
+
server: Server;
|
|
18
|
+
createdAt: number;
|
|
19
|
+
lastActiveAt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface SessionManagerOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Maximum idle time in milliseconds before a session is reaped.
|
|
24
|
+
* Default: 30 minutes. Set to 0 to disable automatic cleanup.
|
|
25
|
+
*/
|
|
26
|
+
ttl?: number;
|
|
27
|
+
/**
|
|
28
|
+
* How often to check for expired sessions, in milliseconds.
|
|
29
|
+
* Default: 60 seconds.
|
|
30
|
+
*/
|
|
31
|
+
sweepInterval?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare class SessionManager {
|
|
34
|
+
private sessions;
|
|
35
|
+
private sweepTimer;
|
|
36
|
+
private readonly ttl;
|
|
37
|
+
constructor(options?: SessionManagerOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Register a session after its ID has been assigned by the transport.
|
|
40
|
+
*/
|
|
41
|
+
register(transport: StreamableHTTPServerTransport, server: Server): void;
|
|
42
|
+
/**
|
|
43
|
+
* Look up a session by its ID and refresh its activity timestamp.
|
|
44
|
+
*/
|
|
45
|
+
get(sessionId: string): ManagedSession | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Remove a session and close its transport + server.
|
|
48
|
+
*/
|
|
49
|
+
remove(sessionId: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Get the number of active sessions.
|
|
52
|
+
*/
|
|
53
|
+
get size(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Sweep expired sessions. Called automatically by the sweep timer.
|
|
56
|
+
* Returns the number of sessions reaped.
|
|
57
|
+
*/
|
|
58
|
+
sweep(): number;
|
|
59
|
+
/**
|
|
60
|
+
* Close all sessions, stop the sweep timer, and clean up.
|
|
61
|
+
*/
|
|
62
|
+
closeAll(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAExG;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,6BAA6B,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAKD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,UAAU,CAA6C;IAC/D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,OAAO,CAAC,EAAE,qBAAqB;IAa3C;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,6BAA6B,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAaxE;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAQlD;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,KAAK,IAAI,MAAM;IAsBf;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAchC"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { a as INSTRUCTIONS, i as getTools, n as executeToolWithCredentials, r as STDIO_ONLY_TOOLS, t as VERSION } from "./version-DaD5zvGh.js";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { getToken, setToken } from "@studiometa/forge-api";
|
|
6
|
+
/**
|
|
7
|
+
* Get all available tools (including stdio-only configuration tools).
|
|
8
|
+
*
|
|
9
|
+
* @param options - Optional filtering. When `readOnly` is true, forge_write is excluded.
|
|
10
|
+
*/
|
|
11
|
+
function getAvailableTools(options) {
|
|
12
|
+
return [...getTools(options), ...STDIO_ONLY_TOOLS];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Handle the forge_configure tool.
|
|
16
|
+
*/
|
|
17
|
+
function handleConfigureTool(args) {
|
|
18
|
+
if (!args.apiToken || typeof args.apiToken !== "string" || args.apiToken.trim().length === 0) return {
|
|
19
|
+
content: [{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: "Error: apiToken is required and must be a non-empty string."
|
|
22
|
+
}],
|
|
23
|
+
structuredContent: {
|
|
24
|
+
success: false,
|
|
25
|
+
error: "apiToken is required and must be a non-empty string."
|
|
26
|
+
},
|
|
27
|
+
isError: true
|
|
28
|
+
};
|
|
29
|
+
setToken(args.apiToken);
|
|
30
|
+
const data = {
|
|
31
|
+
success: true,
|
|
32
|
+
message: "Laravel Forge API token configured successfully",
|
|
33
|
+
apiToken: `***${args.apiToken.slice(-4)}`
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
content: [{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: JSON.stringify(data, null, 2)
|
|
39
|
+
}],
|
|
40
|
+
structuredContent: data
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Handle the forge_get_config tool.
|
|
45
|
+
*/
|
|
46
|
+
function handleGetConfigTool() {
|
|
47
|
+
const token = getToken();
|
|
48
|
+
const data = {
|
|
49
|
+
apiToken: token ? `***${token.slice(-4)}` : "not configured",
|
|
50
|
+
configured: !!token
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: JSON.stringify(data, null, 2)
|
|
56
|
+
}],
|
|
57
|
+
structuredContent: data
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Handle a tool call request.
|
|
62
|
+
*
|
|
63
|
+
* Routes to the appropriate handler based on tool name:
|
|
64
|
+
* - forge_configure / forge_get_config — stdio-only config tools
|
|
65
|
+
* - forge — read-only operations (list, get, help, schema)
|
|
66
|
+
* - forge_write — write operations (create, update, delete, deploy, etc.)
|
|
67
|
+
*/
|
|
68
|
+
async function handleToolCall(name, args, options) {
|
|
69
|
+
if (name === "forge_configure") return handleConfigureTool(args);
|
|
70
|
+
if (name === "forge_get_config") return handleGetConfigTool();
|
|
71
|
+
if (name === "forge_write" && options?.readOnly) return {
|
|
72
|
+
content: [{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: "Error: Server is running in read-only mode. Write operations are disabled."
|
|
75
|
+
}],
|
|
76
|
+
structuredContent: {
|
|
77
|
+
success: false,
|
|
78
|
+
error: "Server is running in read-only mode. Write operations are disabled."
|
|
79
|
+
},
|
|
80
|
+
isError: true
|
|
81
|
+
};
|
|
82
|
+
if (name === "forge" || name === "forge_write") {
|
|
83
|
+
const apiToken = getToken();
|
|
84
|
+
if (!apiToken) return {
|
|
85
|
+
content: [{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: "Error: Forge API token not configured. Use \"forge_configure\" tool or set FORGE_API_TOKEN environment variable."
|
|
88
|
+
}],
|
|
89
|
+
structuredContent: {
|
|
90
|
+
success: false,
|
|
91
|
+
error: "Forge API token not configured. Use \"forge_configure\" tool or set FORGE_API_TOKEN environment variable."
|
|
92
|
+
},
|
|
93
|
+
isError: true
|
|
94
|
+
};
|
|
95
|
+
return executeToolWithCredentials(name, args, { apiToken });
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
content: [{
|
|
99
|
+
type: "text",
|
|
100
|
+
text: `Error: Unknown tool "${name}".`
|
|
101
|
+
}],
|
|
102
|
+
structuredContent: {
|
|
103
|
+
success: false,
|
|
104
|
+
error: `Unknown tool "${name}".`
|
|
105
|
+
},
|
|
106
|
+
isError: true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Forge MCP Server — Stdio Transport
|
|
111
|
+
*
|
|
112
|
+
* This is the local execution mode using stdio transport.
|
|
113
|
+
* For remote HTTP deployment, use server.ts instead.
|
|
114
|
+
*
|
|
115
|
+
* Usage:
|
|
116
|
+
* npx @studiometa/forge-mcp
|
|
117
|
+
* npx @studiometa/forge-mcp --read-only
|
|
118
|
+
* FORGE_READ_ONLY=true npx @studiometa/forge-mcp
|
|
119
|
+
*
|
|
120
|
+
* Or in Claude Desktop config:
|
|
121
|
+
* {
|
|
122
|
+
* "mcpServers": {
|
|
123
|
+
* "forge": {
|
|
124
|
+
* "command": "forge-mcp",
|
|
125
|
+
* "args": ["--read-only"],
|
|
126
|
+
* "env": { "FORGE_API_TOKEN": "your-token" }
|
|
127
|
+
* }
|
|
128
|
+
* }
|
|
129
|
+
* }
|
|
130
|
+
*/
|
|
131
|
+
/**
|
|
132
|
+
* Parse read-only flag from process.argv and environment.
|
|
133
|
+
*/
|
|
134
|
+
function parseReadOnlyFlag() {
|
|
135
|
+
return process.argv.includes("--read-only") || process.env.FORGE_READ_ONLY === "true";
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create and configure the MCP server.
|
|
139
|
+
*/
|
|
140
|
+
function createStdioServer(options) {
|
|
141
|
+
const readOnly = options?.readOnly ?? false;
|
|
142
|
+
const server = new Server({
|
|
143
|
+
name: "forge-mcp",
|
|
144
|
+
version: VERSION
|
|
145
|
+
}, {
|
|
146
|
+
capabilities: { tools: {} },
|
|
147
|
+
instructions: INSTRUCTIONS
|
|
148
|
+
});
|
|
149
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
150
|
+
return { tools: getAvailableTools({ readOnly }) };
|
|
151
|
+
});
|
|
152
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
153
|
+
const { name, arguments: args } = request.params;
|
|
154
|
+
try {
|
|
155
|
+
return await handleToolCall(name, args ?? {}, { readOnly });
|
|
156
|
+
} catch (error) {
|
|
157
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
158
|
+
return {
|
|
159
|
+
content: [{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `Error: ${message}`
|
|
162
|
+
}],
|
|
163
|
+
structuredContent: {
|
|
164
|
+
success: false,
|
|
165
|
+
error: message
|
|
166
|
+
},
|
|
167
|
+
isError: true
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return server;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Start the stdio server.
|
|
175
|
+
*/
|
|
176
|
+
async function startStdioServer(options) {
|
|
177
|
+
const server = createStdioServer(options);
|
|
178
|
+
const transport = new StdioServerTransport();
|
|
179
|
+
await server.connect(transport);
|
|
180
|
+
const mode = options?.readOnly ? " (read-only)" : "";
|
|
181
|
+
console.error(`Forge MCP server v${VERSION} running on stdio${mode}`);
|
|
182
|
+
}
|
|
183
|
+
if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/forge-mcp") || process.argv[1]?.endsWith("\\forge-mcp")) startStdioServer({ readOnly: parseReadOnlyFlag() }).catch((error) => {
|
|
184
|
+
console.error("Fatal error:", error);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
});
|
|
187
|
+
export { parseReadOnlyFlag as n, startStdioServer as r, createStdioServer as t };
|
|
188
|
+
|
|
189
|
+
//# sourceMappingURL=src-BdwavqrN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src-BdwavqrN.js","names":[],"sources":["../src/stdio.ts","../src/index.ts"],"sourcesContent":["import { getToken, setToken } from \"@studiometa/forge-api\";\n\nimport type { ToolResult } from \"./handlers/types.ts\";\n\nimport { executeToolWithCredentials } from \"./handlers/index.ts\";\nimport { getTools, STDIO_ONLY_TOOLS } from \"./tools.ts\";\nimport type { GetToolsOptions } from \"./tools.ts\";\n\nexport type { ToolResult };\n\n/**\n * Get all available tools (including stdio-only configuration tools).\n *\n * @param options - Optional filtering. When `readOnly` is true, forge_write is excluded.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getAvailableTools(options?: GetToolsOptions): any[] {\n return [...getTools(options), ...STDIO_ONLY_TOOLS];\n}\n\n/**\n * Handle the forge_configure tool.\n */\nexport function handleConfigureTool(args: { apiToken: string }): ToolResult {\n if (!args.apiToken || typeof args.apiToken !== \"string\" || args.apiToken.trim().length === 0) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: apiToken is required and must be a non-empty string.\",\n },\n ],\n structuredContent: {\n success: false,\n error: \"apiToken is required and must be a non-empty string.\",\n },\n isError: true,\n };\n }\n\n setToken(args.apiToken);\n\n const maskedToken = `***${args.apiToken.slice(-4)}`;\n const data = {\n success: true,\n message: \"Laravel Forge API token configured successfully\",\n apiToken: maskedToken,\n };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(data, null, 2),\n },\n ],\n structuredContent: data,\n };\n}\n\n/**\n * Handle the forge_get_config tool.\n */\nexport function handleGetConfigTool(): ToolResult {\n const token = getToken();\n\n const data = {\n apiToken: token ? `***${token.slice(-4)}` : \"not configured\",\n configured: !!token,\n };\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(data, null, 2),\n },\n ],\n structuredContent: data,\n };\n}\n\n/**\n * Options for handleToolCall.\n */\nexport interface HandleToolCallOptions {\n /** When true, forge_write is rejected with an error. */\n readOnly?: boolean;\n}\n\n/**\n * Handle a tool call request.\n *\n * Routes to the appropriate handler based on tool name:\n * - forge_configure / forge_get_config — stdio-only config tools\n * - forge — read-only operations (list, get, help, schema)\n * - forge_write — write operations (create, update, delete, deploy, etc.)\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n options?: HandleToolCallOptions,\n): Promise<ToolResult> {\n if (name === \"forge_configure\") {\n return handleConfigureTool(args as { apiToken: string });\n }\n\n if (name === \"forge_get_config\") {\n return handleGetConfigTool();\n }\n\n // Reject forge_write in read-only mode\n if (name === \"forge_write\" && options?.readOnly) {\n return {\n content: [\n {\n type: \"text\",\n text: \"Error: Server is running in read-only mode. Write operations are disabled.\",\n },\n ],\n structuredContent: {\n success: false,\n error: \"Server is running in read-only mode. Write operations are disabled.\",\n },\n isError: true,\n };\n }\n\n // Both forge and forge_write require authentication\n if (name === \"forge\" || name === \"forge_write\") {\n const apiToken = getToken();\n if (!apiToken) {\n return {\n content: [\n {\n type: \"text\",\n text: 'Error: Forge API token not configured. Use \"forge_configure\" tool or set FORGE_API_TOKEN environment variable.',\n },\n ],\n structuredContent: {\n success: false,\n error:\n 'Forge API token not configured. Use \"forge_configure\" tool or set FORGE_API_TOKEN environment variable.',\n },\n isError: true,\n };\n }\n\n return executeToolWithCredentials(name, args, { apiToken });\n }\n\n return {\n content: [\n {\n type: \"text\",\n text: `Error: Unknown tool \"${name}\".`,\n },\n ],\n structuredContent: { success: false, error: `Unknown tool \"${name}\".` },\n isError: true,\n };\n}\n","#!/usr/bin/env node\n\n/**\n * Forge MCP Server — Stdio Transport\n *\n * This is the local execution mode using stdio transport.\n * For remote HTTP deployment, use server.ts instead.\n *\n * Usage:\n * npx @studiometa/forge-mcp\n * npx @studiometa/forge-mcp --read-only\n * FORGE_READ_ONLY=true npx @studiometa/forge-mcp\n *\n * Or in Claude Desktop config:\n * {\n * \"mcpServers\": {\n * \"forge\": {\n * \"command\": \"forge-mcp\",\n * \"args\": [\"--read-only\"],\n * \"env\": { \"FORGE_API_TOKEN\": \"your-token\" }\n * }\n * }\n * }\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { INSTRUCTIONS } from \"./instructions.ts\";\nimport { getAvailableTools, handleToolCall } from \"./stdio.ts\";\nimport { VERSION } from \"./version.ts\";\n\n/**\n * Options for the stdio MCP server.\n */\nexport interface StdioServerOptions {\n /** When true, forge_write tool is not registered and write operations are rejected. */\n readOnly?: boolean;\n}\n\n/**\n * Parse read-only flag from process.argv and environment.\n */\nexport function parseReadOnlyFlag(): boolean {\n return process.argv.includes(\"--read-only\") || process.env.FORGE_READ_ONLY === \"true\";\n}\n\n/**\n * Create and configure the MCP server.\n */\nexport function createStdioServer(options?: StdioServerOptions): Server {\n const readOnly = options?.readOnly ?? false;\n\n const server = new Server(\n {\n name: \"forge-mcp\",\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n instructions: INSTRUCTIONS,\n },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: getAvailableTools({ readOnly }) };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n const result = await handleToolCall(name, (args as Record<string, unknown>) ?? {}, {\n readOnly,\n });\n return result as unknown as Record<string, unknown>;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: \"text\" as const, text: `Error: ${message}` }],\n structuredContent: { success: false, error: message },\n isError: true,\n };\n }\n });\n\n return server;\n}\n\n/**\n * Start the stdio server.\n */\nexport async function startStdioServer(options?: StdioServerOptions): Promise<void> {\n const server = createStdioServer(options);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n const mode = options?.readOnly ? \" (read-only)\" : \"\";\n console.error(`Forge MCP server v${VERSION} running on stdio${mode}`);\n}\n\n// Start server when run directly\nconst isMainModule =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"/forge-mcp\") ||\n process.argv[1]?.endsWith(\"\\\\forge-mcp\");\n\nif (isMainModule) {\n const readOnly = parseReadOnlyFlag();\n startStdioServer({ readOnly }).catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ToolResult } from "./handlers/types.ts";
|
|
2
|
+
import type { GetToolsOptions } from "./tools.ts";
|
|
3
|
+
export type { ToolResult };
|
|
4
|
+
/**
|
|
5
|
+
* Get all available tools (including stdio-only configuration tools).
|
|
6
|
+
*
|
|
7
|
+
* @param options - Optional filtering. When `readOnly` is true, forge_write is excluded.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getAvailableTools(options?: GetToolsOptions): any[];
|
|
10
|
+
/**
|
|
11
|
+
* Handle the forge_configure tool.
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleConfigureTool(args: {
|
|
14
|
+
apiToken: string;
|
|
15
|
+
}): ToolResult;
|
|
16
|
+
/**
|
|
17
|
+
* Handle the forge_get_config tool.
|
|
18
|
+
*/
|
|
19
|
+
export declare function handleGetConfigTool(): ToolResult;
|
|
20
|
+
/**
|
|
21
|
+
* Options for handleToolCall.
|
|
22
|
+
*/
|
|
23
|
+
export interface HandleToolCallOptions {
|
|
24
|
+
/** When true, forge_write is rejected with an error. */
|
|
25
|
+
readOnly?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Handle a tool call request.
|
|
29
|
+
*
|
|
30
|
+
* Routes to the appropriate handler based on tool name:
|
|
31
|
+
* - forge_configure / forge_get_config — stdio-only config tools
|
|
32
|
+
* - forge — read-only operations (list, get, help, schema)
|
|
33
|
+
* - forge_write — write operations (create, update, delete, deploy, etc.)
|
|
34
|
+
*/
|
|
35
|
+
export declare function handleToolCall(name: string, args: Record<string, unknown>, options?: HandleToolCallOptions): Promise<ToolResult>;
|
|
36
|
+
//# sourceMappingURL=stdio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B;;;;GAIG;AAEH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,GAAG,EAAE,CAElE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAmC1E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAiBhD;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,UAAU,CAAC,CA2DrB"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Read-only actions — safe operations that don't modify server state.
|
|
4
|
+
*/
|
|
5
|
+
export declare const READ_ACTIONS: readonly ["list", "get", "help", "schema"];
|
|
6
|
+
/**
|
|
7
|
+
* Write actions — operations that modify server state.
|
|
8
|
+
* These are separated into the `forge_write` tool for safety.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WRITE_ACTIONS: readonly ["create", "update", "delete", "deploy", "reboot", "restart", "activate", "run"];
|
|
11
|
+
export type ReadAction = (typeof READ_ACTIONS)[number];
|
|
12
|
+
export type WriteAction = (typeof WRITE_ACTIONS)[number];
|
|
13
|
+
/**
|
|
14
|
+
* Check if an action is a write action.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isWriteAction(action: string): action is WriteAction;
|
|
17
|
+
/**
|
|
18
|
+
* Check if an action is a read action.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isReadAction(action: string): action is ReadAction;
|
|
21
|
+
/**
|
|
22
|
+
* Core tools available in both stdio and HTTP transports.
|
|
23
|
+
*
|
|
24
|
+
* Split into two tools for safety:
|
|
25
|
+
* - `forge` — read-only operations (auto-approvable by MCP clients)
|
|
26
|
+
* - `forge_write` — write operations (always requires confirmation)
|
|
27
|
+
*/
|
|
28
|
+
export declare const TOOLS: Tool[];
|
|
29
|
+
/**
|
|
30
|
+
* Options for filtering available tools.
|
|
31
|
+
*/
|
|
32
|
+
export interface GetToolsOptions {
|
|
33
|
+
/** When true, only read-only tools are returned (forge_write is excluded). */
|
|
34
|
+
readOnly?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the list of core tools, optionally filtered.
|
|
38
|
+
*
|
|
39
|
+
* In read-only mode, forge_write is excluded entirely — it won't appear
|
|
40
|
+
* in the tool listing and cannot be called.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getTools(options?: GetToolsOptions): Tool[];
|
|
43
|
+
/**
|
|
44
|
+
* Additional tools only available in stdio mode.
|
|
45
|
+
*/
|
|
46
|
+
export declare const STDIO_ONLY_TOOLS: Tool[];
|
|
47
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAI/D;;GAEG;AACH,eAAO,MAAM,YAAY,4CAA6C,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,aAAa,2FAShB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,WAAW,CAEnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,UAAU,CAEjE;AA0OD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EAAwC,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,EAAE,CAK1D;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAsDlC,CAAC"}
|