diff --git a/pkg/github/__toolsnaps__/search_commits_typed.snap b/pkg/github/__toolsnaps__/search_commits_typed.snap
new file mode 100644
index 0000000000..dba069c8fa
--- /dev/null
+++ b/pkg/github/__toolsnaps__/search_commits_typed.snap
@@ -0,0 +1,406 @@
+{
+ "annotations": {
+ "idempotentHint": false,
+ "readOnlyHint": true,
+ "title": "Search commits"
+ },
+ "description": "Search for commits across GitHub repositories using GitHub's commit search syntax. Useful for finding specific changes, authors, or messages across one or many repositories. Searches the default branch only.",
+ "icons": [
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABTklEQVRIie2UPUvDUBSGn5PW2qnYwUXExWhNpY2CUKT+BB10E3R0dnbrppuKLgouHbr5X5qlKRIFB+cuguBHj4O05KYfNsVJ+m7n3Hue54ZcrhDKQqGQTX1YVwg7QIbx0gh8b7VTJMMrqS+5RtgD7oDX2GhhC6UcbhkCVLZVuX1sesex4YCdX6uAGgIrsicjlrTGgQ9KVPDnmQgmgongPwgkXNiOq8ADMAtkx4UGvtflJvus20ANeIlN/vW5/kkt8L3D2HD6P9dRgSI8dQcc9w1IR3acBE3vbFSp8ZMVnoFSqJ/unZDe3pAYXyDIJarn9opbDZrewaAh2y7Oy5S1r6h5QG2Xxbw3piDw6xe244oKyxFmC5ihc+tS1qaqngKJyAEBGmZvSGzHVYT790T7aPozsaFoFZGboFGvDJsbOYuOuxuuc7n1uaV8sRSH8Q1DUVLnYLty3gAAAABJRU5ErkJggg==",
+ "theme": "light"
+ },
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA+ElEQVRIie2WLU5DQRRGzwUEirQCQ9BsoSGtZQHgSFgIsg4JXQCGP8V2QCBIEATZkJDgOJi+MJnMo30TFHmfmzvzfeeKyZ2BROpQvVHfrddDmhkZ4BY4Ai6BD7prAowjIoq7i85nFcGNf6qa1tayM1vAvBZQUg74c/WAHtAD/gMgn6YCT8A2MKwOTaZpCfAF3AGvFdlLx7XqdUVw4186rgWeE8Nn4cU67QLNAS/ASG3qmwVPqdaqjWw9A86BK+CkzaTuAseFBse/AiLiQg1gLzs3Bwb8XIp94AxYL/Af2xordap6v/htHKhv6nTlgBUAh9l6Rx11yfgG8ne/zwh2OysAAAAASUVORK5CYII=",
+ "theme": "dark"
+ }
+ ],
+ "inputSchema": {
+ "properties": {
+ "order": {
+ "description": "Sort order",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "type": "string"
+ },
+ "page": {
+ "description": "Page number for pagination (min 1)",
+ "minimum": 1,
+ "type": "number"
+ },
+ "perPage": {
+ "description": "Results per page for pagination (min 1, max 100)",
+ "maximum": 100,
+ "minimum": 1,
+ "type": "number"
+ },
+ "query": {
+ "description": "Commit search query (GitHub commit search REST). Searches commit messages on the default branch only. Scope the search with `repo:owner/repo`, `org:`, or `user:` (queries without a scope qualifier match across all of GitHub and are usually not what you want). Other qualifiers: `author:`, `committer:`, `author-name:`, `committer-name:`, `author-email:`, `committer-email:`, `author-date:`, `committer-date:` (supports `\u003e`, `\u003c`, `\u003e=`, `\u003c=`, and `YYYY-MM-DD..YYYY-MM-DD` ranges), `merge:true|false`, `hash:`, `tree:`, `parent:`, `is:public`. Examples: `repo:owner/repo fix panic`; `org:github author:defunkt committer-date:\u003e=2024-01-01`; `\"refactor cache\" repo:o/r`; `hash:abc1234 repo:o/r`.",
+ "type": "string"
+ },
+ "sort": {
+ "description": "Sort by author or committer date (defaults to best match)",
+ "enum": [
+ "author-date",
+ "committer-date"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "query"
+ ],
+ "type": "object"
+ },
+ "name": "search_commits",
+ "outputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": "boolean"
+ },
+ "items": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "author": {
+ "additionalProperties": false,
+ "properties": {
+ "avatar_url": {
+ "type": "string"
+ },
+ "details": {
+ "additionalProperties": false,
+ "properties": {
+ "bio": {
+ "type": "string"
+ },
+ "blog": {
+ "type": "string"
+ },
+ "company": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "followers": {
+ "type": "integer"
+ },
+ "following": {
+ "type": "integer"
+ },
+ "hireable": {
+ "type": "boolean"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owned_private_repos": {
+ "type": "integer"
+ },
+ "private_gists": {
+ "type": "integer"
+ },
+ "public_gists": {
+ "type": "integer"
+ },
+ "public_repos": {
+ "type": "integer"
+ },
+ "total_private_repos": {
+ "type": "integer"
+ },
+ "twitter_username": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "public_repos",
+ "public_gists",
+ "followers",
+ "following",
+ "created_at",
+ "updated_at"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "id": {
+ "type": "integer"
+ },
+ "login": {
+ "type": "string"
+ },
+ "profile_url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "login"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "commit": {
+ "additionalProperties": false,
+ "properties": {
+ "author": {
+ "additionalProperties": false,
+ "properties": {
+ "date": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "committer": {
+ "additionalProperties": false,
+ "properties": {
+ "date": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "message"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "committer": {
+ "additionalProperties": false,
+ "properties": {
+ "avatar_url": {
+ "type": "string"
+ },
+ "details": {
+ "additionalProperties": false,
+ "properties": {
+ "bio": {
+ "type": "string"
+ },
+ "blog": {
+ "type": "string"
+ },
+ "company": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "followers": {
+ "type": "integer"
+ },
+ "following": {
+ "type": "integer"
+ },
+ "hireable": {
+ "type": "boolean"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owned_private_repos": {
+ "type": "integer"
+ },
+ "private_gists": {
+ "type": "integer"
+ },
+ "public_gists": {
+ "type": "integer"
+ },
+ "public_repos": {
+ "type": "integer"
+ },
+ "total_private_repos": {
+ "type": "integer"
+ },
+ "twitter_username": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "public_repos",
+ "public_gists",
+ "followers",
+ "following",
+ "created_at",
+ "updated_at"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "id": {
+ "type": "integer"
+ },
+ "login": {
+ "type": "string"
+ },
+ "profile_url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "login"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "files": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "additions": {
+ "type": "integer"
+ },
+ "changes": {
+ "type": "integer"
+ },
+ "deletions": {
+ "type": "integer"
+ },
+ "filename": {
+ "type": "string"
+ },
+ "patch": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "filename"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "html_url": {
+ "type": "string"
+ },
+ "repository": {
+ "additionalProperties": false,
+ "properties": {
+ "full_name": {
+ "type": "string"
+ },
+ "html_url": {
+ "type": "string"
+ },
+ "private": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "full_name"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "sha": {
+ "type": "string"
+ },
+ "stats": {
+ "additionalProperties": false,
+ "properties": {
+ "additions": {
+ "type": "integer"
+ },
+ "deletions": {
+ "type": "integer"
+ },
+ "total": {
+ "type": "integer"
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ }
+ },
+ "required": [
+ "sha",
+ "html_url"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total_count",
+ "incomplete_results",
+ "items"
+ ],
+ "type": "object"
+ }
+}
\ No newline at end of file
diff --git a/pkg/github/__toolsnaps__/search_orgs_typed.snap b/pkg/github/__toolsnaps__/search_orgs_typed.snap
new file mode 100644
index 0000000000..f7340687e9
--- /dev/null
+++ b/pkg/github/__toolsnaps__/search_orgs_typed.snap
@@ -0,0 +1,173 @@
+{
+ "annotations": {
+ "idempotentHint": false,
+ "readOnlyHint": true,
+ "title": "Search organizations"
+ },
+ "description": "Find GitHub organizations by name, location, or other organization metadata. Ideal for discovering companies, open source foundations, or teams.",
+ "icons": [
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABqElEQVRIidWUsW4TQRCGv9kYFzwCRCDEUuxJsCelyiMAXSSs1Cn8ChQg4QiQeANIpHQoQumg4Q1IGxvJviiLKOIWOgQx8g1FOFux1z58SoTyVzvz7843ezs6uGBJsbjj0oeKbgHXF6qg9NXkzS/dzx9jdm20T/UNwnfg7YItPhA1W8CNuQCEZUR2QvegtUh9m6S/UH02yzeLFKuiKMAmvmGdP7FJ+gjAOt+xzndiXplq0exAP8kVea6DfB9AVF7N8ioBQuj0gRdFfJQd7M7yKgGsvbesddZlwLsQOn2b+AZA6Lb3Jr0yQPyR62ZVVF5SN6sAKE9F5UnUm9C1lZWr0ZrWebVJ2irraOpckras83q69hvW+R+3k7v359+gomr5yXvgUNS8nguoOqZZln1D5ANwcwSNtnKZxvT//CrOU/E3+Cub+AbKrTNJ4WvotvfOBYCyCyxN5IbAPwPKPtESIpuh15bQawsim1PAEo1voPRB16zzP8sOWecfj8/pGvB7lDuNj6cAavKm5GYbYTzzMFTNsyKQPD9UkSGc2VOoyB2r0WZZk5dHfwA6M7v5DAVu0gAAAABJRU5ErkJggg==",
+ "theme": "light"
+ },
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABLklEQVRIic2VsUoDQRCGvzVWVj5AUHwM38BoFzBo6zMIFlokqOAb+AYp7LTwEbRPZyWYtGIlIiqfhSssYe8uJ2f0a46ZuZ1/Z2duD+aFuqVOrM9Y7RTlDYnAGHgCrmvubRNYDiGsVFWg2q+ZHLWvWhRfqJuwLlkBtae+qtvRHqmjXKyKxQL/DXAM3Eb7rCQ2G3PtgdpW99V2tHtqLxeroqjJ68BpfAIcAYcFsenNLWUzNnFE6p76nH54TY/pJXAHnJcK/HRMQwiPwBWw+u379THNCoQQJsBJYg+LYlX8zVXRJEU9AL4aCqxNue9DCBeNCABDoDXl+wBmFqg6ohYwCBFgkBEsJa1gAnTVl6pF6kFidoG3xNcFxrlFnfh/TXlXd5J3dqOvjAd1o06V/5tPH0lBqyqxKbkAAAAASUVORK5CYII=",
+ "theme": "dark"
+ }
+ ],
+ "inputSchema": {
+ "properties": {
+ "order": {
+ "description": "Sort order",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "type": "string"
+ },
+ "page": {
+ "description": "Page number for pagination (min 1)",
+ "minimum": 1,
+ "type": "number"
+ },
+ "perPage": {
+ "description": "Results per page for pagination (min 1, max 100)",
+ "maximum": 100,
+ "minimum": 1,
+ "type": "number"
+ },
+ "query": {
+ "description": "Organization search query. Examples: 'microsoft', 'location:california', 'created:\u003e=2025-01-01'. Search is automatically scoped to type:org.",
+ "type": "string"
+ },
+ "sort": {
+ "description": "Sort field by category",
+ "enum": [
+ "followers",
+ "repositories",
+ "joined"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "query"
+ ],
+ "type": "object"
+ },
+ "name": "search_orgs",
+ "outputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": "boolean"
+ },
+ "items": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "avatar_url": {
+ "type": "string"
+ },
+ "details": {
+ "additionalProperties": false,
+ "properties": {
+ "bio": {
+ "type": "string"
+ },
+ "blog": {
+ "type": "string"
+ },
+ "company": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "followers": {
+ "type": "integer"
+ },
+ "following": {
+ "type": "integer"
+ },
+ "hireable": {
+ "type": "boolean"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owned_private_repos": {
+ "type": "integer"
+ },
+ "private_gists": {
+ "type": "integer"
+ },
+ "public_gists": {
+ "type": "integer"
+ },
+ "public_repos": {
+ "type": "integer"
+ },
+ "total_private_repos": {
+ "type": "integer"
+ },
+ "twitter_username": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "public_repos",
+ "public_gists",
+ "followers",
+ "following",
+ "created_at",
+ "updated_at"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "id": {
+ "type": "integer"
+ },
+ "login": {
+ "type": "string"
+ },
+ "profile_url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "login"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total_count",
+ "incomplete_results",
+ "items"
+ ],
+ "type": "object"
+ }
+}
\ No newline at end of file
diff --git a/pkg/github/__toolsnaps__/search_repositories.snap b/pkg/github/__toolsnaps__/search_repositories.snap
index 23b1d5e839..9ba57e968a 100644
--- a/pkg/github/__toolsnaps__/search_repositories.snap
+++ b/pkg/github/__toolsnaps__/search_repositories.snap
@@ -51,5 +51,2642 @@
],
"type": "object"
},
- "name": "search_repositories"
+ "name": "search_repositories",
+ "outputSchema": {
+ "$defs": {
+ "searchPropertyValue": {
+ "anyOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "items": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "array"
+ },
+ {
+ "additionalProperties": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "object"
+ }
+ ]
+ },
+ "searchRepository": {
+ "additionalProperties": false,
+ "properties": {
+ "allow_auto_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_forking": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_merge_commit": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_rebase_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_squash_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_update_branch": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archive_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "archived": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "assignees_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "auto_init": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "blobs_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "branches_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "clone_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "code_of_conduct": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "key": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "collaborators_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "comments_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "commits_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "compare_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "contents_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "contributors_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "custom_properties": {
+ "additionalProperties": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "object"
+ },
+ "default_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "delete_branch_on_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deployments_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "downloads_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "fork": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "forks_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "forks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "full_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_commits_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_refs_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_tags_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gitignore_template": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "has_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_downloads": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_pull_requests": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_wiki": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "homepage": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_template": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issue_comment_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "issue_events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "keys_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "labels_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "language": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "languages_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "license": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "conditions": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "featured": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "implementation": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "key": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "limitations": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "permissions": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "spdx_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "license_template": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "master_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merge_commit_message": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merge_commit_title": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merges_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "milestones_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "mirror_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "network_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notifications_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "open_issues": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "open_issues_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "organization": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archived_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "billing_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_settings": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "dependabot_alerts_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependabot_security_updates_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependency_graph_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deploy_keys_enabled_for_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "display_commenter_full_name_setting_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "has_organization_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_repository_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_verified": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_allowed_repository_creation_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_can_change_repo_visibility": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_internal_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_teams": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_fork_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_invite_outside_collaborators": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_view_dependency_insights": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "readers_can_create_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_validity_checks_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_requirement_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "owner": {
+ "additionalProperties": false,
+ "properties": {
+ "assignment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "bio": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "business_plus": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "followers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gists_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gravatar_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "hireable": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "inherited": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "inherited_from": {
+ "items": {
+ "$ref": "#/$defs/team",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "ldap_dn": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notification_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "organizations_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": false,
+ "properties": {
+ "admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "maintain": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "push": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "triage": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "received_events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "site_admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "starred_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscriptions_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "suspended_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "text_matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "fragment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "indices": {
+ "items": {
+ "type": "integer"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "text": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "object_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "object_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "property": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_authentication": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "user_view_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "parent": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": false,
+ "properties": {
+ "admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "maintain": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "push": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "triage": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull_request_creation_policy": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "pulls_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "pushed_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "releases_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "security_and_analysis": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "code_security": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "dependabot_security_updates": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning_push_protection": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning_validity_checks": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "size": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "source": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "squash_merge_commit_message": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "squash_merge_commit_title": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "ssh_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "stargazers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "stargazers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "statuses_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscribers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "subscribers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscription_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "svn_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "tags_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "team_id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "teams_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "template_repository": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "text_matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "fragment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "indices": {
+ "items": {
+ "type": "integer"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "text": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "object_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "object_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "property": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "topics": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "trees_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "use_squash_pr_title_as_default": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "visibility": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "watchers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "watchers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "team": {
+ "additionalProperties": false,
+ "properties": {
+ "access_source": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "assignment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "ldap_dn": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notification_setting": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "organization": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archived_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "billing_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_settings": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "dependabot_alerts_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependabot_security_updates_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependency_graph_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deploy_keys_enabled_for_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "display_commenter_full_name_setting_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "has_organization_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_repository_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_verified": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_allowed_repository_creation_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_can_change_repo_visibility": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_internal_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_teams": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_fork_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_invite_outside_collaborators": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_view_dependency_insights": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "readers_can_create_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_validity_checks_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_requirement_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "parent": {
+ "$ref": "#/$defs/team",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": {
+ "type": "boolean"
+ },
+ "type": "object"
+ },
+ "privacy": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "repos_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "repositories_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "slug": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ }
+ },
+ "anyOf": [
+ {
+ "type": "null"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": "boolean"
+ },
+ "items": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "archived": {
+ "type": "boolean"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "default_branch": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "fork": {
+ "type": "boolean"
+ },
+ "forks_count": {
+ "type": "integer"
+ },
+ "full_name": {
+ "type": "string"
+ },
+ "html_url": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "language": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "open_issues_count": {
+ "type": "integer"
+ },
+ "private": {
+ "type": "boolean"
+ },
+ "stargazers_count": {
+ "type": "integer"
+ },
+ "topics": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "full_name",
+ "html_url",
+ "stargazers_count",
+ "forks_count",
+ "open_issues_count",
+ "private",
+ "fork",
+ "archived"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total_count",
+ "incomplete_results",
+ "items"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "items": {
+ "items": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": "object"
+ }
+ ]
+ }
}
\ No newline at end of file
diff --git a/pkg/github/__toolsnaps__/search_repositories_typed.snap b/pkg/github/__toolsnaps__/search_repositories_typed.snap
new file mode 100644
index 0000000000..547aba69dc
--- /dev/null
+++ b/pkg/github/__toolsnaps__/search_repositories_typed.snap
@@ -0,0 +1,2704 @@
+{
+ "annotations": {
+ "idempotentHint": false,
+ "readOnlyHint": true,
+ "title": "Search repositories"
+ },
+ "description": "Find GitHub repositories by name, description, readme, topics, or other metadata. Perfect for discovering projects, finding examples, or locating specific repositories across GitHub.",
+ "icons": [
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABTklEQVRIie2UPUvDUBSGn5PW2qnYwUXExWhNpY2CUKT+BB10E3R0dnbrppuKLgouHbr5X5qlKRIFB+cuguBHj4O05KYfNsVJ+m7n3Hue54ZcrhDKQqGQTX1YVwg7QIbx0gh8b7VTJMMrqS+5RtgD7oDX2GhhC6UcbhkCVLZVuX1sesex4YCdX6uAGgIrsicjlrTGgQ9KVPDnmQgmgongPwgkXNiOq8ADMAtkx4UGvtflJvus20ANeIlN/vW5/kkt8L3D2HD6P9dRgSI8dQcc9w1IR3acBE3vbFSp8ZMVnoFSqJ/unZDe3pAYXyDIJarn9opbDZrewaAh2y7Oy5S1r6h5QG2Xxbw3piDw6xe244oKyxFmC5ihc+tS1qaqngKJyAEBGmZvSGzHVYT790T7aPozsaFoFZGboFGvDJsbOYuOuxuuc7n1uaV8sRSH8Q1DUVLnYLty3gAAAABJRU5ErkJggg==",
+ "theme": "light"
+ },
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA+ElEQVRIie2WLU5DQRRGzwUEirQCQ9BsoSGtZQHgSFgIsg4JXQCGP8V2QCBIEATZkJDgOJi+MJnMo30TFHmfmzvzfeeKyZ2BROpQvVHfrddDmhkZ4BY4Ai6BD7prAowjIoq7i85nFcGNf6qa1tayM1vAvBZQUg74c/WAHtAD/gMgn6YCT8A2MKwOTaZpCfAF3AGvFdlLx7XqdUVw4186rgWeE8Nn4cU67QLNAS/ASG3qmwVPqdaqjWw9A86BK+CkzaTuAseFBse/AiLiQg1gLzs3Bwb8XIp94AxYL/Af2xordap6v/htHKhv6nTlgBUAh9l6Rx11yfgG8ne/zwh2OysAAAAASUVORK5CYII=",
+ "theme": "dark"
+ }
+ ],
+ "inputSchema": {
+ "properties": {
+ "minimal_output": {
+ "default": true,
+ "description": "Return minimal repository information (default: true). When false, returns full GitHub API repository objects.",
+ "type": "boolean"
+ },
+ "order": {
+ "description": "Sort order",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "type": "string"
+ },
+ "page": {
+ "description": "Page number for pagination (min 1)",
+ "minimum": 1,
+ "type": "number"
+ },
+ "perPage": {
+ "description": "Results per page for pagination (min 1, max 100)",
+ "maximum": 100,
+ "minimum": 1,
+ "type": "number"
+ },
+ "query": {
+ "description": "Repository search query. Examples: 'machine learning in:name stars:\u003e1000 language:python', 'topic:react', 'user:facebook'. Supports advanced search syntax for precise filtering.",
+ "type": "string"
+ },
+ "sort": {
+ "description": "Sort repositories by field, defaults to best match",
+ "enum": [
+ "stars",
+ "forks",
+ "help-wanted-issues",
+ "updated"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "query"
+ ],
+ "type": "object"
+ },
+ "name": "search_repositories",
+ "outputSchema": {
+ "$defs": {
+ "searchPropertyValue": {
+ "anyOf": [
+ {
+ "type": "null"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "items": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "array"
+ },
+ {
+ "additionalProperties": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "object"
+ }
+ ]
+ },
+ "searchRepository": {
+ "additionalProperties": false,
+ "properties": {
+ "allow_auto_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_forking": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_merge_commit": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_rebase_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_squash_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "allow_update_branch": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archive_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "archived": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "assignees_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "auto_init": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "blobs_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "branches_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "clone_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "code_of_conduct": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "key": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "collaborators_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "comments_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "commits_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "compare_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "contents_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "contributors_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "custom_properties": {
+ "additionalProperties": {
+ "$ref": "#/$defs/searchPropertyValue"
+ },
+ "type": "object"
+ },
+ "default_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "delete_branch_on_merge": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deployments_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "downloads_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "fork": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "forks_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "forks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "full_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_commits_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_refs_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_tags_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "git_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gitignore_template": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "has_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_downloads": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_pull_requests": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_wiki": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "homepage": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_template": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issue_comment_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "issue_events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "keys_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "labels_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "language": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "languages_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "license": {
+ "additionalProperties": false,
+ "properties": {
+ "body": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "conditions": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "featured": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "implementation": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "key": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "limitations": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "permissions": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "spdx_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "license_template": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "master_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merge_commit_message": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merge_commit_title": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "merges_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "milestones_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "mirror_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "network_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notifications_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "open_issues": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "open_issues_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "organization": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archived_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "billing_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_settings": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "dependabot_alerts_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependabot_security_updates_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependency_graph_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deploy_keys_enabled_for_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "display_commenter_full_name_setting_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "has_organization_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_repository_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_verified": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_allowed_repository_creation_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_can_change_repo_visibility": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_internal_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_teams": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_fork_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_invite_outside_collaborators": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_view_dependency_insights": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "readers_can_create_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_validity_checks_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_requirement_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "owner": {
+ "additionalProperties": false,
+ "properties": {
+ "assignment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "bio": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "business_plus": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "followers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gists_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "gravatar_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "hireable": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "inherited": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "inherited_from": {
+ "items": {
+ "$ref": "#/$defs/team",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "ldap_dn": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notification_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "organizations_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": false,
+ "properties": {
+ "admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "maintain": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "push": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "triage": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "received_events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "site_admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "starred_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscriptions_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "suspended_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "text_matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "fragment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "indices": {
+ "items": {
+ "type": "integer"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "text": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "object_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "object_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "property": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_authentication": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "user_view_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "parent": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": false,
+ "properties": {
+ "admin": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "maintain": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "push": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "triage": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "pull_request_creation_policy": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "pulls_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "pushed_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "releases_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "role_name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "security_and_analysis": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "code_security": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "dependabot_security_updates": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning_push_protection": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "secret_scanning_validity_checks": {
+ "additionalProperties": false,
+ "properties": {
+ "status": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "size": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "source": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "squash_merge_commit_message": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "squash_merge_commit_title": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "ssh_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "stargazers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "stargazers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "statuses_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscribers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "subscribers_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "subscription_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "svn_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "tags_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "team_id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "teams_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "template_repository": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "text_matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "fragment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "matches": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "indices": {
+ "items": {
+ "type": "integer"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "text": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "object_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "object_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "property": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "topics": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "trees_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "use_squash_pr_title_as_default": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "visibility": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "watchers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "watchers_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "team": {
+ "additionalProperties": false,
+ "properties": {
+ "access_source": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "assignment": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "ldap_dn": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "notification_setting": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "organization": {
+ "additionalProperties": false,
+ "properties": {
+ "advanced_security_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "archived_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "avatar_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "billing_email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "blog": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "company": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "created_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_branch": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "default_repository_settings": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "dependabot_alerts_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependabot_security_updates_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "dependency_graph_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "deploy_keys_enabled_for_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "description": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "disk_usage": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "display_commenter_full_name_setting_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "email": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "events_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "followers": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "following": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "has_organization_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "has_repository_projects": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "hooks_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "html_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "id": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "is_verified": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "issues_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "location": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "login": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_allowed_repository_creation_type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "members_can_change_repo_visibility": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_internal_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_pages": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_public_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_create_teams": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_issues": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_delete_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_fork_private_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_invite_outside_collaborators": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_can_view_dependency_insights": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "node_id": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "owned_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "plan": {
+ "additionalProperties": false,
+ "properties": {
+ "collaborators": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "filled_seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "name": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "seats": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "space": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "private_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_gists": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "public_members_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "public_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "readers_can_create_discussions": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "repos_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "secret_scanning_push_protection_custom_link_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_push_protection_enabled_for_new_repositories": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "secret_scanning_validity_checks_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "total_private_repos": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "twitter_username": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "two_factor_requirement_enabled": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "updated_at": {
+ "format": "date-time",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "web_commit_signoff_required": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ }
+ },
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "parent": {
+ "$ref": "#/$defs/team",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "permission": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "permissions": {
+ "additionalProperties": {
+ "type": "boolean"
+ },
+ "type": "object"
+ },
+ "privacy": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "repos_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ },
+ "repositories_url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "slug": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "type": {
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ "url": {
+ "type": [
+ "null",
+ "string"
+ ]
+ }
+ },
+ "type": [
+ "object",
+ "null"
+ ]
+ }
+ },
+ "anyOf": [
+ {
+ "type": "null"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": "boolean"
+ },
+ "items": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "archived": {
+ "type": "boolean"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "default_branch": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "fork": {
+ "type": "boolean"
+ },
+ "forks_count": {
+ "type": "integer"
+ },
+ "full_name": {
+ "type": "string"
+ },
+ "html_url": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "language": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "open_issues_count": {
+ "type": "integer"
+ },
+ "private": {
+ "type": "boolean"
+ },
+ "stargazers_count": {
+ "type": "integer"
+ },
+ "topics": {
+ "items": {
+ "type": "string"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "full_name",
+ "html_url",
+ "stargazers_count",
+ "forks_count",
+ "open_issues_count",
+ "private",
+ "fork",
+ "archived"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total_count",
+ "incomplete_results",
+ "items"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": [
+ "null",
+ "boolean"
+ ]
+ },
+ "items": {
+ "items": {
+ "$ref": "#/$defs/searchRepository",
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": [
+ "null",
+ "integer"
+ ]
+ }
+ },
+ "type": "object"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/pkg/github/__toolsnaps__/search_users_typed.snap b/pkg/github/__toolsnaps__/search_users_typed.snap
new file mode 100644
index 0000000000..cbbb8eedbc
--- /dev/null
+++ b/pkg/github/__toolsnaps__/search_users_typed.snap
@@ -0,0 +1,173 @@
+{
+ "annotations": {
+ "idempotentHint": false,
+ "readOnlyHint": true,
+ "title": "Search users"
+ },
+ "description": "Find GitHub users by username, real name, or other profile information. Useful for locating developers, contributors, or team members.",
+ "icons": [
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAADWklEQVRIidWTT2hcVRTGf+e+mUn9Q3WMqbbWgJ1JnMw4meiAUkoxIRG1IKK4ELqoVkQXUsVuXbropoq4EWykuBDURV2I0r9GrC0VopnXTGaefYkhDahBOg4SnSTv3eMiTphMJ6Spq57dPd+933e/794DN3rJWkA+n49W54MB4AE1aoyawqVS1xn4PPzfAsnUg48iOgyaaIJ8I7r/5wn3u2sVMM2N7nTvbsQeB42J6nOOrW12bG2zIs8ohFblZHe6d/d1Oejv74/MzlU8lGibCfqKxeKVRrwzm43HAlMAatvviqdHRkaC9QScxkVk021DwAFRfalcGv+xeXN1bq52x5ats8Crf80vnL3yx29TiZ7e59s7tg7Ft3TEc5n09PT0tG08syoiEckBGF04seaVFtuOA1ixuf9OvQP6rqj5avb3SmlHKptdU0BhaT3L1gbLsVpRgMlSYdvNUb1VlKeAqBFzsjObjbcWMNYFCMxNg2sJmE3B4wCOmEK957ru/KVy4UtxnCeBO2OheaOONX9Tk+zJlRXsUsTunLl4sdIIplKp9oC2MYR//FJ3T6uZSKZzZ7Es+OXCIECkOQFVeUFET8UCU0im+w7WMydWeyKwHEboUCuDaw2cKGpFVx76qjmYLI+dRzkE3IvqZ0RrVaK1KsqnCNsROTTpjX3fijyReSip8LCo+aFlRN3d2ZR15COQnUAFOIVwedmbdCI6CMSBc47V/Z7neivkqWxexHwC2h4lmi2VRn9dJZC4Pzcghi9Qaoq8dfstztHR0dFVvyqfz0f/nA9fFNG3gRhqnvbLP30LkOzJfQP0Kzw7WSocW+Vg+ebmAjCjTrhncnz8cqsI6rUjk+80NvgauMex+ojnuV4ynTuMcgD4G/RNv+QO199ArGOGUWrXQg4wVRydCTF7gCVr5Agg/kThIE6YQjkH8mEi1bcPQLp6+h5T9AToy37JPbIeeWN1pXOvqPKBFR2amnBPA2QymdiidY4pMmhCEgbsXqDSZsKPN0IOoIvzR4GqsbK33isWi4vG8hogoaOvG0V2oXK6WCwublTA9/0FgTMIuxr7nuf+AowIDBjgboz6GyVfcSF4wLarAGEcuC8iyj4JuXC9Ak5o3g8j4fnmvpXIe44NWg7kjVX/Ap7dYx0LcmfJAAAAAElFTkSuQmCC",
+ "theme": "light"
+ },
+ {
+ "mimeType": "image/png",
+ "src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAB20lEQVRIidXUvUuVcRQH8PPc1JYUrKWUDCmwoKa2QsTKoKEwxWhr6G1tqDVqaAn8F6I5oS0ipBp6WZqiAi1bEgIrIpcorD4NHvFye+7Vrkv94Dc853zP93venl/E/36Keg60RsRgROyOiEpEPI+IB0VR/FyzKgYw48/zBv1rJe/HN7zDKNrzDmMqfc2JoAVvk3xjib8zfa/R0ozA4WzFaAPMWGKG8vskLuDIiqK4lMHtDTAdibmY3+9rZrSnGl+piV9YqcpY3jwREUVRdEXEhog4GhGtETGJznrZHchMhhtUcCIxh0p8u/ADV+sFV3KAU2VZYBNmE7OuDsdj3K+XYGAfvua2jGXPOzLz2VzT/Q3iH2GykUCByyU/2dK50iB2B77jWj3ATjxNos+4hfG8E2mDJ+irid2LaXzCljLyQcxjDmctvkW1mFacwwd8wUCV72GKH6+X+TxeYGvd/i3je/AqRfrSNo6F5DldDS6y5LnVkFfFbcPHHGqRtu24i184tQQcytLOrJa8SuR8xh6ssrXhTm5bd+BmDq+tCYH12aYbNfbe3KbrYfH9mPhb8iqy25gusd/Ds0pEbI6ImWYFImI6IrpK7C8jojcwgu5m2dGFYyX2How0y/vvnN8dpHfeBcHNQgAAAABJRU5ErkJggg==",
+ "theme": "dark"
+ }
+ ],
+ "inputSchema": {
+ "properties": {
+ "order": {
+ "description": "Sort order",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "type": "string"
+ },
+ "page": {
+ "description": "Page number for pagination (min 1)",
+ "minimum": 1,
+ "type": "number"
+ },
+ "perPage": {
+ "description": "Results per page for pagination (min 1, max 100)",
+ "maximum": 100,
+ "minimum": 1,
+ "type": "number"
+ },
+ "query": {
+ "description": "User search query. Examples: 'john smith', 'location:seattle', 'followers:\u003e100'. Search is automatically scoped to type:user.",
+ "type": "string"
+ },
+ "sort": {
+ "description": "Sort users by number of followers or repositories, or when the person joined GitHub.",
+ "enum": [
+ "followers",
+ "repositories",
+ "joined"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "query"
+ ],
+ "type": "object"
+ },
+ "name": "search_users",
+ "outputSchema": {
+ "additionalProperties": false,
+ "properties": {
+ "incomplete_results": {
+ "type": "boolean"
+ },
+ "items": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "avatar_url": {
+ "type": "string"
+ },
+ "details": {
+ "additionalProperties": false,
+ "properties": {
+ "bio": {
+ "type": "string"
+ },
+ "blog": {
+ "type": "string"
+ },
+ "company": {
+ "type": "string"
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "followers": {
+ "type": "integer"
+ },
+ "following": {
+ "type": "integer"
+ },
+ "hireable": {
+ "type": "boolean"
+ },
+ "location": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owned_private_repos": {
+ "type": "integer"
+ },
+ "private_gists": {
+ "type": "integer"
+ },
+ "public_gists": {
+ "type": "integer"
+ },
+ "public_repos": {
+ "type": "integer"
+ },
+ "total_private_repos": {
+ "type": "integer"
+ },
+ "twitter_username": {
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "public_repos",
+ "public_gists",
+ "followers",
+ "following",
+ "created_at",
+ "updated_at"
+ ],
+ "type": [
+ "null",
+ "object"
+ ]
+ },
+ "id": {
+ "type": "integer"
+ },
+ "login": {
+ "type": "string"
+ },
+ "profile_url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "login"
+ ],
+ "type": "object"
+ },
+ "type": [
+ "null",
+ "array"
+ ]
+ },
+ "total_count": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "total_count",
+ "incomplete_results",
+ "items"
+ ],
+ "type": "object"
+ }
+}
\ No newline at end of file
diff --git a/pkg/github/search.go b/pkg/github/search.go
index c731b2b701..08881d6088 100644
--- a/pkg/github/search.go
+++ b/pkg/github/search.go
@@ -48,7 +48,7 @@ func SearchRepositories(t translations.TranslationHelperFunc) inventory.ServerTo
}
WithPagination(schema)
- return NewTool(
+ return NewTool[SearchRepositoriesInput, *SearchRepositoriesOutput](
ToolsetMetadataRepos,
mcp.Tool{
Name: "search_repositories",
@@ -57,33 +57,21 @@ func SearchRepositories(t translations.TranslationHelperFunc) inventory.ServerTo
Title: t("TOOL_SEARCH_REPOSITORIES_USER_TITLE", "Search repositories"),
ReadOnlyHint: true,
},
- InputSchema: schema,
+ InputSchema: schema,
+ OutputSchema: searchRepositoriesOutputSchema(),
},
scopes.PublicRead(scopes.Repo),
- func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
- query, err := RequiredParam[string](args, "query")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- sort, err := OptionalParam[string](args, "sort")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- order, err := OptionalParam[string](args, "order")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- pagination, err := OptionalPaginationParams(args)
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- minimalOutput, err := OptionalBoolParamWithDefault(args, "minimal_output", true)
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
+ func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, input SearchRepositoriesInput) (*mcp.CallToolResult, *SearchRepositoriesOutput, error) {
+ var output *SearchRepositoriesOutput
+ if input.Query == "" {
+ return utils.NewToolResultError("missing required parameter: query"), output, nil
}
+ query := input.Query
+ pagination := repositoryPagination(input.Page, input.PerPage)
+ minimalOutput := input.MinimalOutput == nil || *input.MinimalOutput
opts := &github.SearchOptions{
- Sort: sort,
- Order: order,
+ Sort: input.Sort,
+ Order: input.Order,
ListOptions: github.ListOptions{
Page: pagination.Page,
PerPage: pagination.PerPage,
@@ -92,7 +80,7 @@ func SearchRepositories(t translations.TranslationHelperFunc) inventory.ServerTo
client, err := deps.GetClient(ctx)
if err != nil {
- return utils.NewToolResultErrorFromErr("failed to get GitHub client", err), nil, nil
+ return utils.NewToolResultErrorFromErr("failed to get GitHub client", err), output, nil
}
result, resp, err := client.Search.Repositories(ctx, query, opts)
if err != nil {
@@ -100,20 +88,21 @@ func SearchRepositories(t translations.TranslationHelperFunc) inventory.ServerTo
fmt.Sprintf("failed to search repositories with query '%s'", query),
resp,
err,
- ), nil, nil
+ ), output, nil
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
- return utils.NewToolResultErrorFromErr("failed to read response body", err), nil, nil
+ return utils.NewToolResultErrorFromErr("failed to read response body", err), output, nil
}
- return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to search repositories", resp, body), nil, nil
+ return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to search repositories", resp, body), output, nil
}
// Return either minimal or full response based on parameter
var r []byte
+ output = new(SearchRepositoriesOutput)
if minimalOutput {
minimalRepos := make([]MinimalRepository, 0, len(result.Repositories))
for _, repo := range result.Repositories {
@@ -156,17 +145,23 @@ func SearchRepositories(t translations.TranslationHelperFunc) inventory.ServerTo
if err != nil {
return utils.NewToolResultErrorFromErr("failed to marshal minimal response", err), nil, nil
}
+ output.Minimal = minimalResult
} else {
r, err = json.Marshal(result)
if err != nil {
return utils.NewToolResultErrorFromErr("failed to marshal full response", err), nil, nil
}
+ output.Full = new(FullSearchRepositoriesResult)
+ if err := json.Unmarshal(r, output.Full); err != nil {
+ return utils.NewToolResultErrorFromErr("failed to decode full response", err), nil, nil
+ }
}
callResult := utils.NewToolResultText(string(r))
attachSearchRepositoriesIFCLabel(ctx, deps, result.Repositories, callResult)
- return callResult, nil, nil
+ return callResult, output, nil
},
+ normalizeSearchArguments(true),
)
}
@@ -398,27 +393,16 @@ func recordSearchCodeFieldsUsage(ctx context.Context, deps ToolDependencies, ful
recordFieldsUsageFor(ctx, deps, "search_code", full, filtered, sentBytes)
}
-func userOrOrgHandler(ctx context.Context, accountType string, deps ToolDependencies, args map[string]any) (*mcp.CallToolResult, any, error) {
- query, err := RequiredParam[string](args, "query")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- sort, err := OptionalParam[string](args, "sort")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- order, err := OptionalParam[string](args, "order")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- pagination, err := OptionalPaginationParams(args)
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
+func userOrOrgHandler(ctx context.Context, accountType string, deps ToolDependencies, input SearchAccountsInput) (*mcp.CallToolResult, *MinimalSearchUsersResult, error) {
+ if input.Query == "" {
+ return utils.NewToolResultError("missing required parameter: query"), nil, nil
}
+ query := input.Query
+ pagination := repositoryPagination(input.Page, input.PerPage)
opts := &github.SearchOptions{
- Sort: sort,
- Order: order,
+ Sort: input.Sort,
+ Order: input.Order,
ListOptions: github.ListOptions{
PerPage: pagination.PerPage,
Page: pagination.Page,
@@ -485,7 +469,7 @@ func userOrOrgHandler(ctx context.Context, accountType string, deps ToolDependen
// User and organization search returns public profile information that is
// authored by the account holders themselves, so it is public-untrusted.
callResult = attachStaticIFCLabel(ctx, deps, callResult, ifc.PublicUntrusted())
- return callResult, nil, nil
+ return callResult, minimalResp, nil
}
// SearchUsers creates a tool to search for GitHub users.
@@ -512,7 +496,7 @@ func SearchUsers(t translations.TranslationHelperFunc) inventory.ServerTool {
}
WithPagination(schema)
- return NewTool(
+ return NewTool[SearchAccountsInput, *MinimalSearchUsersResult](
ToolsetMetadataUsers,
mcp.Tool{
Name: "search_users",
@@ -524,9 +508,10 @@ func SearchUsers(t translations.TranslationHelperFunc) inventory.ServerTool {
InputSchema: schema,
},
scopes.PublicRead(scopes.Repo),
- func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
- return userOrOrgHandler(ctx, "user", deps, args)
+ func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, input SearchAccountsInput) (*mcp.CallToolResult, *MinimalSearchUsersResult, error) {
+ return userOrOrgHandler(ctx, "user", deps, input)
},
+ normalizeSearchArguments(false),
)
}
@@ -554,7 +539,7 @@ func SearchOrgs(t translations.TranslationHelperFunc) inventory.ServerTool {
}
WithPagination(schema)
- return NewTool(
+ return NewTool[SearchAccountsInput, *MinimalSearchUsersResult](
ToolsetMetadataOrgs,
mcp.Tool{
Name: "search_orgs",
@@ -566,9 +551,10 @@ func SearchOrgs(t translations.TranslationHelperFunc) inventory.ServerTool {
InputSchema: schema,
},
scopes.RequireAll(scopes.ReadOrg),
- func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
- return userOrOrgHandler(ctx, "org", deps, args)
+ func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, input SearchAccountsInput) (*mcp.CallToolResult, *MinimalSearchUsersResult, error) {
+ return userOrOrgHandler(ctx, "org", deps, input)
},
+ normalizeSearchArguments(false),
)
}
@@ -596,7 +582,7 @@ func SearchCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
}
WithPagination(schema)
- return NewTool(
+ return NewTool[SearchCommitsInput, *MinimalSearchCommitsResult](
ToolsetMetadataRepos,
mcp.Tool{
Name: "search_commits",
@@ -608,27 +594,16 @@ func SearchCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
InputSchema: schema,
},
scopes.PublicRead(scopes.Repo),
- func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
- query, err := RequiredParam[string](args, "query")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- sort, err := OptionalParam[string](args, "sort")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- order, err := OptionalParam[string](args, "order")
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
- }
- pagination, err := OptionalPaginationParams(args)
- if err != nil {
- return utils.NewToolResultError(err.Error()), nil, nil
+ func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, input SearchCommitsInput) (*mcp.CallToolResult, *MinimalSearchCommitsResult, error) {
+ if input.Query == "" {
+ return utils.NewToolResultError("missing required parameter: query"), nil, nil
}
+ query := input.Query
+ pagination := repositoryPagination(input.Page, input.PerPage)
opts := &github.SearchOptions{
- Sort: sort,
- Order: order,
+ Sort: input.Sort,
+ Order: input.Order,
ListOptions: github.ListOptions{
Page: pagination.Page,
PerPage: pagination.PerPage,
@@ -684,7 +659,8 @@ func SearchCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
}
}
callResult = attachJoinedIFCLabel(ctx, deps, callResult, visibilities, ifc.LabelSearchIssues)
- return callResult, nil, nil
+ return callResult, minimalResult, nil
},
+ normalizeSearchArguments(false),
)
}
diff --git a/pkg/github/search_tool_types.go b/pkg/github/search_tool_types.go
new file mode 100644
index 0000000000..99d5138011
--- /dev/null
+++ b/pkg/github/search_tool_types.go
@@ -0,0 +1,266 @@
+package github
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "reflect"
+
+ "github.com/google/go-github/v92/github"
+ "github.com/google/jsonschema-go/jsonschema"
+)
+
+type SearchAccountsInput struct {
+ Query string `json:"query"`
+ Sort string `json:"sort,omitempty"`
+ Order string `json:"order,omitempty"`
+ Page *int `json:"page,omitempty"`
+ PerPage *int `json:"perPage,omitempty"`
+}
+
+type SearchRepositoriesInput struct {
+ SearchAccountsInput
+ MinimalOutput *bool `json:"minimal_output,omitempty"`
+}
+
+type SearchCommitsInput = SearchAccountsInput
+
+type SearchRepositoriesOutput struct {
+ Minimal *MinimalSearchRepositoriesResult
+ Full *FullSearchRepositoriesResult
+}
+
+func (out SearchRepositoriesOutput) MarshalJSON() ([]byte, error) {
+ if out.Minimal != nil {
+ return json.Marshal(out.Minimal)
+ }
+ return json.Marshal(out.Full)
+}
+
+func searchRepositoriesOutputSchema() *jsonschema.Schema {
+ minimal := repositoryOutputSchema[MinimalSearchRepositoriesResult]()
+ options := &jsonschema.ForOptions{TypeSchemas: map[reflect.Type]*jsonschema.Schema{
+ reflect.TypeFor[github.Timestamp](): {Type: "string", Format: "date-time"},
+ reflect.TypeFor[github.Team](): {Type: "object", Ref: "#/$defs/team"},
+ reflect.TypeFor[SearchRepository](): {Type: "object", Ref: "#/$defs/searchRepository"},
+ reflect.TypeFor[SearchPropertyValue](): {Ref: "#/$defs/searchPropertyValue"},
+ }}
+ full, err := jsonschema.For[FullSearchRepositoriesResult](options)
+ if err != nil {
+ panic(err)
+ }
+ type repositorySchema SearchRepository
+ repository, err := jsonschema.For[repositorySchema](options)
+ if err != nil {
+ panic(err)
+ }
+ repository.Type = ""
+ repository.Types = []string{"object", "null"}
+ full.Defs = map[string]*jsonschema.Schema{
+ "searchRepository": repository,
+ "team": repositoryOutputSchema[github.Team]().Defs["team"],
+ "searchPropertyValue": {AnyOf: []*jsonschema.Schema{
+ {Type: "null"}, {Type: "string"}, {Type: "number"}, {Type: "boolean"},
+ {Type: "array", Items: &jsonschema.Schema{Ref: "#/$defs/searchPropertyValue"}},
+ {Type: "object", AdditionalProperties: &jsonschema.Schema{Ref: "#/$defs/searchPropertyValue"}},
+ }},
+ }
+ union := repositoryUnionSchema(&jsonschema.Schema{Type: "null"}, minimal, full)
+ // Empty items can satisfy both variants. AnyOf preserves that overlap.
+ union.AnyOf, union.OneOf = union.OneOf, nil
+ return union
+}
+
+type FullSearchRepositoriesResult struct {
+ Total *int `json:"total_count,omitempty"`
+ IncompleteResults *bool `json:"incomplete_results,omitempty"`
+ Repositories []*SearchRepository `json:"items,omitempty"`
+}
+
+// SearchRepository mirrors the full search response without the upstream
+// untyped custom_properties map. Parent/source/template repositories retain
+// the same recursive wire contract.
+type SearchRepository struct {
+ ID *int64 `json:"id,omitempty"`
+ NodeID *string `json:"node_id,omitempty"`
+ Owner *github.User `json:"owner,omitempty"`
+ Name *string `json:"name,omitempty"`
+ FullName *string `json:"full_name,omitempty"`
+ Description *string `json:"description,omitempty"`
+ Homepage *string `json:"homepage,omitempty"`
+ CodeOfConduct *github.CodeOfConduct `json:"code_of_conduct,omitempty"`
+ DefaultBranch *string `json:"default_branch,omitempty"`
+ MasterBranch *string `json:"master_branch,omitempty"`
+ CreatedAt *github.Timestamp `json:"created_at,omitempty"`
+ PushedAt *github.Timestamp `json:"pushed_at,omitempty"`
+ UpdatedAt *github.Timestamp `json:"updated_at,omitempty"`
+ HTMLURL *string `json:"html_url,omitempty"`
+ CloneURL *string `json:"clone_url,omitempty"`
+ GitURL *string `json:"git_url,omitempty"`
+ MirrorURL *string `json:"mirror_url,omitempty"`
+ SSHURL *string `json:"ssh_url,omitempty"`
+ SVNURL *string `json:"svn_url,omitempty"`
+ Language *string `json:"language,omitempty"`
+ Fork *bool `json:"fork,omitempty"`
+ ForksCount *int `json:"forks_count,omitempty"`
+ NetworkCount *int `json:"network_count,omitempty"`
+ OpenIssuesCount *int `json:"open_issues_count,omitempty"`
+ OpenIssues *int `json:"open_issues,omitempty"`
+ StargazersCount *int `json:"stargazers_count,omitempty"`
+ SubscribersCount *int `json:"subscribers_count,omitempty"`
+ WatchersCount *int `json:"watchers_count,omitempty"`
+ Watchers *int `json:"watchers,omitempty"`
+ Size *int `json:"size,omitempty"`
+ AutoInit *bool `json:"auto_init,omitempty"`
+ Parent *SearchRepository `json:"parent,omitempty"`
+ Source *SearchRepository `json:"source,omitempty"`
+ TemplateRepository *SearchRepository `json:"template_repository,omitempty"`
+ Organization *github.Organization `json:"organization,omitempty"`
+ Permissions *github.RepositoryPermissions `json:"permissions,omitempty"`
+ AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"`
+ AllowUpdateBranch *bool `json:"allow_update_branch,omitempty"`
+ AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
+ AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
+ AllowAutoMerge *bool `json:"allow_auto_merge,omitempty"`
+ AllowForking *bool `json:"allow_forking,omitempty"`
+ WebCommitSignoffRequired *bool `json:"web_commit_signoff_required,omitempty"`
+ DeleteBranchOnMerge *bool `json:"delete_branch_on_merge,omitempty"`
+ UseSquashPRTitleAsDefault *bool `json:"use_squash_pr_title_as_default,omitempty"`
+ SquashMergeCommitTitle *string `json:"squash_merge_commit_title,omitempty"`
+ SquashMergeCommitMessage *string `json:"squash_merge_commit_message,omitempty"`
+ MergeCommitTitle *string `json:"merge_commit_title,omitempty"`
+ MergeCommitMessage *string `json:"merge_commit_message,omitempty"`
+ Topics []string `json:"topics,omitempty"`
+ CustomProperties map[string]SearchPropertyValue `json:"custom_properties,omitempty"`
+ Archived *bool `json:"archived,omitempty"`
+ Disabled *bool `json:"disabled,omitempty"`
+ License *github.License `json:"license,omitempty"`
+ Private *bool `json:"private,omitempty"`
+ HasIssues *bool `json:"has_issues,omitempty"`
+ HasWiki *bool `json:"has_wiki,omitempty"`
+ HasPages *bool `json:"has_pages,omitempty"`
+ HasProjects *bool `json:"has_projects,omitempty"`
+ HasDownloads *bool `json:"has_downloads,omitempty"`
+ HasDiscussions *bool `json:"has_discussions,omitempty"`
+ HasPullRequests *bool `json:"has_pull_requests,omitempty"`
+ PullRequestCreationPolicy *string `json:"pull_request_creation_policy,omitempty"`
+ IsTemplate *bool `json:"is_template,omitempty"`
+ LicenseTemplate *string `json:"license_template,omitempty"`
+ GitignoreTemplate *string `json:"gitignore_template,omitempty"`
+ SecurityAndAnalysis *github.SecurityAndAnalysis `json:"security_and_analysis,omitempty"`
+ TeamID *int64 `json:"team_id,omitempty"`
+ URL *string `json:"url,omitempty"`
+ ArchiveURL *string `json:"archive_url,omitempty"`
+ AssigneesURL *string `json:"assignees_url,omitempty"`
+ BlobsURL *string `json:"blobs_url,omitempty"`
+ BranchesURL *string `json:"branches_url,omitempty"`
+ CollaboratorsURL *string `json:"collaborators_url,omitempty"`
+ CommentsURL *string `json:"comments_url,omitempty"`
+ CommitsURL *string `json:"commits_url,omitempty"`
+ CompareURL *string `json:"compare_url,omitempty"`
+ ContentsURL *string `json:"contents_url,omitempty"`
+ ContributorsURL *string `json:"contributors_url,omitempty"`
+ DeploymentsURL *string `json:"deployments_url,omitempty"`
+ DownloadsURL *string `json:"downloads_url,omitempty"`
+ EventsURL *string `json:"events_url,omitempty"`
+ ForksURL *string `json:"forks_url,omitempty"`
+ GitCommitsURL *string `json:"git_commits_url,omitempty"`
+ GitRefsURL *string `json:"git_refs_url,omitempty"`
+ GitTagsURL *string `json:"git_tags_url,omitempty"`
+ HooksURL *string `json:"hooks_url,omitempty"`
+ IssueCommentURL *string `json:"issue_comment_url,omitempty"`
+ IssueEventsURL *string `json:"issue_events_url,omitempty"`
+ IssuesURL *string `json:"issues_url,omitempty"`
+ KeysURL *string `json:"keys_url,omitempty"`
+ LabelsURL *string `json:"labels_url,omitempty"`
+ LanguagesURL *string `json:"languages_url,omitempty"`
+ MergesURL *string `json:"merges_url,omitempty"`
+ MilestonesURL *string `json:"milestones_url,omitempty"`
+ NotificationsURL *string `json:"notifications_url,omitempty"`
+ PullsURL *string `json:"pulls_url,omitempty"`
+ ReleasesURL *string `json:"releases_url,omitempty"`
+ StargazersURL *string `json:"stargazers_url,omitempty"`
+ StatusesURL *string `json:"statuses_url,omitempty"`
+ SubscribersURL *string `json:"subscribers_url,omitempty"`
+ SubscriptionURL *string `json:"subscription_url,omitempty"`
+ TagsURL *string `json:"tags_url,omitempty"`
+ TreesURL *string `json:"trees_url,omitempty"`
+ TeamsURL *string `json:"teams_url,omitempty"`
+ TextMatches []*github.TextMatch `json:"text_matches,omitempty"`
+ Visibility *string `json:"visibility,omitempty"`
+ RoleName *string `json:"role_name,omitempty"`
+}
+
+// Custom property values are JSON unions, not arbitrary Go values.
+type SearchPropertyValue struct {
+ String *string
+ Number *json.Number
+ Bool *bool
+ Array []SearchPropertyValue
+ Object map[string]SearchPropertyValue
+}
+
+func (value SearchPropertyValue) MarshalJSON() ([]byte, error) {
+ switch {
+ case value.String != nil:
+ return json.Marshal(value.String)
+ case value.Number != nil:
+ return json.Marshal(value.Number)
+ case value.Bool != nil:
+ return json.Marshal(value.Bool)
+ case value.Array != nil:
+ return json.Marshal(value.Array)
+ case value.Object != nil:
+ return json.Marshal(value.Object)
+ default:
+ return []byte("null"), nil
+ }
+}
+
+func (value *SearchPropertyValue) UnmarshalJSON(raw []byte) error {
+ *value = SearchPropertyValue{}
+ raw = bytes.TrimSpace(raw)
+ if len(raw) == 0 {
+ return io.ErrUnexpectedEOF
+ }
+ switch raw[0] {
+ case '"':
+ return json.Unmarshal(raw, &value.String)
+ case '[':
+ return json.Unmarshal(raw, &value.Array)
+ case '{':
+ return json.Unmarshal(raw, &value.Object)
+ case 't', 'f':
+ return json.Unmarshal(raw, &value.Bool)
+ case 'n':
+ return json.Unmarshal(raw, new(*string))
+ default:
+ return json.Unmarshal(raw, &value.Number)
+ }
+}
+
+func normalizeSearchArguments(minimalOutput bool) func(json.RawMessage) (json.RawMessage, error) {
+ return func(raw json.RawMessage) (json.RawMessage, error) {
+ var args map[string]any
+ if err := json.Unmarshal(raw, &args); err != nil {
+ return nil, err
+ }
+ if _, err := RequiredParam[string](args, "query"); err != nil {
+ return nil, err
+ }
+ for _, field := range []string{"sort", "order"} {
+ if _, err := OptionalParam[string](args, field); err != nil {
+ return nil, err
+ }
+ }
+ if _, err := OptionalPaginationParams(args); err != nil {
+ return nil, err
+ }
+ if minimalOutput {
+ if _, err := OptionalBoolParamWithDefault(args, "minimal_output", true); err != nil {
+ return nil, err
+ }
+ }
+ return normalizeRepositoryArguments(raw)
+ }
+}
diff --git a/pkg/github/typed_account_repository_search_test.go b/pkg/github/typed_account_repository_search_test.go
new file mode 100644
index 0000000000..3bcecad930
--- /dev/null
+++ b/pkg/github/typed_account_repository_search_test.go
@@ -0,0 +1,352 @@
+package github
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "io"
+ "maps"
+ "net/http"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/github/github-mcp-server/internal/toolsnaps"
+ "github.com/github/github-mcp-server/pkg/inventory"
+ "github.com/github/github-mcp-server/pkg/translations"
+ "github.com/google/go-github/v92/github"
+ "github.com/google/jsonschema-go/jsonschema"
+ "github.com/modelcontextprotocol/go-sdk/mcp"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func typedAccountRepositorySearchTools() []inventory.ServerTool {
+ return []inventory.ServerTool{
+ SearchRepositories(translations.NullTranslationHelper),
+ SearchUsers(translations.NullTranslationHelper),
+ SearchOrgs(translations.NullTranslationHelper),
+ SearchCommits(translations.NullTranslationHelper),
+ }
+}
+
+func connectTypedSearchClient(t *testing.T, tool inventory.ServerTool, deps ToolDependencies, protocol string) *mcp.ClientSession {
+ t.Helper()
+ server := mcp.NewServer(&mcp.Implementation{Name: "typed-search-test", Version: "v1"}, nil)
+ server.AddReceivingMiddleware(InjectDepsMiddleware(deps))
+ tool.RegisterFunc(server, deps)
+ version := protocol
+ if protocol == "" {
+ version = inventory.ProtocolVersionMultiRoundTrip
+ server.AddReceivingMiddleware(func(next mcp.MethodHandler) mcp.MethodHandler {
+ return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
+ switch request := req.(type) {
+ case *mcp.ListToolsRequest:
+ request.Params.Meta = mcp.Meta{mcp.MetaKeyProtocolVersion: ""}
+ case *mcp.CallToolRequest:
+ request.Params.Meta = mcp.Meta{mcp.MetaKeyProtocolVersion: ""}
+ }
+ return next(ctx, method, req)
+ }
+ })
+ }
+ return connectCommentVisibilityClient(t, server, version)
+}
+
+func TestTypedAccountRepositorySearchOutputs(t *testing.T) {
+ fixtures := map[string]struct {
+ path string
+ body string
+ text string
+ }{
+ "search_repositories": {
+ GetSearchRepositories,
+ `{"total_count":1,"incomplete_results":false,"items":[{"id":7,"name":"repo","full_name":"owner/repo","description":"description","html_url":"repo-url","stargazers_count":0,"private":false,"fork":false,"archived":false,"created_at":"2026-01-02T03:04:05Z","topics":["go"],"owner":{"login":"owner"},"parent":{"id":8,"custom_properties":{"nested":{"flag":false}}},"custom_properties":{"text":"value","list":["one","two"],"empty":[],"nil":null,"number":12.5,"bool":true,"object":{}}}]}`,
+ `{"total_count":1,"incomplete_results":false,"items":[{"id":7,"name":"repo","full_name":"owner/repo","description":"\u003cb\u003edescription\u003c/b\u003e","html_url":"repo-url","stargazers_count":0,"forks_count":0,"open_issues_count":0,"created_at":"2026-01-02T03:04:05Z","topics":["go"],"private":false,"fork":false,"archived":false}]}`,
+ },
+ "search_users": {
+ GetSearchUsers,
+ `{"total_count":3,"incomplete_results":true,"items":[{"id":7,"login":"octo","html_url":"profile","avatar_url":"avatar"},{"id":8},{"id":9,"login":""}]}`,
+ `{"total_count":3,"incomplete_results":true,"items":[{"login":"octo","id":7,"profile_url":"profile","avatar_url":"avatar"},{"login":"","id":9}]}`,
+ },
+ "search_orgs": {
+ GetSearchUsers,
+ `{"total_count":3,"incomplete_results":true,"items":[{"id":7,"login":"octo","html_url":"profile","avatar_url":"avatar"},{"id":8},{"id":9,"login":""}]}`,
+ `{"total_count":3,"incomplete_results":true,"items":[{"login":"octo","id":7,"profile_url":"profile","avatar_url":"avatar"},{"login":"","id":9}]}`,
+ },
+ "search_commits": {
+ GetSearchCommits,
+ `{"total_count":2,"incomplete_results":false,"items":[{"sha":"abc","html_url":"commit-url","commit":{"message":"fix","author":{"name":"Author","email":"a@example.com","date":"2026-01-02T03:04:05Z"}},"author":{"login":"octo","id":7,"html_url":"profile","avatar_url":"avatar"},"repository":{"full_name":"owner/repo","html_url":"repo-url","private":true}},{"sha":"def","html_url":""}]}`,
+ `{"total_count":2,"incomplete_results":false,"items":[{"sha":"abc","html_url":"commit-url","commit":{"message":"\u003cb\u003efix\u003c/b\u003e","author":{"name":"Author","email":"a@example.com","date":"2026-01-02T03:04:05Z"}},"author":{"login":"octo","id":7,"profile_url":"profile","avatar_url":"avatar"},"repository":{"full_name":"owner/repo","html_url":"repo-url","private":true}},{"sha":"def","html_url":""}]}`,
+ },
+ }
+ for _, tool := range typedAccountRepositorySearchTools() {
+ fixture := fixtures[tool.Tool.Name]
+ var apiErrorText string
+ for _, protocol := range []string{"2025-11-25", inventory.ProtocolVersionMultiRoundTrip, ""} {
+ t.Run(tool.Tool.Name+"/"+protocol, func(t *testing.T) {
+ body := fixture.body
+ query := "repo:owner/repo fix"
+ page, perPage, sort, order := "1", "30", "", ""
+ calls := 0
+ handler := func(w http.ResponseWriter, r *http.Request) {
+ calls++
+ expectedQuery := query
+ if !hasTypeFilter(query) {
+ switch tool.Tool.Name {
+ case "search_users":
+ expectedQuery = "type:user " + query
+ case "search_orgs":
+ expectedQuery = "type:org " + query
+ }
+ }
+ assert.Equal(t, expectedQuery, r.URL.Query().Get("q"))
+ assert.Equal(t, page, r.URL.Query().Get("page"))
+ assert.Equal(t, perPage, r.URL.Query().Get("per_page"))
+ assert.Equal(t, sort, r.URL.Query().Get("sort"))
+ assert.Equal(t, order, r.URL.Query().Get("order"))
+ if body == "forbidden" {
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"message":"Forbidden"}`))
+ return
+ }
+ _, _ = w.Write([]byte(body))
+ }
+ deps := BaseDeps{
+ Client: mustNewGHClient(t, MockHTTPClientWithHandlers(map[string]http.HandlerFunc{fixture.path: handler})),
+ featureChecker: featureCheckerFor(FeatureFlagIFCLabels),
+ }
+ session := connectTypedSearchClient(t, tool, deps, protocol)
+ list, err := session.ListTools(context.Background(), nil)
+ require.NoError(t, err)
+ require.Len(t, list.Tools, 1)
+ listed := list.Tools[0]
+ assert.Equal(t, tool.Tool.Name, listed.Name)
+ var resolved *jsonschema.Resolved
+ if protocol == inventory.ProtocolVersionMultiRoundTrip {
+ require.NotNil(t, listed.OutputSchema)
+ require.NoError(t, toolsnaps.Test(tool.Tool.Name+"_typed", *listed))
+ var schema jsonschema.Schema
+ require.NoError(t, json.Unmarshal([]byte(mustMarshalJSON(t, listed.OutputSchema)), &schema))
+ resolved, err = schema.Resolve(nil)
+ require.NoError(t, err)
+ } else {
+ assert.Nil(t, listed.OutputSchema)
+ }
+ check := func(args map[string]any, expected string) {
+ t.Helper()
+ args = maps.Clone(args)
+ args["query"] = query
+ result, err := session.CallTool(context.Background(), &mcp.CallToolParams{Name: tool.Tool.Name, Arguments: args})
+ require.NoError(t, err)
+ require.False(t, result.IsError, "%+v", result)
+ require.Len(t, result.Content, 1)
+ assert.Equal(t, expected, getTextResult(t, result).Text)
+ require.NotNil(t, result.Meta)
+ label := unmarshalIFC(t, result.Meta["ifc"])
+ if tool.Tool.Name == "search_commits" && body == fixture.body {
+ assert.Equal(t, "trusted", label["integrity"])
+ assert.Equal(t, "private", label["confidentiality"])
+ } else {
+ assert.Equal(t, "untrusted", label["integrity"])
+ assert.Equal(t, "public", label["confidentiality"])
+ }
+ if resolved == nil {
+ assert.Nil(t, result.StructuredContent)
+ } else {
+ require.NotNil(t, result.StructuredContent)
+ encoded := mustMarshalJSON(t, result.StructuredContent)
+ assert.JSONEq(t, expected, encoded)
+ var output any
+ require.NoError(t, json.Unmarshal([]byte(encoded), &output))
+ require.NoError(t, resolved.Validate(output))
+ }
+ request := createMCPRequest(args)
+ direct, err := tool.Handler(deps)(ContextWithDeps(context.Background(), deps), &request)
+ require.NoError(t, err)
+ require.False(t, direct.IsError)
+ assert.Equal(t, expected, getTextResult(t, direct).Text)
+ }
+ for _, args := range []map[string]any{
+ {}, {"page": 0, "perPage": 0}, {"page": "0", "perPage": "0"},
+ {"page": "0e0", "perPage": "-0"}, {"fields": []string{"id"}},
+ } {
+ check(args, fixture.text)
+ }
+ page, perPage, order = "2", "7", "asc"
+ switch tool.Tool.Name {
+ case "search_repositories":
+ sort = "stars"
+ case "search_commits":
+ sort = "author-date"
+ default:
+ sort = "followers"
+ }
+ check(map[string]any{"page": "2e0", "perPage": "7.0", "sort": sort, "order": order}, fixture.text)
+ page, perPage, sort, order = "1", "30", "", ""
+ query = "type:org (location:seattle OR location:california)"
+ check(map[string]any{}, fixture.text)
+ if tool.Tool.Name == "search_repositories" {
+ var full github.RepositoriesSearchResult
+ require.NoError(t, json.Unmarshal([]byte(body), &full))
+ check(map[string]any{"minimal_output": false}, mustMarshalJSON(t, full))
+ check(map[string]any{"minimal_output": true}, fixture.text)
+ }
+ for _, emptyBody := range []string{`{"total_count":0,"incomplete_results":false,"items":[]}`, `{}`} {
+ body = emptyBody
+ check(map[string]any{}, `{"total_count":0,"incomplete_results":false,"items":[]}`)
+ if tool.Tool.Name == "search_repositories" {
+ expected := `{"total_count":0,"incomplete_results":false}`
+ if emptyBody == "{}" {
+ expected = "{}"
+ }
+ check(map[string]any{"minimal_output": false}, expected)
+ }
+ }
+ before := calls
+ invalid := []struct {
+ args map[string]any
+ text string
+ }{
+ {map[string]any{}, "missing required parameter: query"},
+ {map[string]any{"query": ""}, "missing required parameter: query"},
+ {map[string]any{"query": nil}, "parameter query is not of type string"},
+ {map[string]any{"query": 1}, "parameter query is not of type string"},
+ {map[string]any{"query": query, "sort": nil}, "parameter sort is not of type string"},
+ {map[string]any{"query": query, "order": false}, "parameter order is not of type string"},
+ {map[string]any{"query": query, "page": "1.5"}, "non-integer numeric value"},
+ {map[string]any{"query": query, "page": 1.5}, "non-integer numeric value"},
+ {map[string]any{"query": query, "perPage": false}, "expected number"},
+ {map[string]any{"query": query, "perPage": nil}, "expected number"},
+ {map[string]any{"query": query, "page": "NaN"}, "non-finite numeric value"},
+ {map[string]any{"query": query, "page": "1e30"}, "numeric value out of int range"},
+ {map[string]any{"query": query, "after": nil}, "parameter after is not of type string"},
+ }
+ if tool.Tool.Name == "search_repositories" {
+ invalid = append(invalid, struct {
+ args map[string]any
+ text string
+ }{map[string]any{"query": query, "minimal_output": nil}, "parameter minimal_output is not of type bool"})
+ }
+ for _, tc := range invalid {
+ result, err := session.CallTool(context.Background(), &mcp.CallToolParams{Name: tool.Tool.Name, Arguments: tc.args})
+ require.NoError(t, err)
+ require.True(t, result.IsError)
+ assert.Contains(t, getErrorResult(t, result).Text, tc.text)
+ assert.Nil(t, result.StructuredContent)
+ request := createMCPRequest(tc.args)
+ direct, err := tool.Handler(deps)(ContextWithDeps(context.Background(), deps), &request)
+ require.NoError(t, err)
+ require.True(t, direct.IsError)
+ assert.Contains(t, getErrorResult(t, direct).Text, tc.text)
+ }
+ assert.Equal(t, before, calls, "invalid input must never reach GitHub")
+ body = "forbidden"
+ result, err := session.CallTool(context.Background(), &mcp.CallToolParams{
+ Name: tool.Tool.Name, Arguments: map[string]any{"query": query},
+ })
+ require.NoError(t, err)
+ require.True(t, result.IsError)
+ assert.Contains(t, getErrorResult(t, result).Text, "failed to search")
+ assert.Contains(t, getErrorResult(t, result).Text, query)
+ assert.Nil(t, result.StructuredContent)
+ if apiErrorText == "" {
+ apiErrorText = getErrorResult(t, result).Text
+ }
+ assert.Equal(t, apiErrorText, getErrorResult(t, result).Text, "API errors are identical across protocols")
+ })
+ }
+ }
+}
+
+func TestSearchRepositoryOutputCoversUpstreamFields(t *testing.T) {
+ upstream := reflect.TypeFor[github.Repository]()
+ output := reflect.TypeFor[SearchRepository]()
+ require.Equal(t, upstream.NumField(), output.NumField())
+ for field := range upstream.Fields() {
+ actual, ok := output.FieldByName(field.Name)
+ require.True(t, ok, field.Name)
+ assert.Equal(t, field.Tag, actual.Tag, field.Name)
+ switch field.Name {
+ case "CustomProperties", "Parent", "Source", "TemplateRepository":
+ default:
+ assert.Equal(t, field.Type, actual.Type, field.Name)
+ }
+ }
+}
+
+func TestSearchPropertyValueJSONUnion(t *testing.T) {
+ schema, err := searchRepositoriesOutputSchema().Resolve(nil)
+ require.NoError(t, err)
+ for _, raw := range []string{`null`, `false`, `0`, `""`, `[]`, `{}`, `["a",null]`, `{"nested":[true,1,"a"]}`} {
+ var value SearchPropertyValue
+ require.NoError(t, json.Unmarshal([]byte(raw), &value))
+ assert.JSONEq(t, raw, mustMarshalJSON(t, value))
+ out := FullSearchRepositoriesResult{Repositories: []*SearchRepository{{CustomProperties: map[string]SearchPropertyValue{"value": value}}}}
+ var decoded any
+ require.NoError(t, json.Unmarshal([]byte(mustMarshalJSON(t, out)), &decoded))
+ require.NoError(t, schema.Validate(decoded))
+ }
+ for _, raw := range []string{``, `"`, `[`, `NaN`, `null false`} {
+ var value SearchPropertyValue
+ require.Error(t, json.Unmarshal([]byte(raw), &value))
+ }
+ var value SearchPropertyValue
+ require.ErrorIs(t, value.UnmarshalJSON(nil), io.ErrUnexpectedEOF)
+ for _, tool := range typedAccountRepositorySearchTools() {
+ assert.True(t, tool.IsReadOnly())
+ }
+}
+
+type failingSearchClientDeps struct {
+ BaseDeps
+}
+
+func (failingSearchClientDeps) GetClient(context.Context) (*github.Client, error) {
+ return nil, errors.New("client unavailable")
+}
+
+func TestTypedAccountRepositorySearchClientErrors(t *testing.T) {
+ for _, tool := range typedAccountRepositorySearchTools() {
+ for _, protocol := range []string{"2025-11-25", inventory.ProtocolVersionMultiRoundTrip, ""} {
+ t.Run(tool.Tool.Name+"/"+protocol, func(t *testing.T) {
+ session := connectTypedSearchClient(t, tool, failingSearchClientDeps{}, protocol)
+ result, err := session.CallTool(context.Background(), &mcp.CallToolParams{
+ Name: tool.Tool.Name, Arguments: map[string]any{"query": "query"},
+ })
+ require.NoError(t, err)
+ require.True(t, result.IsError)
+ assert.Equal(t, "failed to get GitHub client: client unavailable", getErrorResult(t, result).Text)
+ assert.Nil(t, result.StructuredContent)
+ })
+ }
+ }
+}
+
+func TestSearchOutputsHaveNoUntypedFields(t *testing.T) {
+ seen := make(map[reflect.Type]bool)
+ var check func(reflect.Type)
+ check = func(typ reflect.Type) {
+ if seen[typ] {
+ return
+ }
+ seen[typ] = true
+ switch typ.Kind() {
+ case reflect.Interface:
+ t.Errorf("untyped output field: %s", typ)
+ case reflect.Pointer, reflect.Slice, reflect.Array:
+ check(typ.Elem())
+ case reflect.Map:
+ check(typ.Elem())
+ case reflect.Struct:
+ for field := range typ.Fields() {
+ if field.IsExported() && !strings.HasPrefix(field.Tag.Get("json"), "-") {
+ check(field.Type)
+ }
+ }
+ }
+ }
+ check(reflect.TypeFor[SearchRepositoriesOutput]())
+ check(reflect.TypeFor[MinimalSearchUsersResult]())
+ check(reflect.TypeFor[MinimalSearchCommitsResult]())
+}