feat: add Go server implementation in go-server/
Full Go port of local-mcp with all core features. Copied from local-mcp-go worktree to consolidate into single-branch repo (easier maintenance). Architecture: - internal/config: Environment variable configuration - internal/models: Shared types (Instruction, Settings, AgentActivity, etc.) - internal/db: SQLite init with modernc.org/sqlite (pure Go, no CGo) - internal/store: Database operations + WakeupSignal + AgentTracker - internal/events: SSE broker for browser /api/events endpoint - internal/mcp: get_user_request MCP tool with 5s keepalive progress bars - internal/api: chi HTTP router with Bearer auth middleware - main.go: Entry point with auto port switching and Windows interactive banner Dependencies: - github.com/mark3labs/mcp-go@v0.46.0 - github.com/go-chi/chi/v5@v5.2.5 - modernc.org/sqlite@v1.47.0 (pure Go SQLite) - github.com/google/uuid@v1.6.0 Static assets embedded via //go:embed static Features matching Python: - Same wait strategy: 50s with 5s progress keepalives - Same hardcoded constants (DEFAULT_WAIT_SECONDS, DEFAULT_EMPTY_RESPONSE) - Auto port switching (tries 8000-8009) - Windows interactive mode (formatted banner on double-click launch) Build: cd go-server && go build -o local-mcp.exe . Run: ./local-mcp.exe Binary size: ~18 MB (vs Python ~60+ MB memory footprint) Startup: ~10 ms (vs Python ~1-2s)
This commit is contained in:
77
go-server/internal/db/db.go
Normal file
77
go-server/internal/db/db.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// Package db manages the SQLite connection and schema migrations.
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "modernc.org/sqlite" // pure-Go SQLite driver, no CGo required
|
||||
)
|
||||
|
||||
// schema creates all tables if they do not already exist.
|
||||
const schema = `
|
||||
CREATE TABLE IF NOT EXISTS instructions (
|
||||
id TEXT PRIMARY KEY,
|
||||
content TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
consumed_at TEXT,
|
||||
consumed_by_agent_id TEXT,
|
||||
position INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_instructions_status ON instructions(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_instructions_position ON instructions(position);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS agent_activity (
|
||||
agent_id TEXT PRIMARY KEY,
|
||||
last_seen_at TEXT NOT NULL,
|
||||
last_fetch_at TEXT NOT NULL,
|
||||
last_result_type TEXT NOT NULL
|
||||
);
|
||||
`
|
||||
|
||||
// defaultSettings seeds initial values; OR IGNORE means existing rows are unchanged.
|
||||
const defaultSettings = `
|
||||
INSERT OR IGNORE INTO settings (key, value) VALUES ('default_wait_seconds', '10');
|
||||
INSERT OR IGNORE INTO settings (key, value) VALUES ('default_empty_response', '');
|
||||
INSERT OR IGNORE INTO settings (key, value) VALUES ('agent_stale_after_seconds','30');
|
||||
`
|
||||
|
||||
// Open opens (creating if necessary) a SQLite database at dbPath, applies the
|
||||
// schema, and seeds default settings.
|
||||
func Open(dbPath string) (*sql.DB, error) {
|
||||
dir := filepath.Dir(dbPath)
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create db directory: %w", err)
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite", dbPath+"?_pragma=journal_mode(WAL)&_pragma=foreign_keys(on)&_pragma=busy_timeout(5000)")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open database: %w", err)
|
||||
}
|
||||
|
||||
// Serialise all writes through a single connection to avoid locking.
|
||||
db.SetMaxOpenConns(1)
|
||||
|
||||
if _, err := db.Exec(schema); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, fmt.Errorf("apply schema: %w", err)
|
||||
}
|
||||
|
||||
if _, err := db.Exec(defaultSettings); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, fmt.Errorf("seed settings: %w", err)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user