mcp-server-cloud-agent 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +61 -23
- package/glama.json +4 -0
- package/index.js +102 -152
- package/package.json +3 -1
- package/server.json +3 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MetalTorque
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,28 +1,43 @@
|
|
|
1
1
|
# mcp-server-cloud-agent
|
|
2
2
|
|
|
3
|
-
MCP server for **Cloud Agent** —
|
|
3
|
+
MCP server for **Cloud Agent** — a hosted AI software engineer that writes code, opens PRs, reviews code, generates tests, runs security scans, and answers codebase questions.
|
|
4
4
|
|
|
5
5
|
Connect from any MCP client (Claude Code, Cursor, Windsurf, or your own agents) and delegate engineering tasks.
|
|
6
6
|
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
This package is a **local stdio MCP proxy** that forwards requests to the Cloud Agent hosted backend at `cloudagent.metaltorque.dev`. Your MCP client communicates with this server over stdio; the server makes authenticated HTTPS calls to the backend on your behalf.
|
|
10
|
+
|
|
11
|
+
**Data flow:** MCP client → (stdio) → this server → (HTTPS) → Cloud Agent backend → GitHub
|
|
12
|
+
|
|
13
|
+
**What data leaves your machine:**
|
|
14
|
+
- Task descriptions, repo names, file paths, and PR URLs you provide
|
|
15
|
+
- Your API key (sent over HTTPS only, never over HTTP)
|
|
16
|
+
|
|
17
|
+
**What the backend does with your data:**
|
|
18
|
+
- Clones repos from GitHub using its own GitHub App credentials
|
|
19
|
+
- Executes tasks in isolated sandboxes
|
|
20
|
+
- Opens PRs and posts reviews to GitHub on your behalf
|
|
21
|
+
|
|
7
22
|
## Tools (9)
|
|
8
23
|
|
|
9
|
-
| Tool | Description |
|
|
10
|
-
|
|
11
|
-
| `run_task` | Write code, fix bugs, add features — returns result + PR URL |
|
|
12
|
-
| `review_pr` | Review a GitHub PR with structured feedback
|
|
13
|
-
| `ask_codebase` | Ask questions about any GitHub repo (auto-indexes on first use) |
|
|
14
|
-
| `generate_tests` | Generate tests for a file
|
|
15
|
-
| `security_scan` | Security + dependency scan across one or more repos |
|
|
16
|
-
| `list_sessions` | List recent sessions with status, cost, duration, PR URLs |
|
|
17
|
-
| `list_playbooks` | List available workflow templates
|
|
18
|
-
| `run_playbook` | Run a playbook against a repo |
|
|
19
|
-
| `get_usage` | Usage stats — sessions, cost, time saved, breakdowns |
|
|
24
|
+
| Tool | Description | Side effects |
|
|
25
|
+
|------|-------------|--------------|
|
|
26
|
+
| `run_task` | Write code, fix bugs, add features — returns result + PR URL | Creates branches and PRs |
|
|
27
|
+
| `review_pr` | Review a GitHub PR with structured feedback | Optionally posts comments to GitHub |
|
|
28
|
+
| `ask_codebase` | Ask questions about any GitHub repo (auto-indexes on first use) | Read-only |
|
|
29
|
+
| `generate_tests` | Generate tests for a file, opens a PR | Creates branches and PRs |
|
|
30
|
+
| `security_scan` | Security + dependency scan across one or more repos | Read-only |
|
|
31
|
+
| `list_sessions` | List recent sessions with status, cost, duration, PR URLs | Read-only |
|
|
32
|
+
| `list_playbooks` | List available workflow templates | Read-only |
|
|
33
|
+
| `run_playbook` | Run a playbook against a repo | Creates branches and PRs |
|
|
34
|
+
| `get_usage` | Usage stats — sessions, cost, time saved, breakdowns | Read-only |
|
|
20
35
|
|
|
21
36
|
## Setup
|
|
22
37
|
|
|
23
38
|
### 1. Get an API key
|
|
24
39
|
|
|
25
|
-
Sign in to your Cloud Agent
|
|
40
|
+
Sign in to your Cloud Agent workspace at [cloudagent.metaltorque.dev](https://cloudagent.metaltorque.dev) and generate an API key at `/auth/api-key`. Keys use the `ca_*` prefix.
|
|
26
41
|
|
|
27
42
|
### 2. Configure your MCP client
|
|
28
43
|
|
|
@@ -68,28 +83,51 @@ Sign in to your Cloud Agent web workspace and generate an API key at `/auth/api-
|
|
|
68
83
|
Once configured, your MCP client can call these tools directly:
|
|
69
84
|
|
|
70
85
|
**Fix a bug:**
|
|
71
|
-
> "Use cloud-agent to fix the broken login flow
|
|
86
|
+
> "Use cloud-agent run_task on myorg/myapp to fix the broken login flow"
|
|
72
87
|
|
|
73
88
|
**Review a PR:**
|
|
74
|
-
> "Use cloud-agent
|
|
89
|
+
> "Use cloud-agent review_pr on https://github.com/myorg/myapp/pull/42"
|
|
75
90
|
|
|
76
91
|
**Ask about code:**
|
|
77
|
-
> "Use cloud-agent
|
|
92
|
+
> "Use cloud-agent ask_codebase on myorg/myapp: how does authentication work?"
|
|
78
93
|
|
|
79
94
|
**Generate tests:**
|
|
80
|
-
> "Use cloud-agent
|
|
95
|
+
> "Use cloud-agent generate_tests on myorg/myapp for src/auth.ts"
|
|
81
96
|
|
|
82
97
|
**Security scan:**
|
|
83
|
-
> "Use cloud-agent
|
|
98
|
+
> "Use cloud-agent security_scan on myorg/myapp and myorg/api"
|
|
99
|
+
|
|
100
|
+
## Sample Output
|
|
84
101
|
|
|
85
|
-
**
|
|
86
|
-
|
|
102
|
+
**run_task response:**
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"response": "Fixed the login redirect bug. Changed src/auth.ts to properly handle OAuth callback URLs.",
|
|
106
|
+
"cost_usd": 0.42,
|
|
107
|
+
"duration_ms": 45000,
|
|
108
|
+
"pr_url": "https://github.com/myorg/myapp/pull/87"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
87
111
|
|
|
88
|
-
|
|
112
|
+
**security_scan response:**
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"repos_scanned": 1,
|
|
116
|
+
"vulnerabilities": 3,
|
|
117
|
+
"secrets_found": 0,
|
|
118
|
+
"findings": [...]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
89
121
|
|
|
90
|
-
|
|
122
|
+
## Troubleshooting
|
|
91
123
|
|
|
92
|
-
|
|
124
|
+
| Problem | Solution |
|
|
125
|
+
|---------|----------|
|
|
126
|
+
| "CLOUD_AGENT_API_KEY is required" | Set the env var in your MCP client config |
|
|
127
|
+
| "Refusing to send API key over insecure HTTP" | Use HTTPS (the default). Don't set `CLOUD_AGENT_URL` to an HTTP URL |
|
|
128
|
+
| "Request timed out" | Tasks can take up to 10 minutes. Check `list_sessions` for status |
|
|
129
|
+
| "HTTP 401" | Your API key is invalid or expired. Generate a new one |
|
|
130
|
+
| "HTTP 429" | Rate limited. Wait and retry |
|
|
93
131
|
|
|
94
132
|
## License
|
|
95
133
|
|
package/glama.json
ADDED
package/index.js
CHANGED
|
@@ -12,6 +12,11 @@ const { version } = require("./package.json");
|
|
|
12
12
|
const API_KEY = process.env.CLOUD_AGENT_API_KEY || "";
|
|
13
13
|
const BASE_URL = (process.env.CLOUD_AGENT_URL || "https://cloudagent.metaltorque.dev").replace(/\/$/, "");
|
|
14
14
|
|
|
15
|
+
// ── Shared schemas ──────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
const repoSchema = z.string().regex(/^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/, "Must be owner/repo format, e.g. 'facebook/react'");
|
|
18
|
+
const prUrlSchema = z.string().url().regex(/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+/, "Must be a GitHub PR URL, e.g. https://github.com/owner/repo/pull/123");
|
|
19
|
+
|
|
15
20
|
// ── HTTP helper ─────────────────────────────────────────────────────
|
|
16
21
|
|
|
17
22
|
const MAX_RESPONSE_SIZE = 5 * 1024 * 1024; // 5MB
|
|
@@ -70,8 +75,11 @@ function request(method, urlPath, body, timeout = 600_000) {
|
|
|
70
75
|
});
|
|
71
76
|
}
|
|
72
77
|
|
|
78
|
+
// ── Shared helpers ──────────────────────────────────────────────────
|
|
79
|
+
|
|
73
80
|
function noKeyError() {
|
|
74
81
|
return {
|
|
82
|
+
isError: true,
|
|
75
83
|
content: [{
|
|
76
84
|
type: "text",
|
|
77
85
|
text: "Error: CLOUD_AGENT_API_KEY environment variable is required.\n\nGet an API key from your Cloud Agent web workspace at /auth/api-key.\nAPI keys use the ca_* prefix.",
|
|
@@ -79,6 +87,29 @@ function noKeyError() {
|
|
|
79
87
|
};
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
function errorResult(e) {
|
|
91
|
+
return {
|
|
92
|
+
isError: true,
|
|
93
|
+
content: [{ type: "text", text: `Error: ${e.message}` }],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function toolResult(text) {
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text }],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function authedCall(method, path, body, formatter) {
|
|
104
|
+
if (!API_KEY) return noKeyError();
|
|
105
|
+
try {
|
|
106
|
+
const result = await request(method, path, body);
|
|
107
|
+
return toolResult(formatter(result));
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return errorResult(e);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
82
113
|
// ── MCP Server ──────────────────────────────────────────────────────
|
|
83
114
|
|
|
84
115
|
const server = new McpServer({
|
|
@@ -87,31 +118,29 @@ const server = new McpServer({
|
|
|
87
118
|
});
|
|
88
119
|
|
|
89
120
|
// ── Tool: run_task ──────────────────────────────────────────────────
|
|
121
|
+
// Positional: tool(name, description, paramsSchema, annotations, handler)
|
|
90
122
|
|
|
91
123
|
server.tool(
|
|
92
124
|
"run_task",
|
|
93
125
|
"Run a coding task: write code, fix bugs, add features, refactor. The AI agent clones the repo, makes changes, and opens a PR. Returns the result and PR URL when complete.",
|
|
94
126
|
{
|
|
95
|
-
|
|
127
|
+
repo: repoSchema.describe("GitHub repo in owner/repo format, e.g. 'facebook/react'"),
|
|
128
|
+
task: z.string().min(1).describe("Task description, e.g. 'Fix the login bug' or 'Add dark mode to the settings page'"),
|
|
129
|
+
base_branch: z.string().optional().describe("Branch to base changes on (default: main)"),
|
|
96
130
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}],
|
|
111
|
-
};
|
|
112
|
-
} catch (e) {
|
|
113
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
114
|
-
}
|
|
131
|
+
{ destructiveHint: true, readOnlyHint: false, openWorldHint: true },
|
|
132
|
+
async ({ repo, task, base_branch }) => {
|
|
133
|
+
const prompt = base_branch
|
|
134
|
+
? `In ${repo} (branch: ${base_branch}): ${task}`
|
|
135
|
+
: `In ${repo}: ${task}`;
|
|
136
|
+
return authedCall("POST", "/query", { prompt }, (result) =>
|
|
137
|
+
JSON.stringify({
|
|
138
|
+
response: result.response,
|
|
139
|
+
cost_usd: result.cost_usd,
|
|
140
|
+
duration_ms: result.duration_ms,
|
|
141
|
+
pr_url: result.pr_url || null,
|
|
142
|
+
}, null, 2)
|
|
143
|
+
);
|
|
115
144
|
}
|
|
116
145
|
);
|
|
117
146
|
|
|
@@ -121,26 +150,14 @@ server.tool(
|
|
|
121
150
|
"review_pr",
|
|
122
151
|
"Review a GitHub pull request. Returns structured feedback with issues, verdict, and suggestions. Optionally posts review comments directly to GitHub.",
|
|
123
152
|
{
|
|
124
|
-
pr_url:
|
|
153
|
+
pr_url: prUrlSchema.describe("Full GitHub PR URL, e.g. https://github.com/owner/repo/pull/123"),
|
|
125
154
|
post_comments: z.boolean().optional().describe("Post review comments directly to GitHub (default: false)"),
|
|
126
155
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
post_review: post_comments === true,
|
|
133
|
-
});
|
|
134
|
-
return {
|
|
135
|
-
content: [{
|
|
136
|
-
type: "text",
|
|
137
|
-
text: result.review || JSON.stringify(result, null, 2),
|
|
138
|
-
}],
|
|
139
|
-
};
|
|
140
|
-
} catch (e) {
|
|
141
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
142
|
-
}
|
|
143
|
-
}
|
|
156
|
+
{ destructiveHint: false, readOnlyHint: false, openWorldHint: true },
|
|
157
|
+
async ({ pr_url, post_comments }) =>
|
|
158
|
+
authedCall("POST", "/review", { pr_url, post_review: post_comments === true }, (result) =>
|
|
159
|
+
result.review || JSON.stringify(result, null, 2)
|
|
160
|
+
)
|
|
144
161
|
);
|
|
145
162
|
|
|
146
163
|
// ── Tool: ask_codebase ──────────────────────────────────────────────
|
|
@@ -149,58 +166,35 @@ server.tool(
|
|
|
149
166
|
"ask_codebase",
|
|
150
167
|
"Ask a question about any GitHub repository's codebase. Auto-indexes the repo on first use. Returns an answer with file references.",
|
|
151
168
|
{
|
|
152
|
-
question: z.string().describe("Question about the codebase, e.g. 'How does authentication work?'"),
|
|
153
|
-
repo:
|
|
169
|
+
question: z.string().min(1).describe("Question about the codebase, e.g. 'How does authentication work?'"),
|
|
170
|
+
repo: repoSchema.describe("GitHub repo in owner/repo format, e.g. 'facebook/react'"),
|
|
154
171
|
},
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
content: [{
|
|
161
|
-
type: "text",
|
|
162
|
-
text: result.answer || JSON.stringify(result, null, 2),
|
|
163
|
-
}],
|
|
164
|
-
};
|
|
165
|
-
} catch (e) {
|
|
166
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
167
|
-
}
|
|
168
|
-
}
|
|
172
|
+
{ destructiveHint: false, readOnlyHint: true, openWorldHint: true },
|
|
173
|
+
async ({ question, repo }) =>
|
|
174
|
+
authedCall("POST", "/ask", { question, repo }, (result) =>
|
|
175
|
+
result.answer || JSON.stringify(result, null, 2)
|
|
176
|
+
)
|
|
169
177
|
);
|
|
170
178
|
|
|
171
179
|
// ── Tool: generate_tests ────────────────────────────────────────────
|
|
172
180
|
|
|
173
181
|
server.tool(
|
|
174
182
|
"generate_tests",
|
|
175
|
-
"Generate tests for a file
|
|
183
|
+
"Generate tests for a specific file in a GitHub repository. Creates test files and opens a PR with them.",
|
|
176
184
|
{
|
|
177
|
-
repo:
|
|
178
|
-
file: z.string().
|
|
179
|
-
feature: z.string().optional().describe("Feature to test, e.g. 'user authentication'"),
|
|
185
|
+
repo: repoSchema.describe("GitHub repo in owner/repo format"),
|
|
186
|
+
file: z.string().min(1).describe("File to generate tests for, e.g. 'src/auth.ts'"),
|
|
180
187
|
},
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
type: "text",
|
|
192
|
-
text: JSON.stringify({
|
|
193
|
-
response: result.response,
|
|
194
|
-
cost_usd: result.cost_usd,
|
|
195
|
-
duration_ms: result.duration_ms,
|
|
196
|
-
pr_url: result.pr_url || null,
|
|
197
|
-
}, null, 2),
|
|
198
|
-
}],
|
|
199
|
-
};
|
|
200
|
-
} catch (e) {
|
|
201
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
202
|
-
}
|
|
203
|
-
}
|
|
188
|
+
{ destructiveHint: true, readOnlyHint: false, openWorldHint: true },
|
|
189
|
+
async ({ repo, file }) =>
|
|
190
|
+
authedCall("POST", "/test", { file, repo }, (result) =>
|
|
191
|
+
JSON.stringify({
|
|
192
|
+
response: result.response,
|
|
193
|
+
cost_usd: result.cost_usd,
|
|
194
|
+
duration_ms: result.duration_ms,
|
|
195
|
+
pr_url: result.pr_url || null,
|
|
196
|
+
}, null, 2)
|
|
197
|
+
)
|
|
204
198
|
);
|
|
205
199
|
|
|
206
200
|
// ── Tool: security_scan ─────────────────────────────────────────────
|
|
@@ -209,23 +203,14 @@ server.tool(
|
|
|
209
203
|
"security_scan",
|
|
210
204
|
"Run a security and dependency scan on one or more GitHub repositories. Checks for vulnerabilities, secret exposure, and security anti-patterns.",
|
|
211
205
|
{
|
|
212
|
-
repos: z.array(
|
|
206
|
+
repos: z.array(repoSchema).min(1).describe("Array of repos in owner/repo format, e.g. ['owner/repo1', 'owner/repo2']"),
|
|
213
207
|
type: z.enum(["all", "dependencies", "secrets", "code"]).optional().describe("Scan type (default: all)"),
|
|
214
208
|
},
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
content: [{
|
|
221
|
-
type: "text",
|
|
222
|
-
text: JSON.stringify(result, null, 2),
|
|
223
|
-
}],
|
|
224
|
-
};
|
|
225
|
-
} catch (e) {
|
|
226
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
227
|
-
}
|
|
228
|
-
}
|
|
209
|
+
{ destructiveHint: false, readOnlyHint: true, openWorldHint: true },
|
|
210
|
+
async ({ repos, type }) =>
|
|
211
|
+
authedCall("POST", "/scan", { repos, type: type || "all" }, (result) =>
|
|
212
|
+
JSON.stringify(result, null, 2)
|
|
213
|
+
)
|
|
229
214
|
);
|
|
230
215
|
|
|
231
216
|
// ── Tool: list_sessions ─────────────────────────────────────────────
|
|
@@ -237,21 +222,13 @@ server.tool(
|
|
|
237
222
|
limit: z.number().int().min(1).max(100).optional().describe("Max sessions to return (default: 20)"),
|
|
238
223
|
status: z.enum(["running", "completed", "error"]).optional().describe("Filter by session status"),
|
|
239
224
|
},
|
|
225
|
+
{ destructiveHint: false, readOnlyHint: true, openWorldHint: false },
|
|
240
226
|
async ({ limit, status }) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
content: [{
|
|
248
|
-
type: "text",
|
|
249
|
-
text: JSON.stringify(result.sessions || result, null, 2),
|
|
250
|
-
}],
|
|
251
|
-
};
|
|
252
|
-
} catch (e) {
|
|
253
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
254
|
-
}
|
|
227
|
+
let path = `/api/sessions?limit=${limit || 20}`;
|
|
228
|
+
if (status) path += `&status=${status}`;
|
|
229
|
+
return authedCall("GET", path, undefined, (result) =>
|
|
230
|
+
JSON.stringify(result.sessions || result, null, 2)
|
|
231
|
+
);
|
|
255
232
|
}
|
|
256
233
|
);
|
|
257
234
|
|
|
@@ -261,20 +238,10 @@ server.tool(
|
|
|
261
238
|
"list_playbooks",
|
|
262
239
|
"List available playbooks — reusable workflow templates for common engineering tasks like bug triage, security remediation, test coverage, docs sync, and more.",
|
|
263
240
|
{},
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return {
|
|
269
|
-
content: [{
|
|
270
|
-
type: "text",
|
|
271
|
-
text: JSON.stringify(result, null, 2),
|
|
272
|
-
}],
|
|
273
|
-
};
|
|
274
|
-
} catch (e) {
|
|
275
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
276
|
-
}
|
|
277
|
-
}
|
|
241
|
+
{ destructiveHint: false, readOnlyHint: true, openWorldHint: false },
|
|
242
|
+
async () => authedCall("GET", "/api/playbooks", undefined, (result) =>
|
|
243
|
+
JSON.stringify(result, null, 2)
|
|
244
|
+
)
|
|
278
245
|
);
|
|
279
246
|
|
|
280
247
|
// ── Tool: run_playbook ──────────────────────────────────────────────
|
|
@@ -283,24 +250,15 @@ server.tool(
|
|
|
283
250
|
"run_playbook",
|
|
284
251
|
"Run a playbook (reusable workflow template) against a repository. Use list_playbooks to see available options. Built-in playbooks include: bug-triage, security-remediation, dependency-upgrade, docs-sync, test-coverage, code-migration, pr-review-cycle.",
|
|
285
252
|
{
|
|
286
|
-
slug: z.string().describe("Playbook slug, e.g. 'bug-triage', 'security-remediation', 'test-coverage'"),
|
|
287
|
-
repo:
|
|
253
|
+
slug: z.string().min(1).describe("Playbook slug, e.g. 'bug-triage', 'security-remediation', 'test-coverage'"),
|
|
254
|
+
repo: repoSchema.describe("GitHub repo in owner/repo format"),
|
|
288
255
|
inputs: z.record(z.string()).optional().describe("Additional inputs for the playbook template variables"),
|
|
289
256
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
content: [{
|
|
296
|
-
type: "text",
|
|
297
|
-
text: JSON.stringify(result, null, 2),
|
|
298
|
-
}],
|
|
299
|
-
};
|
|
300
|
-
} catch (e) {
|
|
301
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
302
|
-
}
|
|
303
|
-
}
|
|
257
|
+
{ destructiveHint: true, readOnlyHint: false, openWorldHint: true },
|
|
258
|
+
async ({ slug, repo, inputs }) =>
|
|
259
|
+
authedCall("POST", `/api/playbooks/${encodeURIComponent(slug)}/run`, { repo, inputs }, (result) =>
|
|
260
|
+
JSON.stringify(result, null, 2)
|
|
261
|
+
)
|
|
304
262
|
);
|
|
305
263
|
|
|
306
264
|
// ── Tool: get_usage ─────────────────────────────────────────────────
|
|
@@ -311,20 +269,12 @@ server.tool(
|
|
|
311
269
|
{
|
|
312
270
|
days: z.number().int().min(1).max(365).optional().describe("Number of days to look back (default: all time)"),
|
|
313
271
|
},
|
|
272
|
+
{ destructiveHint: false, readOnlyHint: true, openWorldHint: false },
|
|
314
273
|
async ({ days }) => {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
content: [{
|
|
321
|
-
type: "text",
|
|
322
|
-
text: JSON.stringify(result, null, 2),
|
|
323
|
-
}],
|
|
324
|
-
};
|
|
325
|
-
} catch (e) {
|
|
326
|
-
return { content: [{ type: "text", text: `Error: ${e.message}` }] };
|
|
327
|
-
}
|
|
274
|
+
const path = days ? `/api/usage?days=${days}` : "/api/usage";
|
|
275
|
+
return authedCall("GET", path, undefined, (result) =>
|
|
276
|
+
JSON.stringify(result, null, 2)
|
|
277
|
+
);
|
|
328
278
|
}
|
|
329
279
|
);
|
|
330
280
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-server-cloud-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"mcpName": "io.github.joepangallo/cloud-agent",
|
|
5
5
|
"description": "MCP server for Cloud Agent — an AI software engineer that writes code, opens PRs, reviews code, generates tests, runs security scans, and answers codebase questions. Connect from any MCP client (Claude Code, Cursor, Windsurf) and delegate engineering tasks.",
|
|
6
6
|
"bin": {
|
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
"files": [
|
|
50
50
|
"index.js",
|
|
51
51
|
"README.md",
|
|
52
|
+
"LICENSE",
|
|
52
53
|
"server.json",
|
|
54
|
+
"glama.json",
|
|
53
55
|
"package.json"
|
|
54
56
|
],
|
|
55
57
|
"devDependencies": {
|
package/server.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.joepangallo/cloud-agent",
|
|
4
|
-
"description": "AI software engineer — writes code, opens PRs, reviews code, generates tests,
|
|
4
|
+
"description": "AI software engineer — writes code, opens PRs, reviews code, generates tests, and more.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/joepangallo/mcp-server-cloud-agent",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.1.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "mcp-server-cloud-agent",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.1.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|