mssql-agent-mcp 1.0.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mssql-agent-mcp
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: MCP server for Microsoft SQL Server with SQL Agent job management and stored procedure version control
5
5
  Project-URL: Homepage, https://github.com/yyinhsu/mssql-agent-mcp
6
6
  Project-URL: Repository, https://github.com/yyinhsu/mssql-agent-mcp
@@ -37,6 +37,10 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  # MSSQL Agent MCP
39
39
 
40
+ [![PyPI version](https://badge.fury.io/py/mssql-agent-mcp.svg)](https://badge.fury.io/py/mssql-agent-mcp)
41
+ [![Python](https://img.shields.io/pypi/pyversions/mssql-agent-mcp.svg)](https://pypi.org/project/mssql-agent-mcp/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
+
40
44
  A Model Context Protocol (MCP) server that provides tools for interacting with Microsoft SQL Server databases and managing SQL Server Agent Jobs.
41
45
  Beyond basic database query functionality, this server supports managing stored procedures and SQL Server Agent jobs as code. Users can easily export, edit, and update these objects, and integrate them into version control systems.
42
46
 
@@ -329,7 +333,9 @@ Download and install from [Microsoft ODBC Driver for SQL Server](https://docs.mi
329
333
 
330
334
  ## Installation
331
335
 
332
- ### Using pip
336
+ This package is available on [PyPI](https://pypi.org/project/mssql-agent-mcp/).
337
+
338
+ ### Using pip (Recommended)
333
339
 
334
340
  ```bash
335
341
  pip install mssql-agent-mcp
@@ -341,9 +347,16 @@ pip install mssql-agent-mcp
341
347
  pip install mssql-agent-mcp[azure]
342
348
  ```
343
349
 
350
+ ### Using uvx (No Installation Required)
351
+
352
+ ```bash
353
+ uvx mssql-agent-mcp
354
+ ```
355
+
344
356
  ### Development Installation
345
357
 
346
358
  ```bash
359
+ git clone https://github.com/yyinhsu/mssql-agent-mcp.git
347
360
  cd mssql-agent-mcp
348
361
  pip install -e .
349
362
  ```
@@ -366,6 +379,40 @@ MSSQL_READONLY=true
366
379
  MSSQL_READONLY=false
367
380
  ```
368
381
 
382
+ ### Granular Permission Control
383
+
384
+ When `MSSQL_READONLY=false`, you can further control which operations are allowed using these environment variables:
385
+
386
+ | Variable | Default | Controls |
387
+ |----------|---------|----------|
388
+ | `MSSQL_ALLOW_INSERT` | `true` | INSERT, MERGE statements |
389
+ | `MSSQL_ALLOW_UPDATE` | `true` | UPDATE statements |
390
+ | `MSSQL_ALLOW_DELETE` | `true` | DELETE, TRUNCATE statements |
391
+ | `MSSQL_ALLOW_DDL` | `true` | CREATE, ALTER, DROP, GRANT, REVOKE, DENY |
392
+ | `MSSQL_ALLOW_EXEC` | `true` | EXEC, EXECUTE (also controls job step updates) |
393
+
394
+ **Example: Allow only SELECT and INSERT:**
395
+ ```env
396
+ MSSQL_READONLY=false
397
+ MSSQL_ALLOW_INSERT=true
398
+ MSSQL_ALLOW_UPDATE=false
399
+ MSSQL_ALLOW_DELETE=false
400
+ MSSQL_ALLOW_DDL=false
401
+ MSSQL_ALLOW_EXEC=false
402
+ ```
403
+
404
+ **Example: Allow data modifications but block schema changes:**
405
+ ```env
406
+ MSSQL_READONLY=false
407
+ MSSQL_ALLOW_INSERT=true
408
+ MSSQL_ALLOW_UPDATE=true
409
+ MSSQL_ALLOW_DELETE=true
410
+ MSSQL_ALLOW_DDL=false
411
+ MSSQL_ALLOW_EXEC=false
412
+ ```
413
+
414
+ > **Note**: These granular settings only take effect when `MSSQL_READONLY=false`. When `MSSQL_READONLY=true`, all write operations are blocked regardless of other settings.
415
+
369
416
  ### Environment Variables
370
417
 
371
418
  | Variable | Default | Description |
@@ -379,7 +426,12 @@ MSSQL_READONLY=false
379
426
  | `MSSQL_ENCRYPT` | `yes` | Connection encryption (`yes`/`no`) |
380
427
  | `MSSQL_TRUST_SERVER_CERTIFICATE` | `no` | Trust self-signed certificates (`yes`/`no`) |
381
428
  | `MSSQL_AUTH_MODE` | `sql` | Authentication mode: `sql`, `windows`, or `azure` |
382
- | `MSSQL_READONLY` | `true` | Block write operations (`true`/`false`) |
429
+ | `MSSQL_READONLY` | `true` | Block all write operations (`true`/`false`) |
430
+ | `MSSQL_ALLOW_INSERT` | `true` | Allow INSERT/MERGE (when not readonly) |
431
+ | `MSSQL_ALLOW_UPDATE` | `true` | Allow UPDATE (when not readonly) |
432
+ | `MSSQL_ALLOW_DELETE` | `true` | Allow DELETE/TRUNCATE (when not readonly) |
433
+ | `MSSQL_ALLOW_DDL` | `true` | Allow DDL operations (when not readonly) |
434
+ | `MSSQL_ALLOW_EXEC` | `true` | Allow EXEC/EXECUTE (when not readonly) | |
383
435
 
384
436
  ### Authentication Modes
385
437
 
@@ -440,28 +492,26 @@ Add to your Claude Desktop configuration file:
440
492
  {
441
493
  "mcpServers": {
442
494
  "mssql": {
443
- "command": "python",
444
- "args": ["-m", "mssql_mcp.server"],
445
- "cwd": "/path/to/eagle_eye_sql_agent_job/mssql_db_mcp/src",
495
+ "command": "mssql-agent-mcp",
446
496
  "env": {
447
497
  "MSSQL_SERVER": "localhost",
448
498
  "MSSQL_DATABASE": "your_database",
449
499
  "MSSQL_USER": "your_username",
450
- "MSSQL_PASSWORD": "your_password",
451
- "MSSQL_PORT": "1433"
500
+ "MSSQL_PASSWORD": "your_password"
452
501
  }
453
502
  }
454
503
  }
455
504
  }
456
505
  ```
457
506
 
458
- Or if installed as a package:
507
+ Or using uvx (no installation required):
459
508
 
460
509
  ```json
461
510
  {
462
511
  "mcpServers": {
463
512
  "mssql": {
464
- "command": "mssql-agent-mcp",
513
+ "command": "uvx",
514
+ "args": ["mssql-agent-mcp"],
465
515
  "env": {
466
516
  "MSSQL_SERVER": "localhost",
467
517
  "MSSQL_DATABASE": "your_database",
@@ -481,9 +531,26 @@ Add to your VS Code MCP configuration (`.vscode/mcp.json`):
481
531
  {
482
532
  "servers": {
483
533
  "mssql": {
484
- "command": "python",
485
- "args": ["-m", "mssql_mcp.server"],
486
- "cwd": "${workspaceFolder}/mssql_db_mcp/src",
534
+ "command": "mssql-agent-mcp",
535
+ "env": {
536
+ "MSSQL_SERVER": "localhost",
537
+ "MSSQL_DATABASE": "your_database",
538
+ "MSSQL_USER": "your_username",
539
+ "MSSQL_PASSWORD": "your_password"
540
+ }
541
+ }
542
+ }
543
+ }
544
+ ```
545
+
546
+ Or using uvx:
547
+
548
+ ```json
549
+ {
550
+ "servers": {
551
+ "mssql": {
552
+ "command": "uvx",
553
+ "args": ["mssql-agent-mcp"],
487
554
  "env": {
488
555
  "MSSQL_SERVER": "localhost",
489
556
  "MSSQL_DATABASE": "your_database",
@@ -1,5 +1,9 @@
1
1
  # MSSQL Agent MCP
2
2
 
3
+ [![PyPI version](https://badge.fury.io/py/mssql-agent-mcp.svg)](https://badge.fury.io/py/mssql-agent-mcp)
4
+ [![Python](https://img.shields.io/pypi/pyversions/mssql-agent-mcp.svg)](https://pypi.org/project/mssql-agent-mcp/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
3
7
  A Model Context Protocol (MCP) server that provides tools for interacting with Microsoft SQL Server databases and managing SQL Server Agent Jobs.
4
8
  Beyond basic database query functionality, this server supports managing stored procedures and SQL Server Agent jobs as code. Users can easily export, edit, and update these objects, and integrate them into version control systems.
5
9
 
@@ -292,7 +296,9 @@ Download and install from [Microsoft ODBC Driver for SQL Server](https://docs.mi
292
296
 
293
297
  ## Installation
294
298
 
295
- ### Using pip
299
+ This package is available on [PyPI](https://pypi.org/project/mssql-agent-mcp/).
300
+
301
+ ### Using pip (Recommended)
296
302
 
297
303
  ```bash
298
304
  pip install mssql-agent-mcp
@@ -304,9 +310,16 @@ pip install mssql-agent-mcp
304
310
  pip install mssql-agent-mcp[azure]
305
311
  ```
306
312
 
313
+ ### Using uvx (No Installation Required)
314
+
315
+ ```bash
316
+ uvx mssql-agent-mcp
317
+ ```
318
+
307
319
  ### Development Installation
308
320
 
309
321
  ```bash
322
+ git clone https://github.com/yyinhsu/mssql-agent-mcp.git
310
323
  cd mssql-agent-mcp
311
324
  pip install -e .
312
325
  ```
@@ -329,6 +342,40 @@ MSSQL_READONLY=true
329
342
  MSSQL_READONLY=false
330
343
  ```
331
344
 
345
+ ### Granular Permission Control
346
+
347
+ When `MSSQL_READONLY=false`, you can further control which operations are allowed using these environment variables:
348
+
349
+ | Variable | Default | Controls |
350
+ |----------|---------|----------|
351
+ | `MSSQL_ALLOW_INSERT` | `true` | INSERT, MERGE statements |
352
+ | `MSSQL_ALLOW_UPDATE` | `true` | UPDATE statements |
353
+ | `MSSQL_ALLOW_DELETE` | `true` | DELETE, TRUNCATE statements |
354
+ | `MSSQL_ALLOW_DDL` | `true` | CREATE, ALTER, DROP, GRANT, REVOKE, DENY |
355
+ | `MSSQL_ALLOW_EXEC` | `true` | EXEC, EXECUTE (also controls job step updates) |
356
+
357
+ **Example: Allow only SELECT and INSERT:**
358
+ ```env
359
+ MSSQL_READONLY=false
360
+ MSSQL_ALLOW_INSERT=true
361
+ MSSQL_ALLOW_UPDATE=false
362
+ MSSQL_ALLOW_DELETE=false
363
+ MSSQL_ALLOW_DDL=false
364
+ MSSQL_ALLOW_EXEC=false
365
+ ```
366
+
367
+ **Example: Allow data modifications but block schema changes:**
368
+ ```env
369
+ MSSQL_READONLY=false
370
+ MSSQL_ALLOW_INSERT=true
371
+ MSSQL_ALLOW_UPDATE=true
372
+ MSSQL_ALLOW_DELETE=true
373
+ MSSQL_ALLOW_DDL=false
374
+ MSSQL_ALLOW_EXEC=false
375
+ ```
376
+
377
+ > **Note**: These granular settings only take effect when `MSSQL_READONLY=false`. When `MSSQL_READONLY=true`, all write operations are blocked regardless of other settings.
378
+
332
379
  ### Environment Variables
333
380
 
334
381
  | Variable | Default | Description |
@@ -342,7 +389,12 @@ MSSQL_READONLY=false
342
389
  | `MSSQL_ENCRYPT` | `yes` | Connection encryption (`yes`/`no`) |
343
390
  | `MSSQL_TRUST_SERVER_CERTIFICATE` | `no` | Trust self-signed certificates (`yes`/`no`) |
344
391
  | `MSSQL_AUTH_MODE` | `sql` | Authentication mode: `sql`, `windows`, or `azure` |
345
- | `MSSQL_READONLY` | `true` | Block write operations (`true`/`false`) |
392
+ | `MSSQL_READONLY` | `true` | Block all write operations (`true`/`false`) |
393
+ | `MSSQL_ALLOW_INSERT` | `true` | Allow INSERT/MERGE (when not readonly) |
394
+ | `MSSQL_ALLOW_UPDATE` | `true` | Allow UPDATE (when not readonly) |
395
+ | `MSSQL_ALLOW_DELETE` | `true` | Allow DELETE/TRUNCATE (when not readonly) |
396
+ | `MSSQL_ALLOW_DDL` | `true` | Allow DDL operations (when not readonly) |
397
+ | `MSSQL_ALLOW_EXEC` | `true` | Allow EXEC/EXECUTE (when not readonly) | |
346
398
 
347
399
  ### Authentication Modes
348
400
 
@@ -403,28 +455,26 @@ Add to your Claude Desktop configuration file:
403
455
  {
404
456
  "mcpServers": {
405
457
  "mssql": {
406
- "command": "python",
407
- "args": ["-m", "mssql_mcp.server"],
408
- "cwd": "/path/to/eagle_eye_sql_agent_job/mssql_db_mcp/src",
458
+ "command": "mssql-agent-mcp",
409
459
  "env": {
410
460
  "MSSQL_SERVER": "localhost",
411
461
  "MSSQL_DATABASE": "your_database",
412
462
  "MSSQL_USER": "your_username",
413
- "MSSQL_PASSWORD": "your_password",
414
- "MSSQL_PORT": "1433"
463
+ "MSSQL_PASSWORD": "your_password"
415
464
  }
416
465
  }
417
466
  }
418
467
  }
419
468
  ```
420
469
 
421
- Or if installed as a package:
470
+ Or using uvx (no installation required):
422
471
 
423
472
  ```json
424
473
  {
425
474
  "mcpServers": {
426
475
  "mssql": {
427
- "command": "mssql-agent-mcp",
476
+ "command": "uvx",
477
+ "args": ["mssql-agent-mcp"],
428
478
  "env": {
429
479
  "MSSQL_SERVER": "localhost",
430
480
  "MSSQL_DATABASE": "your_database",
@@ -444,9 +494,26 @@ Add to your VS Code MCP configuration (`.vscode/mcp.json`):
444
494
  {
445
495
  "servers": {
446
496
  "mssql": {
447
- "command": "python",
448
- "args": ["-m", "mssql_mcp.server"],
449
- "cwd": "${workspaceFolder}/mssql_db_mcp/src",
497
+ "command": "mssql-agent-mcp",
498
+ "env": {
499
+ "MSSQL_SERVER": "localhost",
500
+ "MSSQL_DATABASE": "your_database",
501
+ "MSSQL_USER": "your_username",
502
+ "MSSQL_PASSWORD": "your_password"
503
+ }
504
+ }
505
+ }
506
+ }
507
+ ```
508
+
509
+ Or using uvx:
510
+
511
+ ```json
512
+ {
513
+ "servers": {
514
+ "mssql": {
515
+ "command": "uvx",
516
+ "args": ["mssql-agent-mcp"],
450
517
  "env": {
451
518
  "MSSQL_SERVER": "localhost",
452
519
  "MSSQL_DATABASE": "your_database",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mssql-agent-mcp"
7
- version = "1.0.0"
7
+ version = "1.1.0"
8
8
  description = "MCP server for Microsoft SQL Server with SQL Agent job management and stored procedure version control"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -0,0 +1,109 @@
1
+ """Configuration and environment variables for MSSQL MCP Server."""
2
+
3
+ import os
4
+
5
+
6
+ def _parse_bool(value: str, default: bool = False) -> bool:
7
+ """Parse a string value to boolean."""
8
+ if not value:
9
+ return default
10
+ return value.lower() in ("true", "1", "yes")
11
+
12
+
13
+ # Security configuration
14
+ READONLY_MODE = _parse_bool(os.getenv("MSSQL_READONLY", "true"), default=True)
15
+
16
+ # Granular write permission controls (only effective when READONLY_MODE is False)
17
+ ALLOW_INSERT = _parse_bool(os.getenv("MSSQL_ALLOW_INSERT", "true"), default=True)
18
+ ALLOW_UPDATE = _parse_bool(os.getenv("MSSQL_ALLOW_UPDATE", "true"), default=True)
19
+ ALLOW_DELETE = _parse_bool(os.getenv("MSSQL_ALLOW_DELETE", "true"), default=True)
20
+ ALLOW_DDL = _parse_bool(os.getenv("MSSQL_ALLOW_DDL", "true"), default=True) # CREATE, ALTER, DROP
21
+ ALLOW_EXEC = _parse_bool(os.getenv("MSSQL_ALLOW_EXEC", "true"), default=True) # EXEC, EXECUTE
22
+
23
+ # Database configuration from environment variables
24
+ DB_CONFIG = {
25
+ "server": os.getenv("MSSQL_SERVER", "localhost"),
26
+ "database": os.getenv("MSSQL_DATABASE", "master"),
27
+ "user": os.getenv("MSSQL_USER", ""),
28
+ "password": os.getenv("MSSQL_PASSWORD", ""),
29
+ "port": os.getenv("MSSQL_PORT", "1433"),
30
+ "driver": os.getenv("MSSQL_DRIVER", "ODBC Driver 18 for SQL Server"),
31
+ "encrypt": os.getenv("MSSQL_ENCRYPT", "yes"),
32
+ "trust_server_certificate": os.getenv("MSSQL_TRUST_SERVER_CERTIFICATE", "no"),
33
+ "auth_mode": os.getenv("MSSQL_AUTH_MODE", "sql"), # sql, windows, azure
34
+ }
35
+
36
+ # Statement type categories for granular control
37
+ INSERT_STATEMENTS = {"INSERT", "MERGE"}
38
+ UPDATE_STATEMENTS = {"UPDATE"}
39
+ DELETE_STATEMENTS = {"DELETE", "TRUNCATE"}
40
+ DDL_STATEMENTS = {"CREATE", "ALTER", "DROP", "GRANT", "REVOKE", "DENY"}
41
+ EXEC_STATEMENTS = {"EXEC", "EXECUTE"}
42
+
43
+ # All blocked statement types when in full readonly mode
44
+ BLOCKED_STATEMENT_TYPES = (
45
+ INSERT_STATEMENTS | UPDATE_STATEMENTS | DELETE_STATEMENTS | DDL_STATEMENTS | EXEC_STATEMENTS
46
+ )
47
+
48
+
49
+ def is_readonly() -> bool:
50
+ """Check if the server is in read-only mode."""
51
+ return READONLY_MODE
52
+
53
+
54
+ def is_insert_allowed() -> bool:
55
+ """Check if INSERT operations are allowed."""
56
+ return not READONLY_MODE and ALLOW_INSERT
57
+
58
+
59
+ def is_update_allowed() -> bool:
60
+ """Check if UPDATE operations are allowed."""
61
+ return not READONLY_MODE and ALLOW_UPDATE
62
+
63
+
64
+ def is_delete_allowed() -> bool:
65
+ """Check if DELETE operations are allowed."""
66
+ return not READONLY_MODE and ALLOW_DELETE
67
+
68
+
69
+ def is_ddl_allowed() -> bool:
70
+ """Check if DDL operations (CREATE, ALTER, DROP) are allowed."""
71
+ return not READONLY_MODE and ALLOW_DDL
72
+
73
+
74
+ def is_exec_allowed() -> bool:
75
+ """Check if EXEC/EXECUTE operations are allowed."""
76
+ return not READONLY_MODE and ALLOW_EXEC
77
+
78
+
79
+ def get_blocked_statements() -> set[str]:
80
+ """Get the set of currently blocked statement types based on configuration."""
81
+ if READONLY_MODE:
82
+ return BLOCKED_STATEMENT_TYPES.copy()
83
+
84
+ blocked = set()
85
+ if not ALLOW_INSERT:
86
+ blocked.update(INSERT_STATEMENTS)
87
+ if not ALLOW_UPDATE:
88
+ blocked.update(UPDATE_STATEMENTS)
89
+ if not ALLOW_DELETE:
90
+ blocked.update(DELETE_STATEMENTS)
91
+ if not ALLOW_DDL:
92
+ blocked.update(DDL_STATEMENTS)
93
+ if not ALLOW_EXEC:
94
+ blocked.update(EXEC_STATEMENTS)
95
+
96
+ return blocked
97
+
98
+
99
+ def get_permission_summary() -> dict:
100
+ """Get a summary of current permission settings."""
101
+ return {
102
+ "readonly_mode": READONLY_MODE,
103
+ "allow_insert": is_insert_allowed(),
104
+ "allow_update": is_update_allowed(),
105
+ "allow_delete": is_delete_allowed(),
106
+ "allow_ddl": is_ddl_allowed(),
107
+ "allow_exec": is_exec_allowed(),
108
+ "blocked_statements": list(get_blocked_statements()),
109
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Annotated
4
4
 
5
- from ..config import READONLY_MODE
5
+ from ..config import is_readonly
6
6
  from ..utils import format_result, get_connection, rows_to_dicts, validate_query
7
7
 
8
8
 
@@ -30,10 +30,10 @@ def execute(
30
30
  sql: Annotated[str, "The SQL statement to execute (INSERT, UPDATE, DELETE, CREATE, etc.)"]
31
31
  ) -> str:
32
32
  """Execute a SQL statement (INSERT, UPDATE, DELETE, CREATE, etc.) and return affected rows count."""
33
- if READONLY_MODE:
34
- return format_result({
35
- "error": "Write operations are disabled in read-only mode. Set MSSQL_READONLY=false to enable."
36
- })
33
+ # Use validate_query for granular permission checking
34
+ is_valid, error_msg = validate_query(sql)
35
+ if not is_valid:
36
+ return format_result({"error": error_msg})
37
37
 
38
38
  conn = get_connection()
39
39
  try:
@@ -6,7 +6,7 @@ import shutil
6
6
  from pathlib import Path
7
7
  from typing import Annotated
8
8
 
9
- from ..config import READONLY_MODE
9
+ from ..config import is_exec_allowed
10
10
  from ..utils import (
11
11
  format_result,
12
12
  get_connection,
@@ -488,8 +488,8 @@ def update_job_step_from_file(
488
488
  if not validation_result["valid"]:
489
489
  return format_result({"success": False, "error": f"SQL validation failed: {validation_result['error']}"})
490
490
 
491
- if READONLY_MODE:
492
- return format_result({"success": False, "error": "Write operations are disabled in read-only mode."})
491
+ if not is_exec_allowed():
492
+ return format_result({"success": False, "error": "EXEC operations are disabled by configuration."})
493
493
 
494
494
  # Update job step
495
495
  try:
@@ -627,8 +627,8 @@ def create_job_step_from_file(
627
627
 
628
628
  db_name = database_name or "master"
629
629
 
630
- if READONLY_MODE:
631
- return format_result({"success": False, "error": "Write operations are disabled in read-only mode."})
630
+ if not is_exec_allowed():
631
+ return format_result({"success": False, "error": "EXEC operations are disabled by configuration."})
632
632
 
633
633
  # Create job step
634
634
  try:
@@ -4,7 +4,7 @@ import re
4
4
  from pathlib import Path
5
5
  from typing import Annotated
6
6
 
7
- from ..config import READONLY_MODE
7
+ from ..config import is_ddl_allowed
8
8
  from ..utils import (
9
9
  format_result,
10
10
  get_connection,
@@ -323,8 +323,8 @@ def update_procedure_from_file(
323
323
  elif not sql_upper.startswith("ALTER"):
324
324
  return format_result({"success": False, "error": "SQL must contain CREATE or ALTER PROCEDURE statement"})
325
325
 
326
- if READONLY_MODE:
327
- return format_result({"success": False, "error": "Write operations are disabled in read-only mode."})
326
+ if not is_ddl_allowed():
327
+ return format_result({"success": False, "error": "DDL operations (ALTER PROCEDURE) are disabled by configuration."})
328
328
 
329
329
  safe_db_name = "".join(c for c in database_name if c.isalnum() or c in "_-")
330
330
 
@@ -7,27 +7,36 @@ import struct
7
7
  import pyodbc
8
8
  import sqlparse
9
9
 
10
- from .config import BLOCKED_STATEMENT_TYPES, DB_CONFIG, READONLY_MODE
10
+ from .config import DB_CONFIG, get_blocked_statements, is_readonly
11
11
 
12
12
 
13
13
  def validate_query(sql: str) -> tuple[bool, str]:
14
- """Validate SQL query against readonly restrictions."""
15
- if not READONLY_MODE:
14
+ """Validate SQL query against permission restrictions."""
15
+ blocked_statements = get_blocked_statements()
16
+
17
+ # If nothing is blocked, allow all queries
18
+ if not blocked_statements:
16
19
  return True, ""
17
20
 
18
21
  try:
19
22
  parsed = sqlparse.parse(sql)
20
23
  for statement in parsed:
21
24
  stmt_type = statement.get_type()
22
- if stmt_type and stmt_type.upper() in BLOCKED_STATEMENT_TYPES:
23
- return False, f"Blocked: {stmt_type} statements are not allowed in read-only mode."
25
+ if stmt_type and stmt_type.upper() in blocked_statements:
26
+ if is_readonly():
27
+ return False, f"Blocked: {stmt_type} statements are not allowed in read-only mode."
28
+ else:
29
+ return False, f"Blocked: {stmt_type} statements are disabled by configuration."
24
30
 
25
31
  tokens = [t for t in statement.tokens if not t.is_whitespace]
26
32
  if tokens:
27
33
  first_token = str(tokens[0]).upper().strip()
28
- for blocked in BLOCKED_STATEMENT_TYPES:
34
+ for blocked in blocked_statements:
29
35
  if first_token.startswith(blocked):
30
- return False, f"Blocked: {blocked} statements are not allowed in read-only mode."
36
+ if is_readonly():
37
+ return False, f"Blocked: {blocked} statements are not allowed in read-only mode."
38
+ else:
39
+ return False, f"Blocked: {blocked} statements are disabled by configuration."
31
40
  except Exception as e:
32
41
  return False, f"Query validation failed: {str(e)}"
33
42
 
@@ -1,25 +0,0 @@
1
- """Configuration and environment variables for MSSQL MCP Server."""
2
-
3
- import os
4
-
5
- # Security configuration
6
- READONLY_MODE = os.getenv("MSSQL_READONLY", "true").lower() in ("true", "1", "yes")
7
-
8
- # Database configuration from environment variables
9
- DB_CONFIG = {
10
- "server": os.getenv("MSSQL_SERVER", "localhost"),
11
- "database": os.getenv("MSSQL_DATABASE", "master"),
12
- "user": os.getenv("MSSQL_USER", ""),
13
- "password": os.getenv("MSSQL_PASSWORD", ""),
14
- "port": os.getenv("MSSQL_PORT", "1433"),
15
- "driver": os.getenv("MSSQL_DRIVER", "ODBC Driver 18 for SQL Server"),
16
- "encrypt": os.getenv("MSSQL_ENCRYPT", "yes"),
17
- "trust_server_certificate": os.getenv("MSSQL_TRUST_SERVER_CERTIFICATE", "no"),
18
- "auth_mode": os.getenv("MSSQL_AUTH_MODE", "sql"), # sql, windows, azure
19
- }
20
-
21
- # Blocked SQL statement types when in readonly mode
22
- BLOCKED_STATEMENT_TYPES = {
23
- "INSERT", "UPDATE", "DELETE", "DROP", "CREATE", "ALTER",
24
- "TRUNCATE", "MERGE", "EXEC", "EXECUTE", "GRANT", "REVOKE", "DENY",
25
- }
File without changes