@studiometa/forge-mcp 0.2.0 → 0.2.2
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/dist/flags-LFbdErsZ.js +23 -0
- package/dist/flags-LFbdErsZ.js.map +1 -0
- package/dist/flags.d.ts +19 -0
- package/dist/flags.d.ts.map +1 -0
- package/dist/{http-CfjqK_e4.js → http-BMOiJdyw.js} +2 -2
- package/dist/{http-CfjqK_e4.js.map → http-BMOiJdyw.js.map} +1 -1
- package/dist/http.js +2 -2
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +183 -2
- package/dist/index.js.map +1 -0
- package/dist/server.js +3 -3
- package/dist/server.js.map +1 -1
- package/dist/{version-DaD5zvGh.js → version-D3OFS3DQ.js} +2 -2
- package/dist/{version-DaD5zvGh.js.map → version-D3OFS3DQ.js.map} +1 -1
- package/package.json +2 -2
- package/dist/src-BdwavqrN.js +0 -189
- package/dist/src-BdwavqrN.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studiometa/forge-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "MCP server for Laravel Forge — Model Context Protocol integration for AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"dev": "vite build --watch",
|
|
54
|
-
"build": "vite build && tsc --emitDeclarationOnly",
|
|
54
|
+
"build": "vite build && tsc --emitDeclarationOnly && node scripts/postbuild.js",
|
|
55
55
|
"test": "vitest run",
|
|
56
56
|
"test:watch": "vitest",
|
|
57
57
|
"test:ci": "vitest run --coverage",
|
package/dist/src-BdwavqrN.js
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
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
|
package/dist/src-BdwavqrN.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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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"}
|