{"apiVersion":"v1","directorySlug":"kgit-mcp-976e359841","title":"kroy","description":null,"pageUrl":"https://www.mcpbundles.com/skills/kgit-mcp-976e359841","connectPath":"importable","connectAction":"import_server","catalogListing":false,"bundleSlug":null,"listingKind":"remote_mcp","kind":"provider","transportUrl":"https://kgit.net/mcp","hostedMcpUrl":null,"toolCount":73,"toolInventoryStatus":"observed","refreshedAt":"2026-11-03T13:26:00.516172+00:00","registryName":"net.kgit/kgit-mcp-976e359841","registryVersion":"2026.11.3","registryEligible":true,"tools":[{"name":"repo_get","description":"One repository: its id, its visibility, its default branch and its description. A repository you may not see answers the SAME sentence as one that does not exist, so this is not a way to find out what exists.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"repo_get","displayName":"repo_get","title":"repo_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"refs_list","description":"Every ref this repository ADVERTISES -- branches and tags with the commit each points at. Ask here before naming a ref anywhere else: default_branch is a SETTING, not an observation, so a repository nobody has pushed to still names a branch that has nothing in it.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"refs_list","displayName":"refs_list","title":"refs_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"project_list","description":"The projects of one organization: name and id. A project groups repositories and owns a mailbox and a memory rung of its own. Readable by a member; an organization you do not belong to answers the same sentence as one that does not exist.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"}}},"logicalName":"project_list","displayName":"project_list","title":"project_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_list","description":"Every repository you can read in ONE project: name, id, visibility and state. It does NOT fan out across projects or organizations -- ask project_list for an organization's projects and come back here for each. An organization you do not belong to answers the same sentence as one that does not exist.","inputSchema":{"type":"object","required":["org","project"],"properties":{"org":{"type":"string"},"project":{"type":"string"}}},"logicalName":"repo_list","displayName":"repo_list","title":"repo_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"file_get","description":"One file's text at one ref, BY LINE. The answer always states lines, returned and truncated, so a window is never mistaken for the whole file -- page with offset rather than asking for more. A path that names a directory is refused, and so is a binary file: this reads files, not trees, and it does not mangle bytes to fit them in a string.","inputSchema":{"type":"object","required":["org","project","repo","ref","path"],"properties":{"org":{"type":"string"},"ref":{"type":"string"},"path":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"offset":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"file_get","displayName":"file_get","title":"file_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"commit_log","description":"The commit history reachable from a ref, newest first: 20 by default and 200 at most, via limit. The ref must be one the repository advertises -- refs_list is the honest way to find one. This is the COMMIT log; ci_log is a job's output and audit_list is who did what.","inputSchema":{"type":"object","required":["org","project","repo","ref"],"properties":{"org":{"type":"string"},"ref":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"commit_log","displayName":"commit_log","title":"commit_log","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"commit_get","description":"One commit: its message, its author, its parents and its tree. The ref may be a branch, a tag or a full hex object id -- a name that resolves to nothing is `ref not found`. Until 2026-09-21 this tool advertised `ref` and demanded `oid`, so the call its own schema described was refused.","inputSchema":{"type":"object","required":["org","project","repo","ref"],"properties":{"org":{"type":"string"},"ref":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"commit_get","displayName":"commit_get","title":"commit_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"issue_create","description":"Create an issue, and only ever create one: there is no number argument and nothing here is ever overwritten. The answer carries the number the daemon assigned AND the board it wrote to, project or repo:<name> -- read it, because THE TWO BOARDS NUMBER INDEPENDENTLY. Omitting repo does not fail: it files onto the PROJECT board, where the first issue is also number 1, so a number alone cannot tell you which board you got. Omit repo deliberately for a coordination task that belongs to no repository.","inputSchema":{"type":"object","required":["org","project","title"],"properties":{"org":{"type":"string"},"body":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"issue_create","displayName":"issue_create","title":"issue_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"issue_list","description":"The issue board, WINDOWED: 100 rows by default and 1000 at most. The answer is an object carrying issues plus returned, matched, untouched, total, truncated and the board it read (project or repo:<name>) -- read truncated before believing you have the whole board, and page with offset. UNTOUCHED is how many of the MATCHING rows nobody has ever moved, and it is the number that stops the usual mistake: an issue nobody has moved reads status open with status_changed 0, because open is what an untou","inputSchema":{"type":"object","required":["org","project"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"offset":{"type":"integer"},"status":{"type":"string"},"project":{"type":"string"}}},"logicalName":"issue_list","displayName":"issue_list","title":"issue_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"issue_get","description":"One issue: its title, body, author, status, who last moved that status, the board it lives on, and a COUNT of its comments. It does NOT carry the discussion -- comment_list answers that, and windows it, because an old issue's thread is unbounded and this answer is not. READ THAT COUNT BEFORE YOU ACT ON THE BODY: this answer looks complete, and a body ending in a state section reads exactly like the current state of the work, but a comment can already have refuted it. A non-zero comments means th","inputSchema":{"type":"object","required":["org","project","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"issue_get","displayName":"issue_get","title":"issue_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"issue_delete","description":"Delete an issue INTO YOUR BIN, not away: the answer states the date it will be purged on, and bin_restore puts it back until then - with its status, assignee and comments exactly as they were, because nothing was moved. Its comments, state and pin go with it at the purge. Whoever may move an issue's status may delete it: a board is a shared thing, and an author-only rule would leave nobody able to tidy up after an agent that has gone.","inputSchema":{"type":"object","required":["org","project","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"issue_delete","displayName":"issue_delete","title":"issue_delete","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"comment_create","description":"Write a comment on an issue OR a pull request -- both, because they share one discussion table (D42), which is why this is not called issue_something. This is where you say WHAT YOU CHANGED AND HOW IT WAS VERIFIED before moving work to review: a reviewer who finds an issue in review with nothing to read is being asked to take your word for it. Read the thread back with comment_list. A target that does not exist is REFUSED with issue not found; until 2026-09-20 such a comment was accepted and sto","inputSchema":{"type":"object","required":["org","project","number","body"],"properties":{"org":{"type":"string"},"body":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"comment_create","displayName":"comment_create","title":"comment_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"comment_list","description":"The discussion on one issue OR one pull request, oldest first. WINDOWED: 100 comments by default and 500 at most, and the answer states returned, total and truncated -- read truncated before believing you have the whole thread, and page with offset. A target that does not exist is REFUSED rather than answered with an empty list: no comments and no such issue are both zero rows, and only a refusal tells them apart. Omit repo for a PROJECT issue.","inputSchema":{"type":"object","required":["org","project","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"number":{"type":"integer"},"offset":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"comment_list","displayName":"comment_list","title":"comment_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"issue_update","description":"Move an issue's STATUS, its assignee, or both - this is how a task is tracked, because an issue carrying a status IS one. Pass at least one of them: an update that names neither is refused rather than answering ok to nothing. An omitted assignee KEEPS the stored one and an empty assignee CLEARS it. The answer is read back from storage, so 'moved':false and an older status_changed mean nothing needed doing.","inputSchema":{"type":"object","required":["org","project","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"status":{"type":"string"},"project":{"type":"string"},"assignee":{"type":"string"}}},"logicalName":"issue_update","displayName":"issue_update","title":"issue_update","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_create","description":"Open a pull request from head into base. Both must be refs this repository advertises and they must be DIFFERENT branches. It only proposes: nothing is merged here, and the answer carries the number the daemon assigned -- a number from the SAME sequence issues draw from, so it names this pull request and nothing else in the repository. Its discussion is comment_create and comment_list, which take an issue or a pull request alike.","inputSchema":{"type":"object","required":["org","project","repo","title","base","head"],"properties":{"org":{"type":"string"},"base":{"type":"string"},"body":{"type":"string"},"head":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"pr_create","displayName":"pr_create","title":"pr_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_diff","description":"Every file a pull request changes, with counts and NO patches; ask pr_file_diff for the ones that matter","inputSchema":{"type":"object","required":["org","project","repo","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"pr_diff","displayName":"pr_diff","title":"pr_diff","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_file_diff","description":"One file's patch from a pull request, windowed; the answer states lines, returned and truncated","inputSchema":{"type":"object","required":["org","project","repo","number","path"],"properties":{"org":{"type":"string"},"path":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"number":{"type":"integer"},"offset":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"pr_file_diff","displayName":"pr_file_diff","title":"pr_file_diff","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_get","description":"One pull request: its state, title, body, base, head and head commit -- and, once it is merged, who merged it, when, and the merge commit. It carries no discussion: comment_list answers that, for a pull request exactly as for an issue.","inputSchema":{"type":"object","required":["org","project","repo","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"pr_get","displayName":"pr_get","title":"pr_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_list","description":"The pull requests of one repository. state narrows the list; omitting it answers every state.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"state":{"type":"string"},"project":{"type":"string"}}},"logicalName":"pr_list","displayName":"pr_list","title":"pr_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_status","description":"A CI run and its jobs: what was scheduled, at which commit, and how each job ended (read kroy://ci first: the seven outcome words, partial, and the report rows). Omit run for the LATEST run on this repository. A repository with CI enabled and nothing ever pushed has no runs, which is not a failure.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"run":{"type":"integer"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_status","displayName":"ci_status","title":"ci_status","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_log","description":"One job's output, from one run. Both numbers are required -- a job number is meaningful only inside its run, which ci_status names. Without match it answers the log's tail; with match (1..128 bytes, a case-folded substring) it searches the WHOLE log and answers the matching lines with their line numbers, at most 200, and says how many matched. This is a job's log; commit_log is the history and audit_list is who did what.","inputSchema":{"type":"object","required":["org","project","repo","run","job"],"properties":{"job":{"type":"integer"},"org":{"type":"string"},"run":{"type":"integer"},"repo":{"type":"string"},"match":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_log","displayName":"ci_log","title":"ci_log","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_series","description":"One declared [[metric]] series of a repository, NEWEST first: each point's run, job, commit, runner, toolchain, value (exact decimal, never a float) and unit. Ask it whether a change cost anything and which commit bent a curve. Compare points only on the SAME runner and the SAME toolchain -- ci_status's metric rows already do, and say not_compared when the toolchain moved. runner narrows to one machine; limit is 1..200 (default 50); truncated says whether older points exist.","inputSchema":{"type":"object","required":["org","project","repo","name"],"properties":{"org":{"type":"string"},"name":{"type":"string"},"repo":{"type":"string"},"limit":{"type":"integer"},"runner":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_series","displayName":"ci_series","title":"ci_series","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_environments","description":"The organization's deploy ENVIRONMENTS -- each created by its first [[deploy]] job -- with tier (production, staging, testing, development, other), URL, and current: the deployment that last PASSED (repo, run, job_index, commit, at). A failed deploy is history, never the state. Give env to get that environment's deployments newest first, each with outcome, runner and cause; truncated says whether older ones exist. Members only.","inputSchema":{"type":"object","required":["org"],"properties":{"env":{"type":"string"},"org":{"type":"string"}}},"logicalName":"ci_environments","displayName":"ci_environments","title":"ci_environments","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_runners","description":"The organization's CI RUNNERS and what each is doing: state (idle, busy with the repo/run/job it holds, lost -- silent past the 90 s heartbeat TTL, unseen -- registered and never heard from, disabled), last_seen, the peer address the forge saw (a proxy's, behind one), the build it says it runs (sha256, toolchain, impl, os, arch, serial, host -- the runner's own account), what it provides, its env:* environments, and outdated: true when a release with a greater serial is offered for its platform.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"}}},"logicalName":"ci_runners","displayName":"ci_runners","title":"ci_runners","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_resource_status","description":"The organization's declared CI resources (a host, a bench, a shared account -- any tag an operator declared with kroyd resource), each with its state (available, parked, never), its capacity, and WHO HOLDS IT now: a job (repo, run, job) or a person, exclusive or shared, since when, and for a hand's hold its until and whether it is stale. A job that reads queued with a waiting field in ci_status is waiting for one of these. Give tag to ask about one. Members only.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"},"tag":{"type":"string"}}},"logicalName":"ci_resource_status","displayName":"ci_resource_status","title":"ci_resource_status","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_resource_hold","description":"Take a hold on a declared resource BY HAND, under the same rules a job's [[claim]] obeys: exclusive (the default) needs no other holder; shared needs no exclusive holder and room under every tenant bound. A refusal names the holder. ttl (seconds, at most a week) is REQUIRED: past it the hold is shown STALE but never broken by the forge -- release it yourself. While you hold a tag exclusively, every job claiming it waits and says so. Needs write scope and membership.","inputSchema":{"type":"object","required":["org","tag","ttl"],"properties":{"org":{"type":"string"},"tag":{"type":"string"},"ttl":{"type":"integer"},"mode":{"enum":["exclusive","shared"],"type":"string"},"note":{"type":"string"},"max_tenants":{"type":"integer"}}},"logicalName":"ci_resource_hold","displayName":"ci_resource_hold","title":"ci_resource_hold","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_dispatch","description":"Run CI by hand at a commit: a MANUAL run from the workflow AT THAT COMMIT (never the tip's file), on a commit the repository advertises -- any ref's tip or an ancestor of one. job limits the run to one job. A re-run is a dispatch on the same commit: a new run number, the old run untouched. Answers the run number and its state; a refused workflow is still a run, with the reason on it. Needs write scope and membership.","inputSchema":{"type":"object","required":["org","project","repo","commit"],"properties":{"job":{"type":"string"},"org":{"type":"string"},"repo":{"type":"string"},"commit":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_dispatch","displayName":"ci_dispatch","title":"ci_dispatch","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_env_stop","description":"Tear a REVIEW environment down now: one made by [[deploy]] env = '<prefix>/$KROY_REF' (e.g. review/feature-x). Its [[deploy]] action = 'stop' job runs at its last deployment's commit; the environment is stopping, then stopped when the job passes, or orphaned with the reason (no stop job, a refused run, a red job). An orphaned one may be stopped again. A deleted branch does this by itself.","inputSchema":{"type":"object","required":["org","env"],"properties":{"env":{"type":"string"},"org":{"type":"string"}}},"logicalName":"ci_env_stop","displayName":"ci_env_stop","title":"ci_env_stop","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_rollback","description":"Restore an environment's earlier deployment: a new manual run of that deployment's deploy job at its commit, pinned to its run so $KROY_INPUTS are the same artifacts by digest (nothing is rebuilt). to is the deployment number (ci_environments with env lists them). Refused, with the reason, when the deployment did not pass or an input is no longer kept; the environment's approvals and freeze still apply. The new deployment says restores: to.","inputSchema":{"type":"object","required":["org","env","to"],"properties":{"to":{"type":"integer"},"env":{"type":"string"},"org":{"type":"string"}}},"logicalName":"ci_rollback","displayName":"ci_rollback","title":"ci_rollback","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_approve","description":"Approve a QUEUED deploy job into a protected environment. A deploy job whose environment's policy needs N approvals WAITS in the queue (ci_status shows waiting: approval ...) until N approvers have approved it; you may approve if the policy lists you, or - with no list - if you are an admin of the org. Once per person. job is the job's index in the run.","inputSchema":{"type":"object","required":["org","project","repo","run","job"],"properties":{"job":{"type":"integer"},"org":{"type":"string"},"run":{"type":"integer"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_approve","displayName":"ci_approve","title":"ci_approve","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_cancel","description":"Cancel a run: every job still QUEUED ends as not_run with your name as the reason and the run rolls up. A run with a job already on a runner is refused (the operator's kroyd ci-release ends that one); a run with nothing queued is refused too. Needs write scope and membership.","inputSchema":{"type":"object","required":["org","project","repo","run"],"properties":{"org":{"type":"string"},"run":{"type":"integer"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"ci_cancel","displayName":"ci_cancel","title":"ci_cancel","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"ci_resource_release","description":"Release the hold YOU took with ci_resource_hold. A job's hold cannot be released here: it ends with the job's verdict (or kroyd ci-release ends the job). Needs write scope and membership.","inputSchema":{"type":"object","required":["org","tag"],"properties":{"org":{"type":"string"},"tag":{"type":"string"}}},"logicalName":"ci_resource_release","displayName":"ci_resource_release","title":"ci_resource_release","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"pr_merge","description":"Merge a pull request -- and THE DAEMON DECIDES, not the caller. A merge that conflicts answers the conflicted paths and merges nothing; a pull request already merged is refused; base and head at the same commit is nothing to merge. A merge advances the base ref, which schedules CI on it. Needs a write-scope token and membership.","inputSchema":{"type":"object","required":["org","project","repo","number"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"number":{"type":"integer"},"project":{"type":"string"}}},"logicalName":"pr_merge","displayName":"pr_merge","title":"pr_merge","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"org_create","description":"Create an organization -- the outermost container, which owns projects, members and every access decision under it. A name that already exists is refused, never reused. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"logicalName":"org_create","displayName":"org_create","title":"org_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"user_create","description":"Create a user. It mints NO credential: the account exists and can do nothing until token_issue gives it one. A name that already exists is refused. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"logicalName":"user_create","displayName":"user_create","title":"user_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"project_create","description":"Create a project inside an organization. A project groups repositories and owns a MAILBOX and a MEMORY RUNG of its own, so it is the unit agents coordinate on, not just a folder. An existing name is refused and an unknown org is refused. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["org","name"],"properties":{"org":{"type":"string"},"name":{"type":"string"}}},"logicalName":"project_create","displayName":"project_create","title":"project_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"project_delete","description":"Delete a project and EVERYTHING IT OWNS: its issues, letters, agents, memory, description, goal and access rules all go with it. This cannot be undone - there is no bin for a project. It REFUSES while the project holds repositories, with the count, because a repository is a thing of its own and deleting a container must never be a way to delete one by surprise: delete or move them first. A letter addressed to a deleted project is refused afterwards instead of being accepted and read by nobody. N","inputSchema":{"type":"object","required":["org","project"],"properties":{"org":{"type":"string"},"project":{"type":"string"}}},"logicalName":"project_delete","displayName":"project_delete","title":"project_delete","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_delete","description":"Delete a repository: its git objects, issues, pull requests, CI runs, agents, letters, memory and search-index rows all go, and the store file is removed from disk. This cannot be undone. It REFUSES while a runner holds a CI lease on it, with the count, because a build is in flight. Needs the admin scope.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"repo_delete","displayName":"repo_delete","title":"repo_delete","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"description_get","description":"Read the one-line description of an organization, a project or a repository - the DEEPEST thing you name is the one read, so org alone reads the organization, org+project the project, and all three the repository. `describe` is the tool that SETS one. A container with no description answers an empty string: cleared and never-set are one state, deliberately.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"description_get","displayName":"description_get","title":"description_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"org_delete","description":"Delete an organization and everything it still holds: its memory, description, goal, MCP-server registry and EVERY MEMBERSHIP - deleting it REVOKES the access of every person in it. This cannot be undone. It REFUSES while the organization holds projects, with the count, because deleting a container must never be a way to delete a project by surprise: delete them first. Needs the admin scope.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"}}},"logicalName":"org_delete","displayName":"org_delete","title":"org_delete","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"member_add","description":"Give a user membership of an organization. Membership is what every read and write under that organization is decided against, so this is a permission change and it is recorded in the audit log. An unknown org or user is refused by name; a member who is already there is refused rather than duplicated. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["org","user"],"properties":{"org":{"type":"string"},"user":{"type":"string"}}},"logicalName":"member_add","displayName":"member_add","title":"member_add","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"member_remove","description":"Take a user's membership of an organization away. Nothing they wrote is touched -- issues, comments and commits keep their author. It is idempotent: removing somebody who is not a member says so rather than failing. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["org","user"],"properties":{"org":{"type":"string"},"user":{"type":"string"}}},"logicalName":"member_remove","displayName":"member_remove","title":"member_remove","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"token_revoke","description":"Revoke one token by its value. The answer says whether it existed, because revoking a token that never existed is not an error and must not read like one. WARNING: verify a revocation with an AUTHENTICATED call. tools/list needs no authentication and keeps answering a revoked token exactly as before.","inputSchema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}},"logicalName":"token_revoke","displayName":"token_revoke","title":"token_revoke","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"user_set_state","description":"Enable or disable a user. A disabled user authenticates NOWHERE -- not the API, not this face, not git over SSH -- and their tokens stop working without being revoked. It is not deletion: nothing they wrote goes away, and enabling them again restores the account as it was. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["user","enabled"],"properties":{"user":{"type":"string"},"enabled":{"type":"boolean"}}},"logicalName":"user_set_state","displayName":"user_set_state","title":"user_set_state","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"token_issue","description":"Mint a token for a user. scope is r, rw or admin, and it is the only thing that bounds what the holder can do. THE TOKEN IS ANSWERED ONCE AND IS NOT STORED ANYWHERE YOU CAN READ IT BACK -- lose it and the only path is revoke and mint again. Needs the ADMIN scope, and it is recorded in the audit log without the token itself.","inputSchema":{"type":"object","required":["user","scope"],"properties":{"user":{"type":"string"},"scope":{"type":"string"}}},"logicalName":"token_issue","displayName":"token_issue","title":"token_issue","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_create","description":"Create a repository inside a project. visibility must be public or private and is required -- there is no default, because guessing this one wrong is how a private thing becomes readable. alg is sha1 (the default) or sha256 and cannot be changed afterwards; branch names the default branch and is refs/heads/main when omitted. Needs the ADMIN scope.","inputSchema":{"type":"object","required":["org","project","name","visibility"],"properties":{"alg":{"type":"string"},"org":{"type":"string"},"name":{"type":"string"},"branch":{"type":"string"},"project":{"type":"string"},"visibility":{"type":"string"}}},"logicalName":"repo_create","displayName":"repo_create","title":"repo_create","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"goal_list","description":"The goals that apply where you are working, WIDEST FIRST: the organization's, then the project's, then the repository's. Read them before planning - they are what this work is FOR, in the words of the person who decides it. There is no tool that writes one: a goal is edited by a person in the web face, and asking for a change is a conversation, not a call.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"goal_list","displayName":"goal_list","title":"goal_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"description_set","description":"Set the one-line description of an organization, a project or a repository - the DEEPEST thing you name is the one described, so org alone describes the organization, org+project the project, and all three the repository. An empty description CLEARS it. Needs a MANAGE-scope token and membership of the organization.","inputSchema":{"type":"object","required":["org","description"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"description_set","displayName":"description_set","title":"description_set","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_move","description":"Move a repository into another project, optionally in another organization. The repository KEEPS ITS ID and its git objects: issues, PRs, CI runs, agents, mail, memory and feature switches all follow, and clone URLs at the old path stop resolving. Needs an ADMIN-scope token AND membership of both the source and the destination organization. Moving to where it already is, or onto a name the destination already holds, is refused.","inputSchema":{"type":"object","required":["org","project","repo","to_project"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"to_org":{"type":"string"},"project":{"type":"string"},"to_project":{"type":"string"},"cancel_running":{"type":"boolean"}}},"logicalName":"repo_move","displayName":"repo_move","title":"repo_move","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_register","description":"Register an agent on a repository. WITHOUT \"name\" the SERVER MINTS one, <kind>-<host>-<n>, and answers it with a \"remember\" note: save it and pass it back as \"name\" next session. EVERY answer carries a briefing: the unseen letters waiting for this agent as brief rows, the repository's memory KEYS (never their values), and totals for both - so a session start is ONE call. WITH \"name\" the row is refreshed; an unknown name is refused, never created. Stamps last_seen.","inputSchema":{"type":"object","required":["org","project","kind","host"],"properties":{"org":{"type":"string"},"host":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"repo":{"type":"string"},"role":{"type":"string"},"project":{"type":"string"},"takeover":{"type":"boolean"}}},"logicalName":"agent_register","displayName":"agent_register","title":"agent_register","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_list","description":"The agents registered on a repository, with kind, host, role and last_seen; the answer states total, returned and truncated","inputSchema":{"type":"object","required":["org","project"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"agent_list","displayName":"agent_list","title":"agent_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_send","description":"A message for one named agent, for a ROLE, or for everyone. Pass at most ONE of \"to\" and \"to_role\"; neither means any agent on that repository may take it. A role is a QUEUE, not a fan-out: the first agent to ack it takes it from the others. A LETTER NEVER CROSSES A PROJECT -- \"everyone\" means every agent of THIS container and nothing wider, so announcing something to the estate is one send per project and `project_list` enumerates them. The answer names the container it landed in; read it, beca","inputSchema":{"type":"object","required":["org","project","subject"],"properties":{"to":{"type":"string"},"org":{"type":"string"},"body":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"},"subject":{"type":"string"},"to_role":{"type":"string"}}},"logicalName":"agent_send","displayName":"agent_send","title":"agent_send","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_inbox","description":"Messages for one agent, its ROLE's queue and the broadcasts, newest first; each carries audience, taken_by, body_bytes and body_truncated. Pass brief: true for a bodiless listing 200 letters wide with age_days on every row. taken_by is the agent that acked the letter, or \"\" when nobody has taken it. The agent must be registered. Stamps last_seen.","inputSchema":{"type":"object","required":["org","project","agent"],"properties":{"org":{"type":"string"},"seq":{"type":"integer"},"repo":{"type":"string"},"agent":{"type":"string"},"brief":{"type":"boolean"},"before":{"type":"integer"},"status":{"type":"string"},"project":{"type":"string"}}},"logicalName":"agent_inbox","displayName":"agent_inbox","title":"agent_inbox","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_ack","description":"Set one message's state and record WHO TOOK IT; acking to the state it already holds succeeds. seen or done records \"agent\" as the letter's taker; unseen releases it. A letter another agent holds is refused, naming the holder, unless \"takeover\" is true. Stamps last_seen.","inputSchema":{"type":"object","required":["org","project","seq","status","agent"],"properties":{"org":{"type":"string"},"seq":{"type":"integer"},"repo":{"type":"string"},"agent":{"type":"string"},"status":{"type":"string"},"project":{"type":"string"},"takeover":{"type":"boolean"}}},"logicalName":"agent_ack","displayName":"agent_ack","title":"agent_ack","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"letter_delete","description":"Delete one letter from a mailbox. It goes to YOUR BIN, not away: the answer states the date it will be purged on, and bin_restore puts it back until then. Both of the letter's rows travel together, so a restore gives the body back too. A letter another agent holds is deleted anyway -- the holder is information, not a lock.","inputSchema":{"type":"object","required":["org","project","seq"],"properties":{"org":{"type":"string"},"seq":{"type":"integer"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"letter_delete","displayName":"letter_delete","title":"letter_delete","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"agent_retire","description":"Retire an agent on a mailbox: it leaves the working set and stops being a name to address. It is NOT deleted - an agent name appears as taken_by on every letter it ever acked, so the row stays resolvable and only its state changes. Retiring a name nobody registered is REFUSED rather than answered ok, because 'retired something' and 'there was nothing of that name' are different facts.","inputSchema":{"type":"object","required":["org","project","agent"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"agent":{"type":"string"},"project":{"type":"string"}}},"logicalName":"agent_retire","displayName":"agent_retire","title":"agent_retire","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"memory_put","description":"Remember a fact under a KEY at one rung of repo ⊂ project ⊂ org, or in your own user notebook. An existing key is OVERWRITTEN, not versioned, and the answer says which with \"created\". A value is stored RAW: it comes back byte for byte, never normalised.","inputSchema":{"type":"object","required":["scope","key","value"],"properties":{"key":{"type":"string"},"org":{"type":"string"},"repo":{"type":"string"},"scope":{"type":"string"},"value":{"type":"string"},"project":{"type":"string"}}},"logicalName":"memory_put","displayName":"memory_put","title":"memory_put","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"memory_get","description":"Read one remembered fact. WITHOUT \"scope\" the ladder RESOLVES most specific first — your own user note, then repo, then project, then org — and the answer names the rung it came from with \"resolved\": true. WITH a scope it is an EXACT lookup that does not fall back; a miss answers \"found\": false.","inputSchema":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"org":{"type":"string"},"repo":{"type":"string"},"scope":{"type":"string"},"project":{"type":"string"}}},"logicalName":"memory_get","displayName":"memory_get","title":"memory_get","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"resource_upsert","description":"Store or replace one of this server's own documents, the ones a client reads through resources/list and resources/read. kroy://guide is the session workflow every agent is told to read; editing it is how a convention reaches the whole estate at once. Needs the admin scope, because an agent reads these documents AS INSTRUCTIONS.","inputSchema":{"type":"object","required":["uri","text"],"properties":{"uri":{"type":"string"},"name":{"type":"string"},"text":{"type":"string"},"mimeType":{"type":"string"}}},"logicalName":"resource_upsert","displayName":"resource_upsert","title":"resource_upsert","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"resource_forget","description":"Drop a stored document. Forgetting kroy://guide RESTORES the guide shipped in the binary rather than emptying the shelf, so a forge always answers with instructions. Needs the admin scope.","inputSchema":{"type":"object","required":["uri"],"properties":{"uri":{"type":"string"}}},"logicalName":"resource_forget","displayName":"resource_forget","title":"resource_forget","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"mcp_list","description":"The MCP servers an organization has registered: name, transport, url, auth hint and description. This is where an agent looks up the OTHER servers it can talk to. Readable by a member of that organization; an organization you do not belong to answers the same sentence as one that does not exist.","inputSchema":{"type":"object","required":["org"],"properties":{"org":{"type":"string"}}},"logicalName":"mcp_list","displayName":"mcp_list","title":"mcp_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"mcp_upsert","description":"Register an MCP server in an organization's registry, or replace the row of that name. Answers whether it was created or replaced. Needs the admin scope.","inputSchema":{"type":"object","required":["org","name","url"],"properties":{"org":{"type":"string"},"url":{"type":"string"},"name":{"type":"string"},"auth_hint":{"type":"string"},"transport":{"type":"string"}}},"logicalName":"mcp_upsert","displayName":"mcp_upsert","title":"mcp_upsert","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"mcp_forget","description":"Drop a server from an organization's registry. Forgetting one that is not there answers forgotten:false and succeeds. Needs the admin scope.","inputSchema":{"type":"object","required":["org","name"],"properties":{"org":{"type":"string"},"name":{"type":"string"}}},"logicalName":"mcp_forget","displayName":"mcp_forget","title":"mcp_forget","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"bin_list","description":"What is in your bin: every deleted thing, oldest DEADLINE first, each row carrying the date it will be purged on. Deleting anything on this forge puts it here first and it stays for the retention period (30 days unless an administrator changed it). Pass \"user\" only to read somebody else's bin, which needs the admin scope.","inputSchema":{"type":"object","required":[],"properties":{"user":{"type":"string"},"after":{"type":"string"},"limit":{"type":"integer"}}},"logicalName":"bin_list","displayName":"bin_list","title":"bin_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"bin_restore","description":"Put one thing back where it was, byte for byte. The handle comes from bin_list and is opaque. A handle naming a row that is no longer there answers plainly rather than pretending to succeed.","inputSchema":{"type":"object","required":["handle"],"properties":{"user":{"type":"string"},"handle":{"type":"string"}}},"logicalName":"bin_restore","displayName":"bin_restore","title":"bin_restore","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"bin_purge","description":"Destroy one thing in the bin now, ahead of its deadline. THIS IS THE IRREVERSIBLE HALF: after it there is nothing to restore. The handle comes from bin_list.","inputSchema":{"type":"object","required":["handle"],"properties":{"user":{"type":"string"},"handle":{"type":"string"}}},"logicalName":"bin_purge","displayName":"bin_purge","title":"bin_purge","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"bin_retention","description":"How many days a deleted thing waits in the bin before it is purged, for the whole forge. Called with no argument it READS the setting; with \"days\" it sets it, which needs the admin scope. It never reads as zero, because a bin that purges on arrival is not a bin.","inputSchema":{"type":"object","required":[],"properties":{"days":{"type":"integer"}}},"logicalName":"bin_retention","displayName":"bin_retention","title":"bin_retention","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"audit_list","description":"The forge's audit log, oldest first: who did what, through which face, and whether it succeeded, was REFUSED or errored. Answers more:true when rows remain past the limit, so a reader can page by passing the last ts as since. Needs the admin scope -- it names every actor and what they reached for, including what they were refused.","inputSchema":{"type":"object","required":[],"properties":{"limit":{"type":"integer"},"since":{"type":"integer"}}},"logicalName":"audit_list","displayName":"audit_list","title":"audit_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"memory_search","description":"The facts at ONE rung whose KEY or HOOK carries a needle. A fact's HOOK is its first line, which is what this answers with; values are NOT returned. An empty or absent q is every fact at the rung, so this is a superset of memory_list. Matching is case-folded ASCII substring. The answer states total, returned and window when it was clipped.","inputSchema":{"type":"object","required":["scope"],"properties":{"q":{"type":"string"},"org":{"type":"string"},"repo":{"type":"string"},"scope":{"type":"string"},"project":{"type":"string"}}},"logicalName":"memory_search","displayName":"memory_search","title":"memory_search","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"memory_list","description":"Every key remembered at ONE rung, in key order, optionally narrowed by a prefix. Values are NOT returned; each row states its value's true size in \"bytes\". The answer states total, returned and window when it was clipped.","inputSchema":{"type":"object","required":["scope"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"scope":{"type":"string"},"prefix":{"type":"string"},"project":{"type":"string"}}},"logicalName":"memory_list","displayName":"memory_list","title":"memory_list","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"memory_forget","description":"Drop one remembered fact. Forgetting a key that is not there SUCCEEDS and answers \"forgotten\": false — it is a statement of fact, not an error, so cleanup is idempotent.","inputSchema":{"type":"object","required":["scope","key"],"properties":{"key":{"type":"string"},"org":{"type":"string"},"repo":{"type":"string"},"scope":{"type":"string"},"project":{"type":"string"}}},"logicalName":"memory_forget","displayName":"memory_forget","title":"memory_forget","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_features","description":"Which collaboration features this repository has been configured AWAY from the default. The answer lists ONLY the rows that exist, each with when it was flipped and by whom; a repository nobody has configured answers [] and everything is enabled.","inputSchema":{"type":"object","required":["org","project","repo"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"project":{"type":"string"}}},"logicalName":"repo_features","displayName":"repo_features","title":"repo_features","annotations":{"untrustedContentHint":true,"readOnlyHint":true}},{"name":"repo_feature_set","description":"Turn one collaboration feature on or off for a repository. Disabling HIDES and never deletes: the agent mail and the memory rows stay, the tools refuse, and re-enabling gives every byte back. Needs write scope on that repository.","inputSchema":{"type":"object","required":["org","project","repo","feature","enabled"],"properties":{"org":{"type":"string"},"repo":{"type":"string"},"enabled":{"type":"boolean"},"feature":{"type":"string"},"project":{"type":"string"}}},"logicalName":"repo_feature_set","displayName":"repo_feature_set","title":"repo_feature_set","annotations":{"untrustedContentHint":true,"readOnlyHint":true}}],"toolSource":"directory_preview","agentAction":"both","installLinks":[{"id":"cursor","label":"Cursor","href":"cursor://anysphere.cursor-deeplink/mcp/install?name=kroy&config=eyJ1cmwiOiAiaHR0cHM6Ly9rZ2l0Lm5ldC9tY3AifQ%3D%3D"},{"id":"vscode","label":"VS Code","href":"vscode:mcp/install?%7B%22name%22%3A%22kroy%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fkgit.net%2Fmcp%22%7D"},{"id":"vscode-insiders","label":"VS Code Insiders","href":"vscode-insiders:mcp/install?%7B%22name%22%3A%22kroy%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fkgit.net%2Fmcp%22%7D"},{"id":"claude-web","label":"Claude.ai","href":"https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=kroy&connectorUrl=https%3A%2F%2Fkgit.net%2Fmcp"},{"id":"codex","label":"Codex","copyText":"codex mcp add \"kroy\" --url \"https://kgit.net/mcp\""},{"id":"chatgpt","label":"ChatGPT","href":"https://www.mcpbundles.com/docs/integrations/chatgpt"}],"catalogUrl":"https://www.mcpbundles.com/api/directory/v1/servers/kgit-mcp-976e359841","callUrl":"https://www.mcpbundles.com/api/directory/v1/servers/kgit-mcp-976e359841/tools/{tool}","mcpServerUrl":"https://kgit.net/mcp","liveCatalogUrl":"https://www.mcpbundles.com/api/directory/v1/servers/kgit-mcp-976e359841?live=1"}