Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3948cd6966 | |||
| cef658ce19 | |||
| 31744d01a1 | |||
| 6ee26f1ad8 |
17
CHANGELOG.md
17
CHANGELOG.md
@@ -73,6 +73,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Comprehensive input schema definitions
|
||||
- Security audit of parameter handling
|
||||
|
||||
## [1.1.9] - 2026-04-30
|
||||
|
||||
### Fixed
|
||||
- **Images returned as MCP image content type**: Updated binary file handling so image files (PNG, JPG, JPEG, GIF, WEBP, SVG) are returned as `{ type: "image", data: "<base64>", mimeType: "..." }` per the MCP 2025-11-25 spec for image content in tool results
|
||||
- Non-image binary files (PDF, ZIP, DOCX, etc.) continue to use the embedded resource format `{ type: "resource", resource: { uri, mimeType, blob } }`
|
||||
|
||||
## [1.1.8] - 2026-04-30
|
||||
|
||||
### Fixed
|
||||
- **Binary files returned as MCP embedded resource**: Updated issue #9 fix to use the proper MCP `EmbeddedResource` format instead of a `BASE64:` text prefix
|
||||
- Binary files are now returned as `{ type: "resource", resource: { uri, mimeType, blob } }`
|
||||
- `uri` is constructed as `obsidian://<vault>/<path>`
|
||||
- `mimeType` is detected from the file extension (PDF, ZIP, images, Office formats, audio/video; defaults to `application/octet-stream`)
|
||||
- `blob` contains the base64-encoded raw bytes
|
||||
|
||||
## [1.1.7] - 2026-04-30
|
||||
|
||||
### Fixed
|
||||
@@ -160,6 +175,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Version History
|
||||
|
||||
- **1.1.8** - Bug fix release: Binary files returned as MCP embedded resource (fixes #9)
|
||||
- **1.1.7** - Bug fix release: Binary files returned as base64 in `obsidian_read_note` (fixes #9)
|
||||
- **1.1.6** - Bug fix release: Clarify `name` vs `path` semantics in `obsidian_create_note` (fixes #8)
|
||||
- **1.1.5** - Bug fix release: Preserve `<` and `>` in note content for Mermaid/HTML (fixes #7)
|
||||
@@ -173,6 +189,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Search & Discovery (12 tools)
|
||||
- Task & Property Management (8 tools)
|
||||
|
||||
[1.1.8]: https://git.mortons.site/Peter.Morton/obsidian-mcp/releases/tag/v1.1.8
|
||||
[1.1.7]: https://git.mortons.site/Peter.Morton/obsidian-mcp/releases/tag/v1.1.7
|
||||
[1.1.6]: https://git.mortons.site/Peter.Morton/obsidian-mcp/releases/tag/v1.1.6
|
||||
[1.1.5]: https://git.mortons.site/Peter.Morton/obsidian-mcp/releases/tag/v1.1.5
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": "0.3",
|
||||
"name": "obsidian-mcp",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.9",
|
||||
"display_name": "Obsidian CLI Bundle",
|
||||
"description": "MCP Bundle for Obsidian CLI - Enable AI assistants to manage Obsidian vaults through conversational interface",
|
||||
"long_description": "This MCP bundle provides a comprehensive set of tools for AI assistants to interact with and manage Obsidian vaults. It includes capabilities for creating, reading, updating, and deleting notes, managing links and tags, handling tasks, and more. With this bundle, AI assistants can seamlessly integrate with Obsidian to help users organize their knowledge and workflows.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-mcp",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.9",
|
||||
"description": "MCP Bundle for Obsidian CLI - Enable AI assistants to manage Obsidian vaults through Model Context Protocol",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -40,6 +40,34 @@ function isBinaryContent(buf: Buffer): boolean {
|
||||
return nonPrintable / sample.length > 0.1;
|
||||
}
|
||||
|
||||
/** Map common file extensions to MIME types */
|
||||
const MIME_TYPES: Record<string, string> = {
|
||||
pdf: 'application/pdf',
|
||||
zip: 'application/zip',
|
||||
gz: 'application/gzip',
|
||||
tar: 'application/x-tar',
|
||||
png: 'image/png',
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
webp: 'image/webp',
|
||||
svg: 'image/svg+xml',
|
||||
mp3: 'audio/mpeg',
|
||||
mp4: 'video/mp4',
|
||||
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
};
|
||||
|
||||
function getMimeType(filePath: string): string {
|
||||
const ext = filePath.split('.').pop()?.toLowerCase() ?? '';
|
||||
return MIME_TYPES[ext] ?? 'application/octet-stream';
|
||||
}
|
||||
|
||||
function isImageMimeType(mimeType: string): boolean {
|
||||
return mimeType.startsWith('image/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all file operation tools
|
||||
*/
|
||||
@@ -151,7 +179,7 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
|
||||
// T031: Read note tool
|
||||
server.registerTool(
|
||||
'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, compiled files, etc.) are automatically detected and returned as a base64-encoded string prefixed with "BASE64:" — the client must base64-decode the value to recover the original binary content.',
|
||||
'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',
|
||||
properties: {
|
||||
@@ -174,7 +202,7 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
|
||||
},
|
||||
},
|
||||
createToolHandler(
|
||||
'Read the content of a note. Binary files are returned as a base64-encoded string prefixed with "BASE64:" — decode it to recover the original binary content.',
|
||||
'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',
|
||||
properties: {
|
||||
@@ -209,13 +237,37 @@ export async function registerFileOperationTools(server: ObsidianMCPServer): Pro
|
||||
const result = await executeObsidianCommandBinary('read', cmdArgs);
|
||||
handleCLIResult(result, { operation: 'read_note', identifier: sanitized.file || sanitized.path });
|
||||
|
||||
// Detect binary content from the raw buffer and return as base64
|
||||
// Detect binary content from the raw buffer and return as spec-appropriate MCP content
|
||||
if (result.stdoutBuffer && isBinaryContent(result.stdoutBuffer)) {
|
||||
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 uri = `obsidian://${encodeURIComponent(vaultName)}/${encodeURIComponent(identifier)}`;
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `BASE64:${result.stdoutBuffer.toString('base64')}`,
|
||||
type: 'resource' as const,
|
||||
resource: {
|
||||
uri,
|
||||
mimeType,
|
||||
blob: base64,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -16,10 +16,12 @@ export interface ToolInput {
|
||||
* Successful tool output
|
||||
*/
|
||||
export interface ToolOutput {
|
||||
content: Array<{
|
||||
type: 'text';
|
||||
text: string;
|
||||
}>;
|
||||
content: Array<
|
||||
| { 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 } }
|
||||
>;
|
||||
isError?: false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user