126 lines
5.9 KiB
Go
126 lines
5.9 KiB
Go
// Vikunja MCP - Developed by acidvegas in Go (https://git.acid.vegas)
|
|
// vikunja-mcp/allowlist.go
|
|
|
|
package main
|
|
|
|
type methodPath struct {
|
|
method string
|
|
path string
|
|
}
|
|
|
|
// Curated allowlist of endpoints the MCP exposes. Anything not in this set is
|
|
// dropped at build time. Keeps the tool surface small, predictable, and safe.
|
|
var allowlist = map[methodPath]bool{
|
|
// server / user
|
|
{"GET", "/info"}: true,
|
|
{"GET", "/user"}: true,
|
|
{"GET", "/users"}: true,
|
|
// projects
|
|
{"GET", "/projects"}: true,
|
|
{"PUT", "/projects"}: true,
|
|
{"GET", "/projects/{id}"}: true,
|
|
{"POST", "/projects/{id}"}: true,
|
|
{"DELETE", "/projects/{id}"}: true,
|
|
{"PUT", "/projects/{projectID}/duplicate"}: true,
|
|
{"GET", "/projects/{id}/projectusers"}: true,
|
|
// views
|
|
{"GET", "/projects/{project}/views"}: true,
|
|
{"PUT", "/projects/{project}/views"}: true,
|
|
{"GET", "/projects/{project}/views/{id}"}: true,
|
|
{"POST", "/projects/{project}/views/{id}"}: true,
|
|
{"DELETE", "/projects/{project}/views/{id}"}: true,
|
|
// buckets
|
|
{"GET", "/projects/{id}/views/{view}/buckets"}: true,
|
|
{"PUT", "/projects/{id}/views/{view}/buckets"}: true,
|
|
{"POST", "/projects/{projectID}/views/{view}/buckets/{bucketID}"}: true,
|
|
{"DELETE", "/projects/{projectID}/views/{view}/buckets/{bucketID}"}: true,
|
|
// tasks
|
|
{"GET", "/tasks"}: true,
|
|
{"GET", "/tasks/{id}"}: true,
|
|
{"POST", "/tasks/{id}"}: true,
|
|
{"DELETE", "/tasks/{id}"}: true,
|
|
{"PUT", "/projects/{id}/tasks"}: true,
|
|
{"POST", "/tasks/bulk"}: true,
|
|
{"POST", "/tasks/{id}/position"}: true,
|
|
{"POST", "/tasks/{projecttask}/read"}: true,
|
|
{"GET", "/projects/{id}/views/{view}/tasks"}: true,
|
|
{"POST", "/projects/{project}/views/{view}/buckets/{bucket}/tasks"}: true,
|
|
// task relations
|
|
{"PUT", "/tasks/{taskID}/relations"}: true,
|
|
{"DELETE", "/tasks/{taskID}/relations/{relationKind}/{otherTaskID}"}: true,
|
|
// assignees
|
|
{"GET", "/tasks/{taskID}/assignees"}: true,
|
|
{"PUT", "/tasks/{taskID}/assignees"}: true,
|
|
{"POST", "/tasks/{taskID}/assignees/bulk"}: true,
|
|
{"DELETE", "/tasks/{taskID}/assignees/{userID}"}: true,
|
|
// labels
|
|
{"GET", "/labels"}: true,
|
|
{"PUT", "/labels"}: true,
|
|
{"GET", "/labels/{id}"}: true,
|
|
{"POST", "/labels/{id}"}: true,
|
|
{"DELETE", "/labels/{id}"}: true,
|
|
{"GET", "/tasks/{task}/labels"}: true,
|
|
{"PUT", "/tasks/{task}/labels"}: true,
|
|
{"DELETE", "/tasks/{task}/labels/{label}"}: true,
|
|
{"POST", "/tasks/{taskID}/labels/bulk"}: true,
|
|
// comments
|
|
{"GET", "/tasks/{taskID}/comments"}: true,
|
|
{"GET", "/tasks/{taskID}/comments/{commentID}"}: true,
|
|
{"PUT", "/tasks/{taskID}/comments"}: true,
|
|
{"POST", "/tasks/{taskID}/comments/{commentID}"}: true,
|
|
{"DELETE", "/tasks/{taskID}/comments/{commentID}"}: true,
|
|
// attachments
|
|
{"GET", "/tasks/{id}/attachments"}: true,
|
|
{"GET", "/tasks/{id}/attachments/{attachmentID}"}: true,
|
|
{"PUT", "/tasks/{id}/attachments"}: true,
|
|
{"DELETE", "/tasks/{id}/attachments/{attachmentID}"}: true,
|
|
// reactions
|
|
{"GET", "/{kind}/{id}/reactions"}: true,
|
|
{"PUT", "/{kind}/{id}/reactions"}: true,
|
|
{"POST", "/{kind}/{id}/reactions/delete"}: true,
|
|
// filters
|
|
{"PUT", "/filters"}: true,
|
|
{"GET", "/filters/{id}"}: true,
|
|
{"POST", "/filters/{id}"}: true,
|
|
{"DELETE", "/filters/{id}"}: true,
|
|
// teams
|
|
{"GET", "/teams"}: true,
|
|
{"PUT", "/teams"}: true,
|
|
{"GET", "/teams/{id}"}: true,
|
|
{"POST", "/teams/{id}"}: true,
|
|
{"DELETE", "/teams/{id}"}: true,
|
|
{"PUT", "/teams/{id}/members"}: true,
|
|
{"POST", "/teams/{id}/members/{userID}/admin"}: true,
|
|
{"DELETE", "/teams/{id}/members/{username}"}: true,
|
|
// sharing
|
|
{"GET", "/projects/{id}/users"}: true,
|
|
{"PUT", "/projects/{id}/users"}: true,
|
|
{"POST", "/projects/{projectID}/users/{userID}"}: true,
|
|
{"DELETE", "/projects/{projectID}/users/{userID}"}: true,
|
|
{"GET", "/projects/{id}/teams"}: true,
|
|
{"PUT", "/projects/{id}/teams"}: true,
|
|
{"POST", "/projects/{projectID}/teams/{teamID}"}: true,
|
|
{"DELETE", "/projects/{projectID}/teams/{teamID}"}: true,
|
|
// link shares
|
|
{"GET", "/projects/{project}/shares"}: true,
|
|
{"GET", "/projects/{project}/shares/{share}"}: true,
|
|
{"PUT", "/projects/{project}/shares"}: true,
|
|
{"DELETE", "/projects/{project}/shares/{share}"}: true,
|
|
// subscriptions / notifications
|
|
{"PUT", "/subscriptions/{entity}/{entityID}"}: true,
|
|
{"DELETE", "/subscriptions/{entity}/{entityID}"}: true,
|
|
{"GET", "/notifications"}: true,
|
|
{"POST", "/notifications"}: true,
|
|
{"POST", "/notifications/{id}"}: true,
|
|
// webhooks
|
|
{"GET", "/projects/{id}/webhooks"}: true,
|
|
{"PUT", "/projects/{id}/webhooks"}: true,
|
|
{"POST", "/projects/{id}/webhooks/{webhookID}"}: true,
|
|
{"DELETE", "/projects/{id}/webhooks/{webhookID}"}: true,
|
|
{"GET", "/webhooks/events"}: true,
|
|
}
|
|
|
|
func isAllowlisted(method, path string) bool {
|
|
return allowlist[methodPath{method, path}]
|
|
}
|