Bladeren bron

feat: add Deploy Keys support #10

This commit implements complete support for Gogs Deploy Keys functionality:

- Added GogsDeployKey TypeScript interface in src/types.ts
- Implemented four deploy key client methods in src/gogs-client.ts:
  - listDeployKeys: List all deploy keys for a repository
  - getDeployKey: Get details of a specific deploy key
  - createDeployKey: Create a new deploy key with read-only/read-write support
  - deleteDeployKey: Remove a deploy key from a repository
- Added Zod validation schemas for all deploy key tools
- Registered four new MCP tools:
  - list_deploy_keys
  - get_deploy_key
  - create_deploy_key
  - delete_deploy_key
- Implemented tool handlers in the CallToolRequestSchema handler
- Updated README.md with comprehensive deploy key documentation
- Updated CLAUDE.md MCP Tool Categories section

Deploy keys enable secure, repository-specific SSH access for automated
deployments and CI/CD workflows without requiring user credentials.
Supports both read-only and read-write access modes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
claude 9 maanden geleden
bovenliggende
commit
708bc814ea
5 gewijzigde bestanden met toevoegingen van 294 en 0 verwijderingen
  1. 1 0
      CLAUDE.md
  2. 60 0
      README.md
  3. 43 0
      src/gogs-client.ts
  4. 181 0
      src/server.ts
  5. 9 0
      src/types.ts

+ 1 - 0
CLAUDE.md

@@ -39,6 +39,7 @@ The server exposes tools in these categories:
 - **Release Management**: list_releases
 - **Collaborator Management**: list_collaborators, check_collaborator, add_collaborator, remove_collaborator
 - **Public Key Management**: list_user_keys, list_my_keys, get_public_key, create_public_key, delete_public_key
+- **Deploy Key Management**: list_deploy_keys, get_deploy_key, create_deploy_key, delete_deploy_key
 - **Webhook Management**: list_hooks, create_hook, update_hook, delete_hook
 - **User Followers**: list_followers, list_following, check_following, follow_user, unfollow_user
 

+ 60 - 0
README.md

@@ -78,6 +78,12 @@ This MCP server provides tools to:
   - Create new public SSH key
   - Delete public SSH key
 
+- **Deploy Key Management**
+  - List all deploy keys for a repository
+  - Get details of a specific deploy key
+  - Create new deploy key (read-only or read-write)
+  - Delete deploy key
+
 - **User Followers**
   - List followers of a user
   - List users that a user is following
@@ -710,6 +716,60 @@ Create a new public SSH key for the authenticated user. Returns the created key
 Delete a public SSH key by ID. Only the authenticated user can delete their own keys.
 - `keyId` (number, required): Public key ID to delete
 
+### Deploy Key Management Tools
+
+Deploy keys provide secure, repository-specific SSH access for automated deployments and CI/CD workflows. Unlike user keys, deploy keys are attached to specific repositories and can be configured as read-only or read-write.
+
+#### `list_deploy_keys`
+List all deploy keys configured for a repository. Returns key information including ID, title, key content, URL, read-only status, and creation timestamp.
+- `owner` (string, required): Repository owner username
+- `repo` (string, required): Repository name
+
+**Example response:**
+```json
+[
+  {
+    "id": 1,
+    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAA...",
+    "url": "http://gogs.example.com/api/v1/repos/myuser/myrepo/keys/1",
+    "title": "production-deploy",
+    "created_at": "2024-01-15T10:30:00Z",
+    "read_only": true
+  }
+]
+```
+
+#### `get_deploy_key`
+Get details of a specific deploy key by ID. Returns full key information for the specified deploy key.
+- `owner` (string, required): Repository owner username
+- `repo` (string, required): Repository name
+- `keyId` (number, required): Deploy key ID
+
+#### `create_deploy_key`
+Add a new deploy key to a repository. Deploy keys can be configured as read-only (default) for secure deployments or read-write for automated commits.
+- `owner` (string, required): Repository owner username
+- `repo` (string, required): Repository name
+- `title` (string, required): Deploy key title/name for identification
+- `key` (string, required): The public key content in SSH public key format (e.g., "ssh-rsa AAAA...")
+- `read_only` (boolean, optional): Whether the key is read-only. Default: true. Set to false for read-write access.
+
+**Example:**
+```json
+{
+  "owner": "myuser",
+  "repo": "myrepo",
+  "title": "CI/CD Pipeline",
+  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUbm... ci-server@example.com",
+  "read_only": true
+}
+```
+
+#### `delete_deploy_key`
+Remove a deploy key from a repository. Requires admin access to the repository.
+- `owner` (string, required): Repository owner username
+- `repo` (string, required): Repository name
+- `keyId` (number, required): Deploy key ID to delete
+
 ### Webhook Management Tools
 
 #### `list_hooks`

+ 43 - 0
src/gogs-client.ts

@@ -28,6 +28,7 @@ import type {
   GogsWebhookType,
   GogsWebhookConfig,
   GogsFollower,
+  GogsDeployKey,
 } from './types.js';
 
 export class GogsClient {
@@ -842,4 +843,46 @@ export class GogsClient {
   async unfollowUser(username: string): Promise<void> {
     await this.client.delete(`/user/following/${username}`);
   }
+
+  /**
+   * List deploy keys for a repository
+   */
+  async listDeployKeys(owner: string, repo: string): Promise<GogsDeployKey[]> {
+    const response = await this.client.get<GogsDeployKey[]>(`/repos/${owner}/${repo}/keys`);
+    return response.data;
+  }
+
+  /**
+   * Get a specific deploy key by ID
+   */
+  async getDeployKey(owner: string, repo: string, keyId: number): Promise<GogsDeployKey> {
+    const response = await this.client.get<GogsDeployKey>(`/repos/${owner}/${repo}/keys/${keyId}`);
+    return response.data;
+  }
+
+  /**
+   * Create a new deploy key for a repository
+   */
+  async createDeployKey(
+    owner: string,
+    repo: string,
+    data: {
+      title: string;
+      key: string;
+      read_only?: boolean;
+    }
+  ): Promise<GogsDeployKey> {
+    const response = await this.client.post<GogsDeployKey>(
+      `/repos/${owner}/${repo}/keys`,
+      data
+    );
+    return response.data;
+  }
+
+  /**
+   * Delete a deploy key from a repository
+   */
+  async deleteDeployKey(owner: string, repo: string, keyId: number): Promise<void> {
+    await this.client.delete(`/repos/${owner}/${repo}/keys/${keyId}`);
+  }
 }

+ 181 - 0
src/server.ts

@@ -421,6 +421,31 @@ const UnfollowUserSchema = z.object({
   username: z.string().describe('Username to unfollow'),
 });
 
+const ListDeployKeysSchema = z.object({
+  owner: z.string().describe('Repository owner username'),
+  repo: z.string().describe('Repository name'),
+});
+
+const GetDeployKeySchema = z.object({
+  owner: z.string().describe('Repository owner username'),
+  repo: z.string().describe('Repository name'),
+  keyId: z.number().describe('Deploy key ID'),
+});
+
+const CreateDeployKeySchema = z.object({
+  owner: z.string().describe('Repository owner username'),
+  repo: z.string().describe('Repository name'),
+  title: z.string().describe('Deploy key title/name for identification'),
+  key: z.string().describe('The public key content (SSH public key format)'),
+  read_only: z.boolean().optional().describe('Whether the key is read-only (default: true)'),
+});
+
+const DeleteDeployKeySchema = z.object({
+  owner: z.string().describe('Repository owner username'),
+  repo: z.string().describe('Repository name'),
+  keyId: z.number().describe('Deploy key ID to delete'),
+});
+
 /**
  * Create and configure an MCP server with all tools and handlers
  */
@@ -1990,6 +2015,98 @@ export function createMcpServer(gogsClient: GogsClient): Server {
             required: ['username'],
           },
         },
+        {
+          name: 'list_deploy_keys',
+          description: 'List all deploy keys for a repository',
+          inputSchema: {
+            type: 'object',
+            properties: {
+              owner: {
+                type: 'string',
+                description: 'Repository owner username',
+              },
+              repo: {
+                type: 'string',
+                description: 'Repository name',
+              },
+            },
+            required: ['owner', 'repo'],
+          },
+        },
+        {
+          name: 'get_deploy_key',
+          description: 'Get details of a specific deploy key',
+          inputSchema: {
+            type: 'object',
+            properties: {
+              owner: {
+                type: 'string',
+                description: 'Repository owner username',
+              },
+              repo: {
+                type: 'string',
+                description: 'Repository name',
+              },
+              keyId: {
+                type: 'number',
+                description: 'Deploy key ID',
+              },
+            },
+            required: ['owner', 'repo', 'keyId'],
+          },
+        },
+        {
+          name: 'create_deploy_key',
+          description: 'Add a new deploy key to a repository',
+          inputSchema: {
+            type: 'object',
+            properties: {
+              owner: {
+                type: 'string',
+                description: 'Repository owner username',
+              },
+              repo: {
+                type: 'string',
+                description: 'Repository name',
+              },
+              title: {
+                type: 'string',
+                description: 'Deploy key title/name for identification',
+              },
+              key: {
+                type: 'string',
+                description: 'The public key content (SSH public key format)',
+              },
+              read_only: {
+                type: 'boolean',
+                description: 'Whether the key is read-only (default: true)',
+              },
+            },
+            required: ['owner', 'repo', 'title', 'key'],
+          },
+        },
+        {
+          name: 'delete_deploy_key',
+          description: 'Remove a deploy key from a repository',
+          inputSchema: {
+            type: 'object',
+            properties: {
+              owner: {
+                type: 'string',
+                description: 'Repository owner username',
+              },
+              repo: {
+                type: 'string',
+                description: 'Repository name',
+              },
+              keyId: {
+                type: 'number',
+                description: 'Deploy key ID to delete',
+              },
+            },
+            required: ['owner', 'repo', 'keyId'],
+          },
+        },
       ],
     };
   });
@@ -2976,6 +3093,70 @@ export function createMcpServer(gogsClient: GogsClient): Server {
           };
         }
 
+        case 'list_deploy_keys': {
+          const { owner, repo } = ListDeployKeysSchema.parse(args);
+          const keys = await gogsClient.listDeployKeys(owner, repo);
+          return {
+            content: [
+              {
+                type: 'text',
+                text: JSON.stringify(keys, null, 2),
+              },
+            ],
+          };
+        }
+
+        case 'get_deploy_key': {
+          const { owner, repo, keyId } = GetDeployKeySchema.parse(args);
+          const key = await gogsClient.getDeployKey(owner, repo, keyId);
+          return {
+            content: [
+              {
+                type: 'text',
+                text: JSON.stringify(key, null, 2),
+              },
+            ],
+          };
+        }
+
+        case 'create_deploy_key': {
+          const { owner, repo, title, key, read_only } = CreateDeployKeySchema.parse(args);
+          const deployKey = await gogsClient.createDeployKey(owner, repo, {
+            title,
+            key,
+            read_only,
+          });
+          return {
+            content: [
+              {
+                type: 'text',
+                text: JSON.stringify({
+                  success: true,
+                  message: 'Deploy key created successfully',
+                  key: deployKey
+                }, null, 2),
+              },
+            ],
+          };
+        }
+
+        case 'delete_deploy_key': {
+          const { owner, repo, keyId } = DeleteDeployKeySchema.parse(args);
+          await gogsClient.deleteDeployKey(owner, repo, keyId);
+          return {
+            content: [
+              {
+                type: 'text',
+                text: JSON.stringify({
+                  success: true,
+                  message: `Successfully deleted deploy key ${keyId}`,
+                  keyId
+                }, null, 2),
+              },
+            ],
+          };
+        }
+
         default:
           throw new Error(`Unknown tool: ${name}`);
       }

+ 9 - 0
src/types.ts

@@ -249,3 +249,12 @@ export interface GogsWebhook {
 export interface GogsFollower extends GogsUser {
   // Follower is a user, inherits all GogsUser properties
 }
+
+export interface GogsDeployKey {
+  id: number;
+  key: string;
+  url: string;
+  title: string;
+  created_at: string;
+  read_only: boolean;
+}