# Story 2.6.5: Implement DELETE /credentials/{id}
<!-- Powered by BMAD™ Core -->
## Status
**Draft**
## Story
**As a** workflow automation user,
**I want** to delete unused credentials from my n8n instance through the MCP server,
**so that** I can maintain security hygiene by removing obsolete authentication data and prevent credential sprawl.
## Acceptance Criteria
1. New `delete_credential` MCP tool registered and functional
2. Tool deletes credential by ID
3. Safety check: Warn/block deletion if credential is in use by workflows
4. Multi-instance routing works correctly
5. Error handling for non-existent credentials (404)
6. Error handling for credentials in use (409 or warning)
7. Deletion is permanent (not soft delete)
8. Comprehensive testing including in-use scenarios
9. Documentation with safety warnings
10. Cascade behavior documented and tested
## Tasks / Subtasks
### Task 1: Implement deleteCredential (AC: 1, 2, 4)
- [ ] Add `deleteCredential` method to N8NApiWrapper
- [ ] Use callWithInstance pattern
- [ ] Use DELETE method
- [ ] Support credentialId parameter
- [ ] Add error handling
### Task 2: Register delete_credential Tool (AC: 1)
- [ ] Add tool definition to src/index.ts
- [ ] Define input schema with credentialId
- [ ] Include instance parameter
- [ ] Add safety warnings in description
- [ ] Implement request handler
### Task 3: Safety Logic (AC: 3, 6)
- [ ] Research n8n deletion behavior
- [ ] Document in-use credential handling
- [ ] Test deletion of active credentials
- [ ] Verify error responses
- [ ] Add safety documentation
### Task 4: Create Tests (AC: 8)
- [ ] **Test 4.1**: Delete unused credential
- [ ] Create credential
- [ ] Delete immediately
- [ ] Verify removed from list
- [ ] Confirm 404 on retrieval
- [ ] **Test 4.2**: Delete credential in use (AC: 3, 6)
- [ ] Create credential
- [ ] Assign to workflow
- [ ] Attempt deletion
- [ ] Verify behavior (blocked or cascaded)
- [ ] Document actual behavior
- [ ] **Test 4.3**: Deletion permanence (AC: 7)
- [ ] Delete credential
- [ ] Verify truly removed
- [ ] Check no soft delete
- [ ] Confirm unrecoverable
- [ ] **Test 4.4**: Workflow impact
- [ ] Delete credential used by workflow
- [ ] Check workflow behavior
- [ ] Verify workflow still exists
- [ ] Document credential removal impact
- [ ] **Test 4.5**: Multi-instance deletion
- [ ] Delete from default instance
- [ ] Delete from specific instance
- [ ] Test cross-instance (404)
- [ ] **Test 4.6**: Error scenarios
- [ ] Delete non-existent credential (404)
- [ ] Delete already deleted credential
- [ ] Invalid credential ID
- [ ] **Test 4.7**: Cascade behavior (AC: 10)
- [ ] Document what happens to workflows
- [ ] Test node credential references
- [ ] Verify cascade semantics
### Task 5: Documentation (AC: 9, 10)
- [ ] Add deletion examples
- [ ] Document safety considerations
- [ ] Explain cascade behavior
- [ ] Add warnings about in-use credentials
- [ ] Update README and CHANGELOG
### Task 6: Integration
- [ ] Add to test suite
- [ ] Safety check tests
- [ ] Cleanup utilities
## Dev Notes
### Deletion Safety
**Question:** What happens when deleting credential in use?
**Possible Behaviors:**
1. **Blocked (409 Conflict):** "Credential is in use by X workflows"
2. **Allowed with Warning:** Credential deleted, workflows keep reference
3. **Cascade:** Credential deleted, removed from all workflows
**Testing Required:** Determine actual n8n behavior
### MCP Tool Schema
```typescript
{
name: 'delete_credential',
description: 'Delete a credential (WARNING: Check if in use first)',
inputSchema: {
type: 'object',
properties: {
credentialId: {
type: 'string',
description: 'ID of credential to delete'
},
instance: {
type: 'string',
description: 'Instance identifier (optional)'
}
},
required: ['credentialId']
}
}
```
### Safety Check Strategy
**Option 1:** Pre-delete check
```javascript
async function deleteCredential(id) {
// Check usage first
const credential = await getCredential(id);
if (credential.nodesAccess.length > 0) {
throw new Error('Credential in use by workflows');
}
// Proceed with deletion
await api.delete(`/credentials/${id}`);
}
```
**Option 2:** Let n8n enforce
```javascript
async function deleteCredential(id) {
// Let n8n API handle safety checks
// Return appropriate error if blocked
await api.delete(`/credentials/${id}`);
}
```
**Decision:** Test n8n behavior first, then implement appropriate strategy
## Testing
### Test Pattern
```javascript
// Test deletion of unused credential
const cred = await createCredential({...});
await deleteCredential(cred.id);
const list = await listCredentials();
assert(!list.data.find(c => c.id === cred.id));
// Test deletion of in-use credential
const workflow = await createWorkflow({
// ... uses credential
});
try {
await deleteCredential(cred.id);
// Document if allowed or blocked
} catch (error) {
// Document error response
}
```
## Change Log
| Date | Version | Description | Author |
|------|---------|-------------|--------|
| 2025-12-26 | 1.0 | Story created for DELETE /credentials/{id} | Sarah (PO) |