@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.
Files changed (91) hide show
  1. package/README.md +152 -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 +187 -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 +20 -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 +38 -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 +29 -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-CfjqK_e4.js +277 -0
  65. package/dist/http-CfjqK_e4.js.map +1 -0
  66. package/dist/http.d.ts +55 -0
  67. package/dist/http.d.ts.map +1 -0
  68. package/dist/http.js +3 -0
  69. package/dist/index.d.ts +44 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +4 -0
  72. package/dist/instructions.d.ts +11 -0
  73. package/dist/instructions.d.ts.map +1 -0
  74. package/dist/server.d.ts +35 -0
  75. package/dist/server.d.ts.map +1 -0
  76. package/dist/server.js +76 -0
  77. package/dist/server.js.map +1 -0
  78. package/dist/sessions.d.ts +64 -0
  79. package/dist/sessions.d.ts.map +1 -0
  80. package/dist/src-BdwavqrN.js +189 -0
  81. package/dist/src-BdwavqrN.js.map +1 -0
  82. package/dist/stdio.d.ts +36 -0
  83. package/dist/stdio.d.ts.map +1 -0
  84. package/dist/tools.d.ts +47 -0
  85. package/dist/tools.d.ts.map +1 -0
  86. package/dist/version-DaD5zvGh.js +3470 -0
  87. package/dist/version-DaD5zvGh.js.map +1 -0
  88. package/dist/version.d.ts +2 -0
  89. package/dist/version.d.ts.map +1 -0
  90. package/package.json +53 -1
  91. package/skills/SKILL.md +219 -0
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # @studiometa/forge-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@studiometa/forge-mcp?style=flat&colorB=3e63dd&colorA=414853)](https://www.npmjs.com/package/@studiometa/forge-mcp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat&colorB=3e63dd&colorA=414853)](https://opensource.org/licenses/MIT)
5
+
6
+ MCP (Model Context Protocol) server for [Laravel Forge](https://forge.laravel.com). Enables Claude Desktop and other MCP clients to manage servers, sites, deployments, and more through natural language.
7
+
8
+ ## Features
9
+
10
+ - **Two tools with clear safety split** — `forge` (read) and `forge_write` (write)
11
+ - MCP clients auto-approve `forge` reads, always prompt for `forge_write` writes
12
+ - Resource/action routing from centralized constants
13
+ - Built-in help system — `action=help` for any resource
14
+ - Stdio and Streamable HTTP transports
15
+ - Configuration tools for interactive token setup
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g @studiometa/forge-mcp
21
+ ```
22
+
23
+ ## Claude Desktop Configuration
24
+
25
+ Add to your Claude Desktop config:
26
+
27
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
28
+ - **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
29
+ - **Linux**: `~/.config/Claude/claude_desktop_config.json`
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "forge": {
35
+ "command": "forge-mcp",
36
+ "env": {
37
+ "FORGE_API_TOKEN": "your-api-token"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ Alternatively, omit the `env` block and ask Claude to configure credentials using the `forge_configure` tool.
45
+
46
+ ### Read-Only Mode
47
+
48
+ To guarantee no write operations are possible at the server level:
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "forge": {
54
+ "command": "forge-mcp",
55
+ "args": ["--read-only"],
56
+ "env": {
57
+ "FORGE_API_TOKEN": "your-api-token"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ Or via environment variable: `FORGE_READ_ONLY=true`.
65
+
66
+ When enabled, the `forge_write` tool is not registered at all — only `forge`, `forge_configure`, and `forge_get_config` are available.
67
+
68
+ ## Tools
69
+
70
+ ### `forge` — Read Operations
71
+
72
+ Safe, read-only queries. Annotated `readOnlyHint: true` so MCP clients can auto-approve.
73
+
74
+ **Actions**: `list`, `get`, `help`, `schema`
75
+
76
+ ```json
77
+ { "resource": "servers", "action": "list" }
78
+ { "resource": "servers", "action": "get", "id": "123" }
79
+ { "resource": "sites", "action": "list", "server_id": "123" }
80
+ { "resource": "servers", "action": "help" }
81
+ ```
82
+
83
+ ### `forge_write` — Write Operations
84
+
85
+ Mutating operations. Annotated `destructiveHint: true` so MCP clients always prompt for confirmation.
86
+
87
+ **Actions**: `create`, `update`, `delete`, `deploy`, `reboot`, `restart`, `activate`, `run`
88
+
89
+ ```json
90
+ { "resource": "deployments", "action": "deploy", "server_id": "123", "site_id": "456" }
91
+ // deploy blocks until complete, returning: status, deployment log, elapsed time
92
+ { "resource": "servers", "action": "reboot", "id": "123" }
93
+ { "resource": "daemons", "action": "create", "server_id": "123", "command": "php artisan queue:work" }
94
+ ```
95
+
96
+ ### Resources & Actions
97
+
98
+ | Resource | Read Actions | Write Actions | Required Fields |
99
+ | --------------- | ------------ | ------------------------ | -------------------------- |
100
+ | servers | list, get | create, delete, reboot | id (for get/delete/reboot) |
101
+ | sites | list, get | create, delete | server_id |
102
+ | deployments | list | deploy, update | server_id, site_id |
103
+ | env | get | update | server_id, site_id |
104
+ | nginx | get | update | server_id, site_id |
105
+ | certificates | list, get | create, delete, activate | server_id, site_id |
106
+ | databases | list, get | create, delete | server_id |
107
+ | daemons | list, get | create, delete, restart | server_id |
108
+ | firewall-rules | list, get | create, delete | server_id |
109
+ | ssh-keys | list, get | create, delete | server_id |
110
+ | security-rules | list, get | create, delete | server_id, site_id |
111
+ | redirect-rules | list, get | create, delete | server_id, site_id |
112
+ | monitors | list, get | create, delete | server_id |
113
+ | nginx-templates | list, get | create, update, delete | server_id |
114
+ | recipes | list, get | create, delete, run | id (for get/delete/run) |
115
+
116
+ ### Discovery
117
+
118
+ Use `action: "help"` with any resource:
119
+
120
+ ```json
121
+ { "resource": "servers", "action": "help" }
122
+ { "resource": "deployments", "action": "help" }
123
+ ```
124
+
125
+ ## Stdio-Only Tools
126
+
127
+ | Tool | Description |
128
+ | ------------------ | ---------------------------------- |
129
+ | `forge_configure` | Save API token to local config |
130
+ | `forge_get_config` | Show current config (token masked) |
131
+
132
+ ## Audit Logging
133
+
134
+ All write operations (`forge_write` tool calls) are automatically logged for traceability:
135
+
136
+ - **Default path**: `~/.config/forge-tools/audit.log`
137
+ - **Override**: Set `FORGE_AUDIT_LOG` environment variable
138
+ - **Format**: JSON lines (via pino) with timestamp, resource, action, sanitized args, and status
139
+ - **Safety**: Logging never interrupts operations — silent on failure
140
+
141
+ The CLI also logs write commands to the same audit log.
142
+
143
+ ## Getting Your API Token
144
+
145
+ 1. Log into [Laravel Forge](https://forge.laravel.com)
146
+ 2. Go to **Account → API Tokens**
147
+ 3. Create a new token with the scopes you need
148
+ 4. Copy the token (it's only shown once)
149
+
150
+ ## License
151
+
152
+ MIT © [Studio Meta](https://www.studiometa.fr)
package/dist/auth.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Authentication utilities for Forge MCP HTTP server
3
+ */
4
+ export interface ForgeCredentials {
5
+ apiToken: string;
6
+ }
7
+ /**
8
+ * Parse Bearer token containing Forge API credentials.
9
+ * Token format: raw Forge API token (no base64 encoding needed).
10
+ *
11
+ * @param authHeader - Authorization header value (e.g., "Bearer <token>")
12
+ * @returns Parsed credentials or null if invalid
13
+ */
14
+ export declare function parseAuthHeader(authHeader: string | undefined | null): ForgeCredentials | null;
15
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,gBAAgB,GAAG,IAAI,CAiB9F"}
package/dist/auth.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Parse Bearer token containing Forge API credentials.
3
+ * Token format: raw Forge API token (no base64 encoding needed).
4
+ *
5
+ * @param authHeader - Authorization header value (e.g., "Bearer <token>")
6
+ * @returns Parsed credentials or null if invalid
7
+ */
8
+ function parseAuthHeader(authHeader) {
9
+ if (!authHeader) return null;
10
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
11
+ if (!match) return null;
12
+ const token = match[1].trim();
13
+ if (!token) return null;
14
+ return { apiToken: token };
15
+ }
16
+ export { parseAuthHeader };
17
+
18
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["/**\n * Authentication utilities for Forge MCP HTTP server\n */\n\nexport interface ForgeCredentials {\n apiToken: string;\n}\n\n/**\n * Parse Bearer token containing Forge API credentials.\n * Token format: raw Forge API token (no base64 encoding needed).\n *\n * @param authHeader - Authorization header value (e.g., \"Bearer <token>\")\n * @returns Parsed credentials or null if invalid\n */\nexport function parseAuthHeader(authHeader: string | undefined | null): ForgeCredentials | null {\n if (!authHeader) {\n return null;\n }\n\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n if (!match) {\n return null;\n }\n\n const token = match[1].trim();\n\n if (!token) {\n return null;\n }\n\n return { apiToken: token };\n}\n"],"mappings":";;;;;;;AAeA,SAAgB,gBAAgB,YAAgE;AAC9F,KAAI,CAAC,WACH,QAAO;CAGT,MAAM,QAAQ,WAAW,MAAM,mBAAmB;AAClD,KAAI,CAAC,MACH,QAAO;CAGT,MAAM,QAAQ,MAAM,GAAG,MAAM;AAE7B,KAAI,CAAC,MACH,QAAO;AAGT,QAAO,EAAE,UAAU,OAAO"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Custom error classes for MCP server
3
+ *
4
+ * These provide structured error handling with LLM-friendly messages
5
+ * that include guidance on how to resolve issues.
6
+ */
7
+ /**
8
+ * Error thrown when user input validation fails.
9
+ * These errors should be returned to the user directly.
10
+ *
11
+ * Includes optional hints for how to resolve the issue.
12
+ */
13
+ export declare class UserInputError extends Error {
14
+ readonly hints?: string[];
15
+ constructor(message: string, hints?: string[]);
16
+ /**
17
+ * Format error message with hints for LLM consumption
18
+ */
19
+ toFormattedMessage(): string;
20
+ }
21
+ /**
22
+ * Error messages with guidance for common validation failures
23
+ */
24
+ export declare const ErrorMessages: {
25
+ readonly missingId: (action: string) => UserInputError;
26
+ readonly missingRequiredFields: (resource: string, fields: string[]) => UserInputError;
27
+ readonly invalidAction: (action: string, resource: string, validActions: string[]) => UserInputError;
28
+ readonly unknownResource: (resource: string, validResources: string[]) => UserInputError;
29
+ readonly noUpdateFieldsSpecified: (allowedFields: string[]) => UserInputError;
30
+ readonly apiError: (statusCode: number, message: string) => UserInputError;
31
+ };
32
+ /**
33
+ * Check if an error is a UserInputError
34
+ */
35
+ export declare function isUserInputError(error: unknown): error is UserInputError;
36
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE;IAM7C;;OAEG;IACH,kBAAkB,IAAI,MAAM;CAO7B;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;iCAEJ,MAAM;+CAMQ,MAAM,UAAU,MAAM,EAAE;qCAUlC,MAAM,YAAY,MAAM,gBAAgB,MAAM,EAAE;yCAO5C,MAAM,kBAAkB,MAAM,EAAE;sDAOnB,MAAM,EAAE;oCAO1B,MAAM,WAAW,MAAM;CAsBtC,CAAC;AAEX;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Response formatters for MCP tool output.
3
+ *
4
+ * This module contains per-resource formatter functions that convert
5
+ * executor data payloads into human-readable text for MCP responses.
6
+ *
7
+ * Keeping formatting in the MCP layer ensures executors remain pure data
8
+ * functions that can be reused by any adapter (CLI, SDK, etc.).
9
+ */
10
+ import type { ForgeBackupConfig, ForgeCertificate, ForgeCommand, ForgeDaemon, ForgeDatabase, ForgeDatabaseUser, ForgeDeployment, ForgeFirewallRule, ForgeMonitor, ForgeNginxTemplate, ForgeRecipe, ForgeRedirectRule, ForgeScheduledJob, ForgeSecurityRule, ForgeServer, ForgeSite, ForgeSshKey, ForgeUser } from "@studiometa/forge-api";
11
+ /**
12
+ * Format a list of servers.
13
+ */
14
+ export declare function formatServerList(servers: ForgeServer[]): string;
15
+ /**
16
+ * Format a single server.
17
+ */
18
+ export declare function formatServer(server: ForgeServer): string;
19
+ /**
20
+ * Format a list of sites.
21
+ */
22
+ export declare function formatSiteList(sites: ForgeSite[], serverId?: string): string;
23
+ /**
24
+ * Format a single site.
25
+ */
26
+ export declare function formatSite(site: ForgeSite): string;
27
+ /**
28
+ * Format a list of databases.
29
+ */
30
+ export declare function formatDatabaseList(databases: ForgeDatabase[]): string;
31
+ /**
32
+ * Format a single database.
33
+ */
34
+ export declare function formatDatabase(db: ForgeDatabase): string;
35
+ /**
36
+ * Format a list of database users.
37
+ */
38
+ export declare function formatDatabaseUserList(users: ForgeDatabaseUser[]): string;
39
+ /**
40
+ * Format a single database user.
41
+ */
42
+ export declare function formatDatabaseUser(user: ForgeDatabaseUser): string;
43
+ /**
44
+ * Format a list of deployments.
45
+ */
46
+ export declare function formatDeploymentList(deployments: ForgeDeployment[]): string;
47
+ /**
48
+ * Format a deployment action result.
49
+ *
50
+ * When a `DeployResult` is provided the output includes status, elapsed time,
51
+ * and the deployment log. When called with just IDs (legacy) it falls back to
52
+ * the simple confirmation message so existing tests keep passing.
53
+ */
54
+ export declare function formatDeployAction(siteId: string, serverId: string, result?: {
55
+ status: "success" | "failed";
56
+ log: string;
57
+ elapsed_ms: number;
58
+ }): string;
59
+ /**
60
+ * Format deployment script content.
61
+ */
62
+ export declare function formatDeploymentScript(script: string): string;
63
+ /**
64
+ * Format deployment output.
65
+ */
66
+ export declare function formatDeploymentOutput(deploymentId: string, output: string): string;
67
+ /**
68
+ * Format a deployment script update confirmation.
69
+ */
70
+ export declare function formatDeploymentScriptUpdated(siteId: string, serverId: string): string;
71
+ /**
72
+ * Format a list of certificates.
73
+ */
74
+ export declare function formatCertificateList(certificates: ForgeCertificate[]): string;
75
+ /**
76
+ * Format a single certificate.
77
+ */
78
+ export declare function formatCertificate(cert: ForgeCertificate): string;
79
+ /**
80
+ * Format a list of daemons.
81
+ */
82
+ export declare function formatDaemonList(daemons: ForgeDaemon[]): string;
83
+ /**
84
+ * Format a single daemon.
85
+ */
86
+ export declare function formatDaemon(daemon: ForgeDaemon): string;
87
+ /**
88
+ * Format a list of firewall rules.
89
+ */
90
+ export declare function formatFirewallRuleList(rules: ForgeFirewallRule[]): string;
91
+ /**
92
+ * Format a single firewall rule.
93
+ */
94
+ export declare function formatFirewallRule(rule: ForgeFirewallRule): string;
95
+ /**
96
+ * Format a list of monitors.
97
+ */
98
+ export declare function formatMonitorList(monitors: ForgeMonitor[]): string;
99
+ /**
100
+ * Format a single monitor.
101
+ */
102
+ export declare function formatMonitor(monitor: ForgeMonitor): string;
103
+ /**
104
+ * Format a list of SSH keys.
105
+ */
106
+ export declare function formatSshKeyList(keys: ForgeSshKey[]): string;
107
+ /**
108
+ * Format a single SSH key.
109
+ */
110
+ export declare function formatSshKey(key: ForgeSshKey): string;
111
+ /**
112
+ * Format a list of scheduled jobs.
113
+ */
114
+ export declare function formatScheduledJobList(jobs: ForgeScheduledJob[]): string;
115
+ /**
116
+ * Format a single scheduled job.
117
+ */
118
+ export declare function formatScheduledJob(job: ForgeScheduledJob): string;
119
+ /**
120
+ * Format a list of security rules.
121
+ */
122
+ export declare function formatSecurityRuleList(rules: ForgeSecurityRule[]): string;
123
+ /**
124
+ * Format a single security rule.
125
+ */
126
+ export declare function formatSecurityRule(rule: ForgeSecurityRule): string;
127
+ /**
128
+ * Format a list of redirect rules.
129
+ */
130
+ export declare function formatRedirectRuleList(rules: ForgeRedirectRule[]): string;
131
+ /**
132
+ * Format a single redirect rule.
133
+ */
134
+ export declare function formatRedirectRule(rule: ForgeRedirectRule): string;
135
+ /**
136
+ * Format nginx configuration content.
137
+ */
138
+ export declare function formatNginxConfig(content: string): string;
139
+ /**
140
+ * Format a list of nginx templates.
141
+ */
142
+ export declare function formatNginxTemplateList(templates: ForgeNginxTemplate[]): string;
143
+ /**
144
+ * Format a single nginx template.
145
+ */
146
+ export declare function formatNginxTemplate(template: ForgeNginxTemplate): string;
147
+ /**
148
+ * Format a list of backup configurations.
149
+ */
150
+ export declare function formatBackupConfigList(backups: ForgeBackupConfig[]): string;
151
+ /**
152
+ * Format a single backup configuration.
153
+ */
154
+ export declare function formatBackupConfig(backup: ForgeBackupConfig): string;
155
+ /**
156
+ * Format a list of recipes.
157
+ */
158
+ export declare function formatRecipeList(recipes: ForgeRecipe[]): string;
159
+ /**
160
+ * Format a single recipe.
161
+ */
162
+ export declare function formatRecipe(recipe: ForgeRecipe): string;
163
+ /**
164
+ * Format a list of commands.
165
+ */
166
+ export declare function formatCommandList(commands: ForgeCommand[]): string;
167
+ /**
168
+ * Format a single command.
169
+ */
170
+ export declare function formatCommand(command: ForgeCommand): string;
171
+ /**
172
+ * Format environment variables content.
173
+ */
174
+ export declare function formatEnv(content: string): string;
175
+ /**
176
+ * Format the authenticated user.
177
+ */
178
+ export declare function formatUser(user: ForgeUser): string;
179
+ /**
180
+ * Format a deleted resource confirmation.
181
+ */
182
+ export declare function formatDeleted(resource: string, id: string): string;
183
+ /**
184
+ * Format a created resource confirmation (for simple cases).
185
+ */
186
+ export declare function formatCreated(resource: string, name: string, id: number | string): string;
187
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const handleBackups: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=backups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backups.d.ts","sourceRoot":"","sources":["../../src/handlers/backups.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,aAAa,+IA8BxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleCertificates: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=certificates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificates.d.ts","sourceRoot":"","sources":["../../src/handlers/certificates.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,+IAsC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleCommands: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/handlers/commands.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc,+IA0BzB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleDaemons: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=daemons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemons.d.ts","sourceRoot":"","sources":["../../src/handlers/daemons.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,aAAa,+IAsCxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleDatabaseUsers: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=database-users.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-users.d.ts","sourceRoot":"","sources":["../../src/handlers/database-users.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,mBAAmB,+IAkC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleDatabases: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=databases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"databases.d.ts","sourceRoot":"","sources":["../../src/handlers/databases.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,eAAe,+IAkC1B,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { CommonArgs, HandlerContext, ToolResult } from "./types.ts";
2
+ /**
3
+ * Handle deployment resource actions.
4
+ *
5
+ * Not using the factory because the `get` action has special logic
6
+ * (with id → output, without id → script).
7
+ */
8
+ export declare function handleDeployments(action: string, args: CommonArgs, ctx: HandlerContext): Promise<ToolResult>;
9
+ //# sourceMappingURL=deployments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployments.d.ts","sourceRoot":"","sources":["../../src/handlers/deployments.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIzE;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,UAAU,CAAC,CAyDrB"}
@@ -0,0 +1,2 @@
1
+ export declare const handleEnv: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/handlers/env.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,SAAS,+IA2BpB,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Factory for creating Forge resource handlers.
3
+ *
4
+ * Encapsulates the repetitive list/get/create/update/delete pattern
5
+ * shared by all MCP resource handlers.
6
+ */
7
+ import type { ExecutorContext, ExecutorResult } from "@studiometa/forge-core";
8
+ import type { ContextualHints } from "../hints.ts";
9
+ import type { CommonArgs, HandlerContext, ToolResult } from "./types.ts";
10
+ /**
11
+ * Configuration for a resource handler.
12
+ */
13
+ export interface ResourceHandlerConfig {
14
+ /** Resource name for error messages */
15
+ resource: string;
16
+ /** Valid actions for this resource */
17
+ actions: string[];
18
+ /** Fields required per action (in addition to defaults) */
19
+ requiredFields?: Record<string, string[]>;
20
+ /** Executor functions keyed by action name */
21
+ executors: Record<string, (options: any, ctx: ExecutorContext) => Promise<ExecutorResult<unknown>>>;
22
+ /**
23
+ * Generate contextual hints for the get action response.
24
+ *
25
+ * Called with the executor result data and the resource id.
26
+ * Only injected when `ctx.includeHints` is true.
27
+ */
28
+ hints?: (data: unknown, id: string) => ContextualHints;
29
+ /** Map tool args to executor options. Defaults to pass-through. */
30
+ mapOptions?: (action: string, args: CommonArgs) => Record<string, unknown>;
31
+ /**
32
+ * Format the executor result data into human-readable text for MCP output.
33
+ *
34
+ * Called with the executor result data and the tool args when compact mode
35
+ * is enabled. If not provided, the data is JSON-serialized.
36
+ */
37
+ formatResult?: (action: string, data: any, args: CommonArgs) => string;
38
+ }
39
+ /**
40
+ * Create a resource handler from configuration.
41
+ *
42
+ * Returns a function that routes actions to the correct executor,
43
+ * validates required fields, and formats results.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * export const handleDatabases = createResourceHandler({
48
+ * resource: 'databases',
49
+ * actions: ['list', 'get', 'create', 'delete'],
50
+ * requiredFields: {
51
+ * list: ['server_id'],
52
+ * get: ['server_id', 'id'],
53
+ * create: ['server_id', 'name'],
54
+ * delete: ['server_id', 'id'],
55
+ * },
56
+ * executors: {
57
+ * list: listDatabases,
58
+ * get: getDatabase,
59
+ * create: createDatabase,
60
+ * delete: deleteDatabase,
61
+ * },
62
+ * formatResult: (action, data) => {
63
+ * if (action === 'list') return formatDatabaseList(data);
64
+ * if (action === 'get') return formatDatabase(data);
65
+ * return 'Done.';
66
+ * },
67
+ * });
68
+ * ```
69
+ */
70
+ export declare function createResourceHandler(config: ResourceHandlerConfig): (action: string, args: CommonArgs, ctx: HandlerContext) => Promise<ToolResult>;
71
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/handlers/factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIzE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IAEjB,sCAAsC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1C,8CAA8C;IAE9C,SAAS,EAAE,MAAM,CACf,MAAM,EAEN,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CACzE,CAAC;IAEF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,eAAe,CAAC;IAEvD,mEAAmE;IACnE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3E;;;;;OAKG;IAEH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;CACxE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC5B,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,UAAU,CAAC,CA8EhF"}
@@ -0,0 +1,2 @@
1
+ export declare const handleFirewallRules: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=firewall-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firewall-rules.d.ts","sourceRoot":"","sources":["../../src/handlers/firewall-rules.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,mBAAmB,+IAkC9B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Help handler — provides detailed documentation for each resource.
3
+ *
4
+ * Follows the productive-tools convention: per-resource docs with
5
+ * actions, required fields, field descriptions, and examples.
6
+ */
7
+ import type { ToolResult } from "./types.ts";
8
+ /**
9
+ * Handle help action — returns documentation for a specific resource.
10
+ */
11
+ export declare function handleHelp(resource: string): ToolResult;
12
+ /**
13
+ * Get help for all resources (overview).
14
+ */
15
+ export declare function handleHelpOverview(): ToolResult;
16
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/handlers/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA0oB7C;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAQvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAa/C"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Tool execution handlers for Forge MCP server.
3
+ * Shared between stdio and HTTP transports.
4
+ *
5
+ * Two tools with clear separation:
6
+ * - forge: read-only operations (list, get, help, schema)
7
+ * - forge_write: write operations (create, update, delete, deploy, reboot, etc.)
8
+ */
9
+ import type { ToolResult } from "./types.ts";
10
+ export type { ToolResult } from "./types.ts";
11
+ /**
12
+ * Execute a tool call with provided credentials.
13
+ *
14
+ * This is the main entry point shared between stdio and HTTP transports.
15
+ * Validates that the action matches the tool (read vs write).
16
+ */
17
+ export declare function executeToolWithCredentials(name: string, args: Record<string, unknown>, credentials: {
18
+ apiToken: string;
19
+ }): Promise<ToolResult>;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAA8B,UAAU,EAAE,MAAM,YAAY,CAAC;AA8BzE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwE7C;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAChC,OAAO,CAAC,UAAU,CAAC,CAyFrB"}
@@ -0,0 +1,2 @@
1
+ export declare const handleMonitors: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=monitors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitors.d.ts","sourceRoot":"","sources":["../../src/handlers/monitors.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc,+IA8BzB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const handleNginxConfig: (action: string, args: import("./types.ts").CommonArgs, ctx: import("./types.ts").HandlerContext) => Promise<import("./types.ts").ToolResult>;
2
+ //# sourceMappingURL=nginx-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx-config.d.ts","sourceRoot":"","sources":["../../src/handlers/nginx-config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB,+IA2B5B,CAAC"}