Skip to content

Packaging #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build and Publish Package to PyPI

on:
push:
tags:
- "v[0-9].[0-9]+.[0-9]+*"
workflow_dispatch:

jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
cache: "pip"

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install hatch ruff

- name: Lint with ruff
run: |
ruff check .

- name: Install package
run: |
pip install -e .

- name: Build package
run: |
hatch build

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: dist/*
generate_release_notes: true
draft: false
prerelease: false
25 changes: 23 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
[project]
name = "mcp-couchbase"
version = "0.1.0"
name = "mcp-server-couchbase"
version = "0.2.0-rc.0"
description = "Couchbase MCP Server - The Developer Data Platform for Critical Applications in Our AI World"
readme = "README.md"
requires-python = ">=3.10"
license = "Apache-2.0"
authors = [
{ name="Nithish Raghunandanan", email="[email protected]" },
]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
"Topic :: Database",
]

dependencies = [
"click>=8.1.8",
Expand All @@ -18,3 +26,16 @@ dependencies = [
Homepage = "https://github.com/Couchbase-Ecosystem/mcp-server-couchbase"
Documentation = "https://github.com/Couchbase-Ecosystem/mcp-server-couchbase#readme"
Issues = "https://github.com/Couchbase-Ecosystem/mcp-server-couchbase/issues"

[project.scripts]
mcp-couchbase-server = "mcp_server_couchbase:main"

[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"

[tool.ruff.lint]
select = ["E", "F", "I", "T201"]

[tool.hatch.build]
packages = ["src/mcp_server_couchbase"]
3 changes: 3 additions & 0 deletions src/mcp_server_couchbase/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from server import main

__all__ = ["main"]
29 changes: 17 additions & 12 deletions src/mcp_server.py → src/mcp_server_couchbase/server.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import logging
from contextlib import asynccontextmanager
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
from mcp.server.fastmcp import FastMCP, Context
from couchbase.cluster import Cluster
from typing import Any, AsyncIterator

import click
from couchbase.auth import PasswordAuthenticator
from couchbase.cluster import Cluster
from couchbase.options import ClusterOptions
import logging
from dataclasses import dataclass
from contextlib import asynccontextmanager
from typing import AsyncIterator
from lark_sqlpp import modifies_data, modifies_structure, parse_sqlpp
import click
from mcp.server.fastmcp import Context, FastMCP

MCP_SERVER_NAME = "couchbase"

Expand Down Expand Up @@ -75,7 +75,10 @@ def get_settings() -> dict:
envvar="READ_ONLY_QUERY_MODE",
type=bool,
default=True,
help="Enable read-only query mode. Set to True (default) to allow only read-only queries. Can be set to False to allow data modification queries.",
help=(
"Enable read-only query mode. Set to True (default) to allow only read-only "
"queries. Can be set to False to allow data modification queries."
),
)
@click.option(
"--transport",
Expand Down Expand Up @@ -166,7 +169,8 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
@mcp.tool()
def get_scopes_and_collections_in_bucket(ctx: Context) -> dict[str, list[str]]:
"""Get the names of all scopes and collections in the bucket.
Returns a dictionary with scope names as keys and lists of collection names as values.
Returns a dictionary with scope names as keys and lists of
collection names as values.
"""
bucket = ctx.request_context.lifespan_context.bucket
try:
Expand All @@ -187,7 +191,8 @@ def get_schema_for_collection(
ctx: Context, scope_name: str, collection_name: str
) -> dict[str, Any]:
"""Get the schema for a collection in the specified scope.
Returns a dictionary with the schema returned by running INFER on the Couchbase collection.
Returns a dictionary with the schema returned by running INFER on the Couchbase
collection.
"""
try:
query = f"INFER {collection_name}"
Expand Down Expand Up @@ -264,7 +269,7 @@ def run_sql_plus_plus_query(
scope = bucket.scope(scope_name)

results = []
# If read-only mode is enabled, check if the query is a data or structure modification query
# If read-only mode is enabled, check if the query modifies data or structure
if read_only_query_mode:
data_modification_query = modifies_data(parse_sqlpp(query))
structure_modification_query = modifies_structure(parse_sqlpp(query))
Expand Down