Skip to content

Commit 7d62beb

Browse files
Pull vector.db from oci registry
1 parent 8406e41 commit 7d62beb

File tree

6 files changed

+482
-9
lines changed

6 files changed

+482
-9
lines changed

cmd/docker-mcp/commands/feature.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ func isFeatureEnabledFromConfig(configFile *configfile.ConfigFile, feature strin
212212
// Features that are enabled by default
213213
defaultEnabledFeatures := map[string]bool{
214214
"mcp-oauth-dcr": true,
215+
"dynamic-tools": true,
215216
}
216217

217218
if configFile.Features == nil {

examples/embeddings/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Embeddings OCI Examples
2+
3+
This directory contains examples for pulling and pushing vector database embeddings to/from OCI registries.
4+
5+
## Pull Example
6+
7+
Downloads the embeddings OCI artifact and installs the vector.db directory to `~/.docker/mcp/`.
8+
9+
### Usage
10+
11+
```bash
12+
# From repository root
13+
go run ./examples/embeddings/pull.go
14+
```
15+
16+
The Pull function will:
17+
1. Download the image from `jimclark106/embeddings:latest`
18+
2. Extract all layers to a temporary directory
19+
3. Verify that `vectors.db` file exists
20+
4. Copy `vectors.db` to `~/.docker/mcp/` (skips if already exists)
21+
5. Clean up temporary files
22+
23+
## Push Example
24+
25+
Creates an OCI artifact from a local vector.db directory and pushes it to a registry.
26+
27+
### Usage
28+
29+
```bash
30+
# From repository root
31+
go run ./examples/embeddings/push.go <vector-db-path> <oci-ref>
32+
```
33+
34+
### Example
35+
36+
```bash
37+
# Push the local vectors.db to your own registry
38+
go run ./examples/embeddings/push.go ~/.docker/mcp/vectors.db jimclark106/embeddings:v1.0
39+
```
40+
41+
The Push function will:
42+
1. Verify the source directory exists
43+
2. Create a tar archive from the entire directory tree (always naming the root as `vectors.db` in the archive)
44+
3. Create an OCI image layer from the tar
45+
4. Push the image to the specified OCI reference
46+
47+
Note: Regardless of your local directory name, the OCI artifact will always contain `vectors.db` at the root for consistency.
48+
49+
## Authentication
50+
51+
Both examples use the Docker credential helper for authentication. Make sure you're logged in to the registry:
52+
53+
```bash
54+
docker login
55+
```
56+
57+
## Notes
58+
59+
- Pull is idempotent - it won't overwrite existing `vectors.db` files
60+
- Push requires write access to the specified OCI registry
61+
- Push always stores the directory as `vectors.db` in the OCI artifact for consistency
62+
- File permissions and symlinks are preserved during push/pull operations

examples/embeddings/pull.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/docker/mcp-gateway/pkg/gateway/embeddings"
9+
)
10+
11+
func main() {
12+
fmt.Println("Pulling embeddings from OCI registry...")
13+
14+
if err := embeddings.Pull(context.Background()); err != nil {
15+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
16+
os.Exit(1)
17+
}
18+
19+
fmt.Println("Successfully pulled embeddings!")
20+
}

examples/embeddings/push.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/docker/mcp-gateway/pkg/gateway/embeddings"
9+
)
10+
11+
func main() {
12+
if len(os.Args) != 3 {
13+
fmt.Fprintf(os.Stderr, "Usage: %s <vector-db-path> <oci-ref>\n", os.Args[0])
14+
fmt.Fprintf(os.Stderr, "\nExample:\n")
15+
fmt.Fprintf(os.Stderr, " %s ~/.docker/mcp/vectors.db jimclark106/embeddings:v1.0\n", os.Args[0])
16+
fmt.Fprintf(os.Stderr, "\nNote: The directory will be stored as 'vectors.db' in the OCI artifact.\n")
17+
os.Exit(1)
18+
}
19+
20+
vectorDBPath := os.Args[1]
21+
ociRef := os.Args[2]
22+
23+
fmt.Printf("Pushing vector database from %s to %s...\n", vectorDBPath, ociRef)
24+
25+
if err := embeddings.Push(context.Background(), vectorDBPath, ociRef); err != nil {
26+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
27+
os.Exit(1)
28+
}
29+
30+
fmt.Printf("Successfully pushed to %s!\n", ociRef)
31+
}

examples/sqlite-vec/main.go

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ type AddVectorRequest struct {
6565
type SearchRequest struct {
6666
Vector []float32 `json:"vector"`
6767
Limit int `json:"limit,omitempty"`
68-
CollectionName string `json:"collection_name,omitempty"` // Empty = search all (or use exclude)
68+
CollectionName string `json:"collection_name,omitempty"` // Deprecated: use collection_names instead
69+
CollectionNames []string `json:"collection_names,omitempty"` // Search in specific collections (empty = search all)
6970
ExcludeCollections []string `json:"exclude_collections,omitempty"` // Collections to exclude from search
7071
}
7172

@@ -133,7 +134,7 @@ func main() {
133134
// Create transport with logging
134135
transport := &mcp.LoggingTransport{
135136
Transport: &mcp.StdioTransport{},
136-
Writer: os.Stderr,
137+
Writer: os.Stderr,
137138
}
138139

139140
// Run server
@@ -303,7 +304,14 @@ func (vs *VectorServer) registerTools(server *mcp.Server) {
303304
},
304305
"collection_name": {
305306
Type: "string",
306-
Description: "Optional: search only within this collection",
307+
Description: "Optional: search only within this single collection (deprecated, use collection_names instead)",
308+
},
309+
"collection_names": {
310+
Type: "array",
311+
Description: "Optional: search only within these collections. If empty, searches all collections.",
312+
Items: &jsonschema.Schema{
313+
Type: "string",
314+
},
307315
},
308316
"exclude_collections": {
309317
Type: "array",
@@ -527,24 +535,38 @@ func (vs *VectorServer) handleSearch(ctx context.Context, req *mcp.CallToolReque
527535
params.Limit = 10
528536
}
529537

538+
// Support backward compatibility: if collection_name is set, add it to collection_names
539+
if params.CollectionName != "" && len(params.CollectionNames) == 0 {
540+
params.CollectionNames = []string{params.CollectionName}
541+
}
542+
530543
vectorJSON, _ := json.Marshal(params.Vector)
531544

532545
var rows *sql.Rows
533546
var err error
534547

535-
if params.CollectionName != "" {
536-
// Search within a specific collection
537-
rows, err = vs.db.Query(`
548+
if len(params.CollectionNames) > 0 {
549+
// Search within specific collections using IN clause
550+
placeholders := make([]string, len(params.CollectionNames))
551+
args := []any{string(vectorJSON)}
552+
for i, name := range params.CollectionNames {
553+
placeholders[i] = "?"
554+
args = append(args, name)
555+
}
556+
args = append(args, params.Limit)
557+
558+
query := fmt.Sprintf(`
538559
SELECT v.id, c.name, v.metadata, vec_distance_cosine(v.vector_blob, vec_f32(?)) as distance
539560
FROM vectors v
540561
JOIN collections c ON v.collection_id = c.id
541-
WHERE c.name = ?
562+
WHERE c.name IN (%s)
542563
ORDER BY distance
543564
LIMIT ?
544-
`, string(vectorJSON), params.CollectionName, params.Limit)
565+
`, strings.Join(placeholders, ","))
566+
567+
rows, err = vs.db.Query(query, args...)
545568
} else if len(params.ExcludeCollections) > 0 {
546569
// Search across all collections EXCEPT the excluded ones
547-
// Build placeholders for the IN clause
548570
placeholders := make([]string, len(params.ExcludeCollections))
549571
args := []any{string(vectorJSON)}
550572
for i, name := range params.ExcludeCollections {

0 commit comments

Comments
 (0)