Client Onboarding MCP
Enables querying client onboarding status and basic client info (name, family) via two tools, designed for integration with Microsoft Copilot and Teams.
README
Client Onboarding MCP for Microsoft Copilot and Teams
Minimal Python 3.12 project with:
- MCP server with four tools
- Separate mock backend server
- REST/OpenAPI facade
- Microsoft 365 Copilot plugin package files
- Microsoft Teams app manifest
- Docker, tests, local setup, auth placeholders, and examples
Architecture:
[Microsoft Teams]
|
v
[Microsoft Copilot]
|
v
[MCP Server]
|
v
[Mock Backend Server]
Folder Tree
.
|-- appPackage/
| |-- adaptive-cards/
| | `-- client-result.json
| |-- color.png
| |-- declarativeAgent.json
| |-- manifest.json
| |-- mcp-tools.json
| |-- openapi.yaml
| |-- outline.png
| |-- plugin.json
| `-- plugin.openapi.json
|-- examples/
| |-- curl.md
| |-- json-rpc.md
| |-- requests.http
| `-- responses/
| |-- basic_info_family.json
| |-- basic_info_name.json
| |-- error_invalid_field.json
| |-- facility_limit.json
| |-- onboarding_status.json
| `-- outreach_summary.json
|-- mcp_server/
| |-- __init__.py
| |-- __main__.py
| |-- app.py
| |-- auth.py
| |-- backend_client.py
| |-- config.py
| |-- errors.py
| |-- jsonrpc.py
| |-- logging_config.py
| |-- mcp_app.py
| |-- models.py
| |-- routes.py
| `-- tool_registry.py
|-- mock_backend/
| |-- __init__.py
| |-- __main__.py
| |-- app.py
| |-- config.py
| |-- logging_config.py
| |-- models.py
| `-- routes.py
|-- tests/
| |-- conftest.py
| |-- test_backend.py
| |-- test_mcp_http.py
| `-- test_tool_registry.py
|-- .env.example
|-- .vscode/launch.json
|-- Dockerfile
|-- docker-compose.yml
|-- main.py
|-- openapi.yaml
|-- pytest.ini
|-- requirements.txt
`-- tools.json
Tools
The MCP exposes these four tools.
get_client_onboarding_status
Input:
{
"client_id": "123"
}
Output:
{
"client_id": "123",
"status": "Completed",
"message": "Client onboarding completed successfully"
}
get_client_basic_info
Input:
{
"client_id": "123",
"field": "name"
}
Allowed field values:
namefamily
Output:
{
"client_id": "123",
"field": "name",
"value": "John"
}
{
"client_id": "123",
"field": "family",
"value": "Doe"
}
get_client_facility_limit
Input:
{
"client_id": "123"
}
Output:
{
"client_id": "123",
"client_name": "John Doe",
"facility_limit_eur": 75000000,
"currency": "EUR",
"formatted_limit": "EUR 75,000,000"
}
summarize_client_outreach
Input:
{
"client_id": "123"
}
Output includes the outreach reasons, highlights, and total questions to answer:
{
"client_id": "123",
"client_name": "John Doe",
"outreach_count": 2,
"questions_to_answer_count": 5,
"reasons": ["Annual facility review", "Updated cash-flow forecast"],
"summary": "John Doe has 2 outreach items. Reasons: Annual facility review, Updated cash-flow forecast. You should answer 5 questions in total."
}
Local Setup
Use Python 3.12.
python -m venv .venv312
.venv312\Scripts\activate
pip install -r requirements.txt
copy .env.example .env
Terminal 1:
uvicorn mock_backend.app:app --host 0.0.0.0 --port 8001 --reload
Terminal 2:
uvicorn mcp_server.app:app --host 0.0.0.0 --port 8000 --reload
Health checks:
curl http://localhost:8001/health
curl http://localhost:8000/health
REST API
OpenAPI 3.1 schema:
- Static YAML:
openapi.yaml - Runtime JSON:
http://localhost:8000/openapi.json - Runtime YAML file endpoint:
http://localhost:8000/openapi.yaml
Endpoints:
curl http://localhost:8000/api/v1/clients/123/onboarding-status
curl http://localhost:8000/api/v1/clients/123/basic-info/name
curl http://localhost:8000/api/v1/clients/123/basic-info/family
curl http://localhost:8000/api/v1/clients/123/facility
curl http://localhost:8000/api/v1/clients/123/outreach-summary
MCP JSON-RPC
List tools:
curl -X POST http://localhost:8000/mcp ^
-H "Content-Type: application/json" ^
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}"
Call tool:
curl -X POST http://localhost:8000/mcp ^
-H "Content-Type: application/json" ^
-d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"get_client_onboarding_status\",\"arguments\":{\"client_id\":\"123\"}}}"
The MCP Python SDK registration is in mcp_server/mcp_app.py. For stdio-style MCP testing:
python -m mcp_server.mcp_app
Mock Backend
The mock backend is a separate FastAPI service and returns hardcoded data only.
curl http://localhost:8001/status/123
curl http://localhost:8001/info/123/name
curl http://localhost:8001/info/123/family
curl http://localhost:8001/facility/123
curl http://localhost:8001/outreach/123/summary
Authentication Placeholder
Authentication is intentionally disabled for local development.
Enable API key validation:
MCP_AUTH_REQUIRED=true
MCP_API_KEY_HEADER=x-api-key
MCP_API_KEY=local-dev-key
Then call:
curl http://localhost:8000/api/v1/clients/123/onboarding-status -H "x-api-key: local-dev-key"
Production replacement points:
- Replace
APIKeyAuthMiddlewarewith Microsoft Entra ID JWT validation. - Register an app in Microsoft Entra ID.
- Configure Teams bot and Copilot plugin auth references with the production app registration.
- Store secrets in Azure Key Vault or a managed secret store.
Docker
docker compose up --build
Services:
- MCP server:
http://localhost:8000 - Mock backend:
http://localhost:8001
Copilot Package
Package files are in appPackage/.
manifest.json: Microsoft 365/Teams app manifestdeclarativeAgent.json: declarative agent manifestplugin.json: Microsoft 365 Copilot plugin manifest usingRemoteMCPServerplugin.openapi.json: OpenAPI fallback plugin manifestmcp-tools.json: MCP tool discovery metadata mirror of the inline plugin metadataopenapi.yaml: OpenAPI schema for the REST facadecolor.pngandoutline.png: Teams package icons
Before packaging:
- Replace the hosted domain in
appPackage/plugin.json,appPackage/openapi.yaml, andappPackage/manifest.jsonif you move away from the current Railway URL. - Replace the GUIDs in
appPackage/manifest.jsonwith real Microsoft Entra app and bot registration IDs. - Zip the contents of
appPackage/, not the folder itself. - Upload the zip in Teams Developer Portal or Microsoft 365 Agents Toolkit.
Example Copilot prompts:
- Get onboarding status for client 123
- What is the client's name?
- What is the client's family name?
- For client 123, get the family field
- What is the current limit on my company's facility for client 123?
- Summarize the outreach highlights for client 123
Teams Local Testing
- Start both local services.
- Start an HTTPS tunnel:
ngrok http 8000
- Copy the HTTPS ngrok domain, for example
https://abc123.ngrok-free.app. - Replace the hosted domain in
appPackage/manifest.json,appPackage/plugin.json, andappPackage/openapi.yaml. - In Microsoft Entra ID, create or reuse an app registration for the Teams bot placeholder.
- In Azure Bot Service or Bot Framework registration, set the messaging endpoint to your bot endpoint if you add a real Teams bot implementation.
- In Teams Developer Portal, import the app package zip.
- Validate the manifest and test in a personal scope first.
This project includes bot manifest placeholders but does not implement a Bot Framework message handler. Copilot calls the MCP server/plugin action; the bot block is present for Teams app packaging and future Teams conversational extensions.
Error Handling Examples
Invalid basic info field through REST:
curl http://localhost:8000/api/v1/clients/123/basic-info/age
Response shape:
{
"error": {
"code": "validation_error",
"message": "Request validation failed.",
"details": []
}
}
Invalid MCP tool call:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_client_basic_info",
"arguments": {
"client_id": "123",
"field": "age"
}
}
}
Response shape:
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32602,
"message": "Tool arguments failed validation.",
"data": {
"code": "invalid_arguments",
"details": []
}
}
}
Logging
Both services log requests with method, path, status code, and elapsed time.
Log levels:
MCP_LOG_LEVEL=INFO
BACKEND_LOG_LEVEL=INFO
Tests
pytest -q
Tests cover:
- Mock backend responses
- REST facade responses
- MCP
tools/list - MCP
tools/call - Tool validation
API Versioning Strategy
REST endpoints are versioned under /api/v1.
Recommended evolution:
- Keep
/api/v1stable for existing Copilot plugins. - Add
/api/v2for breaking response or parameter changes. - Keep MCP tool names stable where possible.
- Add new tool names for breaking tool contract changes.
- Keep
operationIdvalues aligned with Copilot plugin function names.
References
- Microsoft 365 Copilot plugins support REST APIs and MCP servers through declarative agent actions.
- Current Microsoft plugin manifest schema version used here:
v2.4. - Current Microsoft 365 app manifest schema used here:
v1.27.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。