Skip to content

Commit c4167a8

Browse files
authored
Merge pull request #7 from ydb-platform/auth_methods
Add several auth methods
2 parents fb2a3ce + 32924d9 commit c4167a8

File tree

3 files changed

+108
-41
lines changed

3 files changed

+108
-41
lines changed

README.md

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,58 +31,67 @@
3131
}
3232
```
3333

34-
#### Example: Using Login/Password Authentication
34+
### Via pipx
3535

36-
To use login/password authentication, specify the `--ydb-auth-mode`, `--ydb-login`, and `--ydb-password` arguments:
36+
[pipx](https://pipx.pypa.io/stable/) allows you to run various applications from PyPI without explicitly installing each one. However, it must be [installed](https://pipx.pypa.io/stable/#install-pipx) first. Below are examples of how to configure YDB MCP using `pipx`.
37+
38+
#### Example: Using Anonymous Authentication
3739

3840
```json
3941
{
4042
"mcpServers": {
4143
"ydb": {
42-
"command": "uvx",
44+
"command": "pipx",
4345
"args": [
44-
"ydb-mcp",
45-
"--ydb-endpoint", "grpc://localhost:2136/local",
46-
"--ydb-auth-mode", "login-password",
47-
"--ydb-login", "<your-username>",
48-
"--ydb-password", "<your-password>"
46+
"run", "ydb-mcp",
47+
"--ydb-endpoint", "grpc://localhost:2136/local"
4948
]
5049
}
5150
}
5251
}
5352
```
5453

55-
### Via pipx
54+
### Via pip
5655

57-
[pipx](https://pipx.pypa.io/stable/) allows you to run various applications from PyPI without explicitly installing each one. However, it must be [installed](https://pipx.pypa.io/stable/#install-pipx) first. Below are examples of how to configure YDB MCP using `pipx`.
56+
YDB MCP can be installed using `pip`, [Python's package installer](https://pypi.org/project/pip/). The package is [available on PyPI](https://pypi.org/project/ydb-mcp/) and includes all necessary dependencies.
57+
58+
```bash
59+
pip install ydb-mcp
60+
```
61+
62+
To get started with YDB MCP, you'll need to configure your MCP client to communicate with the YDB instance. Below are example configuration files that you can customize according to your setup and then put into MCP client's settings. Path to the Python interpreter might also need to be adjusted to the correct virtual environment that has the `ydb-mcp` package installed.
5863

5964
#### Example: Using Anonymous Authentication
6065

6166
```json
6267
{
6368
"mcpServers": {
6469
"ydb": {
65-
"command": "pipx",
70+
"command": "python3",
6671
"args": [
67-
"run", "ydb-mcp",
72+
"-m", "ydb_mcp",
6873
"--ydb-endpoint", "grpc://localhost:2136/local"
6974
]
7075
}
7176
}
7277
}
7378
```
7479

75-
#### Example: Using Login/Password Authentication
80+
### Authentication
81+
82+
Regardless of the usage method (`uvx`, `pipx` or `pip`), you can configure authentication for your YDB installation. To do this, pass special command line arguments.
83+
84+
#### Using Login/Password Authentication
7685

7786
To use login/password authentication, specify the `--ydb-auth-mode`, `--ydb-login`, and `--ydb-password` arguments:
7887

7988
```json
8089
{
8190
"mcpServers": {
8291
"ydb": {
83-
"command": "pipx",
92+
"command": "uvx",
8493
"args": [
85-
"run", "ydb-mcp",
94+
"ydb-mcp",
8695
"--ydb-endpoint", "grpc://localhost:2136/local",
8796
"--ydb-auth-mode", "login-password",
8897
"--ydb-login", "<your-username>",
@@ -93,47 +102,40 @@ To use login/password authentication, specify the `--ydb-auth-mode`, `--ydb-logi
93102
}
94103
```
95104

96-
### Via pip
97-
98-
YDB MCP can be installed using `pip`, [Python's package installer](https://pypi.org/project/pip/). The package is [available on PyPI](https://pypi.org/project/ydb-mcp/) and includes all necessary dependencies.
105+
#### Using Access Token Authentication
99106

100-
```bash
101-
pip install ydb-mcp
102-
```
103-
104-
To get started with YDB MCP, you'll need to configure your MCP client to communicate with the YDB instance. Below are example configuration files that you can customize according to your setup and then put into MCP client's settings. Path to the Python interpreter might also need to be adjusted to the correct virtual environment that has the `ydb-mcp` package installed.
105-
106-
#### Example: Using Anonymous Authentication
107+
To use access token authentication, specify the `--ydb-auth-mode` and `--ydb-access-token` arguments:
107108

108109
```json
109110
{
110111
"mcpServers": {
111112
"ydb": {
112-
"command": "python3",
113+
"command": "uvx",
113114
"args": [
114-
"-m", "ydb_mcp",
115-
"--ydb-endpoint", "grpc://localhost:2136/local"
115+
"ydb-mcp",
116+
"--ydb-endpoint", "grpc://localhost:2136/local",
117+
"--ydb-auth-mode", "access-token",
118+
"--ydb-access-token", "qwerty123"
116119
]
117120
}
118121
}
119122
}
120123
```
121124

122-
#### Example: Using Login/Password Authentication
125+
#### Using Service Account Authentication
123126

124-
To use login/password authentication, specify the `--ydb-auth-mode`, `--ydb-login`, and `--ydb-password` arguments:
127+
To use service account authentication, specify the `--ydb-auth-mode` and `--ydb-sa-key-file` arguments:
125128

126129
```json
127130
{
128131
"mcpServers": {
129132
"ydb": {
130-
"command": "python3",
133+
"command": "uvx",
131134
"args": [
132-
"-m", "ydb_mcp",
135+
"ydb-mcp",
133136
"--ydb-endpoint", "grpc://localhost:2136/local",
134-
"--ydb-auth-mode", "login-password",
135-
"--ydb-login", "<your-username>",
136-
"--ydb-password", "<your-password>"
137+
"--ydb-auth-mode", "service-account",
138+
"--ydb-sa-key-file", "~/sa_key.json"
137139
]
138140
}
139141
}

ydb_mcp/__main__.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
import os
66
import sys
77

8-
from ydb_mcp.server import AUTH_MODE_ANONYMOUS, AUTH_MODE_LOGIN_PASSWORD, YDBMCPServer
8+
from ydb_mcp.server import (
9+
AUTH_MODE_ACCESS_TOKEN,
10+
AUTH_MODE_ANONYMOUS,
11+
AUTH_MODE_LOGIN_PASSWORD,
12+
AUTH_MODE_SERVICE_ACCOUNT,
13+
YDBMCPServer,
14+
)
915

1016

1117
def parse_args():
@@ -66,7 +72,12 @@ def main():
6672
)
6773

6874
# Validate auth mode and required credentials
69-
supported_auth_modes = {AUTH_MODE_ANONYMOUS, AUTH_MODE_LOGIN_PASSWORD}
75+
supported_auth_modes = {
76+
AUTH_MODE_ANONYMOUS,
77+
AUTH_MODE_LOGIN_PASSWORD,
78+
AUTH_MODE_ACCESS_TOKEN,
79+
AUTH_MODE_SERVICE_ACCOUNT,
80+
}
7081
auth_mode = args.ydb_auth_mode or AUTH_MODE_ANONYMOUS
7182
if auth_mode not in supported_auth_modes:
7283
print(
@@ -81,26 +92,46 @@ def main():
8192
file=sys.stderr,
8293
)
8394
exit(1)
95+
if auth_mode == AUTH_MODE_ACCESS_TOKEN:
96+
if not args.ydb_access_token:
97+
print(
98+
"Error: --ydb-access-token is required for access-token authentication mode.",
99+
file=sys.stderr,
100+
)
101+
exit(1)
102+
if auth_mode == AUTH_MODE_SERVICE_ACCOUNT:
103+
if not args.ydb_sa_key_file:
104+
print(
105+
"Error: --ydb-sa-key-file is required for service-account authentication mode.",
106+
file=sys.stderr,
107+
)
108+
exit(1)
84109

85110
# Set environment variables for YDB if provided via arguments
86111
if args.ydb_endpoint:
87112
os.environ["YDB_ENDPOINT"] = args.ydb_endpoint
88113
if args.ydb_database:
89114
os.environ["YDB_DATABASE"] = args.ydb_database
115+
if args.ydb_auth_mode:
116+
os.environ["YDB_AUTH_MODE"] = args.ydb_auth_mode
90117
if args.ydb_login:
91118
os.environ["YDB_LOGIN"] = args.ydb_login
92119
if args.ydb_password:
93120
os.environ["YDB_PASSWORD"] = args.ydb_password
94-
if args.ydb_auth_mode:
95-
os.environ["YDB_AUTH_MODE"] = args.ydb_auth_mode
121+
if args.ydb_sa_key_file:
122+
os.environ["YDB_SA_KEY_FILE"] = args.ydb_sa_key_file
123+
if args.ydb_access_token:
124+
os.environ["YDB_ACCESS_TOKEN"] = args.ydb_access_token
96125

97126
# Create and run the server
98127
server = YDBMCPServer(
99128
endpoint=args.ydb_endpoint,
100129
database=args.ydb_database,
130+
auth_mode=auth_mode,
101131
login=args.ydb_login,
102132
password=args.ydb_password,
103-
auth_mode=auth_mode,
133+
access_token=args.ydb_access_token,
134+
sa_key_file=args.ydb_sa_key_file,
104135
)
105136

106137
print("Starting YDB MCP server with stdio transport")

ydb_mcp/server.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
# Authentication mode constants
2323
AUTH_MODE_ANONYMOUS = "anonymous"
2424
AUTH_MODE_LOGIN_PASSWORD = "login-password"
25+
AUTH_MODE_ACCESS_TOKEN = "access-token"
26+
AUTH_MODE_SERVICE_ACCOUNT = "service-account"
2527

2628

2729
class CustomJSONEncoder(json.JSONEncoder):
@@ -99,6 +101,8 @@ def __init__(
99101
auth_mode: str | None = None,
100102
login: str | None = None,
101103
password: str | None = None,
104+
access_token: str | None = None,
105+
sa_key_file: str | None = None,
102106
root_certificates: str | None = None,
103107
*args,
104108
**kwargs,
@@ -134,7 +138,12 @@ def __init__(
134138
self._original_methods: Dict = {}
135139

136140
# Authentication settings
137-
supported_auth_modes = {AUTH_MODE_ANONYMOUS, AUTH_MODE_LOGIN_PASSWORD}
141+
supported_auth_modes = {
142+
AUTH_MODE_ANONYMOUS,
143+
AUTH_MODE_LOGIN_PASSWORD,
144+
AUTH_MODE_ACCESS_TOKEN,
145+
AUTH_MODE_SERVICE_ACCOUNT,
146+
}
138147
self.auth_mode = auth_mode or AUTH_MODE_ANONYMOUS
139148
if self.auth_mode not in supported_auth_modes:
140149
raise ValueError(
@@ -143,6 +152,9 @@ def __init__(
143152
self.login = login
144153
self.password = password
145154

155+
self.sa_key_file = sa_key_file
156+
self.access_token = access_token
157+
146158
# Initialize logging
147159
logging.basicConfig(level=logging.INFO)
148160

@@ -171,6 +183,16 @@ def _login_password_credentials(self) -> ydb.Credentials:
171183
logger.info(f"Using login-password authentication with login: {self.login}")
172184
return ydb.credentials.StaticCredentials.from_user_password(self.login, self.password)
173185

186+
def _access_token_credentials(self) -> ydb.Credentials:
187+
"""Create access token credentials."""
188+
logger.info("Using access token authentication")
189+
return ydb.credentials.AccessTokenCredentials(self.access_token)
190+
191+
def _service_account_credentials(self) -> ydb.Credentials:
192+
"""Create service account credentials."""
193+
logger.info(f"Using service account authentication with key file: {self.sa_key_file}")
194+
return ydb.iam.ServiceAccountCredentials.from_file(self.sa_key_file)
195+
174196
async def create_driver(self):
175197
"""Create a YDB driver with the current settings.
176198
@@ -995,6 +1017,18 @@ def get_credentials_factory(self) -> Optional[Callable[[], ydb.Credentials]]:
9951017
return None
9961018
logger.info(f"Using login/password authentication with user '{self.login}'")
9971019
return self._login_password_credentials
1020+
if self.auth_mode == AUTH_MODE_SERVICE_ACCOUNT:
1021+
if not self.sa_key_file:
1022+
self.auth_error = "Service account key file must be provided for service-account authentication mode."
1023+
return None
1024+
logger.info(f"Using service-account authentication with key file '{self.sa_key_file}'")
1025+
return self._service_account_credentials
1026+
if self.auth_mode == AUTH_MODE_ACCESS_TOKEN:
1027+
if not self.access_token:
1028+
self.auth_error = "Access token must be provided for access-token authentication mode."
1029+
return None
1030+
logger.info("Using access-token authentication with token")
1031+
return self._access_token_credentials
9981032
else:
9991033
# Default to anonymous auth
10001034
logger.info("Using anonymous authentication")

0 commit comments

Comments
 (0)