gkoos/confluence2md-mcp

Go

3

15 commits

updated Sep 20, 2026

See the code

See what people are saying (1)

SourceMessageScoreDate

3 pure-Go CLIs for local-first Confluence search - CGO_ENABLED=0, pluggable embeddings, MCP (r/golang)

I posted this pipeline earlier, but I worked a lot on it and it's getting actually useful :D 3 Go tools: * [confluence2md](https://github.com/gkoos/confluence2md) crawls a Confluence Cloud space into Markdown on disk (one file per page, plus attachments, comments and a link graph in…

1

Sep 20, 2026

README

confluence2md-mcp - MCP Server for confluence2md Indexes

CI Release License: MIT Go Version

MCP server that exposes confluence2md-indexer search to any MCP-compatible AI client. Runs as a local stdio server, queries a SQLite index built from confluence2md exports, and returns ranked results with score metadata.

Part of the confluence2md Platform

confluence2md-mcp is the third step in a three-tool local Confluence knowledge pipeline. It wraps a SQLite index built by confluence2md-indexer (which indexes output from confluence2md) and serves it to AI clients via MCP. See docs/platform.md for the full architecture.

Requirements

Environment Variables

VariableRequiredDescription
CONFLUENCE_INDEX_DBrecommendedPath to the SQLite DB file. Falls back to confluence2md-index.db in the current working directory if unset.
CONFLUENCE2MD_EMBEDDING_PROVIDERoptionalbow-local (default: local, offline, no API key), openai, or openai-compatible.
CONFLUENCE2MD_EMBEDDING_MODELoptionalModel id, for example text-embedding-3-small.
CONFLUENCE2MD_EMBEDDING_DIMoptionalVector dimension such as 1024. Part of the embedding identity.
CONFLUENCE2MD_EMBEDDING_BASE_URLoptionalEndpoint for an openai-compatible provider.
CONFLUENCE2MD_EMBEDDING_API_KEY_ENVoptionalName of the variable that holds the API key (preferred over a literal key).
CONFLUENCE2MD_EMBEDDING_API_KEYoptionalLiteral API key.
CONFLUENCE2MD_EMBEDDING_SKIPoptionaltrue disables the vector channel and leaves lexical search.

The remaining CONFLUENCE2MD_EMBEDDING_* variables of the indexer are honoured too — AUTH_HEADER, AUTH_SCHEME, HEADERS, QUERY_PARAMS, DOCUMENT_PREFIX, QUERY_PREFIX, BATCH_SIZE, TIMEOUT, MAX_RETRIES — see the indexer's docs/embedding-providers.md.

The index and the query must agree on the embedding configuration. An index records the identity of the vectors it holds (provider:variant@dimension, for example bow-local:fnv1a@256), while a hybrid or vector query resolves its own identity from these variables. When the two differ, the query fails with embedding mismatch: ... instead of returning weak results; the tool error names both identities and how to fix it. Use mode: "lexical" to search without embeddings at all.

This server reads environment variables only. The indexer CLI additionally accepts a config.yaml; if you indexed through a configuration file, export the equivalent CONFLUENCE2MD_EMBEDDING_* variables here so that both sides resolve the same provider.

Upgrading an Index

This server links confluence2md-indexer v0.5.0, which reads document metadata columns that indexes built by earlier indexer versions do not have. Such indexes are not migrated in place, so rebuild once after upgrading:

confluence2md-indexer index ./output --rebuild

Querying an index built by an older indexer fails with a database error; rebuilding is the supported fix.

Installation

Download the binary for your platform from Releases and place it somewhere on your PATH.

VS Code

Create or edit .vscode/mcp.json in your workspace:

{
  "servers": {
    "confluence2md": {
      "type": "stdio",
      "command": "confluence2md-mcp",
      "args": [],
      "env": {
        "CONFLUENCE_INDEX_DB": "/path/to/confluence2md-index.db"
      }
    }
  }
}

MCP: Add Server in the Command Palette also works.

Claude Code

claude mcp add confluence2md \
  confluence2md-mcp \
  -e CONFLUENCE_INDEX_DB=/path/to/confluence2md-index.db

WSL note: Use the Linux binary, not the Windows .exe — the .exe does not inherit WSL environment variables. The DB path must be a native Linux path (e.g. /home/user/confluence2md-index.db), not /mnt/c/, to avoid SQLite locking issues on NTFS mounts.

Codex CLI

Add to ~/.codex/config.json:

{
  "mcpServers": {
    "confluence2md": {
      "command": "confluence2md-mcp",
      "args": [],
      "env": {
        "CONFLUENCE_INDEX_DB": "/path/to/confluence2md-index.db"
      }
    }
  }
}

Tools

confluence.search

Search indexed Confluence content from a local SQLite DB.

ArgumentRequiredDescription
querySearch query text
dbPathOverride DB path. Falls back to CONFLUENCE_INDEX_DB env var, then to confluence2md-index.db in the current working directory.
modehybrid (default) | lexical | vector
fusionweighted (default) | rrf
alphaWeighted fusion alpha [0..1], default 0.70
rrfKRRF k constant, default 60
topKCandidates to rank, default 10
limitMax results to return
offsetResult offset
candidateKCandidates per retrieval channel, default 50
expandContext expansion chunk count
spaceKeyFilter by space key
pageIdFilter by page ID
fromDateLower bound YYYY-MM-DD
toDateUpper bound YYYY-MM-DD
spacesFilter by any of several space keys; wins over spaceKey
hostFilter by crawled site host
authorCreator or last modifier name, case-insensitive
createdByCreator name only
modifiedByLast modifier name only
depthMin / depthMaxCrawl depth bounds; depthMin: 1 excludes seed pages
seedOnlyOnly the pages the crawl started from
hasAttachmentsOnly pages that carry at least one attachment
updatedSinceModified within an age (30d, 2w, 12h) or after an absolute date (2026-01-01)
embeddingProviderOverride the provider for this call: bow-local | openai | openai-compatible
embeddingModelOverride the embedding model
embeddingDimOverride the embedding dimension
embeddingBaseURLOverride the embedding endpoint
embeddingApiKeyEnvName of the environment variable that holds the API key
embeddingAuthHeader / embeddingAuthSchemeOverride the authentication header and scheme
embeddingSkipDisable the vector channel for this call
embeddingDocumentPrefix / embeddingQueryPrefixText prefixes for asymmetric models

Metadata filters apply to lexical, vector and hybrid retrieval alike. Arguments win over environment variables: the indexer fills only the embedding fields that the arguments leave unset, so embeddingModel overrides CONFLUENCE2MD_EMBEDDING_MODEL for that call. A literal API key is deliberately not an argument — it would travel through the client conversation and the server log — so set CONFLUENCE2MD_EMBEDDING_API_KEY or name another variable with embeddingApiKeyEnv.

Response fields:

FieldDescription
schemaVersionSchema version string for contract stability
toolAlways "confluence.search"
dbPathResolved DB path used for the query
requestEchoed request parameters
countNumber of results returned in this response
totalTotal ranked results before pagination
resultsArray of result objects with chunk text and score breakdown

Failures are returned as tool errors that keep the indexer's message and add the fix when the cause is actionable: an embedding mismatch names both identities, a missing or vector-less index names the rebuild command, and a disabled vector channel points at CONFLUENCE2MD_EMBEDDING_SKIP. mode: "lexical" works without any embedding configuration.

confluence.list_spaces

List the Confluence space keys the index contains, so a client can scope a search without knowing the keys in advance.

ArgumentRequiredDescription
dbPathOverride DB path. Falls back to CONFLUENCE_INDEX_DB, then to confluence2md-index.db in the current working directory.

Response fields: schemaVersion, tool, dbPath, count, and spaces — a sorted array of space key strings, empty when the index holds no spaces.

Development

Build

# Linux / macOS / WSL
go build -o bin/confluence2md-mcp .

# Windows
go build -o bin/confluence2md-mcp.exe .

# Cross-compile Linux binary from Windows
GOOS=linux GOARCH=amd64 go build -o bin/confluence2md-mcp-linux-amd64 .

If module downloads fail with 403, set GOPROXY=direct.

Test

go test ./... -run TestMCPStdioSmoke -v

The suite also contains an offline end-to-end test: it installs the pinned indexer (go install ...@v0.5.0), builds an index from a temporary corpus with the default bow-local provider, and drives the server over stdio — checking the tool list, the space list, a search narrowed by space and the provider-mismatch error. It needs no API key or running service, and skips only when the indexer CLI cannot be installed.

Version

Release builds stamp the binary through ldflags; the version is reported in the MCP initialize response and written to the startup log. An unstamped go build reports dev.

Troubleshooting

  • No results: verify CONFLUENCE_INDEX_DB points to a built index containing the chunks_fts and embeddings tables.
  • WSL + Windows binary: use the Linux binary with a native Linux DB path — see the WSL note above.
  • Tools not appearing in chat: restart your MCP client after registration.

Contributors

gkoos

15 commits

gkoos/confluence2md-mcp

Go

3

15 commits

updated Sep 20, 2026

See the code

See what people are saying (1)

SourceMessageScoreDate

3 pure-Go CLIs for local-first Confluence search - CGO_ENABLED=0, pluggable embeddings, MCP (r/golang)

I posted this pipeline earlier, but I worked a lot on it and it's getting actually useful :D 3 Go tools: * [confluence2md](https://github.com/gkoos/confluence2md) crawls a Confluence Cloud space into Markdown on disk (one file per page, plus attachments, comments and a link graph in…

1

Sep 20, 2026

README

confluence2md-mcp - MCP Server for confluence2md Indexes

CI Release License: MIT Go Version

MCP server that exposes confluence2md-indexer search to any MCP-compatible AI client. Runs as a local stdio server, queries a SQLite index built from confluence2md exports, and returns ranked results with score metadata.

Part of the confluence2md Platform

confluence2md-mcp is the third step in a three-tool local Confluence knowledge pipeline. It wraps a SQLite index built by confluence2md-indexer (which indexes output from confluence2md) and serves it to AI clients via MCP. See docs/platform.md for the full architecture.

Requirements

Environment Variables

VariableRequiredDescription
CONFLUENCE_INDEX_DBrecommendedPath to the SQLite DB file. Falls back to confluence2md-index.db in the current working directory if unset.
CONFLUENCE2MD_EMBEDDING_PROVIDERoptionalbow-local (default: local, offline, no API key), openai, or openai-compatible.
CONFLUENCE2MD_EMBEDDING_MODELoptionalModel id, for example text-embedding-3-small.
CONFLUENCE2MD_EMBEDDING_DIMoptionalVector dimension such as 1024. Part of the embedding identity.
CONFLUENCE2MD_EMBEDDING_BASE_URLoptionalEndpoint for an openai-compatible provider.
CONFLUENCE2MD_EMBEDDING_API_KEY_ENVoptionalName of the variable that holds the API key (preferred over a literal key).
CONFLUENCE2MD_EMBEDDING_API_KEYoptionalLiteral API key.
CONFLUENCE2MD_EMBEDDING_SKIPoptionaltrue disables the vector channel and leaves lexical search.

The remaining CONFLUENCE2MD_EMBEDDING_* variables of the indexer are honoured too — AUTH_HEADER, AUTH_SCHEME, HEADERS, QUERY_PARAMS, DOCUMENT_PREFIX, QUERY_PREFIX, BATCH_SIZE, TIMEOUT, MAX_RETRIES — see the indexer's docs/embedding-providers.md.

The index and the query must agree on the embedding configuration. An index records the identity of the vectors it holds (provider:variant@dimension, for example bow-local:fnv1a@256), while a hybrid or vector query resolves its own identity from these variables. When the two differ, the query fails with embedding mismatch: ... instead of returning weak results; the tool error names both identities and how to fix it. Use mode: "lexical" to search without embeddings at all.

This server reads environment variables only. The indexer CLI additionally accepts a config.yaml; if you indexed through a configuration file, export the equivalent CONFLUENCE2MD_EMBEDDING_* variables here so that both sides resolve the same provider.

Upgrading an Index

This server links confluence2md-indexer v0.5.0, which reads document metadata columns that indexes built by earlier indexer versions do not have. Such indexes are not migrated in place, so rebuild once after upgrading:

confluence2md-indexer index ./output --rebuild

Querying an index built by an older indexer fails with a database error; rebuilding is the supported fix.

Installation

Download the binary for your platform from Releases and place it somewhere on your PATH.

VS Code

Create or edit .vscode/mcp.json in your workspace:

{
  "servers": {
    "confluence2md": {
      "type": "stdio",
      "command": "confluence2md-mcp",
      "args": [],
      "env": {
        "CONFLUENCE_INDEX_DB": "/path/to/confluence2md-index.db"
      }
    }
  }
}

MCP: Add Server in the Command Palette also works.

Claude Code

claude mcp add confluence2md \
  confluence2md-mcp \
  -e CONFLUENCE_INDEX_DB=/path/to/confluence2md-index.db

WSL note: Use the Linux binary, not the Windows .exe — the .exe does not inherit WSL environment variables. The DB path must be a native Linux path (e.g. /home/user/confluence2md-index.db), not /mnt/c/, to avoid SQLite locking issues on NTFS mounts.

Codex CLI

Add to ~/.codex/config.json:

{
  "mcpServers": {
    "confluence2md": {
      "command": "confluence2md-mcp",
      "args": [],
      "env": {
        "CONFLUENCE_INDEX_DB": "/path/to/confluence2md-index.db"
      }
    }
  }
}

Tools

confluence.search

Search indexed Confluence content from a local SQLite DB.

ArgumentRequiredDescription
querySearch query text
dbPathOverride DB path. Falls back to CONFLUENCE_INDEX_DB env var, then to confluence2md-index.db in the current working directory.
modehybrid (default) | lexical | vector
fusionweighted (default) | rrf
alphaWeighted fusion alpha [0..1], default 0.70
rrfKRRF k constant, default 60
topKCandidates to rank, default 10
limitMax results to return
offsetResult offset
candidateKCandidates per retrieval channel, default 50
expandContext expansion chunk count
spaceKeyFilter by space key
pageIdFilter by page ID
fromDateLower bound YYYY-MM-DD
toDateUpper bound YYYY-MM-DD
spacesFilter by any of several space keys; wins over spaceKey
hostFilter by crawled site host
authorCreator or last modifier name, case-insensitive
createdByCreator name only
modifiedByLast modifier name only
depthMin / depthMaxCrawl depth bounds; depthMin: 1 excludes seed pages
seedOnlyOnly the pages the crawl started from
hasAttachmentsOnly pages that carry at least one attachment
updatedSinceModified within an age (30d, 2w, 12h) or after an absolute date (2026-01-01)
embeddingProviderOverride the provider for this call: bow-local | openai | openai-compatible
embeddingModelOverride the embedding model
embeddingDimOverride the embedding dimension
embeddingBaseURLOverride the embedding endpoint
embeddingApiKeyEnvName of the environment variable that holds the API key
embeddingAuthHeader / embeddingAuthSchemeOverride the authentication header and scheme
embeddingSkipDisable the vector channel for this call
embeddingDocumentPrefix / embeddingQueryPrefixText prefixes for asymmetric models

Metadata filters apply to lexical, vector and hybrid retrieval alike. Arguments win over environment variables: the indexer fills only the embedding fields that the arguments leave unset, so embeddingModel overrides CONFLUENCE2MD_EMBEDDING_MODEL for that call. A literal API key is deliberately not an argument — it would travel through the client conversation and the server log — so set CONFLUENCE2MD_EMBEDDING_API_KEY or name another variable with embeddingApiKeyEnv.

Response fields:

FieldDescription
schemaVersionSchema version string for contract stability
toolAlways "confluence.search"
dbPathResolved DB path used for the query
requestEchoed request parameters
countNumber of results returned in this response
totalTotal ranked results before pagination
resultsArray of result objects with chunk text and score breakdown

Failures are returned as tool errors that keep the indexer's message and add the fix when the cause is actionable: an embedding mismatch names both identities, a missing or vector-less index names the rebuild command, and a disabled vector channel points at CONFLUENCE2MD_EMBEDDING_SKIP. mode: "lexical" works without any embedding configuration.

confluence.list_spaces

List the Confluence space keys the index contains, so a client can scope a search without knowing the keys in advance.

ArgumentRequiredDescription
dbPathOverride DB path. Falls back to CONFLUENCE_INDEX_DB, then to confluence2md-index.db in the current working directory.

Response fields: schemaVersion, tool, dbPath, count, and spaces — a sorted array of space key strings, empty when the index holds no spaces.

Development

Build

# Linux / macOS / WSL
go build -o bin/confluence2md-mcp .

# Windows
go build -o bin/confluence2md-mcp.exe .

# Cross-compile Linux binary from Windows
GOOS=linux GOARCH=amd64 go build -o bin/confluence2md-mcp-linux-amd64 .

If module downloads fail with 403, set GOPROXY=direct.

Test

go test ./... -run TestMCPStdioSmoke -v

The suite also contains an offline end-to-end test: it installs the pinned indexer (go install ...@v0.5.0), builds an index from a temporary corpus with the default bow-local provider, and drives the server over stdio — checking the tool list, the space list, a search narrowed by space and the provider-mismatch error. It needs no API key or running service, and skips only when the indexer CLI cannot be installed.

Version

Release builds stamp the binary through ldflags; the version is reported in the MCP initialize response and written to the startup log. An unstamped go build reports dev.

Troubleshooting

  • No results: verify CONFLUENCE_INDEX_DB points to a built index containing the chunks_fts and embeddings tables.
  • WSL + Windows binary: use the Linux binary with a native Linux DB path — see the WSL note above.
  • Tools not appearing in chat: restart your MCP client after registration.

Contributors

gkoos

15 commits

Languages

Go

100.0%