obsidian_fetch 0.1.10 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f1f3795373c330483a11d7c66fdb4bf44b7312a6f4065e7aefd230e9a4fe245
4
- data.tar.gz: 8cd7c19f1780e3c9f89ca537f26ec5ad711073b7cd8e7ba07ed6a4d015b0b9e4
3
+ metadata.gz: 02563af73296a2af37e1ea12b6943dad193c5dc77a24ee5d77462d2d846366a2
4
+ data.tar.gz: fabf0d51658773dc3b708e737116914bde4b55f9e43dda066911c6576f5b38bd
5
5
  SHA512:
6
- metadata.gz: 0ea95a17289bd2ec4f5d940a947abea3c458febdec89ffb7695e58d2ad4ea5cb3f281194552e56ec6ebc4c67557cf6ca12aafeab9c5aad0e2373a3b7a484ff7d
7
- data.tar.gz: 0a089431af584dba6faeafe73b8d86f41ee2dc42bcdd5ef640e56dd65421fb539eaf8107ed4cea5421bbda397103268b234f27c043546a366a4ed9137952f776
6
+ metadata.gz: 83967477cbd13c96797d9254b755af6f5436a70877344b1353dc48c406e8cd9a0bd8d7a061480a125da53e4f66c7126290295645ade26f47a64ba64d9be15c61
7
+ data.tar.gz: f2baff1697d33d8fe8c97fef41b9efeac56b0386bcfc623745e1658a1d7ad1fb9e4c1e0a363c171814f156dad0fc3ca61de9f8c469ca3eef6344ba7622a8e29d
data/README.md CHANGED
@@ -1,20 +1,19 @@
1
1
  # ObsidianFetch
2
2
 
3
- MCP servers specialising in retrieving information from Obsidian vaults.
3
+ MCP servers focused on fetching and presenting information from Obsidian vaults.
4
4
 
5
5
  The existing MCP server has the following drawbacks:
6
- - There are many commands, and when computational resources are limited, it can take a long time to load the prompt.
7
- - When reading a note labeled "LLM," it is necessary to search for the path first before loading it, but the LLM may not always follow this procedure.
8
- - Some tools have unnecessary options, causing the LLM to sometimes fail to invoke the tool correctly.
6
+ - It supports many commands, which can cause slow prompt loading when computational resources are limited.
7
+ - When reading a note labeled "Sample Note", it is necessary to search for its path first before loading it, but the LLM may not always follow this procedure.
8
+ - Some tools include unnecessary options, leading the LLM to sometimes fail to invoke them correctly.
9
9
 
10
10
  These issues become particularly noticeable when running an LLM on a local GPU.
11
- To address this, we developed a new MCP server that simply retrieves and loads a list of notes.
11
+ To address this, we developed a new MCP server that simply retrieves and loads lists of notes.
12
12
 
13
- Additionally, the new server has the following features:
14
- - When the LLM tries to retrieve link information and searches with brackets like `[[link name]]`, it automatically removes characters that cannot be used in links.
15
- - When reading a file, if there are links pointing to the opened file, it displays them.
16
- - Especially in network-style note tools like Obsidian, following such links to load related notes can be very powerful.
17
- - Support for aliases.
13
+ The new server also provides the following additional features:
14
+ - When the LLM attempts to retrieve link information by searching with brackets like `[[link name]]`, the server automatically removes any characters that cannot be used in links.
15
+ - In addition to loading the note contents, it also displays backlinks—notes that link to the currently opened note.
16
+ - This allows the LLM to load and understand the connections between related notes via backlinks.
18
17
 
19
18
  ## Installation
20
19
 
data/exe/obsidian_fetch CHANGED
@@ -1,73 +1,4 @@
1
1
  # !/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'obsidian_fetch'
5
-
6
-
7
- name 'obsidian-fetch'
8
-
9
- version '0.1.0'
10
-
11
- vault_pathes = ARGV
12
-
13
- vault = ObsidianFetch::Vault.new(vault_pathes)
14
- STDERR.puts "Found #{vault.notes.size} notes"
15
- STDERR.puts "Found #{vault.links_by_file_name.size} links and #{vault.links_by_file_path.size} files linked by notes"
16
-
17
- tool 'read' do
18
- description <<~EOS
19
- Read a note from Obsidian vault.
20
- If I find multiple notes with the same name, I will show you all of them.
21
- EOS
22
- argument :name, String, required: true, description: "Note name to read"
23
- call do |args|
24
- name = args[:name]
25
- # 名前が文字列でない場合
26
- next 'Name must be a string' unless name.is_a?(String)
27
- vault.tool_read(name)
28
- end
29
- end
30
-
31
- tool 'read_multiple' do
32
- description <<~EOS
33
- Read a notes from Obsidian vault.
34
- If I find multiple notes with the same name, I will show you all of them.
35
- EOS
36
- argument :names, Array, items: String, required: true, description: "Note names to read"
37
- call do |args|
38
- names = args[:names]
39
- # 名前が文字列の配列でない場合
40
- next 'Name must be an array of strings' unless names.is_a?(Array) && names.all? { |name| name.is_a?(String) }
41
- names.map do |name|
42
- vault.tool_read(name)
43
- end.join("\n\n---\n\n")
44
- end
45
- end
46
-
47
- tool 'list' do
48
- description <<~EOS
49
- Search for files with matching names partially.
50
- EOS
51
- argument :name, String, required: true, description: "Note name to search"
52
- call do |args|
53
- name = args[:name]
54
- # 名前が文字列でない場合
55
- next 'Name must be a string' unless name.is_a?(String)
56
- vault.tool_list(name)
57
- end
58
- end
59
-
60
- tool 'list_multiple' do
61
- description <<~EOS
62
- Search for files with matching names partially.
63
- EOS
64
- argument :names, Array, items: String, required: true, description: "Note names to search"
65
- call do |args|
66
- names = args[:names]
67
- # 名前が文字列の配列でない場合
68
- next 'Name must be an array of strings' unless names.is_a?(Array) && names.all? { |name| name.is_a?(String) }
69
- names.map do |name|
70
- vault.tool_list(name)
71
- end.join("\n\n---\n\n")
72
- end
73
- end
4
+ require 'exe'
data/lib/exe.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'mcp'
2
+ require 'obsidian_fetch'
3
+
4
+ # Obsidian Vaultの初期化
5
+ vault_paths = ARGV
6
+ $vault = ObsidianFetch::Vault.new(vault_paths)
7
+ STDERR.puts "Found #{$vault.notes.size} notes"
8
+ STDERR.puts "Found #{$vault.links_by_file_name.size} links and #{$vault.links_by_file_path.size} files linked by notes"
9
+
10
+ # readツールの定義
11
+ class ReadTool < MCP::Tool
12
+ description "Read a note from Obsidian vault. If multiple notes with the same name are found, all will be shown."
13
+ input_schema(
14
+ properties: {
15
+ name: { type: "string", description: "Note name to read" }
16
+ },
17
+ required: ["name"]
18
+ )
19
+
20
+ def self.call(name:)
21
+ # 名前が文字列でない場合
22
+ return MCP::Tool::Response.new([{ type: "text", text: "Name must be a string" }]) unless name.is_a?(String)
23
+
24
+ # Vaultからノートを読み取る
25
+ result = $vault.tool_read(name)
26
+ MCP::Tool::Response.new([{ type: "text", text: result }])
27
+ end
28
+ end
29
+
30
+ # listツールの定義
31
+ class ListTool < MCP::Tool
32
+ description "Search for files with matching names partially."
33
+ input_schema(
34
+ properties: {
35
+ name: { type: "string", description: "Note name to search" }
36
+ },
37
+ required: ["name"]
38
+ )
39
+
40
+ def self.call(name:)
41
+ # 名前が文字列でない場合
42
+ return MCP::Tool::Response.new([{ type: "text", text: "Name must be a string" }]) unless name.is_a?(String)
43
+
44
+ # Vaultからノートを検索
45
+ result = $vault.tool_list(name)
46
+ MCP::Tool::Response.new([{ type: "text", text: result }])
47
+ end
48
+ end
49
+
50
+ # MCPサーバーの初期化
51
+ server = MCP::Server.new(
52
+ name: "obsidian-fetch",
53
+ version: "0.1.0",
54
+ tools: [ReadTool, ListTool],
55
+ )
56
+
57
+ # Stdioトランスポートを使用してサーバーを起動
58
+ transport = MCP::Server::Transports::StdioTransport.new(server)
59
+ transport.open
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ObsidianFetch
4
- VERSION = "0.1.10"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'yaml'
4
4
  require 'date'
5
- require 'mcp'
6
5
 
7
6
  require_relative "obsidian_fetch/version"
8
7
 
@@ -82,6 +81,7 @@ module ObsidianFetch
82
81
  # もしリンクが設定されていれば、linksに追加する
83
82
  # [[link]]と[[link|displayname]]の場合
84
83
  # linkに.mdが付いている場合、付いていない場合両方を考慮する
84
+ # TODO : linkにディレクトリ名が着くことがあるので、それを除去する
85
85
  content.scan(/\[\[(.*?)(?:\|.*)?\]\]/) do |match|
86
86
  link_name = match[0]
87
87
  link_name = link_name.sub(/\.md$/, '') # .mdを削除
@@ -133,19 +133,60 @@ module ObsidianFetch
133
133
  def tool_read name
134
134
  name = Vault.normalize_note_name(name)
135
135
  file_pathes = @notes[name]
136
+
137
+ # 名前のノートが見つからないが、nameがパスっぽい場合は、パスを修正したうえでもう一度試す
138
+ preface = ""
139
+ if file_pathes.nil? && name.include?('/')
140
+ fixed_name = File.basename(name, '.md')
141
+ file_pathes = @notes[fixed_name]
142
+ if file_pathes.nil?
143
+ # もしも名前で見つからなければ、リンクにも存在しないか確認する
144
+ link_pathes = @links_by_file_name[fixed_name]
145
+ if link_pathes.nil?
146
+ return note_not_found(name)
147
+ else
148
+ # リンク先のノートが見つかった場合は、prefaceを追加する
149
+ preface = <<~EOS
150
+ Presumably a path was specified. The process was automatically renamed and processed.
151
+ EOS
152
+ return list_links(fixed_name, preface)
153
+ end
154
+ else
155
+ # ノート名が見つかった場合は、prefaceを追加する
156
+ preface = <<~EOS
157
+ Presumably a path was specified. The process was automatically renamed and processed.
158
+ EOS
159
+ return open_file(fixed_name, file_pathes, preface)
160
+ end
161
+ end
162
+
136
163
  # 名前のノートが存在しない場合
137
164
  if file_pathes.nil?
138
- return "Note not found: #{name}" if @links_by_file_name[name].nil?
139
- file_pathes = @links_by_file_name[name]
140
- return <<~EOS
141
- Note not found: #{name}
142
- However, I found other notes linked to this note.
143
- #{file_pathes.map { |file_path| "- #{file_path}" }.join("\n")}
144
- EOS
165
+ return note_not_found(name) if @links_by_file_name[name].nil?
166
+ return list_links(name, preface)
145
167
  end
146
-
168
+
169
+ open_file(name, file_pathes, preface)
170
+ end
171
+
172
+ private def note_not_found name
173
+ return <<~EOS
174
+ Note not found: #{name}
175
+ EOS
176
+ end
177
+
178
+ private def list_links name, preface
179
+ return <<~EOS
180
+ #{preface}
181
+ Note not found: #{name}
182
+ However, I found other notes linked to this note.
183
+ #{@links_by_file_name[name].shuffle.map { |file_path| "- #{File.basename(file_path, '.md')}" }.join("\n")}
184
+ EOS
185
+ end
186
+
187
+ private def open_file name, file_pathes, preface
147
188
  # 複数のファイルがある場合は、---とファイル名で区切って返す
148
- file_pathes.map do |file_path|
189
+ result = file_pathes.map do |file_path|
149
190
  content = open(file_path) { |f| f.read.force_encoding('UTF-8') }
150
191
  link_notes = if @links_by_file_path[file_path].nil?
151
192
  ""
@@ -155,16 +196,16 @@ module ObsidianFetch
155
196
  #{(@links_by_file_path[file_path] || []).shuffle.map { |file_path| "- #{File.basename(file_path, '.md')}" }.join("\n")}
156
197
  EOS
157
198
  end
158
- preface = <<~EOS
199
+ metadata = <<~EOS
159
200
  The contents of the note '#{name}' is as follows.
160
201
  #{link_notes}
161
202
  ---
162
-
163
203
  EOS
164
- preface + content
204
+ metadata + content
165
205
  end.join("\n\n---\n\n")
206
+ preface + result
166
207
  end
167
-
208
+
168
209
  MAX_LIST_SIZE = 20
169
210
  def tool_list name
170
211
  name = Vault.normalize_note_name(name)
metadata CHANGED
@@ -1,30 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obsidian_fetch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sou7
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-04-29 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: mcp-rb
13
+ name: mcp
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: 0.3.2
18
+ version: 0.2.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: 0.3.2
27
- description:
25
+ version: 0.2.0
28
26
  email:
29
27
  - soukouki0@yahoo.co.jp
30
28
  executables:
@@ -37,6 +35,7 @@ files:
37
35
  - README.md
38
36
  - Rakefile
39
37
  - exe/obsidian_fetch
38
+ - lib/exe.rb
40
39
  - lib/obsidian_fetch.rb
41
40
  - lib/obsidian_fetch/version.rb
42
41
  - sig/obsidian_fetch.rbs
@@ -47,7 +46,6 @@ metadata:
47
46
  homepage_uri: https://ob.sou7.io/2025-04/week17/obsidian_fetch
48
47
  source_code_uri: https://github.com/soukouki/obsidian_fetch
49
48
  changelog_uri: https://github.com/soukouki/obsidian_fetch/blob/main/CHANGELOG.md
50
- post_install_message:
51
49
  rdoc_options: []
52
50
  require_paths:
53
51
  - lib
@@ -62,8 +60,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
60
  - !ruby/object:Gem::Version
63
61
  version: '0'
64
62
  requirements: []
65
- rubygems_version: 3.5.22
66
- signing_key:
63
+ rubygems_version: 3.6.7
67
64
  specification_version: 4
68
- summary: MCP servers specialising in retrieving information from Obsidian vaults.
65
+ summary: MCP servers focused on fetching and presenting information from Obsidian
66
+ vaults
69
67
  test_files: []