Guide for embedding mcp-vector-search as a library in MCP servers
Add semantic search to your MCP server by embedding mcp-vector-search as a library. Use this when building MCP servers that need bundled documentation search without separate user configuration.
/plugin marketplace add hugoduncan/mcp-vector-search/plugin install embed-guide@mcp-vector-search-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Comprehensive guide for embedding mcp-vector-search within your own MCP server to provide semantic search capabilities over bundled documentation or resources.
mcp-vector-search can be used as a library to add semantic search to custom MCP servers. This enables you to bundle documentation with your server and provide semantic search without requiring users to configure vector search separately.
Use cases:
Add mcp-vector-search to your deps.edn:
{:deps
{org.hugoduncan/mcp-vector-search
{:git/url "https://github.com/hugoduncan/mcp-vector-search"
:git/sha "LATEST_SHA_HERE"}}}
Important: Replace LATEST_SHA_HERE with the latest commit SHA from the repository. You can find this by visiting the repository or running:
git ls-remote https://github.com/hugoduncan/mcp-vector-search HEAD
mcp-vector-search supports two types of source specifications:
Use the :path key with absolute paths:
{:sources [{:path "/Users/me/docs/**/*.md"}]}
Characteristics:
/Use the :class-path key with relative paths:
{:sources [{:class-path "docs/**/*.md"}]}
Characteristics:
/When to use each:
You can mix both types in a single configuration to combine bundled resources with user-specific content.
Organize your project to bundle resources:
my-mcp-server/
├── resources/
│ ├── .mcp-vector-search/
│ │ └── config.edn # Configuration for bundled resources
│ └── docs/
│ ├── guide.md
│ ├── api/
│ │ └── reference.md
│ └── examples/
│ └── usage.md
├── src/
│ └── my_server/
│ └── main.clj
└── deps.edn
Key points:
resources/ directoryresources/.mcp-vector-search/config.ednresources/ on the classpathCreate resources/.mcp-vector-search/config.edn:
{:description "Search my-server documentation"
:sources [{:class-path "docs/**/*.md"
:name "Documentation"
:type "docs"}]}
Configuration rules:
:class-path instead of :path/)**/*.md), named captures ((?<category>[^/]+)):watch?) has no effect on classpath sourcesIn your MCP server's main namespace:
(ns my-server.main
(:require
[mcp-vector-search.main :as vector-search]))
(defn -main []
;; Start vector search with classpath config
;; The config at resources/.mcp-vector-search/config.edn
;; will be found automatically on the classpath
(vector-search/start)
;; Your server code here
...)
The server will:
.mcp-vector-search/config.edn on the classpath:class-path sourcesWhen using mcp-vector-search as a library, configuration is loaded from the first location found:
resources/.mcp-vector-search/config.edn (bundled in JAR)./.mcp-vector-search/config.edn (runtime override)~/.mcp-vector-search/config.edn (user-specific)This loading order enables:
Example workflow:
Development with project override:
# Create project-specific config during development
mkdir -p .mcp-vector-search
cat > .mcp-vector-search/config.edn <<EOF
{:description "Development search with local files"
:watch? true
:sources [{:path "/Users/me/project/docs/**/*.md"}]}
EOF
Production with bundled config:
# Build JAR - includes resources/.mcp-vector-search/config.edn
clojure -T:build uber
# Run - uses bundled config
java -jar target/my-server.jar
Ensure resources/ is in your :paths in deps.edn:
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.12.3"}
org.hugoduncan/mcp-vector-search
{:git/url "https://github.com/hugoduncan/mcp-vector-search"
:git/sha "LATEST_SHA_HERE"}}
:aliases
{:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.6"}}
:ns-default build}}}
Create build.clj:
(ns build
(:require [clojure.tools.build.api :as b]))
(def class-dir "target/classes")
(def uber-file "target/my-server.jar")
(defn uber [_]
(b/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-dir})
(b/compile-clj {:basis (b/create-basis)
:class-dir class-dir})
(b/uber {:class-dir class-dir
:uber-file uber-file
:basis (b/create-basis)
:main 'my-server.main}))
Important: Include both "src" and "resources" in :src-dirs to bundle all resources.
# Build the JAR
clojure -T:build uber
# Verify resources are included
jar tf target/my-server.jar | grep -E "(docs|.mcp-vector-search)"
# Run the server
java -jar target/my-server.jar
Users can now run your MCP server with semantic search over your bundled documentation, without any configuration needed.
;; resources/.mcp-vector-search/config.edn
{:description "Search API documentation and examples"
:sources [{:class-path "api-docs/**/*.md"
:category "api"}
{:class-path "examples/**/*.clj"
:ingest :namespace-doc
:category "examples"}]}
Combine bundled resources with filesystem sources:
{:description "Search bundled docs and local project files"
:sources [
;; Bundled documentation (from JAR)
{:class-path "lib-docs/**/*.md"
:source "library"
:type "docs"}
;; Local project documentation (filesystem)
{:path "/Users/me/project/docs/**/*.md"
:source "project"
:type "docs"}
;; Local source code (filesystem)
{:path "/Users/me/project/src/**/*.clj"
:ingest :namespace-doc
:source "project"
:type "source"}]}
Extract language metadata from paths:
{:description "Search multi-language documentation"
:sources [{:class-path "docs/(?<lang>en|es|fr)/**/*.md"
:type "documentation"}]}
For resource docs/en/guide.md:
{:type "documentation", :lang "en"}{:description "Search bundled API documentation"
:sources [{:class-path "src/**/*.clj"
:ingest :code-analysis
:visibility :public-only
:category "api"}]}
my-mcp-server/
├── resources/
│ ├── .mcp-vector-search/
│ │ └── config.edn
│ └── docs/
│ ├── README.md
│ └── api/
│ └── reference.md
├── src/
│ └── my_server/
│ └── main.clj
├── deps.edn
└── build.clj
;; resources/.mcp-vector-search/config.edn
{:description "Search my-server documentation"
:sources [{:class-path "docs/**/*.md"
:project "my-server"
:type "documentation"}]}
;; src/my_server/main.clj
(ns my-server.main
(:require
[mcp-vector-search.main :as vector-search]
[mcp-vector-search.server :as mcp-server]))
(defn -main []
;; Start vector search (loads classpath config automatically)
(vector-search/start)
;; Add your custom tools here
;; ...
;; Start MCP server
(mcp-server/start!))
;; deps.edn
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.12.3"}
org.hugoduncan/mcp-vector-search
{:git/url "https://github.com/hugoduncan/mcp-vector-search"
:git/sha "LATEST_SHA_HERE"}}
:aliases
{:build {:deps {io.github.clojure/tools.build {:mvn/version "0.9.6"}}
:ns-default build}}}
;; build.clj
(ns build
(:require [clojure.tools.build.api :as b]))
(def class-dir "target/classes")
(def uber-file "target/my-server.jar")
(defn uber [_]
(b/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-dir})
(b/compile-clj {:basis (b/create-basis)
:class-dir class-dir})
(b/uber {:class-dir class-dir
:uber-file uber-file
:basis (b/create-basis)
:main 'my-server.main}))
Classpath sources do not support file watching:
:watch? flag has no effect on :class-path sourcesWorkaround for development: Use filesystem sources instead:
;; Development config (local file) - with watching
{:watch? true
:sources [{:path "/Users/me/project/resources/docs/**/*.md"}]}
;; Production config (bundled) - no watching needed
{:sources [{:class-path "docs/**/*.md"}]}
Classpath resource discovery walks the entire classpath:
docs/**/*.md not **/*.md)Error: No configuration file found
Check:
resources/.mcp-vector-search/config.ednresources/ is on the classpath (should be automatic in :paths)Verify config is on classpath:
(require '[clojure.java.io :as io])
(io/resource ".mcp-vector-search/config.edn") ;; Should return URL
Error: No documents indexed from classpath sources
Check:
resources/ directory/ in :class-path values (should be relative)Verify resources are on classpath:
(require '[clojure.java.io :as io])
(io/resource "docs/guide.md") ;; Should return URL
Error: Resources missing from JAR
Check:
resources/ is in :paths in deps.edn:{:paths ["src" "resources"]
:deps {...}}
resources/ is in :src-dirs in build.clj:(b/copy-dir {:src-dirs ["src" "resources"]
:target-dir class-dir})
jar tf my-server.jar | grep docs
jar tf my-server.jar | grep .mcp-vector-search
Error: Some resources not matched
Common mistakes:
/ with :class-path (should be relative)** for recursive matchingTest patterns:
;; Wrong - leading slash
{:class-path "/docs/**/*.md"}
;; Correct - relative path
{:class-path "docs/**/*.md"}
;; Wrong - single glob doesn't recurse
{:class-path "docs/*.md"} ;; only matches docs/file.md
;; Correct - recursive glob
{:class-path "docs/**/*.md"} ;; matches docs/api/file.md
Resource organization:
resources/ directorydocs/, api/, examples/).mcp-vector-search/config.edn in resources/Configuration strategy:
resources/.mcp-vector-search/config.edn:class-path for bundled contentPath specifications:
docs/**/*.md not **/*.md)Build process:
"resources" in both :paths and :src-dirsDevelopment workflow:
:watch? during developmentTesting:
This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.