feat(mcps): add wiki/packages/releases/projects to gitea + new umami & serpbear MCPs

This commit is contained in:
2026-03-05 10:52:05 +01:00
parent dca35a9900
commit 5c10eb0009
11 changed files with 985 additions and 8 deletions

View File

@@ -180,6 +180,169 @@ const SEARCH_REPOS_TOOL: Tool = {
},
};
// --- Wiki ---
const LIST_WIKI_PAGES_TOOL: Tool = {
name: "gitea_list_wiki_pages",
description: "List all wiki pages of a repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
},
required: ["owner", "repo"],
},
};
const GET_WIKI_PAGE_TOOL: Tool = {
name: "gitea_get_wiki_page",
description: "Get the content of a specific wiki page",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
page_name: { type: "string", description: "Name/slug of the wiki page (e.g., 'Home')" },
},
required: ["owner", "repo", "page_name"],
},
};
const CREATE_WIKI_PAGE_TOOL: Tool = {
name: "gitea_create_wiki_page",
description: "Create a new wiki page in a repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
title: { type: "string", description: "Page title" },
content: { type: "string", description: "Page content in Markdown (base64 encoded internally)" },
message: { type: "string", description: "Optional commit message" },
},
required: ["owner", "repo", "title", "content"],
},
};
const EDIT_WIKI_PAGE_TOOL: Tool = {
name: "gitea_edit_wiki_page",
description: "Edit an existing wiki page",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
page_name: { type: "string", description: "Current name/slug of the wiki page" },
title: { type: "string", description: "Optional: new title" },
content: { type: "string", description: "New content in Markdown" },
message: { type: "string", description: "Optional commit message" },
},
required: ["owner", "repo", "page_name", "content"],
},
};
// --- Packages ---
const LIST_PACKAGES_TOOL: Tool = {
name: "gitea_list_packages",
description: "List packages published to the Gitea package registry for a user or org",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "User or organization name" },
type: { type: "string", description: "Optional: Package type filter (e.g., 'npm', 'docker', 'generic')" },
limit: { type: "number", description: "Number of packages to return (default: 10)" },
},
required: ["owner"],
},
};
const LIST_PACKAGE_VERSIONS_TOOL: Tool = {
name: "gitea_list_package_versions",
description: "List all published versions of a specific package",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "User or organization name" },
type: { type: "string", description: "Package type (e.g., 'npm', 'docker')" },
name: { type: "string", description: "Package name" },
},
required: ["owner", "type", "name"],
},
};
// --- Releases ---
const LIST_RELEASES_TOOL: Tool = {
name: "gitea_list_releases",
description: "List releases for a repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
limit: { type: "number", description: "Number of releases to fetch (default: 10)" },
},
required: ["owner", "repo"],
},
};
const GET_LATEST_RELEASE_TOOL: Tool = {
name: "gitea_get_latest_release",
description: "Get the latest release for a repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
},
required: ["owner", "repo"],
},
};
const CREATE_RELEASE_TOOL: Tool = {
name: "gitea_create_release",
description: "Create a new release for a repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "Repository owner" },
repo: { type: "string", description: "Repository name" },
tag_name: { type: "string", description: "Git tag to build the release from (e.g., 'v1.2.3')" },
name: { type: "string", description: "Release title" },
body: { type: "string", description: "Optional: Release notes/description in Markdown" },
draft: { type: "boolean", description: "Optional: Create as draft (default: false)" },
prerelease: { type: "boolean", description: "Optional: Mark as prerelease (default: false)" },
},
required: ["owner", "repo", "tag_name", "name"],
},
};
// --- Projects ---
const LIST_PROJECTS_TOOL: Tool = {
name: "gitea_list_projects",
description: "List projects (kanban boards) for a user, organization, or repository",
inputSchema: {
type: "object",
properties: {
owner: { type: "string", description: "User or organization name" },
repo: { type: "string", description: "Optional: Repository name (for repo-level projects)" },
type: { type: "string", description: "Optional: 'individual' or 'repository' or 'organization'" },
},
required: ["owner"],
},
};
const GET_PROJECT_COLUMNS_TOOL: Tool = {
name: "gitea_get_project_columns",
description: "Get the columns (board columns) of a specific project",
inputSchema: {
type: "object",
properties: {
project_id: { type: "number", description: "Numeric project ID from gitea_list_projects" },
},
required: ["project_id"],
},
};
// Subscription State
const subscriptions = new Set<string>();
const runStatusCache = new Map<string, string>(); // uri -> status
@@ -210,7 +373,22 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
UPDATE_ISSUE_TOOL,
CREATE_ISSUE_COMMENT_TOOL,
CREATE_PULL_REQUEST_TOOL,
SEARCH_REPOS_TOOL
SEARCH_REPOS_TOOL,
// Wiki
LIST_WIKI_PAGES_TOOL,
GET_WIKI_PAGE_TOOL,
CREATE_WIKI_PAGE_TOOL,
EDIT_WIKI_PAGE_TOOL,
// Packages
LIST_PACKAGES_TOOL,
LIST_PACKAGE_VERSIONS_TOOL,
// Releases
LIST_RELEASES_TOOL,
GET_LATEST_RELEASE_TOOL,
CREATE_RELEASE_TOOL,
// Projects
LIST_PROJECTS_TOOL,
GET_PROJECT_COLUMNS_TOOL,
],
};
});
@@ -410,6 +588,140 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}
}
// --- Wiki Handlers ---
if (request.params.name === "gitea_list_wiki_pages") {
const { owner, repo } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/repos/${owner}/${repo}/wiki/pages`);
const pages = (response.data || []).map((p: any) => ({ title: p.title, last_commit: p.last_commit?.message }));
return { content: [{ type: "text", text: JSON.stringify(pages, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error listing wiki pages: ${error.message}` }] };
}
}
if (request.params.name === "gitea_get_wiki_page") {
const { owner, repo, page_name } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/repos/${owner}/${repo}/wiki/page/${encodeURIComponent(page_name)}`);
const content = Buffer.from(response.data.content_base64 || '', 'base64').toString('utf-8');
return { content: [{ type: "text", text: `# ${response.data.title}\n\n${content}` }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error fetching wiki page: ${error.message}` }] };
}
}
if (request.params.name === "gitea_create_wiki_page") {
const { owner, repo, title, content, message } = request.params.arguments as any;
try {
const response = await giteaClient.post(`/repos/${owner}/${repo}/wiki/pages`, {
title,
content_base64: Buffer.from(content).toString('base64'),
message: message || `Create wiki page: ${title}`,
});
return { content: [{ type: "text", text: `Wiki page '${response.data.title}' created.` }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error creating wiki page: ${error.message}` }] };
}
}
if (request.params.name === "gitea_edit_wiki_page") {
const { owner, repo, page_name, title, content, message } = request.params.arguments as any;
try {
const updateData: Record<string, any> = {
content_base64: Buffer.from(content).toString('base64'),
message: message || `Update wiki page: ${page_name}`,
};
if (title) updateData.title = title;
const response = await giteaClient.patch(`/repos/${owner}/${repo}/wiki/pages/${encodeURIComponent(page_name)}`, updateData);
return { content: [{ type: "text", text: `Wiki page '${response.data.title}' updated.` }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error updating wiki page: ${error.message}` }] };
}
}
// --- Package Handlers ---
if (request.params.name === "gitea_list_packages") {
const { owner, type, limit = 10 } = request.params.arguments as any;
try {
const params: Record<string, any> = { limit };
if (type) params.type = type;
const response = await giteaClient.get(`/packages/${owner}`, { params });
const packages = (response.data || []).map((p: any) => ({
name: p.name, type: p.type, version: p.version, created: p.created_at
}));
return { content: [{ type: "text", text: JSON.stringify(packages, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error listing packages: ${error.message}` }] };
}
}
if (request.params.name === "gitea_list_package_versions") {
const { owner, type, name } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/packages/${owner}/${type}/${encodeURIComponent(name)}`);
return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error listing package versions: ${error.message}` }] };
}
}
// --- Release Handlers ---
if (request.params.name === "gitea_list_releases") {
const { owner, repo, limit = 10 } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/repos/${owner}/${repo}/releases`, { params: { limit } });
return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error listing releases: ${error.message}` }] };
}
}
if (request.params.name === "gitea_get_latest_release") {
const { owner, repo } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/repos/${owner}/${repo}/releases/latest`);
return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error fetching latest release: ${error.message}` }] };
}
}
if (request.params.name === "gitea_create_release") {
const { owner, repo, tag_name, name, body, draft = false, prerelease = false } = request.params.arguments as any;
try {
const response = await giteaClient.post(`/repos/${owner}/${repo}/releases`, {
tag_name, name, body, draft, prerelease
});
return { content: [{ type: "text", text: `Release '${response.data.name}' created: ${response.data.html_url}` }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error creating release: ${error.message}` }] };
}
}
// --- Project Handlers ---
if (request.params.name === "gitea_list_projects") {
const { owner, repo } = request.params.arguments as any;
try {
// Gitea API: repo-level projects or user projects
const url = repo ? `/repos/${owner}/${repo}/projects` : `/users/${owner}/projects`;
const response = await giteaClient.get(url);
return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error listing projects: ${error.message}` }] };
}
}
if (request.params.name === "gitea_get_project_columns") {
const { project_id } = request.params.arguments as any;
try {
const response = await giteaClient.get(`/projects/${project_id}/columns`);
return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] };
} catch (error: any) {
return { isError: true, content: [{ type: "text", text: `Error fetching project columns: ${error.message}` }] };
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});