メインコンテンツへスキップ

ClineのMCPで認証が使えなかった話

·554 文字·3 分·
MCP Cline コードリーディング 技術記事
著者
on-keyday
隠者
目次

TL;DR
#

回帰テストは大事だよね

経緯
#

巷で話題のFastAPI-MCPというものを使ってみようとしてとりあえず作ってみたらいい感じに出来たのでインターネット経由で使えるようにしようとした(公開用ではなく個人用)

https://qiita.com/takuya77088/items/4db3bcaedd8ad721b077

インターネット経由なので認証が必要だよなというのでとりあえずBasic認証をかけようと思ったが自分が使っているclineでBasic認証は使えるんだろうかと思い、ドキュメントを見てみると以下のような記述を見つけた。

https://docs.cline.bot/mcp-servers/configuring-mcp-servers#sse-transport

{
  "mcpServers": {
    "remote-server": {
      "url": "https://your-server-url.com/mcp",
      "headers": {
        "Authorization": "Bearer your-token"
      },
      "alwaysAllow": ["tool3"],
      "disabled": false
    }
  }
}

おお、Basic認証もいけそうじゃんということでcline_mcp_settings.json

{
  "mcpServers": {
    "mcp-server": {
      "disabled": false,
      "url": "https://example.com/mcp",
      "headers": {
        "Authorization": "Basic <base64>"
      }
    }
  }
}

上みたいな感じ(イメージ)に編集しさあ早速使ってみようとやってみると

…え? いやいやちゃんと設定したよね? と確認してみるも設定に異常はなさそうだ。

そこでサーバーのログを確認してみると

(マスキング済み)

Log Message
ID
    1160193
Level
    ERROR
Start Time
    2025-04-25T16:11:36.576410265Z
End Time
    2025-04-25T16:11:36.579863591Z
Status Code
    401 Unauthorized
Request Method
    GET
Request URL
    ****
Host
    ****
Remote Address
    ****
Private Remote Address
    ****
Private Local Address
    ****
User Agent
    node
Request Headers
    Accept: text/event-stream
    Accept-Encoding: gzip, br
    Accept-Language: *
    Cache-Control: no-cache
    Cdn-Loop: cloudflare; loops=1
    Cf-Connecting-Ip: ********
    Cf-Ipcontinent: ****
    Cf-Ipcountry: ****
    Cf-Iplatitude: ****
    Cf-Iplongitude: ****
    Cf-Ray: ****
    Cf-Region: ****
    Cf-Region-Code: ****
    Cf-Timezone: ****
    Cf-Visitor: {"scheme":"https"}
    Cf-Warp-Tag-Id: ****
    Connection: keep-alive
    Hs-Connecting-Port: ****
    Pragma: no-cache
    Sec-Fetch-Mode: cors
    User-Agent: node
    X-Forwarded-For: ****
    X-Forwarded-Proto: https
Response Headers
    Content-Security-Policy: default-src 'self'; upgrade-insecure-requests; block-all-mixed-content
    Referrer-Policy: strict-origin-when-cross-origin
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    Vary: Origin
    Www-Authenticate: Basic
    X-Content-Type-Options: nosniff
    X-Frame-Options: SAMEORIGIN
    X-Powered-By: PHP/7.1.32
    X-Xss-Protection: 1; mode=block
Response Body Size
    0
Taken Time
    127.685µs
Taken Time (Nano)
    127685
Log
    {"time":"2025-04-25T16:11:36.576482085Z","level":"ERROR","file":"*","line":"*","message":"access denied deny: default (basic_auth)"}

…あれ?Authorizationヘッダ送られてないっぽい????

ということで調査に乗り出した

調査
#

まずissueを探してみると早速ヒット

どうやらMcpの設定の読み込み箇所にバグがあったようだ 下の方にPRが確認できたので見てみると

const SseConfigSchema = BaseConfigSchema.extend({
 	url: z.string().url(),
+ 	headers: z.record(z.string()).optional(),

といったような記述が発見された。ではこれは元からなかったのかというとそうでもないようで記録をたどってみるとこの時点では存在したことが確認できる

ではどこで消えたかと言うとzodを使ったスキーマに書き直した際に消失したようだ。

なおこのzodに変更する際には普通にPRでレビューをしているが通過している。AIツールもついぞ指摘することはなかったようだ

なおスキーマ以外にもこの修正PRではMCPのtypescript-sdkSSEClientTransportの初期化部分も正確に初期化されていなかったことが示唆されている。時系列的には以下のSSEトランスポートを実装した時点で既にスキーマからはheadersが消えた状態であったためSSEトランスポート実装者から見落とされた可能性がある。

結論
#

とりあえずこのバグが直るまではインターネット経由で自作mcpサーバーを使うのはお預けである..

あとAIのレビューを鵜呑みにするのは危ないということと仕様を書いたらテストを書くのは大事ということが改めて感じられた…

追記: mcp-remoteというライブラリで普通に行けた… みんなこっち使うからバグが表に出なかったのかな…