@studiometa/forge-mcp 0.0.1 → 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.
Files changed (90) hide show
  1. package/README.md +102 -0
  2. package/dist/auth.d.ts +15 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +18 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/errors.d.ts +36 -0
  7. package/dist/errors.d.ts.map +1 -0
  8. package/dist/formatters.d.ts +179 -0
  9. package/dist/formatters.d.ts.map +1 -0
  10. package/dist/handlers/backups.d.ts +2 -0
  11. package/dist/handlers/backups.d.ts.map +1 -0
  12. package/dist/handlers/certificates.d.ts +2 -0
  13. package/dist/handlers/certificates.d.ts.map +1 -0
  14. package/dist/handlers/commands.d.ts +2 -0
  15. package/dist/handlers/commands.d.ts.map +1 -0
  16. package/dist/handlers/daemons.d.ts +2 -0
  17. package/dist/handlers/daemons.d.ts.map +1 -0
  18. package/dist/handlers/database-users.d.ts +2 -0
  19. package/dist/handlers/database-users.d.ts.map +1 -0
  20. package/dist/handlers/databases.d.ts +2 -0
  21. package/dist/handlers/databases.d.ts.map +1 -0
  22. package/dist/handlers/deployments.d.ts +9 -0
  23. package/dist/handlers/deployments.d.ts.map +1 -0
  24. package/dist/handlers/env.d.ts +2 -0
  25. package/dist/handlers/env.d.ts.map +1 -0
  26. package/dist/handlers/factory.d.ts +71 -0
  27. package/dist/handlers/factory.d.ts.map +1 -0
  28. package/dist/handlers/firewall-rules.d.ts +2 -0
  29. package/dist/handlers/firewall-rules.d.ts.map +1 -0
  30. package/dist/handlers/help.d.ts +16 -0
  31. package/dist/handlers/help.d.ts.map +1 -0
  32. package/dist/handlers/index.d.ts +18 -0
  33. package/dist/handlers/index.d.ts.map +1 -0
  34. package/dist/handlers/monitors.d.ts +2 -0
  35. package/dist/handlers/monitors.d.ts.map +1 -0
  36. package/dist/handlers/nginx-config.d.ts +2 -0
  37. package/dist/handlers/nginx-config.d.ts.map +1 -0
  38. package/dist/handlers/nginx-templates.d.ts +2 -0
  39. package/dist/handlers/nginx-templates.d.ts.map +1 -0
  40. package/dist/handlers/recipes.d.ts +2 -0
  41. package/dist/handlers/recipes.d.ts.map +1 -0
  42. package/dist/handlers/redirect-rules.d.ts +2 -0
  43. package/dist/handlers/redirect-rules.d.ts.map +1 -0
  44. package/dist/handlers/scheduled-jobs.d.ts +2 -0
  45. package/dist/handlers/scheduled-jobs.d.ts.map +1 -0
  46. package/dist/handlers/schema.d.ts +16 -0
  47. package/dist/handlers/schema.d.ts.map +1 -0
  48. package/dist/handlers/security-rules.d.ts +2 -0
  49. package/dist/handlers/security-rules.d.ts.map +1 -0
  50. package/dist/handlers/servers.d.ts +2 -0
  51. package/dist/handlers/servers.d.ts.map +1 -0
  52. package/dist/handlers/sites.d.ts +2 -0
  53. package/dist/handlers/sites.d.ts.map +1 -0
  54. package/dist/handlers/ssh-keys.d.ts +2 -0
  55. package/dist/handlers/ssh-keys.d.ts.map +1 -0
  56. package/dist/handlers/types.d.ts +33 -0
  57. package/dist/handlers/types.d.ts.map +1 -0
  58. package/dist/handlers/user.d.ts +2 -0
  59. package/dist/handlers/user.d.ts.map +1 -0
  60. package/dist/handlers/utils.d.ts +26 -0
  61. package/dist/handlers/utils.d.ts.map +1 -0
  62. package/dist/hints.d.ts +60 -0
  63. package/dist/hints.d.ts.map +1 -0
  64. package/dist/http-BJUKoZdb.js +253 -0
  65. package/dist/http-BJUKoZdb.js.map +1 -0
  66. package/dist/http.d.ts +47 -0
  67. package/dist/http.d.ts.map +1 -0
  68. package/dist/http.js +3 -0
  69. package/dist/index.d.ts +30 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +127 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/instructions.d.ts +11 -0
  74. package/dist/instructions.d.ts.map +1 -0
  75. package/dist/server.d.ts +26 -0
  76. package/dist/server.d.ts.map +1 -0
  77. package/dist/server.js +67 -0
  78. package/dist/server.js.map +1 -0
  79. package/dist/sessions.d.ts +64 -0
  80. package/dist/sessions.d.ts.map +1 -0
  81. package/dist/stdio.d.ts +21 -0
  82. package/dist/stdio.d.ts.map +1 -0
  83. package/dist/tools.d.ts +22 -0
  84. package/dist/tools.d.ts.map +1 -0
  85. package/dist/version-Cw8OGt4r.js +3250 -0
  86. package/dist/version-Cw8OGt4r.js.map +1 -0
  87. package/dist/version.d.ts +2 -0
  88. package/dist/version.d.ts.map +1 -0
  89. package/package.json +53 -1
  90. package/skills/SKILL.md +189 -0
package/dist/index.js ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ import { a as INSTRUCTIONS, i as executeToolWithCredentials, n as STDIO_ONLY_TOOLS, r as TOOLS, t as VERSION } from "./version-Cw8OGt4r.js";
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import { getToken, setToken } from "@studiometa/forge-api";
7
+ /**
8
+ * Get all available tools (including stdio-only configuration tools).
9
+ */
10
+ function getAvailableTools() {
11
+ return [...TOOLS, ...STDIO_ONLY_TOOLS];
12
+ }
13
+ /**
14
+ * Handle the forge_configure tool.
15
+ */
16
+ function handleConfigureTool(args) {
17
+ if (!args.apiToken || typeof args.apiToken !== "string" || args.apiToken.trim().length === 0) return {
18
+ content: [{
19
+ type: "text",
20
+ text: "Error: apiToken is required and must be a non-empty string."
21
+ }],
22
+ isError: true
23
+ };
24
+ setToken(args.apiToken);
25
+ return { content: [{
26
+ type: "text",
27
+ text: JSON.stringify({
28
+ success: true,
29
+ message: "Laravel Forge API token configured successfully",
30
+ apiToken: `***${args.apiToken.slice(-4)}`
31
+ }, null, 2)
32
+ }] };
33
+ }
34
+ /**
35
+ * Handle the forge_get_config tool.
36
+ */
37
+ function handleGetConfigTool() {
38
+ const token = getToken();
39
+ return { content: [{
40
+ type: "text",
41
+ text: JSON.stringify({
42
+ apiToken: token ? `***${token.slice(-4)}` : "not configured",
43
+ configured: !!token
44
+ }, null, 2)
45
+ }] };
46
+ }
47
+ /**
48
+ * Handle a tool call request.
49
+ */
50
+ async function handleToolCall(name, args) {
51
+ if (name === "forge_configure") return handleConfigureTool(args);
52
+ if (name === "forge_get_config") return handleGetConfigTool();
53
+ const apiToken = getToken();
54
+ if (!apiToken) return {
55
+ content: [{
56
+ type: "text",
57
+ text: "Error: Forge API token not configured. Use \"forge_configure\" tool or set FORGE_API_TOKEN environment variable."
58
+ }],
59
+ isError: true
60
+ };
61
+ return executeToolWithCredentials(name, args, { apiToken });
62
+ }
63
+ /**
64
+ * Forge MCP Server — Stdio Transport
65
+ *
66
+ * This is the local execution mode using stdio transport.
67
+ * For remote HTTP deployment, use server.ts instead.
68
+ *
69
+ * Usage:
70
+ * npx @studiometa/forge-mcp
71
+ *
72
+ * Or in Claude Desktop config:
73
+ * {
74
+ * "mcpServers": {
75
+ * "forge": {
76
+ * "command": "forge-mcp",
77
+ * "env": { "FORGE_API_TOKEN": "your-token" }
78
+ * }
79
+ * }
80
+ * }
81
+ */
82
+ /**
83
+ * Create and configure the MCP server.
84
+ */
85
+ function createStdioServer() {
86
+ const server = new Server({
87
+ name: "forge-mcp",
88
+ version: VERSION
89
+ }, {
90
+ capabilities: { tools: {} },
91
+ instructions: INSTRUCTIONS
92
+ });
93
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
94
+ return { tools: getAvailableTools() };
95
+ });
96
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
97
+ const { name, arguments: args } = request.params;
98
+ try {
99
+ return await handleToolCall(name, args ?? {});
100
+ } catch (error) {
101
+ return {
102
+ content: [{
103
+ type: "text",
104
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
105
+ }],
106
+ isError: true
107
+ };
108
+ }
109
+ });
110
+ return server;
111
+ }
112
+ /**
113
+ * Start the stdio server.
114
+ */
115
+ async function startStdioServer() {
116
+ const server = createStdioServer();
117
+ const transport = new StdioServerTransport();
118
+ await server.connect(transport);
119
+ console.error(`Forge MCP server v${VERSION} running on stdio`);
120
+ }
121
+ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/forge-mcp") || process.argv[1]?.endsWith("\\forge-mcp")) startStdioServer().catch((error) => {
122
+ console.error("Fatal error:", error);
123
+ process.exit(1);
124
+ });
125
+ export { createStdioServer, startStdioServer };
126
+
127
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.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 { STDIO_ONLY_TOOLS, TOOLS } from \"./tools.ts\";\n\nexport type { ToolResult };\n\n/**\n * Get all available tools (including stdio-only configuration tools).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getAvailableTools(): any[] {\n return [...TOOLS, ...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 isError: true,\n };\n }\n\n setToken(args.apiToken);\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n success: true,\n message: \"Laravel Forge API token configured successfully\",\n apiToken: `***${args.apiToken.slice(-4)}`,\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle the forge_get_config tool.\n */\nexport function handleGetConfigTool(): ToolResult {\n const token = getToken();\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n apiToken: token ? `***${token.slice(-4)}` : \"not configured\",\n configured: !!token,\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle a tool call request.\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\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 // Get API token\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 isError: true,\n };\n }\n\n return executeToolWithCredentials(name, args, { apiToken });\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 *\n * Or in Claude Desktop config:\n * {\n * \"mcpServers\": {\n * \"forge\": {\n * \"command\": \"forge-mcp\",\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 * Create and configure the MCP server.\n */\nexport function createStdioServer(): Server {\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() };\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 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 isError: true,\n };\n }\n });\n\n return server;\n}\n\n/**\n * Start the stdio server.\n */\nexport async function startStdioServer(): Promise<void> {\n const server = createStdioServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error(`Forge MCP server v${VERSION} running on stdio`);\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 startStdioServer().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,oBAA2B;AACzC,QAAO,CAAC,GAAG,OAAO,GAAG,iBAAiB;;;;;AAMxC,SAAgB,oBAAoB,MAAwC;AAC1E,KAAI,CAAC,KAAK,YAAY,OAAO,KAAK,aAAa,YAAY,KAAK,SAAS,MAAM,CAAC,WAAW,EACzF,QAAO;EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACP,CACF;EACD,SAAS;EACV;AAGH,UAAS,KAAK,SAAS;AAEvB,QAAO,EACL,SAAS,CACP;EACE,MAAM;EACN,MAAM,KAAK,UACT;GACE,SAAS;GACT,SAAS;GACT,UAAU,MAAM,KAAK,SAAS,MAAM,GAAG;GACxC,EACD,MACA,EACD;EACF,CACF,EACF;;;;;AAMH,SAAgB,sBAAkC;CAChD,MAAM,QAAQ,UAAU;AAExB,QAAO,EACL,SAAS,CACP;EACE,MAAM;EACN,MAAM,KAAK,UACT;GACE,UAAU,QAAQ,MAAM,MAAM,MAAM,GAAG,KAAK;GAC5C,YAAY,CAAC,CAAC;GACf,EACD,MACA,EACD;EACF,CACF,EACF;;;;;AAMH,eAAsB,eACpB,MACA,MACqB;AACrB,KAAI,SAAS,kBACX,QAAO,oBAAoB,KAA6B;AAG1D,KAAI,SAAS,mBACX,QAAO,qBAAqB;CAI9B,MAAM,WAAW,UAAU;AAC3B,KAAI,CAAC,SACH,QAAO;EACL,SAAS,CACP;GACE,MAAM;GACN,MAAM;GACP,CACF;EACD,SAAS;EACV;AAGH,QAAO,2BAA2B,MAAM,MAAM,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;ACxE7D,SAAgB,oBAA4B;CAC1C,MAAM,SAAS,IAAI,OACjB;EACE,MAAM;EACN,SAAS;EACV,EACD;EACE,cAAc,EACZ,OAAO,EAAE,EACV;EACD,cAAc;EACf,CACF;AAED,QAAO,kBAAkB,wBAAwB,YAAY;AAC3D,SAAO,EAAE,OAAO,mBAAmB,EAAE;GACrC;AAEF,QAAO,kBAAkB,uBAAuB,OAAO,YAAY;EACjE,MAAM,EAAE,MAAM,WAAW,SAAS,QAAQ;AAE1C,MAAI;AAEF,UADe,MAAM,eAAe,MAAO,QAAoC,EAAE,CAAC;WAE3E,OAAO;AAEd,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAiB,MAAM,UAF3B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;KAEN,CAAC;IAC/D,SAAS;IACV;;GAEH;AAEF,QAAO;;;;;AAMT,eAAsB,mBAAkC;CACtD,MAAM,SAAS,mBAAmB;CAClC,MAAM,YAAY,IAAI,sBAAsB;AAC5C,OAAM,OAAO,QAAQ,UAAU;AAC/B,SAAQ,MAAM,qBAAqB,QAAQ,mBAAmB;;AAShE,IAJE,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,QAC3C,QAAQ,KAAK,IAAI,SAAS,aAAa,IACvC,QAAQ,KAAK,IAAI,SAAS,cAAc,CAGxC,mBAAkB,CAAC,OAAO,UAAU;AAClC,SAAQ,MAAM,gBAAgB,MAAM;AACpC,SAAQ,KAAK,EAAE;EACf"}
@@ -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"}
@@ -0,0 +1,26 @@
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
+ * PORT=3000 forge-mcp-server
13
+ *
14
+ * Endpoints:
15
+ * POST /mcp - MCP Streamable HTTP (JSON-RPC messages)
16
+ * GET /mcp - MCP Streamable HTTP (SSE stream for server notifications)
17
+ * DELETE /mcp - MCP Streamable HTTP (session termination)
18
+ * GET / - Service info
19
+ * GET /health - Health check
20
+ */
21
+ import { type Server } from "node:http";
22
+ /**
23
+ * Start the HTTP server with Streamable HTTP transport.
24
+ */
25
+ export declare function startHttpServer(port?: number, host?: string): Promise<Server>;
26
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAStD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,GAAE,MAAqB,EAC3B,IAAI,GAAE,MAAqB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAwCjB"}
package/dist/server.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { t as VERSION } from "./version-Cw8OGt4r.js";
3
+ import { a as SessionManager, n as createMcpRequestHandler, t as createHealthApp } from "./http-BJUKoZdb.js";
4
+ import { toNodeHandler } from "h3/node";
5
+ import { createServer } from "node:http";
6
+ /**
7
+ * Forge MCP Server - HTTP Transport (Streamable HTTP)
8
+ *
9
+ * Implements the official MCP Streamable HTTP transport specification.
10
+ * Credentials are passed via Bearer token in the Authorization header.
11
+ *
12
+ * Token format: raw Forge API token
13
+ *
14
+ * Usage:
15
+ * forge-mcp-server
16
+ * PORT=3000 forge-mcp-server
17
+ *
18
+ * Endpoints:
19
+ * POST /mcp - MCP Streamable HTTP (JSON-RPC messages)
20
+ * GET /mcp - MCP Streamable HTTP (SSE stream for server notifications)
21
+ * DELETE /mcp - MCP Streamable HTTP (session termination)
22
+ * GET / - Service info
23
+ * GET /health - Health check
24
+ */
25
+ var DEFAULT_PORT = 3e3;
26
+ var DEFAULT_HOST = "0.0.0.0";
27
+ /**
28
+ * Start the HTTP server with Streamable HTTP transport.
29
+ */
30
+ function startHttpServer(port = DEFAULT_PORT, host = DEFAULT_HOST) {
31
+ return new Promise((resolve) => {
32
+ const handleMcp = createMcpRequestHandler(new SessionManager());
33
+ const healthHandler = toNodeHandler(createHealthApp());
34
+ const server = createServer(async (req, res) => {
35
+ const url = req.url ?? "/";
36
+ if (url === "/mcp" || url.startsWith("/mcp?")) {
37
+ await handleMcp(req, res);
38
+ return;
39
+ }
40
+ healthHandler(req, res);
41
+ });
42
+ server.listen(port, host, () => {
43
+ const displayHost = host === "0.0.0.0" ? "localhost" : host;
44
+ console.log(`Forge MCP server v${VERSION}`);
45
+ console.log(`Node.js ${process.version}`);
46
+ console.log("");
47
+ console.log(`Running at http://${displayHost}:${port}`);
48
+ console.log("");
49
+ console.log("Endpoints:");
50
+ console.log(` POST/GET/DELETE http://${displayHost}:${port}/mcp - MCP Streamable HTTP endpoint`);
51
+ console.log(` GET http://${displayHost}:${port}/health - Health check`);
52
+ console.log("");
53
+ console.log("Authentication:");
54
+ console.log(" Bearer token in Authorization header");
55
+ console.log(" Token format: your raw Forge API token");
56
+ console.log("");
57
+ resolve(server);
58
+ });
59
+ });
60
+ }
61
+ 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).catch((error) => {
62
+ console.error("Fatal error:", error);
63
+ process.exit(1);
64
+ });
65
+ export { startHttpServer };
66
+
67
+ //# 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 * 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 { SessionManager } from \"./sessions.ts\";\nimport { VERSION } from \"./version.ts\";\n\nconst DEFAULT_PORT = 3000;\nconst DEFAULT_HOST = \"0.0.0.0\";\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): Promise<Server> {\n return new Promise((resolve) => {\n const sessions = new SessionManager();\n const handleMcp = createMcpRequestHandler(sessions);\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 console.log(`Forge MCP server v${VERSION}`);\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 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\n startHttpServer(port, host).catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAM,eAAe;AACrB,IAAM,eAAe;;;;AAKrB,SAAgB,gBACd,OAAe,cACf,OAAe,cACE;AACjB,QAAO,IAAI,SAAS,YAAY;EAE9B,MAAM,YAAY,wBADD,IAAI,gBAAgB,CACc;EAEnD,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;AACvD,WAAQ,IAAI,qBAAqB,UAAU;AAC3C,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,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,CAM/C,iBAHa,OAAO,SAAS,QAAQ,IAAI,QAAQ,OAAO,aAAa,EAAE,GAAG,EAC7D,QAAQ,IAAI,QAAQ,aAEN,CAAC,OAAO,UAAU;AAC3C,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,21 @@
1
+ import type { ToolResult } from "./handlers/types.ts";
2
+ export type { ToolResult };
3
+ /**
4
+ * Get all available tools (including stdio-only configuration tools).
5
+ */
6
+ export declare function getAvailableTools(): any[];
7
+ /**
8
+ * Handle the forge_configure tool.
9
+ */
10
+ export declare function handleConfigureTool(args: {
11
+ apiToken: string;
12
+ }): ToolResult;
13
+ /**
14
+ * Handle the forge_get_config tool.
15
+ */
16
+ export declare function handleGetConfigTool(): ToolResult;
17
+ /**
18
+ * Handle a tool call request.
19
+ */
20
+ export declare function handleToolCall(name: string, args: Record<string, unknown>): Promise<ToolResult>;
21
+ //# 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;AAKtD,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B;;GAEG;AAEH,wBAAgB,iBAAiB,IAAI,GAAG,EAAE,CAEzC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CA+B1E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAkBhD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,CAwBrB"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Tool type matching MCP SDK expectations.
3
+ */
4
+ interface Tool {
5
+ name: string;
6
+ description: string;
7
+ annotations?: Record<string, unknown>;
8
+ inputSchema: Record<string, unknown>;
9
+ }
10
+ /**
11
+ * Single consolidated tool for Laravel Forge MCP server.
12
+ *
13
+ * The resource/action enums and description are derived from
14
+ * the shared constants in forge-core — the single source of truth.
15
+ */
16
+ export declare const TOOLS: Tool[];
17
+ /**
18
+ * Additional tools only available in stdio mode.
19
+ */
20
+ export declare const STDIO_ONLY_TOOLS: Tool[];
21
+ export {};
22
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,UAAU,IAAI;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAgBD;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EA2EvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAkClC,CAAC"}