mcp-ovh-api
@mgcrea/mcp-ovh-api
一个面向 OVHcloud API 的 Model Context Protocol 服务器,专注于对象存储:存储桶、对象、项目用户、S3 凭证以及将它们关联在一起的存储策略。
该服务器默认只读。当写入未开启时,变更工具不仅仅是被拒绝——它们根本不会被注册,因此代理完全无法调用它们。
功能特性
基于 OVHcloud 的
/1.0API 精选工具,其描述阐明了其中的陷阱(请参阅值得了解的陷阱)。默认只读。
OVH_ALLOW_WRITES=1会注册写入工具;而破坏性工具在每次调用时还额外要求显式的confirm: true。支持全部三种 OVH 认证方式,会根据存在的环境变量自动选择:OAuth2 服务账户(推荐)、应用密钥 + 消费者密钥(SHA1 签名,带自动时钟漂移校正)或静态访问令牌。
策略预设——包括 OVH 自身角色快捷方式不提供的
write-only。列表结果会被汇总,并且 OVH 已弃用的按存储桶
objects[]数组(其中嵌入了存储桶中的每个对象)在两端都会被抑制。X-Ovh-QueryID会在每个错误中显示,因为这是 OVH 支持人员首先会询问的信息。提供
ovh_request逃生舱口以访问 API 的其余部分(除非启用写入,否则仅限 GET)。原生
fetch,除 MCP SDK 和 Zod 外无运行时依赖。
安装
pnpm install
pnpm build配置
选择一种认证方式。
(A) OAuth2 服务账户 — 推荐
在 https://www.ovh.com/manager/#/iam/service-account 创建 IAM 服务账户。
附加一个 IAM 策略,授予其对公共云项目的访问权限(对于对象存储:项目资源上的
publicCloudProject:apiovh:*)。将客户端 ID 和密钥复制到
.env中。
令牌有效期为一小时,会提前缓存并在过期前刷新。
(B) 应用密钥 + 消费者密钥
在 https://eu.api.ovh.com/createToken/ 一次性创建三元组。你在此列出的访问规则将永久固定——消费者密钥之后无法扩大范围,因此请预先授予所需权限:
GET /cloud/project/*
POST /cloud/project/*
PUT /cloud/project/*
DELETE /cloud/project/*
GET /me请求使用 secret+consumerKey+METHOD+URL+BODY+TIMESTAMP 进行 SHA1 签名。如果时钟与 OVH 相差超过约 30 秒,则每次调用都会以误导性的 Invalid signature 失败,因此服务器会在启动时探测一次 /auth/time 并校正差值。
(C) 静态访问令牌
设置 OVH_ACCESS_TOKEN,它将作为 Authorization: Bearer 发送。
cp .env.example .env变量 | 必需 | 描述 |
| 否 |
|
| (A) | IAM 服务账户。它们的存在会选择 OAuth2。 |
| (B) | 应用密钥对。 |
| (B) | 随其一起签发的消费者密钥。 |
| (C) | 预铸造的 Bearer 令牌。 |
| 否 | 强制指定 |
| 否 | 默认项目 — 32 位十六进制 |
| 否 | 默认存储区域,大写( |
| 否 | 设置为 |
| 否 | 完全覆盖 API 基础 URL。 |
| 否 | 401 / 429 / 5xx 的重试预算。默认为 |
| 否 | 在过期前这么久刷新 OAuth2 令牌。默认为 |
| 否 | 设置为 |
运行
pnpm start # speaks JSON-RPC over stdio接入 Claude Code
添加到 .mcp.json(项目)或 ~/.claude.json(全局):
{
"mcpServers": {
"ovh": {
"command": "node",
"args": ["/absolute/path/to/mcp-ovh-api/dist/cli.js"],
"env": {
"OVH_CLIENT_ID": "...",
"OVH_CLIENT_SECRET": "...",
"OVH_CLOUD_PROJECT": "abcdef0123456789abcdef0123456789",
"OVH_REGION": "UK"
}
}
}
}检查工具
npx @modelcontextprotocol/inspector node dist/cli.js值得了解的陷阱
所有这些都已融入工具描述中,但它们解释了此服务器的形态:
OVH 没有存储桶策略——只有用户策略。 每个项目用户一份原始 JSON 文档,而该文档就是整个访问控制面。设置策略会替换该用户之前在所有存储桶上可以执行的所有操作。
策略无法限制存储桶的所有者。 OVH 会回退到 ACL,而所有者拥有
FULL_CONTROL:"如果用户是存储桶所有者,即使策略文件中没有显式允许,该用户也将被授权。" 因此,受限密钥必须属于一个新的项目用户,而不是创建该存储桶的用户。ovh_provision_s3_user会检查存储桶的ownerId,并在你将其指向所有者时拒绝。同样的回退也适用于每个对象。 上传对象的任何人都拥有它,并通过对象 ACL 对其拥有
FULL_CONTROL。因此,仅仅省略s3:GetObject并不能阻止仅上传的密钥读回其写入的所有内容——这已针对实时 API 验证过,一个裸允许列表策略可以愉快地为其密钥提供自己的上传内容,同时正确拒绝其他人上传的每个对象。显式的Deny是必需的,而且它确实胜过 ACL。这就是为什么write-only预设附带一个Deny语句,而不是裸允许列表。
还有两个较小的问题。单独的 s3:PutObject 仍然允许在允许的前缀内盲目覆盖现有密钥——"只写"密钥不是仅追加密钥,这是为存储桶启用版本控制的一个很好的理由。此外,策略更改需要长达约 30 秒才能生效:在 ovh_set_storage_policy 之后五秒进行的探测运行仍然显示旧行为,这看起来就像策略静默失败了一样。
工具
每个项目范围的工具都接受可选的 project,每个存储工具都接受可选的 region,以覆盖每次调用的 OVH_CLOUD_PROJECT / OVH_REGION。标记为 W 的工具仅在 OVH_ALLOW_WRITES=1 时存在;标记为 ⚠️ 的工具具有破坏性,并且额外要求 confirm: true。
从 ovh_whoami 开始。 它报告哪种认证方法处于活动状态、你是哪个账户以及相对于 OVH 的时钟偏差——这几乎总是签名方法上出现 401 的原因。
区域 | 工具 |
元数据 |
|
存储桶 |
|
对象 |
|
用户与密钥 |
|
策略 |
|
逃生舱口 |
|
ovh_presign_object 是字节移动的唯一方式:服务器从不代理对象内容,而是生成一个限时预签名 S3 URL。关闭写入时,它仅对 GET 签名。
策略预设
ovh_preview_policy、ovh_set_storage_policy 和 ovh_provision_s3_user 共享三个预设,所有预设都可以限定到密钥前缀:
预设 | 授予的权限 |
| 允许前缀上的 |
| 存储桶上的 |
| 两者兼有,外加 |
OVH 的内置角色(admin、deny、readOnly、readWrite,通过 ovh_grant_bucket_access)没有只写等效项——这就是原始策略路径存在的原因。多部分对是故意包含的:每个 S3 SDK 都会在约 8-16MB 以上自动切换到多部分,如果没有中止/列出,失败的上传会使密钥持有者无法清理孤立的部分,并持续为此付费。
OVH 会根据固定的枚举验证策略操作,如果某个操作未知,则会以 400 拒绝整个文档——s3:GetObjectVersion 和 s3:DeleteObjectVersion 存在于 AWS 中,但不存在于此。预设仅使用接受的操作,并且测试固定了这一点。
分发只写上传密钥
动机案例:应用在发布的二进制文件中嵌入了 S3 密钥,因此该密钥必须能够上传而不能做其他任何事情,而读/写密钥则保留在开发人员手中。
ovh_get_bucket bucket=dev-rgis-ar → note ownerId
ovh_preview_policy bucket=dev-rgis-ar preset=write-only prefix=uploads/
ovh_provision_s3_user bucket=dev-rgis-ar preset=write-only prefix=uploads/ \
description=ar-app-uploader confirm=true这会创建一个新的项目用户(绝不是存储桶所有者),应用策略,然后才铸造凭证——在策略之前存在的密钥是一个短暂拥有默认允许的任何权限的密钥。密钥只返回一次。
在移交之前对照真实的 S3 API 进行验证——正确读取的策略仍可能被所有权遮蔽,并且在设置后等待约 30 秒,否则你探测的将是以前的策略:
export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=...
# An array, not a string: zsh does not word-split an unquoted $var, so the
# `S3='aws ...'` form you would write in bash silently becomes "command not found".
S3=(aws --endpoint-url https://s3.uk.io.cloud.ovh.net --region uk s3api)
"${S3[@]}" put-object --bucket dev-rgis-ar --key uploads/probe.txt --body /dev/null # 200
"${S3[@]}" get-object --bucket dev-rgis-ar --key uploads/probe.txt /dev/null # 403
"${S3[@]}" list-objects-v2 --bucket dev-rgis-ar # 403
"${S3[@]}" delete-object --bucket dev-rgis-ar --key uploads/probe.txt # 403
"${S3[@]}" put-object --bucket dev-rgis-ar --key elsewhere/probe.txt --body /dev/null # 403get-object 行才是关键:这是捕获陷阱 3 的检查,并且仅仅因为预设的 Deny 而通过。
开发
pnpm dev # tsdown --watch
pnpm test # vitest
pnpm typecheck
pnpm lint
pnpm format许可证
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
MCP server for interacting with the Supabase platform
A MCP server built for developers enabling Git based project management with project and personal…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mgcrea/mcp-ovh-api'
If you have feedback or need assistance with the MCP directory API, please join our Discord server