node-server #10

Merged
Peter.Morton merged 7 commits from node-server into main 2026-04-30 20:46:52 -05:00
2 changed files with 27 additions and 5 deletions
Showing only changes of commit cef658ce19 - Show all commits

View File

@@ -64,6 +64,10 @@ function getMimeType(filePath: string): string {
return MIME_TYPES[ext] ?? 'application/octet-stream'; return MIME_TYPES[ext] ?? 'application/octet-stream';
} }
function isImageMimeType(mimeType: string): boolean {
return mimeType.startsWith('image/');
}
/** /**
* Register all file operation tools * Register all file operation tools
*/ */
@@ -175,7 +179,7 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
// T031: Read note tool // T031: Read note tool
server.registerTool( server.registerTool(
'obsidian_read_note', 'obsidian_read_note',
'Read the content of a note from the Obsidian vault. Specify either the note name (file) or full path (path). For large files (e.g. PDFs), use max_chars and offset to read in chunks and avoid exceeding context limits. Binary files (ZIP, images, PDFs, etc.) are automatically detected and returned as an MCP embedded resource with a uri, mimeType, and base64-encoded blob field instead of plain text.', 'Read the content of a note from the Obsidian vault. Specify either the note name (file) or full path (path). For large files (e.g. PDFs), use max_chars and offset to read in chunks and avoid exceeding context limits. Binary files are automatically detected: images (PNG, JPG, GIF, WEBP, SVG) are returned as MCP image content (type: "image") with base64-encoded data and mimeType; all other binary files (ZIP, PDF, DOCX, etc.) are returned as MCP embedded resource content (type: "resource") with uri, mimeType, and base64-encoded blob.',
{ {
type: 'object', type: 'object',
properties: { properties: {
@@ -198,7 +202,7 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
}, },
}, },
createToolHandler( createToolHandler(
'Read the content of a note. Binary files are returned as an MCP embedded resource (type: "resource") with uri, mimeType, and a base64-encoded blob field.', 'Read the content of a note. Images (PNG, JPG, GIF, WEBP, SVG) are returned as MCP image content (type: "image") with base64-encoded data. Other binary files are returned as MCP embedded resource content (type: "resource") with uri, mimeType, and base64-encoded blob.',
{ {
type: 'object', type: 'object',
properties: { properties: {
@@ -233,12 +237,28 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
const result = await executeObsidianCommandBinary('read', cmdArgs); const result = await executeObsidianCommandBinary('read', cmdArgs);
handleCLIResult(result, { operation: 'read_note', identifier: sanitized.file || sanitized.path }); handleCLIResult(result, { operation: 'read_note', identifier: sanitized.file || sanitized.path });
// Detect binary content from the raw buffer and return as MCP resource // Detect binary content from the raw buffer and return as spec-appropriate MCP content
if (result.stdoutBuffer && isBinaryContent(result.stdoutBuffer)) { if (result.stdoutBuffer && isBinaryContent(result.stdoutBuffer)) {
const identifier = sanitized.file || sanitized.path as string; const identifier = sanitized.file || sanitized.path as string;
const mimeType = getMimeType(identifier);
const base64 = result.stdoutBuffer.toString('base64');
// Images use the MCP image content type per spec
if (isImageMimeType(mimeType)) {
return {
content: [
{
type: 'image' as const,
data: base64,
mimeType,
},
],
};
}
// All other binary files use the embedded resource content type per spec
const vaultName = process.env.OBSIDIAN_VAULT ?? 'vault'; const vaultName = process.env.OBSIDIAN_VAULT ?? 'vault';
const uri = `obsidian://${encodeURIComponent(vaultName)}/${encodeURIComponent(identifier)}`; const uri = `obsidian://${encodeURIComponent(vaultName)}/${encodeURIComponent(identifier)}`;
const mimeType = getMimeType(identifier);
return { return {
content: [ content: [
{ {
@@ -246,7 +266,7 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
resource: { resource: {
uri, uri,
mimeType, mimeType,
blob: result.stdoutBuffer.toString('base64'), blob: base64,
}, },
}, },
], ],

View File

@@ -18,6 +18,8 @@ export interface ToolInput {
export interface ToolOutput { export interface ToolOutput {
content: Array< content: Array<
| { type: 'text'; text: string } | { type: 'text'; text: string }
| { type: 'image'; data: string; mimeType: string }
| { type: 'audio'; data: string; mimeType: string }
| { type: 'resource'; resource: { uri: string; mimeType?: string; blob: string } } | { type: 'resource'; resource: { uri: string; mimeType?: string; blob: string } }
>; >;
isError?: false; isError?: false;