import { z } from 'zod';
import { get, post, put, del, patch } from '../services/api-client.js';
import { CreateCredentialSchema, UpdateCredentialSchema, ListCredentialsSchema, CredentialSchemaRequestSchema, IdParamSchema } from '../schemas/index.js';
// Format credential for display (without sensitive data)
const formatCredential = (credential) => {
return [
`**${credential.name}** (ID: ${credential.id})`,
`- Type: ${credential.type}`,
`- Created: ${credential.createdAt || 'N/A'}`,
`- Updated: ${credential.updatedAt || 'N/A'}`
].join('\n');
};
export const registerCredentialTools = (server) => {
// ============ List Credentials ============
server.registerTool('n8n_list_credentials', {
title: 'List n8n Credentials',
description: `List all credentials (without sensitive data).
Args:
- type (string, optional): Filter by credential type (e.g., "slackApi", "httpBasicAuth")
- limit (number): Maximum results (default: 100)
- cursor (string, optional): Pagination cursor
Returns:
List of credentials with id, name, type, and timestamps.
⚠️ Credential data/secrets are NOT included for security.`,
inputSchema: ListCredentialsSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
const queryParams = { limit: params.limit };
if (params.type)
queryParams.type = params.type;
if (params.cursor)
queryParams.cursor = params.cursor;
const response = await get('/credentials', queryParams);
const formatted = response.data.map(formatCredential).join('\n\n---\n\n');
const output = {
count: response.data.length,
credentials: response.data,
nextCursor: response.nextCursor
};
let text = `Found ${response.data.length} credential(s):\n\n${formatted}`;
if (response.nextCursor) {
text += `\n\n_More results available. Use cursor: ${response.nextCursor}_`;
}
return {
content: [{ type: 'text', text }],
structuredContent: output
};
});
// ============ Get Credential ============
server.registerTool('n8n_get_credential', {
title: 'Get n8n Credential',
description: `Get details of a specific credential (without sensitive data).
Args:
- id (string): Credential ID
Returns:
Credential metadata (id, name, type, timestamps).
⚠️ Credential data/secrets are NOT returned for security.`,
inputSchema: IdParamSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
const credential = await get(`/credentials/${params.id}`);
return {
content: [{ type: 'text', text: formatCredential(credential) }],
structuredContent: credential
};
});
// ============ Create Credential ============
server.registerTool('n8n_create_credential', {
title: 'Create n8n Credential',
description: `Create a new credential.
Args:
- name (string): Credential name
- type (string): Credential type (use n8n_get_credential_schema to see required fields)
- data (object): Credential data (fields depend on type)
Common credential types:
- slackApi: { accessToken }
- httpBasicAuth: { user, password }
- httpHeaderAuth: { name, value }
- oAuth2Api: { clientId, clientSecret, ... }
- gmailOAuth2Api: OAuth credentials for Gmail
- notionApi: { apiKey }
- openAiApi: { apiKey }
Use n8n_get_credential_schema to get the exact fields required for a type.
Returns:
The created credential (without sensitive data).`,
inputSchema: CreateCredentialSchema,
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: false
}
}, async (params) => {
const credential = await post('/credentials', params);
return {
content: [{ type: 'text', text: `✅ Credential created!\n\n${formatCredential(credential)}` }],
structuredContent: credential
};
});
// ============ Update Credential ============
server.registerTool('n8n_update_credential', {
title: 'Update n8n Credential',
description: `Update an existing credential.
Args:
- id (string): Credential ID to update
- name (string, optional): New credential name
- data (object, optional): Updated credential data
Returns:
The updated credential (without sensitive data).`,
inputSchema: UpdateCredentialSchema,
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
const { id, ...updateData } = params;
const credential = await patch(`/credentials/${id}`, updateData);
return {
content: [{ type: 'text', text: `✅ Credential updated!\n\n${formatCredential(credential)}` }],
structuredContent: credential
};
});
// ============ Delete Credential ============
server.registerTool('n8n_delete_credential', {
title: 'Delete n8n Credential',
description: `Delete a credential.
⚠️ WARNING: This will break any workflows using this credential!
Args:
- id (string): Credential ID to delete
Returns:
Confirmation of deletion.`,
inputSchema: IdParamSchema,
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
await del(`/credentials/${params.id}`);
return {
content: [{ type: 'text', text: `✅ Credential ${params.id} deleted successfully.` }],
structuredContent: { deleted: true, id: params.id }
};
});
// ============ Get Credential Schema ============
server.registerTool('n8n_get_credential_schema', {
title: 'Get Credential Schema',
description: `Get the schema/fields required for a credential type.
Args:
- credentialType (string): The credential type (e.g., "slackApi", "httpBasicAuth")
Returns:
JSON schema showing required and optional fields for the credential type.
Use this before creating credentials to know what data fields are needed.`,
inputSchema: CredentialSchemaRequestSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
const schema = await get(`/credentials/schema/${params.credentialType}`);
const properties = Object.entries(schema.properties || {}).map(([key, value]) => {
const required = schema.required?.includes(key) ? '(required)' : '(optional)';
return ` - ${key} ${required}: ${value.type}${value.description ? ` - ${value.description}` : ''}`;
}).join('\n');
const text = `**Credential Schema: ${params.credentialType}**\n\nFields:\n${properties}`;
return {
content: [{ type: 'text', text }],
structuredContent: schema
};
});
// ============ Transfer Credential to Project ============
server.registerTool('n8n_transfer_credential', {
title: 'Transfer Credential to Project',
description: `Transfer a credential to a different project.
Args:
- credentialId (string): Credential ID to transfer
- destinationProjectId (string): Target project ID
Returns:
Confirmation of transfer.`,
inputSchema: z.object({
credentialId: z.string().min(1).describe('Credential ID to transfer'),
destinationProjectId: z.string().min(1).describe('Target project ID')
}).strict(),
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false
}
}, async (params) => {
await put(`/credentials/${params.credentialId}/transfer`, {
destinationProjectId: params.destinationProjectId
});
return {
content: [{ type: 'text', text: `✅ Credential transferred to project ${params.destinationProjectId}` }],
structuredContent: { transferred: true, credentialId: params.credentialId, projectId: params.destinationProjectId }
};
});
};
//# sourceMappingURL=credentials.js.map