feat: new MCP tools (#10)
Universal: Cascade Main → Dev / Cascade main → branches (push) Successful in 3s
Universal: Changelog Validation / Validate CHANGELOG.md (push) Failing after 4s
MCP: Build & Validate / build (20) (push) Failing after 6s
MCP: Build & Validate / build (22) (push) Failing after 8s
MCP: Tool Inventory / inventory (push) Failing after 5s
MCP: Build & Release / Build, Validate & Release (push) Failing after 33s
Generic: Repo Health / Access control (push) Successful in 1s
Generic: Repo Health / Site Health (push) Has been skipped
MCP: Standards Compliance / Secret Scanning (push) Successful in 4s
MCP: Standards Compliance / Repository Structure Validation (push) Failing after 3s
MCP: Standards Compliance / License Header Validation (push) Failing after 5s
MCP: Standards Compliance / Coding Standards Check (push) Failing after 4s
MCP: Standards Compliance / Workflow Configuration Check (push) Failing after 4s
MCP: Standards Compliance / Documentation Quality Check (push) Successful in 5s
MCP: Standards Compliance / README Completeness Check (push) Failing after 3s
Universal: CodeQL Analysis / Analyze (actions) (push) Failing after 53s
MCP: Standards Compliance / Git Repository Hygiene (push) Successful in 4s
MCP: Standards Compliance / Line Length Check (push) Failing after 3s
MCP: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 4s
MCP: Standards Compliance / File Naming Standards (push) Successful in 5s
MCP: Standards Compliance / Script Integrity Validation (push) Successful in 9s
MCP: Standards Compliance / File Size Limits (push) Successful in 5s
MCP: Standards Compliance / Dead Code Detection (push) Successful in 7s
MCP: Standards Compliance / Binary File Detection (push) Successful in 5s
MCP: Standards Compliance / TODO/FIXME Tracking (push) Successful in 5s
MCP: Standards Compliance / Broken Link Detection (push) Successful in 3s
MCP: Standards Compliance / API Documentation Coverage (push) Successful in 4s
MCP: Standards Compliance / Accessibility Check (push) Successful in 3s
MCP: Standards Compliance / Version Consistency Check (push) Successful in 43s
MCP: Standards Compliance / Performance Metrics (push) Successful in 3s
MCP: Standards Compliance / Code Complexity Analysis (push) Successful in 40s
MCP: Standards Compliance / Code Duplication Detection (push) Successful in 41s
MCP: Standards Compliance / Terraform Configuration Validation (push) Successful in 12s
MCP: Standards Compliance / Unused Dependencies Check (push) Successful in 41s
MCP: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 46s
MCP: Standards Compliance / Enterprise Readiness Check (push) Successful in 42s
MCP: Standards Compliance / Repository Health Check (push) Successful in 43s
Universal: Sync Version on Merge / Propagate README version (push) Failing after 36s
Generic: Repo Health / Release configuration (push) Failing after 3s
Generic: Repo Health / Scripts governance (push) Successful in 3s
Generic: Repo Health / Repository health (push) Failing after 4s
MCP: Standards Compliance / Compliance Summary (push) Failing after 1s
Universal: CodeQL Analysis / Analyze (javascript) (push) Failing after 16m40s
Universal: CodeQL Analysis / Security Scan Summary (push) Successful in 2s

This commit was merged in pull request #10.
This commit is contained in:
2026-05-23 00:58:26 +00:00
parent 65912e2a86
commit da70622ee2
+125
View File
@@ -782,6 +782,131 @@ server.tool(
async ({ owner, repo, run_id, connection }) => formatResponse(await clientFor(connection).get(`/repos/${owner}/${repo}/actions/runs/${run_id}`)),
);
server.tool(
'gitea_actions_dispatch',
'Trigger a workflow dispatch (e.g. pre-release, deploy)',
{
...OwnerRepo,
workflow: z.string().describe('Workflow filename (e.g. pre-release.yml)'),
ref: z.string().describe('Branch or tag to run on (e.g. dev, main)'),
inputs: z.record(z.string()).optional().describe('Workflow input key-value pairs'),
...ConnectionParam,
},
async ({ owner, repo, workflow, ref, inputs, connection }) =>
formatResponse(await clientFor(connection).post(
`/repos/${owner}/${repo}/actions/workflows/${workflow}/dispatches`,
{ ref, inputs: inputs ?? {} },
)),
);
server.tool(
'gitea_actions_jobs_list',
'List jobs for a workflow run',
{ ...OwnerRepo, run_id: z.number().describe('Run ID'), ...ConnectionParam },
async ({ owner, repo, run_id, connection }) =>
formatResponse(await clientFor(connection).get(`/repos/${owner}/${repo}/actions/runs/${run_id}/jobs`)),
);
server.tool(
'gitea_actions_job_logs',
'Get log output for a workflow job',
{ ...OwnerRepo, job_id: z.number().describe('Job ID'), ...ConnectionParam },
async ({ owner, repo, job_id, connection }) => {
const client = clientFor(connection);
const res = await client.get(`/repos/${owner}/${repo}/actions/jobs/${job_id}/logs`);
if (res.status >= 400) return formatResponse(res);
// Logs come as plain text
const text = typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
return { content: [{ type: 'text' as const, text }] };
},
);
server.tool(
'gitea_release_asset_upload',
'Upload a file as a release asset (provide base64-encoded content)',
{
...OwnerRepo,
release_id: z.number().describe('Release ID'),
name: z.string().describe('Asset filename'),
content_base64: z.string().describe('Base64-encoded file content'),
...ConnectionParam,
},
async ({ owner, repo, release_id, name, content_base64, connection }) => {
const client = clientFor(connection);
// Gitea expects multipart form data for asset upload
// For now, use the API with the binary content
const res = await client.post(
`/repos/${owner}/${repo}/releases/${release_id}/assets?name=${encodeURIComponent(name)}`,
Buffer.from(content_base64, 'base64'),
);
return formatResponse(res);
},
);
server.tool(
'gitea_release_asset_delete',
'Delete a release asset',
{
...OwnerRepo,
release_id: z.number().describe('Release ID'),
asset_id: z.number().describe('Asset ID'),
...ConnectionParam,
},
async ({ owner, repo, release_id, asset_id, connection }) =>
formatResponse(await clientFor(connection).delete(`/repos/${owner}/${repo}/releases/${release_id}/assets/${asset_id}`)),
);
server.tool(
'gitea_bulk_file_push',
'Push the same file content to multiple repos (uses Contents API)',
{
owner: z.string().describe('Organization name'),
repos: z.array(z.string()).describe('List of repository names'),
path: z.string().describe('File path in each repo (e.g. .mokogitea/workflows/pre-release.yml)'),
content_base64: z.string().describe('Base64-encoded file content'),
message: z.string().describe('Commit message'),
branch: z.string().optional().describe('Target branch (default: main)'),
...ConnectionParam,
},
async ({ owner, repos, path, content_base64, message, branch, connection }) => {
const client = clientFor(connection);
const targetBranch = branch ?? 'main';
const results: Array<{ repo: string; status: string }> = [];
for (const repo of repos) {
try {
// Get current file SHA
const existing = await client.get(`/repos/${owner}/${repo}/contents/${path}?ref=${targetBranch}`);
const sha = (existing.data as { sha?: string })?.sha;
if (sha) {
// Update existing file
await client.put(`/repos/${owner}/${repo}/contents/${path}`, {
content: content_base64,
sha,
message,
branch: targetBranch,
});
results.push({ repo, status: 'updated' });
} else {
// Create new file
await client.post(`/repos/${owner}/${repo}/contents/${path}`, {
content: content_base64,
message,
branch: targetBranch,
});
results.push({ repo, status: 'created' });
}
} catch (e) {
results.push({ repo, status: `error: ${e}` });
}
}
const summary = results.map(r => `${r.repo}: ${r.status}`).join('\n');
return { content: [{ type: 'text' as const, text: summary }] };
},
);
// ── Organizations ───────────────────────────────────────────────────────
server.tool(