mcp-server

mcp-server

Provides read-only operational tools (sales summaries, orders, top customers) over a multi-tenant dataset, with tenant isolation enforced server-side so no tenant parameter appears in the tool schema.

Category
访问服务器

README

mcp-server — tenant-safe, read-only

A Model Context Protocol server exposing operational tools over a multi-tenant dataset to any MCP client, with the tenant bound server-side and never present in the published tool schema.

The argument

An MCP server publishes its tool schema to whatever client connects — Claude Desktop, an IDE, a third-party agent. That makes the schema a trust boundary, and it changes the calculus compared to an agent you own end to end.

If a tool took a company parameter, tenant selection would be delegated to a model on the other side of the connection: one you did not write, cannot audit, and whose version can change without telling you. No prompt on your side constrains it, because the prompt lives over there.

So the tenant is not a parameter. It is read once, at process start, from the server's own configuration:

TENANT = resolve_tenant()   # from MCP_TENANT_ID; fails hard if unset

Cross-tenant access is not "unlikely" or "blocked by instructions" — there is no argument in which to express it. That is the entire design, and everything below exists to prove it holds rather than assert it.

This matches how MCP is actually deployed: one server process per user, launched by the client with its own configuration. Identity belongs to that config, not to the conversation.

Verified, not asserted

MCP_TENANT_ID=acme python scripts/check_isolation.py   # 5 properties
python scripts/check_e2e.py                            # real stdio handshake

check_isolation.py asserts, against the running server:

# Property
1 No published tool exposes a tenant-like parameter (company, tenant_id, merchant, …)
2 Every tool is annotated read_only_hint
3 Executing every published tool leaks no other tenant's canary
4 Injecting company=<other> into a call returns nothing belonging to that tenant
5 Without MCP_TENANT_ID the server fails to start instead of defaulting

Check 3 enumerates whatever the server publishes and builds arguments from each schema, rather than calling a hardcoded list. A hardcoded list would silently skip exactly the tool someone adds later — which is the case worth catching.

check_e2e.py starts the server as a subprocess and drives it through initialize → list_tools → call_tool over stdio: proof it speaks the protocol, not just that the Python objects behave.

The checks are themselves checked

MCP_UNSAFE_MODE=1 publishes a deliberately broken tool that accepts company and honours it. The isolation check must go red under it:

MCP_TENANT_ID=acme MCP_UNSAFE_MODE=1 python scripts/check_isolation.py
# FAIL  no tool exposes a tenant parameter   -> list_orders_unsafe.company
# FAIL  no output contains another tenant's canary -> leaked: ['globex']

A guard that has never gone red has not been shown to detect anything. Shipping the broken variant is what makes the green run mean something.

Run it

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

cp .env.example .env
MCP_TENANT_ID=acme python -m server.main    # stdio

In an MCP client (Claude Desktop and similar), register one process per tenant:

{
  "mcpServers": {
    "acme-ops": {
      "command": "/path/to/.venv/bin/python",
      "args": ["-m", "server.main"],
      "cwd": "/path/to/mcp-server",
      "env": { "MCP_TENANT_ID": "acme" }
    }
  }
}

Tools

All read-only. None takes a tenant argument.

Tool Returns
sales_summary(start_date, end_date) Order count and total for a date range
list_orders(status) Orders with status paid / pending / refunded
top_customers() Customers ranked by total spend

Structure

mcp-server/
├── server/
│   ├── tenant.py   # the only place a tenant is decided
│   ├── data.py     # synthetic multi-tenant dataset with per-tenant canaries
│   └── main.py     # MCP server; tools + the gated unsafe variant
├── scripts/
│   ├── check_isolation.py   # the 5 properties above
│   └── check_e2e.py         # stdio protocol handshake

The dataset is fictional so the repo is clonable and runnable as-is.

Scope

This is a portfolio implementation of one pattern, not a product. See SECURITY.md for what it does and does not cover — notably that MCP_TENANT_ID stands in for a verified token, which is what a real deployment would use.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选