Skip to main content
Glama
mgcrea

mcp-ovh-api

by mgcrea

@mgcrea/mcp-ovh-api

npm version GHCR

一个面向 OVHcloud APIModel Context Protocol 服务器,专注于对象存储:存储桶、对象、项目用户、S3 凭证以及将它们关联在一起的存储策略。

该服务器默认只读。当写入未开启时,变更工具不仅仅是被拒绝——它们根本不会被注册,因此代理完全无法调用它们。

功能特性

  • 基于 OVHcloud 的 /1.0 API 精选工具,其描述阐明了其中的陷阱(请参阅值得了解的陷阱)。

  • 默认只读。 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 服务账户 — 推荐

  1. https://www.ovh.com/manager/#/iam/service-account 创建 IAM 服务账户。

  2. 附加一个 IAM 策略,授予其对公共云项目的访问权限(对于对象存储:项目资源上的 publicCloudProject:apiovh:*)。

  3. 将客户端 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

变量

必需

描述

OVH_ENDPOINT

ovh-eu(默认)、ovh-caovh-uskimsufi-*soyoustart-*

OVH_CLIENT_ID / OVH_CLIENT_SECRET

(A)

IAM 服务账户。它们的存在会选择 OAuth2。

OVH_APPLICATION_KEY / _SECRET

(B)

应用密钥对。

OVH_CONSUMER_KEY

(B)

随其一起签发的消费者密钥。

OVH_ACCESS_TOKEN

(C)

预铸造的 Bearer 令牌。

OVH_AUTH_METHOD

强制指定 oauth2signatureaccessToken。否则自动推断。

OVH_CLOUD_PROJECT

默认项目 — 32 位十六进制 serviceName,而非显示名称。

OVH_REGION

默认存储区域,大写(GRASBGDEUK)。

OVH_ALLOW_WRITES

设置为 1 以注册写入工具。默认关闭。

OVH_API_URL

完全覆盖 API 基础 URL。

OVH_MAX_RETRIES

401 / 429 / 5xx 的重试预算。默认为 3

OVH_REFRESH_SKEW_SECONDS

在过期前这么久刷新 OAuth2 令牌。默认为 60

OVH_DEBUG

设置为 1 以将调试输出记录到 stderr。

运行

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

值得了解的陷阱

所有这些都已融入工具描述中,但它们解释了此服务器的形态:

  1. OVH 没有存储桶策略——只有用户策略。 每个项目用户一份原始 JSON 文档,而该文档就是整个访问控制面。设置策略会替换该用户之前在所有存储桶上可以执行的所有操作。

  2. 策略无法限制存储桶的所有者。 OVH 会回退到 ACL,而所有者拥有 FULL_CONTROL"如果用户是存储桶所有者,即使策略文件中没有显式允许,该用户也将被授权。" 因此,受限密钥必须属于一个新的项目用户,而不是创建该存储桶的用户。ovh_provision_s3_user 会检查存储桶的 ownerId,并在你将其指向所有者时拒绝。

  3. 同样的回退也适用于每个对象。 上传对象的任何人都拥有它,并通过对象 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_whoami, ovh_list_projects, ovh_get_project, ovh_list_regions, ovh_get_region

存储桶

ovh_list_buckets, ovh_get_bucket, ovh_get_bucket_lifecycle · W ovh_create_bucket, ovh_update_bucket, ovh_set_bucket_lifecycle, ⚠️ ovh_delete_bucket_lifecycle, ⚠️ ovh_delete_bucket

对象

ovh_list_objects, ovh_get_object, ovh_list_object_versions, ovh_presign_object · W ovh_copy_object, ⚠️ ovh_delete_object, ⚠️ ovh_delete_object_version, ⚠️ ovh_bulk_delete_objects

用户与密钥

ovh_list_project_users, ovh_get_project_user, ovh_list_s3_credentials · W ovh_create_project_user, ovh_create_s3_credentials, ovh_reveal_s3_secret, ⚠️ ovh_delete_s3_credentials, ⚠️ ovh_delete_project_user

策略

ovh_get_storage_policy, ovh_preview_policy · W ⚠️ ovh_set_storage_policy, ⚠️ ovh_grant_bucket_access, ⚠️ ovh_provision_s3_user

逃生舱口

ovh_request — 任何 /1.0 路径,除非启用写入,否则仅限 GET

ovh_presign_object 是字节移动的唯一方式:服务器从不代理对象内容,而是生成一个限时预签名 S3 URL。关闭写入时,它仅对 GET 签名。

策略预设

ovh_preview_policyovh_set_storage_policyovh_provision_s3_user 共享三个预设,所有预设都可以限定到密钥前缀:

预设

授予的权限

write-only

允许前缀上的 s3:PutObjects3:AbortMultipartUploads3:ListMultipartUploadParts外加存储桶范围内对 s3:GetObject / s3:GetObjectAcl 的显式 Deny

read-only

存储桶上的 s3:ListBucket + s3:GetBucketLocation,对象上的 s3:GetObject

read-write

两者兼有,外加 s3:DeleteObject

OVH 的内置角色(admindenyreadOnlyreadWrite,通过 ovh_grant_bucket_access)没有只写等效项——这就是原始策略路径存在的原因。多部分对是故意包含的:每个 S3 SDK 都会在约 8-16MB 以上自动切换到多部分,如果没有中止/列出,失败的上传会使密钥持有者无法清理孤立的部分,并持续为此付费。

OVH 会根据固定的枚举验证策略操作,如果某个操作未知,则会以 400 拒绝整个文档——s3:GetObjectVersions3: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 # 403

get-object 行才是关键:这是捕获陷阱 3 的检查,并且仅仅因为预设的 Deny 而通过。

开发

pnpm dev            # tsdown --watch
pnpm test           # vitest
pnpm typecheck
pnpm lint
pnpm format

许可证

MIT

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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…

View all MCP Connectors

Latest Blog Posts

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