From 40dea9a2c252684712b642a4abd1c110ce1588e1 Mon Sep 17 00:00:00 2001 From: albnnc Date: Mon, 6 Jul 2026 01:58:46 +0300 Subject: [PATCH] w --- README.md | 273 +----------------- exchange_mcp/__init__.py | 1 - exchange_mcp/tools/__init__.py | 1 - owa_mcp/__init__.py | 1 + {exchange_mcp => owa_mcp}/models.py | 0 {exchange_mcp => owa_mcp}/owa_client.py | 2 - {exchange_mcp => owa_mcp}/server.py | 46 +-- {exchange_mcp => owa_mcp}/server_lifecycle.py | 4 +- owa_mcp/tools/__init__.py | 1 + {exchange_mcp => owa_mcp}/tools/analytics.py | 8 +- {exchange_mcp => owa_mcp}/tools/auth.py | 8 +- .../tools/availability.py | 8 +- {exchange_mcp => owa_mcp}/tools/calendar.py | 10 +- {exchange_mcp => owa_mcp}/tools/email.py | 10 +- {exchange_mcp => owa_mcp}/tools/folders.py | 8 +- {exchange_mcp => owa_mcp}/tools/people.py | 8 +- {exchange_mcp => owa_mcp}/utils.py | 2 +- pyproject.toml | 12 +- 18 files changed, 69 insertions(+), 334 deletions(-) delete mode 100644 exchange_mcp/__init__.py delete mode 100644 exchange_mcp/tools/__init__.py create mode 100644 owa_mcp/__init__.py rename {exchange_mcp => owa_mcp}/models.py (100%) rename {exchange_mcp => owa_mcp}/owa_client.py (99%) rename {exchange_mcp => owa_mcp}/server.py (82%) rename {exchange_mcp => owa_mcp}/server_lifecycle.py (98%) create mode 100644 owa_mcp/tools/__init__.py rename {exchange_mcp => owa_mcp}/tools/analytics.py (98%) rename {exchange_mcp => owa_mcp}/tools/auth.py (93%) rename {exchange_mcp => owa_mcp}/tools/availability.py (98%) rename {exchange_mcp => owa_mcp}/tools/calendar.py (99%) rename {exchange_mcp => owa_mcp}/tools/email.py (99%) rename {exchange_mcp => owa_mcp}/tools/folders.py (98%) rename {exchange_mcp => owa_mcp}/tools/people.py (94%) rename {exchange_mcp => owa_mcp}/utils.py (98%) diff --git a/README.md b/README.md index c61f58f..ae385b0 100644 --- a/README.md +++ b/README.md @@ -1,287 +1,44 @@ # OWA MCP Server -MCP (Model Context Protocol) server for any Microsoft Exchange / OWA (Outlook Web Access) deployment. Gives LLM agents access to email, calendar, directory search, folders, availability, and meeting analytics via 30 tools. - -Works with any on-premise or hosted Exchange server that exposes OWA. - -## Quick Start - -```bash -# Install -pip install -e . - -# Add to your MCP client config with --owa-url -# Then use the login tool to paste your session cookies -``` - -## Install - -Add to your MCP client config. Replace `https://owa.example.com` with your OWA URL. - -**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`): - -```json -{ - "mcpServers": { - "exchange": { - "command": "uvx", - "args": [ - "exchange-mcp-server", - "--owa-url", "https://owa.example.com" - ] - } - } -} -``` - -**Cursor** (`.cursor/mcp.json`): - -```json -{ - "mcpServers": { - "exchange": { - "command": "uvx", - "args": [ - "exchange-mcp-server", - "--owa-url", "https://owa.example.com" - ] - } - } -} -``` - -**Claude Code** (`.mcp.json`): - -```json -{ - "mcpServers": { - "exchange": { - "command": "uvx", - "args": [ - "exchange-mcp-server", - "--owa-url", "https://owa.example.com" - ] - } - } -} -``` +MCP server for any Microsoft Exchange / OWA deployment. 30 tools for email, +calendar, directory search, folder management, availability, and analytics. ## CLI Arguments | Argument | Default | Required | Description | |---|---|---|---| -| `--owa-url` | — | Yes | Base URL of the OWA instance (e.g. `https://owa.example.com`) | +| `--owa-url` | — | Yes | Base URL of the OWA instance | | `--cookie-file` | `session-cookies.txt` | No | Path to session cookies file | | `--transport` | `stdio` | — | `stdio`, `sse`, or `streamable-http` | -| `--token-hash` | — | For HTTP | SHA-256 hash of the bearer token | +| `--token-hash` | — | HTTP only | SHA-256 hash of the bearer token | | `--port` | `8000` | — | HTTP/SSE listener port | | `--host` | `127.0.0.1` | — | HTTP/SSE listener host | | `--enabled-tools` | — | No | Comma-separated whitelist of tool names | | `--disabled-tools` | — | No | Comma-separated blacklist of tool names | -### Tool filtering examples - -```bash -# Hide only the most dangerous tools -exchange-mcp-server --owa-url https://owa.example.com \ - --disabled-tools "send_email,delete_email,cancel_meeting" - -# Allow only email and calendar tools -exchange-mcp-server --owa-url https://owa.example.com \ - --enabled-tools "get_emails,get_email,send_email,get_calendar_events,create_meeting" - -# Whitelist a set, then remove one from it -exchange-mcp-server --owa-url https://owa.example.com \ - --enabled-tools "get_emails,get_email,send_email,delete_email" \ - --disabled-tools "delete_email" -# → only get_emails, get_email, send_email remain -``` - -## HTTP Transport - -Run the server over HTTP (streamable-http or SSE) instead of stdio. This is -useful when the MCP client cannot spawn a local process, or when you want to -expose the server on a network. - -### Installation - -```bash -pip install -e ".[http]" # adds uvicorn + sse-starlette -``` - -### Start the server - -```bash -# Compute the token hash once (store only the hash, never the plaintext token) -TOKEN_HASH=$(echo -n 'my-secret-token' | sha256sum | cut -d' ' -f1) - -# stdio (default, for local MCP clients) -exchange-mcp-server --owa-url https://owa.example.com - -# streamable-http (recommended for HTTP) -exchange-mcp-server \ - --owa-url https://owa.example.com \ - --transport streamable-http \ - --token-hash "$TOKEN_HASH" \ - --port 8000 \ - --host 127.0.0.1 - -# SSE -exchange-mcp-server \ - --owa-url https://owa.example.com \ - --transport sse \ - --token-hash "$TOKEN_HASH" \ - --port 8000 -``` - -### CLI arguments - -| Argument | Default | Required | Description | -|---|---|---|---| -| `--owa-url` | — | Yes | Base URL of the OWA instance (e.g. `https://owa.example.com`) | -| `--cookie-file` | `session-cookies.txt` | No | Path to session cookies file | -| `--transport` | `stdio` | — | `stdio`, `sse`, or `streamable-http` | -| `--token-hash` | — | For HTTP | SHA-256 hash of the bearer token | -| `--port` | `8000` | — | HTTP/SSE listener port | -| `--host` | `127.0.0.1` | — | HTTP/SSE listener host | -| `--enabled-tools` | — | No | Comma-separated whitelist of tool names | -| `--disabled-tools` | — | No | Comma-separated blacklist of tool names | - -### Client configuration (HTTP) - -```json -{ - "mcpServers": { - "exchange": { - "url": "http://127.0.0.1:8000/mcp", - "headers": { - "Authorization": "Bearer my-secret-token" - } - } - } -} -``` - -### Authentication - -The server stores only the SHA-256 hash of your token — the plaintext token -never touches the filesystem. Every HTTP request must include: - -``` -Authorization: Bearer -``` - -The server hashes the incoming token and compares it with the stored hash. -Pass the hash via `--token-hash`: - -```bash -echo -n 'my-secret-token' | sha256sum -# → 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 -``` - -### Security notes - -- Always use a strong random token. -- Bind to `127.0.0.1` unless you have a reverse proxy / firewall. -- For `streamable-http` the client must send `Accept: text/event-stream`. -- The `--token-hash` is required whenever `--transport` is not `stdio`. - -## Login - -The `login` MCP tool accepts session cookies that you copy from your browser. - -1. Log into OWA in your browser. -2. Open DevTools (F12) → Application → Cookies → select your OWA domain. -3. Copy all cookies as `name=value` pairs (one per line). -4. Call the `login` tool with the cookies string. - -Example cookies string: - -``` -X-OWA-CANARY=abc123 -CookieAuth1=def456 -... -``` - -``` -login(cookies="X-OWA-CANARY=abc123\nCookieAuth1=def456\n...") -``` - -On success, cookies are saved to `session-cookies.txt` and all tools become usable. When the session expires, repeat the steps. - ## Tools (30) ### Email (10) -| Tool | Description | -|---|---| -| `get_emails` | List emails from a folder with filtering | -| `get_email` | Get full email content by ID | -| `send_email` | Send a new email | -| `reply_email` | Reply to an email | -| `forward_email` | Forward an email | -| `delete_email` | Delete an email | -| `move_email` | Move email to another folder | -| `mark_email_read` | Mark email as read/unread | -| `download_attachments` | Download file attachments from an email | -| `get_email_links` | Extract hyperlinks from an email body | +`get_emails`, `get_email`, `send_email`, `reply_email`, `forward_email`, +`delete_email`, `move_email`, `mark_email_read`, `download_attachments`, +`get_email_links`, `search_emails` ### Calendar (7) -| Tool | Description | -|---|---| -| `get_calendar_events` | Get events in a date range (supports recurring expansion) | -| `create_meeting` | Create a meeting with attendees | -| `update_meeting` | Update an existing meeting | -| `cancel_meeting` | Cancel a meeting and notify attendees | -| `respond_to_meeting` | Accept, decline, or tentatively accept | -| `download_event_attachments` | Download file attachments from a calendar event | -| `get_event_links` | Extract hyperlinks from the event description | +`get_calendar_events`, `create_meeting`, `update_meeting`, `cancel_meeting`, +`respond_to_meeting`, `download_event_attachments`, `get_event_links` ### Directory (1) -| Tool | Description | -|---|---| -| `find_person` | Search people in Active Directory | +`find_person` ### Folders (7) -| Tool | Description | -|---|---| -| `get_folders` | List mail folders with unread counts | -| `create_folder` | Create a new mail folder | -| `rename_folder` | Rename an existing folder | -| `empty_folder` | Empty all items from a folder | -| `delete_folder` | Delete a mail folder | -| `move_folder` | Move a folder to a different parent | -| `check_session` | Check if the OWA session is authenticated | +`get_folders`, `create_folder`, `rename_folder`, `empty_folder`, `delete_folder`, +`move_folder`, `check_session` ### Availability (2) -| Tool | Description | -|---|---| -| `find_free_time` | Find free slots in your calendar | -| `find_meeting_time` | Find common free slots for multiple people | +`find_free_time`, `find_meeting_time` ### Analytics (2) -| Tool | Description | -|---|---| -| `get_meeting_stats` | Meeting count statistics for multiple people | -| `get_meeting_contacts` | Connection matrix — who you meet with most | +`get_meeting_stats`, `get_meeting_contacts` ### Auth (1) -| Tool | Description | -|---|---| -| `login` | Authenticate to OWA using browser session cookies | - -## Files - -``` -exchange_mcp/ - server.py # FastMCP server entry point - owa_client.py # OWA HTTP client - tools/ - email.py # Email tools - calendar.py # Calendar tools - people.py # Directory search - folders.py # Folder management & session check - availability.py # Free time / meeting time - analytics.py # Meeting stats & contacts - auth.py # Login tool -pyproject.toml # Package config -``` +`login` diff --git a/exchange_mcp/__init__.py b/exchange_mcp/__init__.py deleted file mode 100644 index ef83d87..0000000 --- a/exchange_mcp/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Exchange MCP Server - access OWA email, calendar, directory via MCP.""" diff --git a/exchange_mcp/tools/__init__.py b/exchange_mcp/tools/__init__.py deleted file mode 100644 index d0c4846..0000000 --- a/exchange_mcp/tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""MCP tool modules for Exchange.""" diff --git a/owa_mcp/__init__.py b/owa_mcp/__init__.py new file mode 100644 index 0000000..506a731 --- /dev/null +++ b/owa_mcp/__init__.py @@ -0,0 +1 @@ +"""OWA MCP Server — access OWA email, calendar, directory via MCP.""" diff --git a/exchange_mcp/models.py b/owa_mcp/models.py similarity index 100% rename from exchange_mcp/models.py rename to owa_mcp/models.py diff --git a/exchange_mcp/owa_client.py b/owa_mcp/owa_client.py similarity index 99% rename from exchange_mcp/owa_client.py rename to owa_mcp/owa_client.py index b6b8bd3..c4a5e28 100644 --- a/exchange_mcp/owa_client.py +++ b/owa_mcp/owa_client.py @@ -9,7 +9,6 @@ mirroring what the OWA web frontend sends. """ import json -import os import time from urllib.parse import quote, urlparse from pathlib import Path @@ -55,7 +54,6 @@ class OWAClient: ): self.cookie_file = Path( cookie_file - or os.environ.get("EXCHANGE_COOKIE_FILE", "") or str(Path(__file__).parent.parent / "session-cookies.txt") ) self.owa_url = (owa_url or "").rstrip("/") diff --git a/exchange_mcp/server.py b/owa_mcp/server.py similarity index 82% rename from exchange_mcp/server.py rename to owa_mcp/server.py index 30ca197..6e1afbc 100644 --- a/exchange_mcp/server.py +++ b/owa_mcp/server.py @@ -1,4 +1,4 @@ -"""Exchange MCP Server. +"""OWA MCP Server. Exposes OWA email, calendar, directory, and availability tools via MCP. Uses FastMCP with a lifespan context manager to share a single OWAClient @@ -13,19 +13,12 @@ CLI arguments: --host HTTP host (default 127.0.0.1) --enabled-tools Comma-separated whitelist of tool names --disabled-tools Comma-separated blacklist of tool names - -Tool filtering (env fallback): - EXCHANGE_ENABLED_TOOLS — comma-separated whitelist (used only when - --enabled-tools is not provided). - EXCHANGE_DISABLED_TOOLS — comma-separated blacklist (used only when - --disabled-tools is not provided). """ from __future__ import annotations import argparse import logging -import os from collections.abc import AsyncIterator from contextlib import asynccontextmanager from dataclasses import dataclass @@ -34,8 +27,8 @@ from mcp.server.auth.provider import AccessToken, TokenVerifier from mcp.server.auth.settings import AuthSettings from mcp.server.fastmcp import FastMCP -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import ( +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import ( HashTokenVerifier, SessionKeepalive, apply_tool_filters, @@ -55,7 +48,7 @@ class AppContext: async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: """Initialise the OWA client on first connection, then keep the session alive. - A :class:`~exchange_mcp.server_lifecycle.SessionKeepalive` task starts + A :class:`~owa_mcp.server_lifecycle.SessionKeepalive` task starts immediately (pings inbox, extends the session, persists fresh cookies) and repeats every 5 minutes until the server shuts down. """ @@ -80,13 +73,13 @@ _lifespan_cookie_file: str | None = None # ── Module-level MCP server (imported by all tool modules) ──────────────── -mcp: FastMCP = FastMCP("exchange", lifespan=app_lifespan) +mcp: FastMCP = FastMCP("owa", lifespan=app_lifespan) def _parse_args(argv=None) -> argparse.Namespace: """Parse command-line arguments.""" parser = argparse.ArgumentParser( - description="Exchange MCP Server — OWA/Exchange integration via MCP", + description="OWA MCP Server — OWA/Exchange integration via MCP", ) parser.add_argument( "--transport", @@ -184,38 +177,25 @@ def main(argv=None) -> None: raise SystemExit(1) # ── Register tools (imports populate module-level `mcp`) ─────────────── - import exchange_mcp.tools.email # noqa: E402, F401 - import exchange_mcp.tools.calendar # noqa: E402, F401 - import exchange_mcp.tools.people # noqa: E402, F401 - import exchange_mcp.tools.folders # noqa: E402, F401 - import exchange_mcp.tools.availability # noqa: E402, F401 - import exchange_mcp.tools.analytics # noqa: E402, F401 - import exchange_mcp.tools.auth # noqa: E402, F401 + import owa_mcp.tools.email # noqa: E402, F401 + import owa_mcp.tools.calendar # noqa: E402, F401 + import owa_mcp.tools.people # noqa: E402, F401 + import owa_mcp.tools.folders # noqa: E402, F401 + import owa_mcp.tools.availability # noqa: E402, F401 + import owa_mcp.tools.analytics # noqa: E402, F401 + import owa_mcp.tools.auth # noqa: E402, F401 # ── Auth for HTTP transports ─────────────────────────────────────────── _configure_auth(mcp, args.token_hash) # ── Tool filtering ───────────────────────────────────────────────────── - # CLI args take precedence over env vars. enabled: list[str] | None = None if args.enabled_tools is not None: enabled = [t.strip() for t in args.enabled_tools.split(",") if t.strip()] - elif os.environ.get("EXCHANGE_ENABLED_TOOLS", "").strip(): - enabled = [ - t.strip() - for t in os.environ["EXCHANGE_ENABLED_TOOLS"].split(",") - if t.strip() - ] disabled: list[str] | None = None if args.disabled_tools is not None: disabled = [t.strip() for t in args.disabled_tools.split(",") if t.strip()] - elif os.environ.get("EXCHANGE_DISABLED_TOOLS", "").strip(): - disabled = [ - t.strip() - for t in os.environ["EXCHANGE_DISABLED_TOOLS"].split(",") - if t.strip() - ] if enabled or disabled: apply_tool_filters(mcp, enabled=enabled, disabled=disabled) diff --git a/exchange_mcp/server_lifecycle.py b/owa_mcp/server_lifecycle.py similarity index 98% rename from exchange_mcp/server_lifecycle.py rename to owa_mcp/server_lifecycle.py index e1e26ec..c37ed74 100644 --- a/exchange_mcp/server_lifecycle.py +++ b/owa_mcp/server_lifecycle.py @@ -1,4 +1,4 @@ -"""Shared lifecycle utilities for the Exchange MCP server. +"""Shared lifecycle utilities for the OWA MCP server. Centralises three concerns so that tool modules do not duplicate code: @@ -17,7 +17,7 @@ import asyncio import logging from typing import TYPE_CHECKING -from exchange_mcp.owa_client import OWAClient, SessionExpiredError +from owa_mcp.owa_client import OWAClient, SessionExpiredError from mcp.server.auth.provider import AccessToken, TokenVerifier if TYPE_CHECKING: diff --git a/owa_mcp/tools/__init__.py b/owa_mcp/tools/__init__.py new file mode 100644 index 0000000..58c1ffb --- /dev/null +++ b/owa_mcp/tools/__init__.py @@ -0,0 +1 @@ +"""MCP tool modules for OWA.""" diff --git a/exchange_mcp/tools/analytics.py b/owa_mcp/tools/analytics.py similarity index 98% rename from exchange_mcp/tools/analytics.py rename to owa_mcp/tools/analytics.py index 672c499..cadbade 100644 --- a/exchange_mcp/tools/analytics.py +++ b/owa_mcp/tools/analytics.py @@ -1,4 +1,4 @@ -"""Analytics tools for the Exchange MCP server. +"""Analytics tools for the OWA MCP server. Provides meeting statistics and connection matrix analysis using GetUserAvailability and GetItem APIs. @@ -10,9 +10,9 @@ from datetime import datetime, timedelta, date from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import require_client +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import require_client def _get_client(ctx: Context) -> OWAClient: diff --git a/exchange_mcp/tools/auth.py b/owa_mcp/tools/auth.py similarity index 93% rename from exchange_mcp/tools/auth.py rename to owa_mcp/tools/auth.py index 2d66930..df85919 100644 --- a/exchange_mcp/tools/auth.py +++ b/owa_mcp/tools/auth.py @@ -1,4 +1,4 @@ -"""Authentication tool for the Exchange MCP server. +"""Authentication tool for the OWA MCP server. Provides a `login` tool that accepts session cookies from the user, saves them to disk, loads them into the OWA client, and verifies the session. @@ -12,9 +12,9 @@ import json from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient, SessionExpiredError -from exchange_mcp.server_lifecycle import require_client +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient, SessionExpiredError +from owa_mcp.server_lifecycle import require_client def _get_app_ctx(ctx: Context) -> AppContext: diff --git a/exchange_mcp/tools/availability.py b/owa_mcp/tools/availability.py similarity index 98% rename from exchange_mcp/tools/availability.py rename to owa_mcp/tools/availability.py index 46da79b..aa8bd02 100644 --- a/exchange_mcp/tools/availability.py +++ b/owa_mcp/tools/availability.py @@ -1,4 +1,4 @@ -"""Availability / free-time tools for the Exchange MCP server. +"""Availability / free-time tools for the OWA MCP server. Ports find-free-time.py and find-meeting-time.py logic into MCP tools using OWAClient. @@ -9,9 +9,9 @@ from datetime import datetime, timedelta from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import require_client +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import require_client def _get_client(ctx: Context) -> OWAClient: diff --git a/exchange_mcp/tools/calendar.py b/owa_mcp/tools/calendar.py similarity index 99% rename from exchange_mcp/tools/calendar.py rename to owa_mcp/tools/calendar.py index 9df712b..06dabd7 100644 --- a/exchange_mcp/tools/calendar.py +++ b/owa_mcp/tools/calendar.py @@ -1,4 +1,4 @@ -"""Calendar tools for the Exchange MCP server. +"""Calendar tools for the OWA MCP server. Provides MCP tools for calendar event retrieval, meeting creation, update, cancellation, and meeting response management via OWA API. @@ -11,10 +11,10 @@ from datetime import datetime, timedelta from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import require_client -from exchange_mcp.utils import html_to_text, parse_iso_datetime, extract_links_from_html +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import require_client +from owa_mcp.utils import html_to_text, parse_iso_datetime, extract_links_from_html def _get_client(ctx: Context) -> OWAClient: diff --git a/exchange_mcp/tools/email.py b/owa_mcp/tools/email.py similarity index 99% rename from exchange_mcp/tools/email.py rename to owa_mcp/tools/email.py index 4cb2095..681fa03 100644 --- a/exchange_mcp/tools/email.py +++ b/owa_mcp/tools/email.py @@ -1,4 +1,4 @@ -"""Email tools for the Exchange MCP server. +"""Email tools for the OWA MCP server. Provides tools for reading, sending, replying, forwarding, and managing emails via the OWA Exchange API. @@ -8,10 +8,10 @@ import json from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient, SessionExpiredError -from exchange_mcp.server_lifecycle import require_client -from exchange_mcp.utils import html_to_text, extract_links_from_html +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient, SessionExpiredError +from owa_mcp.server_lifecycle import require_client +from owa_mcp.utils import html_to_text, extract_links_from_html def _get_client(ctx: Context) -> OWAClient: diff --git a/exchange_mcp/tools/folders.py b/owa_mcp/tools/folders.py similarity index 98% rename from exchange_mcp/tools/folders.py rename to owa_mcp/tools/folders.py index f81a0af..6ff7603 100644 --- a/exchange_mcp/tools/folders.py +++ b/owa_mcp/tools/folders.py @@ -1,4 +1,4 @@ -"""Folder tools for the Exchange MCP server. +"""Folder tools for the OWA MCP server. Ports the get-folders.py logic into an MCP tool using OWAClient. """ @@ -7,9 +7,9 @@ import json from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import require_client +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import require_client _DISTINGUISHED_NAMES = { diff --git a/exchange_mcp/tools/people.py b/owa_mcp/tools/people.py similarity index 94% rename from exchange_mcp/tools/people.py rename to owa_mcp/tools/people.py index 083a14b..88a7db8 100644 --- a/exchange_mcp/tools/people.py +++ b/owa_mcp/tools/people.py @@ -1,4 +1,4 @@ -"""People / directory search tools for the Exchange MCP server. +"""People / directory search tools for the OWA MCP server. Ports the find-person.py logic into an MCP tool using OWAClient. """ @@ -7,9 +7,9 @@ import json from mcp.server.fastmcp import Context -from exchange_mcp.server import mcp, AppContext -from exchange_mcp.owa_client import OWAClient -from exchange_mcp.server_lifecycle import require_client +from owa_mcp.server import mcp, AppContext +from owa_mcp.owa_client import OWAClient +from owa_mcp.server_lifecycle import require_client def _get_client(ctx: Context) -> OWAClient: diff --git a/exchange_mcp/utils.py b/owa_mcp/utils.py similarity index 98% rename from exchange_mcp/utils.py rename to owa_mcp/utils.py index d263c96..8f8f996 100644 --- a/exchange_mcp/utils.py +++ b/owa_mcp/utils.py @@ -1,4 +1,4 @@ -"""Shared utility functions for the Exchange MCP server. +"""Shared utility functions for the OWA MCP server. Extracts duplicated helpers from the standalone scripts: html_to_text, date/time formatting and parsing. diff --git a/pyproject.toml b/pyproject.toml index 433a7a4..205b3b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [project] -name = "exchange-mcp-server" -version = "1.0.1" -description = "MCP server for Exchange / OWA - email, calendar, directory, availability" +name = "owa-mcp-server" +version = "0.1.0" +description = "MCP server for OWA — email, calendar, directory, availability" readme = "README.md" license = "MIT" requires-python = ">=3.10" -keywords = ["mcp", "exchange", "owa", "outlook", "email", "calendar"] +keywords = ["mcp", "owa", "outlook", "exchange", "email", "calendar"] classifiers = [ "Programming Language :: Python :: 3", ] @@ -23,7 +23,7 @@ Repository = "https://git.kosyrev.name/zoo/owa-mcp" http = ["uvicorn>=0.30.0"] [project.scripts] -exchange-mcp-server = "exchange_mcp.server:main" +owa-mcp-server = "owa_mcp.server:main" [build-system] requires = ["setuptools>=68.0"] @@ -31,4 +31,4 @@ build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["."] -include = ["exchange_mcp*"] +include = ["owa_mcp*"]