Skip to content

Commit 8f65f84

Browse files
committed
initial commit
1 parent ad4f33f commit 8f65f84

30 files changed

+4058
-24
lines changed

.gitignore

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
1-
# If you prefer the allow list template instead of the deny list, see community template:
2-
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3-
#
4-
# Binaries for programs and plugins
5-
*.exe
6-
*.exe~
7-
*.dll
8-
*.so
9-
*.dylib
10-
111
# Test binary, built with `go test -c`
122
*.test
133

14-
# Code coverage profiles and other test artifacts
4+
# Output of the go coverage tool
155
*.out
16-
coverage.*
17-
*.coverprofile
18-
profile.cov
6+
coverage.html
7+
8+
# SQLite databases
9+
*.db
10+
*.sqlite
11+
*.sqlite3
1912

20-
# Dependency directories (remove the comment below to include it)
21-
# vendor/
13+
# IDE specific files
14+
.idea/
15+
.vscode/
16+
*.swp
17+
*.swo
2218

23-
# Go workspace file
24-
go.work
25-
go.work.sum
19+
# OS specific files
20+
.DS_Store
21+
Thumbs.db
2622

27-
# env file
28-
.env
23+
# Binary files
24+
bin/
25+
dist/
2926

30-
# Editor/IDE
31-
# .idea/
32-
# .vscode/
27+
# Dependency directories
28+
vendor/

Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.PHONY: test coverage coverage-html clean mcp-coverage mcp-coverage-html
2+
3+
# Test all packages
4+
test:
5+
go test -v ./...
6+
7+
# Generate coverage report
8+
coverage:
9+
go test -coverprofile=coverage.out ./...
10+
go tool cover -func=coverage.out
11+
12+
# Generate HTML coverage report
13+
coverage-html: coverage
14+
go tool cover -html=coverage.out -o coverage.html
15+
16+
# MCP-specific coverage
17+
mcp-coverage:
18+
./scripts/test_coverage.sh
19+
20+
# MCP coverage with HTML reports
21+
mcp-coverage-html: mcp-coverage
22+
@echo "HTML reports generated in coverage/ directory"
23+
24+
# Run tests with race detector
25+
test-race:
26+
go test -race -v ./...
27+
28+
# Clean up coverage files
29+
clean:
30+
rm -f coverage.out coverage.html
31+
rm -rf coverage/
32+
33+
# Run all tests and generate coverage report
34+
test-all: clean test-race coverage coverage-html
35+
36+
# Run MCP tests and generate coverage report
37+
mcp-test-all: clean mcp-coverage mcp-coverage-html

README.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# SQLite MCP (Model Context Protocol) Server
2+
3+
A server-side implementation of the Model Context Protocol (MCP) for SQLite databases, enabling AI applications to interact with **multiple SQLite databases** through a standardized protocol. Each database must be registered before use, allowing dynamic database management and multi-database operations.
4+
5+
## Project Structure
6+
7+
```
8+
sqlite-mcp-server/
9+
├── cmd/
10+
│ └── server/ # Main application entry point
11+
├── internal/
12+
│ ├── mcp/ # MCP implementation
13+
│ │ ├── tools/ # Tool implementations
14+
│ │ ├── resources/ # Resource implementations
15+
│ │ └── prompts/ # Prompt templates
16+
│ └── db/ # Database management
17+
│ └── migrations/ # Database migrations
18+
```
19+
20+
## Features
21+
22+
### Database Management Tools
23+
- `db/register_database`: Register a new SQLite database for use
24+
- `db/list_databases`: List all registered databases
25+
26+
### Database Operation Tools
27+
- `db/get_table_schema`: Get schema for a specific table in a database
28+
- `db/insert_record`: Insert a new record into a table
29+
- `db/query`: Execute a read-only SQL query on a specific database
30+
- `db/get_tables`: List all tables in a specific database
31+
- `db/get_schema`: Get full schema of a specific database
32+
33+
### Resources
34+
- `db/databases`: List of all registered databases
35+
36+
### Prompts
37+
- `db/multi_database_help`: Overview of multi-database capabilities
38+
- `db/register_help`: Help for registering databases
39+
- `db/query_help`: Help text for constructing queries
40+
- `db/schema_help`: Help text for understanding schemas
41+
- `db/insert_help`: Help text for inserting records
42+
43+
## Prerequisites
44+
45+
- Go 1.21 or later
46+
- SQLite 3
47+
48+
## Installation
49+
50+
```bash
51+
go install github.com/nipunap/sqlite-mcp-server@latest
52+
```
53+
54+
## Usage
55+
56+
### Starting the Server
57+
58+
Run as a local MCP server:
59+
60+
```bash
61+
# Start with registry only (no default database)
62+
sqlite-mcp-server --registry registry.db
63+
64+
# Start with registry and register a default database
65+
sqlite-mcp-server --registry registry.db --db path/to/default.sqlite
66+
```
67+
68+
The server communicates via STDIO using JSON-RPC 2.0 messages.
69+
70+
### Multi-Database Workflow
71+
72+
1. **Register a database**:
73+
```json
74+
{
75+
"jsonrpc": "2.0",
76+
"id": 1,
77+
"method": "invoke",
78+
"params": {
79+
"name": "db/register_database",
80+
"params": {
81+
"name": "users_db",
82+
"path": "/absolute/path/to/users.sqlite",
83+
"description": "User management database",
84+
"readonly": false,
85+
"owner": "app_user"
86+
}
87+
}
88+
}
89+
```
90+
91+
2. **List registered databases**:
92+
```json
93+
{
94+
"jsonrpc": "2.0",
95+
"id": 2,
96+
"method": "invoke",
97+
"params": {
98+
"name": "db/list_databases",
99+
"params": {}
100+
}
101+
}
102+
```
103+
104+
3. **Query a specific database**:
105+
```json
106+
{
107+
"jsonrpc": "2.0",
108+
"id": 3,
109+
"method": "invoke",
110+
"params": {
111+
"name": "db/query",
112+
"params": {
113+
"database_name": "users_db",
114+
"query": "SELECT * FROM users WHERE id = ?",
115+
"args": [1]
116+
}
117+
}
118+
}
119+
```
120+
121+
4. **Get tables from a specific database**:
122+
```json
123+
{
124+
"jsonrpc": "2.0",
125+
"id": 4,
126+
"method": "invoke",
127+
"params": {
128+
"name": "db/get_tables",
129+
"params": {
130+
"database_name": "users_db"
131+
}
132+
}
133+
}
134+
```
135+
136+
5. **Insert into a specific database**:
137+
```json
138+
{
139+
"jsonrpc": "2.0",
140+
"id": 5,
141+
"method": "invoke",
142+
"params": {
143+
"name": "db/insert_record",
144+
"params": {
145+
"database_name": "users_db",
146+
"table_name": "users",
147+
"data": {
148+
"name": "John Doe",
149+
"email": "john@example.com"
150+
}
151+
}
152+
}
153+
}
154+
```
155+
156+
## Development
157+
158+
1. Clone the repository:
159+
```bash
160+
git clone https://github.com/nipunap/sqlite-mcp-server.git
161+
cd sqlite-mcp-server
162+
```
163+
164+
2. Install dependencies:
165+
```bash
166+
go mod download
167+
```
168+
169+
3. Run tests:
170+
```bash
171+
go test ./...
172+
```
173+
174+
## Contributing
175+
176+
1. Fork the repository
177+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
178+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
179+
4. Push to the branch (`git push origin feature/amazing-feature`)
180+
5. Open a Pull Request
181+
182+
## License
183+
184+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

cmd/server/main.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"log"
7+
"os"
8+
"os/signal"
9+
"path/filepath"
10+
"syscall"
11+
12+
_ "github.com/mattn/go-sqlite3"
13+
"github.com/nipunap/sqlite-mcp-server/internal/db"
14+
"github.com/nipunap/sqlite-mcp-server/internal/mcp"
15+
)
16+
17+
func main() {
18+
// Parse flags
19+
registryPath := flag.String("registry", "registry.db", "Path to database registry")
20+
defaultDB := flag.String("db", "", "Default database to register (optional)")
21+
flag.Parse()
22+
23+
// Create absolute path for registry
24+
absRegistryPath, err := filepath.Abs(*registryPath)
25+
if err != nil {
26+
log.Fatalf("Failed to resolve registry path: %v", err)
27+
}
28+
29+
// Set up database registry
30+
registry, err := db.NewRegistry(absRegistryPath)
31+
if err != nil {
32+
log.Fatalf("Failed to create database registry: %v", err)
33+
}
34+
defer registry.Close()
35+
36+
// Create database manager
37+
manager := db.NewManager(registry)
38+
defer manager.CloseAll()
39+
40+
// Register default database if provided
41+
if *defaultDB != "" {
42+
absDefaultDB, err := filepath.Abs(*defaultDB)
43+
if err != nil {
44+
log.Fatalf("Failed to resolve default database path: %v", err)
45+
}
46+
47+
defaultInfo := &db.DatabaseInfo{
48+
ID: "default",
49+
Name: "default",
50+
Path: absDefaultDB,
51+
Description: "Default database",
52+
ReadOnly: false,
53+
Owner: "system",
54+
Status: "active",
55+
}
56+
57+
if err := registry.RegisterDatabase(defaultInfo); err != nil {
58+
log.Printf("Warning: Failed to register default database (might already exist): %v", err)
59+
} else {
60+
log.Printf("Registered default database: %s", absDefaultDB)
61+
}
62+
}
63+
64+
// Create MCP server
65+
server, err := mcp.NewServer(manager)
66+
if err != nil {
67+
log.Fatalf("Failed to create server: %v", err)
68+
}
69+
70+
// Set up context with cancellation
71+
ctx, cancel := context.WithCancel(context.Background())
72+
defer cancel()
73+
74+
// Handle interrupts
75+
sigChan := make(chan os.Signal, 1)
76+
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
77+
go func() {
78+
<-sigChan
79+
cancel()
80+
}()
81+
82+
// Run server using STDIO transport
83+
if err := server.Run(ctx); err != nil {
84+
log.Fatalf("Server error: %v", err)
85+
}
86+
}

go.mod

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module github.com/nipunap/sqlite-mcp-server
2+
3+
go 1.24.5
4+
5+
require (
6+
github.com/golang-jwt/jwt/v5 v5.3.0
7+
github.com/google/uuid v1.6.0
8+
github.com/graphql-go/graphql v0.8.1
9+
github.com/mattn/go-sqlite3 v1.14.32
10+
golang.org/x/crypto v0.41.0
11+
)
12+
13+
require (
14+
github.com/google/jsonschema-go v0.2.1-0.20250825175020-748c325cec76 // indirect
15+
github.com/modelcontextprotocol/go-sdk v0.3.1 // indirect
16+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
17+
)

go.sum

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
2+
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
3+
github.com/google/jsonschema-go v0.2.1-0.20250825175020-748c325cec76 h1:mBlBwtDebdDYr+zdop8N62a44g+Nbv7o2KjWyS1deR4=
4+
github.com/google/jsonschema-go v0.2.1-0.20250825175020-748c325cec76/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
5+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
6+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
7+
github.com/graphql-go/graphql v0.8.1 h1:p7/Ou/WpmulocJeEx7wjQy611rtXGQaAcXGqanuMMgc=
8+
github.com/graphql-go/graphql v0.8.1/go.mod h1:nKiHzRM0qopJEwCITUuIsxk9PlVlwIiiI8pnJEhordQ=
9+
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
10+
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
11+
github.com/modelcontextprotocol/go-sdk v0.3.1 h1:0z04yIPlSwTluuelCBaL+wUag4YeflIU2Fr4Icb7M+o=
12+
github.com/modelcontextprotocol/go-sdk v0.3.1/go.mod h1:whv0wHnsTphwq7CTiKYHkLtwLC06WMoY2KpO+RB9yXQ=
13+
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
14+
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
15+
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
16+
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=

0 commit comments

Comments
 (0)