read_credentials_file
Extract and display C2PA Content Credentials from local files to verify creator identity, AI generation details, and content authenticity.
Instructions
Read Content Credentials from a local file. USE THIS TOOL when the user drops a file or provides a file path AND asks questions like: "who made this", "how was this made", "where does this come from", "is this AI", "is this real", "does this have Content Credentials", "what are the c2pa details", or mentions "c2pa" or "Content Credentials". If the user asks a SPECIFIC question (e.g., "Is this AI?"), answer their question directly using the relevant data, then offer to share more details from the Content Credentials. If the user asks GENERALLY about the file or its credentials, present the information in this order (SKIP sections that have no data): 1) Who this comes from (use BULLET POINTS, prioritize LinkedIn verified identities at the top - OMIT THIS ENTIRE SECTION if no CAWG or personal identity is found), 2) About this content (actions taken - EXCLUDE "c2pa.opened" actions unless specifically requested), 3) About these Content Credentials (signer and timestamp), 4) Validation info (certificate details).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | Absolute or relative path to the file to check for Content Credentials. Supports all filesystem characters including periods, numbers, dashes, underscores, and spaces. Examples: /path/to/file-name.jpg, /mnt/data/image 2.png, ./my-file.2024-01.jpg |
Implementation Reference
- src/index.ts:262-281 (handler)Main handler for read_credentials_file tool in stdio transport. Validates filePath parameter, calls c2paService.readCredentialsFromFile(), and formats the result with TrustMark data support.case 'read_credentials_file': { const params = args as Partial<ReadCredentialsFileParams>; const { filePath } = params; if (!filePath) { throw new Error('Missing required parameter: filePath'); } logger.debug('Processing read_credentials_file', { filePath }); const result = await c2paService.readCredentialsFromFile(filePath); return { content: [ { type: 'text', text: formatResult(result), }, ], }; }
- src/types/request.types.ts:5-10 (schema)Type definition for read_credentials_file tool parameters. Defines the filePath parameter interface./** * Parameters for read_credentials_file tool */ export interface ReadCredentialsFileParams { filePath: string; }
- src/mcp-sse.ts:269-288 (handler)Handler for read_credentials_file tool in SSE transport. Same logic as stdio version but uses ChatGPT-optimized formatting via formatForChatGPT().case 'read_credentials_file': { const params = args as Partial<ReadCredentialsFileParams>; const { filePath } = params; if (!filePath) { throw new Error('Missing required parameter: filePath'); } logger.debug('Processing read_credentials_file', { filePath }); const result = await c2paService.readCredentialsFromFile(filePath); return { content: [ { type: 'text', text: formatResult(result), }, ], }; }
- src/c2pa-service.ts:115-196 (helper)Core implementation of readCredentialsFromFile method. Validates input, checks for embedded C2PA manifests using c2patool, falls back to TrustMark watermark detection, and returns structured results.async readCredentialsFromFile(filePath: string): Promise<C2PAResult> { logger.info('Reading credentials from file', { filePath }); try { // Validate input validateFilePath(filePath); // Check file exists await ensureFileExists(filePath); // Step 1: Execute c2patool to check for embedded credentials logger.info('Checking for embedded C2PA manifest'); const { stdout, stderr } = await this.executeC2PATool(filePath); // Parse C2PA output const c2paResult = this.parseC2PAOutput(stdout, stderr); // If embedded credentials found, return immediately if (c2paResult.hasCredentials) { logger.info('Embedded C2PA credentials found, skipping watermark check'); return c2paResult; } // Step 2: No embedded credentials found, check for TrustMark watermark logger.info('No embedded C2PA found, checking for TrustMark watermark'); const trustMarkResult = await this.trustMarkService.detectWatermark(filePath); // Log TrustMark detection result for debugging logger.debug('TrustMark detection result', { success: trustMarkResult.success, hasWatermark: trustMarkResult.hasWatermark, hasError: !!trustMarkResult.error, }); // If TrustMark detection failed, log the error but continue if (!trustMarkResult.success && trustMarkResult.error) { logger.warn('TrustMark detection failed', { error: trustMarkResult.error }); } // If watermark found, return with watermark data if (trustMarkResult.hasWatermark && trustMarkResult.watermarkData) { logger.info('TrustMark watermark found'); return { success: true, hasCredentials: true, trustMarkData: trustMarkResult.watermarkData, ...(c2paResult.rawOutput && { rawOutput: c2paResult.rawOutput }), }; } // Step 3: Neither embedded credentials nor watermark found logger.info('No Content Credentials found (neither embedded nor watermark)'); return { success: true, hasCredentials: false, ...(c2paResult.rawOutput && { rawOutput: c2paResult.rawOutput }), }; } catch (error: unknown) { logger.error('Failed to read credentials from file', error, { filePath }); const errorMessage = error instanceof Error ? error.message : 'Failed to read credentials'; const errorStderr = error && typeof error === 'object' && 'stderr' in error && typeof (error as { stderr?: string }).stderr === 'string' ? (error as { stderr: string }).stderr : undefined; const result: C2PAResult = { success: false, hasCredentials: false, error: errorMessage, }; if (errorStderr) { result.rawOutput = errorStderr; } return result; } }
- src/index.ts:58-75 (registration)Tool registration in stdio transport server. Defines the tool name, description, and input schema for read_credentials_file.{ name: 'read_credentials_file', description: 'Read Content Credentials from a local file. USE THIS TOOL when the user drops a file or provides a file path AND asks questions like: "who made this", "how was this made", "where does this come from", "is this AI", "is this real", "does this have Content Credentials", "what are the c2pa details", or mentions "c2pa" or "Content Credentials". ' + 'If the user asks a SPECIFIC question (e.g., "Is this AI?"), answer their question directly using the relevant data, then offer to share more details from the Content Credentials. ' + 'If the user asks GENERALLY about the file or its credentials, present the information in this order (SKIP sections that have no data): 1) Who this comes from (use BULLET POINTS, prioritize LinkedIn verified identities at the top - OMIT THIS ENTIRE SECTION if no CAWG or personal identity is found), 2) About this content (actions taken - EXCLUDE "c2pa.opened" actions unless specifically requested), 3) About these Content Credentials (signer and timestamp), 4) Validation info (certificate details).', inputSchema: { type: 'object', properties: { filePath: { type: 'string', description: 'Absolute or relative path to the file to check for Content Credentials. Supports all filesystem characters including periods, numbers, dashes, underscores, and spaces. Examples: /path/to/file-name.jpg, /mnt/data/image 2.png, ./my-file.2024-01.jpg', }, }, required: ['filePath'], }, },