Skip to main content
Glama
Mustawphar-Tusk

MCP-Local-SharePoint-Server-Setup

README.md
# Corporate SharePoint MCP — Finance Pilot M005L

This milestone keeps the MCP service local and read-only while using a OneDrive shortcut to expose an approved SharePoint folder under the signed-in Windows user's existing SharePoint access.

## Added in M005L

- `sharepoint_list_folder` (filters local OneDrive clutter such as `desktop.ini`)
- `sharepoint_inspect_excel`
- `sharepoint_read_excel_range`
- `.xlsx` only for this milestone
- 100 MiB (configurable with `EXCEL_MAX_FILE_SIZE_MB`) workbook cap
- range requests capped at 100 rows × 30 columns
- Excel opened using `openpyxl` read-only mode with cached formula values (`data_only=True`)
- all file paths must resolve beneath `SHAREPOINT_SYNC_ROOT`
- no create/update/delete/move/rename tools

## Install/update dependencies

```powershell
pip install -r .\requirements.txt
```

## Run tests

```powershell
$env:PYTHONPATH = "$PWD\src"
pytest -q
```

## Run server

```powershell
python -m sharepoint_mcp.server
```

## Test the real synced workbook

In a second PowerShell window:

```powershell
.\.venv\Scripts\Activate.ps1
$env:PYTHONPATH = "$PWD\src"
python .\scripts\test_excel_reader.py
```

The script expects `SalesDelivery Note.xlsx` in the configured root. It inspects the workbook, reads `A1:J10` from the first worksheet, and confirms `../` remains blocked.


## M006L - Safe document discovery

This milestone adds `sharepoint_search_files`, a recursive metadata-only search
inside `SHAREPOINT_SYNC_ROOT`.

It searches:
- file names
- approved-root-relative paths

It deliberately does **not** open file contents during discovery. This avoids
hydrating or parsing large OneDrive-backed workbooks simply to locate them.

Example:

```text
sharepoint_search_files(
    query="sales delivery",
    extension="xlsx",
    max_results=10
)
```

The tool:
- remains read-only
- blocks `../` traversal
- ignores `desktop.ini`, `Thumbs.db`, and temporary `~$` Office files
- caps a request at 50 returned results
- caps one scan at 10,000 files
- returns relative paths rather than exposing the full local Windows path

Run:

```powershell
pytest -q tests
python .\scripts\test_document_search.py
```


## M007L - Content-aware Excel querying

Adds two read-only tools:

- `sharepoint_get_excel_columns`
- `sharepoint_find_excel_rows`

The first discovers every named header in a worksheet. The second scans a
bounded number of rows and returns matching records using one named business
column.

Safety limits:
- SharePoint sync root sandbox still enforced
- `.xlsx` only
- workbook opened read-only
- at most 500,000 rows scanned per request
- at most 100 matching rows returned
- at most 20 returned columns
- no edit, rename, move, delete, or upload capability

Example:

```text
sharepoint_find_excel_rows(
    relative_path="SalesDelivery Note.xlsx",
    sheet_name="Data",
    column_name="Packing Slip",
    search_value="GRP0000124",
    match_mode="equals",
    return_columns_csv="Product Id,Packing Slip,Quantity"
)
```

Live test:

```powershell
pytest -q tests
python .\scripts\test_excel_content_query.py
```


## M007.1 - Query completeness and continuation

This patch prevents a partial worksheet scan from being mistaken for a complete
answer.

`sharepoint_find_excel_rows` now returns:

- `scan_complete`
- `next_start_row`
- `worksheet_max_row`

The default scan allowance is now 500,000 rows, enough to cover the current
443,759-row Finance workbook in one call. If a future worksheet exceeds the
bounded scan or the result cap is reached, Claude can continue with
`start_row=next_start_row`.

The reader also narrows the streamed Excel column window to only the filter
column and requested output columns, reducing unnecessary work on wide sheets.

Run:

```powershell
pytest -q tests
python .\scripts\test_excel_content_query.py
```


## M008L - Multi-condition Finance queries and aggregations

Adds:

- `sharepoint_query_excel`
- `sharepoint_aggregate_excel`

Multi-condition filters are passed as a bounded JSON array, for example:

```json
[
  {"column":"Business Unit","operator":"equals","value":"Dean"},
  {"column":"Delivery Date","operator":"gte","value":"2026-01-01"},
  {"column":"Delivery Date","operator":"lte","value":"2026-12-31"}
]
```

Supported filter operators:

- equals / not_equals
- contains / starts_with / ends_with
- gt / gte / lt / lte
- is_blank / is_not_blank

Aggregations:

- count
- sum
- avg
- min
- max
- optional group_by_column

Guardrails:

- maximum 8 filter conditions
- maximum 500,000 scanned rows
- maximum 100 returned query rows
- maximum 20 returned columns
- maximum 100 aggregation groups
- aggregations refuse partial scans
- strict SharePoint sync-root sandbox
- `.xlsx` only
- read-only; no write/delete/move/upload tools

Run:

```powershell
pytest -q tests
python .\scripts\test_finance_multiquery.py
```


## M009L - Claude Desktop local connection

Adds a dedicated local stdio transport entry point:

```text
python -m sharepoint_mcp.desktop
```

The HTTP development server remains available separately:

```text
python -m sharepoint_mcp.server
```

Claude Desktop should launch the stdio process itself, so port 8000 is not
required for the Desktop connection.

Generate a machine-specific config snippet:

```powershell
$env:PYTHONPATH = "$PWD\\src"
python .\\scripts\\show_claude_desktop_config.py
```

The generated JSON contains local executable/folder paths and read-only pilot
settings only. It does not include Entra secrets.