mcp-remote

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

2posts · 30d
Nov 30 posts
  1. Zenn · · @senuma

    Kiro から Backlog・Chat・ドライブを横断検索できるようにしてみた(公式MCP) ! 2026年10月時点の情報です。Google Workspace の MCP サーバーはデベロッパー プレビュー段階のため、仕様や手順は今後変わる可能性があります。 はじめに 日本瓦斯株式会社の子会社である、株式会社雲の宇宙船で社内SEをしている瀬沼です。 抱えていた課題 仕事を進めていく中で、1つの問い合わせや作業のために、複数のサービスを行き来して情報を集めることがよくあります。 依頼の内容や経緯は Backlog 関連する資料や手順書は Google ドライブ 担当者とのやり取りは Google Chat ベンダーさんや社外との連絡は Gmail それぞれのサービスで検索して、必要な情報を探すだけでも時間がかかります。さらに、別々に調べた情報を 自分の手でつなぎ合わせたり、食い違いがないか照合したり する必要があり、ここにも手間がかかっていました。 やったこと そこで、Kiro(デスクトップ版 IDE)から、Google Chat・Gmail・Google ドライブ・Google カレンダー・Backlog を直接扱えるようにしました。 Google Workspace は Google 公式の MCP サーバー、Backlog は Nulab 公式の backlog-mcp-server を使っています。 楽になったこと 複数のサービスをまたいだ調べものを、Kiro にまとめて頼めるようになりました。 Before After サービスごとに画面を開いて、それぞれ検索する Kiro に1回頼むだけで、横断して探してくれる 調べた情報を自分でつなぎ合わせ、照合する 複数のサービスの情報を突き合わせて、まとめた形で返してくれる たとえば、次のような頼み方ができます。 「この Backlog の課題について、Google Chat でどんなやり取りがあったかまとめて」 「〇〇の件で、ドライブにある手順書と、Backlog の過去の対応を突き合わせて」 「今日の予定と、自分が担当している Backlog の課題をまとめて」 実際に、Kiro の制約と OAuth まわりで何か所か詰まったので、設定の流れと詰まったところをまとめます。 構成 Kiro(デスクトップ版 IDE) ├─ mcp-remote(PC 上で起動)── OAuth ──→ Google Workspace MCP(4サービス) └─ backlog-mcp-server(PC 上で起動)── API キー ──→ Backlog サービス MCP サーバー Google Chat chatmcp.googleapis.com Gmail gmailmcp.googleapis.com Google ドライブ drivemcp.googleapis.com Google カレンダー calendarmcp.googleapis.com Backlog backlog-mcp-server(PC 上で起動) 前提条件 Google Workspace のアカウント(Gmail アドレスは不可) Google Cloud のプロジェクト Google Workspace デベロッパー プレビュー プログラムへの参加 Node.js(mcp-remote と backlog-mcp-server で使います) Backlog の API キー(個人設定から発行) プレビュープログラムは、Google Workspace のアカウントと Google Cloud のプロジェクト番号を申請フォームで登録します。私の場合は、申請した当日のうちに承認メールが届きました(公式には「数日、1週間連絡がなければ問い合わせ」とされています)。 ! プレビュー規約には、プレビュー API で送受信したデータを Google が API の改善などに利用することがある、という条項があります。業務で使う場合は、扱うデータの範囲を社内で決めておくのがおすすめです。私も上長の許可を得て、社内の確認を経てから導入しています。 1. Google Cloud 側の設定 API を有効にする 使うサービスごとに、通常の API と MCP 用の API の両方を有効にします。 gcloud services enable \ chat.googleapis.com chatmcp.googleapis.com \ gmail.googleapis.com gmailmcp.googleapis.com \ drive.googleapis.com drivemcp.googleapis.com \ calendar-json.googleapis.com calendarmcp.googleapis.com \ --project=<PROJECT_ID> OAuth 同意画面を作る Google Auth Platform で同意画面を作成します。社内だけで使うなら、対象は 「内部」 にします。組織外のアカウントでは認証できなくなるので、安心して使えます。 データアクセスには、使うサービスのスコープを登録します(いずれも googleapis.com 配下)。 サービス スコープ Chat chat.spaces.readonly chat.memberships.readonly chat.messages.readonly chat.messages.create chat.users.readstate Gmail gmail.readonly gmail.compose ドライブ drive.readonly drive.file カレンダー calendar.calendarlist.readonly calendar.events.freebusy calendar.events.readonly Chat アプリを構成する(Chat を使う場合) Google Chat API の「構成」で、アプリ名(例:Chat MCP)を入れ、インタラクティブ機能をオフにして保存します。 最初は「書き込みをするときだけ必要」と読み違えていましたが、Chat MCP を使うのであれば設定が必須になります。 OAuth クライアントを作る 種類は「ウェブアプリケーション」です。 作成画面にある 「Use this client for an AI-powered agent」 にはチェックを入れます。AI エージェントが使うクライアントであることを申告する項目で、Workspace の MCP サーバーの中には、このチェックが入ったクライアントからの呼び出ししか受け付けないものがある、と Google のヘルプに書かれています。 承認済みのリダイレクト URI には、mcp-remote が使うコールバックを サービスごとに 登録します(ポート番号は後述の mcp.json と揃えます)。 127.0.0.1 # Google Chat 127.0.0.1 # Gmail 127.0.0.1 # Google ドライブ 127.0.0.1 # Google カレンダー 2. Kiro × Google Workspace mcp-remote を挟む理由 Kiro もリモートの MCP サーバーと OAuth に対応していますが、ドキュメントによると IDE 版は「シークレットを使わない公開クライアント」にしか対応していません(シークレットを指定できるのは CLI 版のみ)。 Google の「ウェブアプリケーション」のクライアントはトークンの交換でシークレットが必要なので、IDE 版から直接はつながりません。 そこで、Node.js 製の中継ツール mcp-remote をローカルの MCP サーバーとして起動し、OAuth は mcp-remote に任せる形にしました。 Kiro ── stdio ──→ mcp-remote(PC 上)── OAuth ──→ Google Workspace MCP 認証情報をファイルに分ける クライアント ID・シークレットとスコープは、JSON ファイルに分けて mcp-remote に渡します。 Windows では、引数にスペースが入ると正しく渡らないことがあり、スペース区切りのスコープを直接書くと失敗しやすいためです。 %USERPROFILE%.mcp-auth-config\client_info.json {"client_id":"<クライアントID>","client_secret":"<クライアントシークレット>"} %USERPROFILE%.mcp-auth-config\chat_client_metadata.json {"scope":"googleapis.com googleapis.com googleapis.com googleapis.com googleapis.com"} Gmail・ドライブ・カレンダーも、同じ形でスコープのファイルを作ります。クライアント情報のファイルは共用で大丈夫です(ファイル名は任意です)。 メモ帳で手打ちすると打ち間違いが起きやすいので、PowerShell で書き出すのがおすすめです。[IO.File]::WriteAllText なら BOM なしで保存されます。 Gmail [IO.File]::WriteAllText("$env:USERPROFILE.mcp-auth-config\gmail_client_metadata.json", '{"scope":"googleapis.com googleapis.com"}') ドライブ [IO.File]::WriteAllText("$env:USERPROFILE.mcp-auth-config\drive_client_metadata.json", '{"scope":"googleapis.com googleapis.com"}') カレンダー [IO.File]::WriteAllText("$env:USERPROFILE.mcp-auth-config\calendar_client_metadata.json", '{"scope":"googleapis.com googleapis.com googleapis.com"}') Kiro の mcp.json %USERPROFILE%.kiro\settings\mcp.json に、サービスごとに mcp-remote を登録します。 ポート番号はサービスごとに分けます。 同じポートにすると、同時に起動したときに競合します。 mcp.json(Google Chat の例) { "mcpServers": { "google-chat": { "command": "npx", "args": [ "-y", "mcp-remote", "chatmcp.googleapis.com", "7778", "--static-oauth-client-info", "@C:/Users/<ユーザー名>/.mcp-auth-config/client_info.json", "--static-oauth-client-metadata", "@C:/Users/<ユーザー名>/.mcp-auth-config/chat_client_metadata.json" ] } } } 4サービス分の設定例(Gmail 7779 / ドライブ 7780 / カレンダー 7781) mcp.json { "mcpServers": { "google-chat": { "command": "npx", "args": ["-y", "mcp-remote", "chatmcp.googleapis.com", "7778", "--static-oauth-client-info", "@C:/Users/<ユーザー名>/.mcp-auth-config/client_info.json", "--static-oauth-client-metadata", "@C:/Users/<ユーザー名>/.mcp-auth-config/chat_client_metadata.json"] }, "gmail": { "command": "npx", "args": ["-y", "mcp-remote", "gmailmcp.googleapis.com", "7779", "--static-oauth-client-info", "@C:/Users/<ユーザー名>/.mcp-auth-config/client_info.json", "--static-oauth-client-metadata", "@C:/Users/<ユーザー名>/.mcp-auth-config/gmail_client_metadata.json"] }, "google-drive": { "command": "npx", "args": ["-y", "mcp-remote", "drivemcp.googleapis.com", "7780", "--static-oauth-client-info", "@C:/Users/<ユーザー名>/.mcp-auth-config/client_info.json", "--static-oauth-client-metadata", "@C:/Users/<ユーザー名>/.mcp-auth-config/drive_client_metadata.json"] }, "google-calendar": { "command": "npx", "args": ["-y", "mcp-remote", "calendarmcp.googleapis.com", "7781", "--static-oauth-client-info", "@C:/Users/<ユーザー名>/.mcp-auth-config/client_info.json", "--static-oauth-client-metadata", "@C:/Users/<ユーザー名>/.mcp-auth-config/calendar_client_metadata.json"] } } } 保存すると Kiro が読み込み、サービスごとにブラウザが開くので、Google アカウントで許可します。 詰まったところ ① ツールを呼ぶと、しばらく待たされて中断される Kiro から Chat のスペースを検索しようとしたところ、50秒〜3分ほど待たされたあと、次のように中断されました。 This tool was interrupted before it reported a result 原因は、OAuth の認証が終わっていなかったことです。mcp-remote は、認証が済んでいないとブラウザでの許可を待ち続けるので、Kiro からはエラーではなく「待たされて中断される」ように見えます。 ブラウザの許可画面が開いていないか、開いたけれど次のエラーで失敗していないかを確認します。 ② invalid_client(The OAuth client was not found) Google のログイン画面で「アクセスをブロック:認証エラーです」と出ました。 Error 401: invalid_client The OAuth client was not found. エラー画面の URL を見ると、client_id= の値の前後に全角のカッコ(%EF%BC%88 と %EF%BC%89)が付いていました。手順のメモに書いていた「(クライアントID)」のカッコを消し忘れていたのが原因です。シークレットの欄にも、仮の文字列が残っていました。 ! エラー画面のアドレスバーの client_id= を見ると、実際に送られた値が分かります。 原因の特定に一番役立ちました。 ③ 設定を直しても同じエラーが出る mcp-remote は、初回の接続で使ったクライアント情報やトークンを %USERPROFILE%.mcp-auth\ に保存し、次からはそれを使い回します。 設定ファイルを直したら、Kiro を終了し、このフォルダを消してから起動し直します。 Remove-Item -Recurse -Force "$env:USERPROFILE.mcp-auth" ④ Node のプロセスを止めたら、ほかの MCP まで止まった 裏で mcp-remote のプロセスが残っていると、古い設定のまま動き続けることがあります。 そこで Get-Process node | Stop-Process で止めたところ、同じ PC で動いていたほかのツールの MCP サーバー(Claude デスクトップの Backlog MCP)まで一緒に止まりました。どちらも Node.js で動いているためです。 止めるときは、まず Kiro やほかの AI ツールを終了してから行うのが安全です。 ⑤ redirect_uri_mismatch mcp-remote は、コールバックを localhost ではなく 127.0.0.1 で受け取ります。 Error 400: redirect_uri_mismatch The redirect URI in the request, 127.0.0.1, does not match the ones authorized for the OAuth client. そのため、リダイレクト URI は 127.0.0.1 のように、ポートごとに1つずつ登録する必要があります。私はカレンダー(7781)の登録を忘れていて、同じエラーをもう一度踏んでしまいました。 エラーの詳細に実際の redirect_uri が表示されるので、それをそのまま登録するのが確実です。登録してもすぐには反映されないことがあり、私の環境では保存後しばらく待つと通りました。 3. Kiro × Backlog Backlog は、Nulab 公式の backlog-mcp-server をローカルの MCP サーバーとして起動します。認証は OAuth ではなく API キーなので、Google と比べて手順はシンプルです。 mcp.json の mcpServers に、次のブロックを追加します。 mcp.json(追加分) "backlog": { "command": "npx", "args": ["-y", "backlog-mcp-server"], "env": { "BACKLOG_DOMAIN": "<スペースID>.backlog.com", "BACKLOG_API_KEY": "<APIキー>" }, "disabled": false } 必要に応じて、環境変数 ENABLE_TOOLSETS で有効にするツールの種類を絞れます(指定できる値は README を参照)。使わないツールを減らしておくと、AI がツールを選び間違えにくくなります OAuth がないぶん、Google のような詰まりどころはありませんでした。 ! 同じ backlog-mcp-server の設定は、Claude デスクトップ(claude_desktop_config.json)でもそのまま使えます。 4. 運用で気をつけていること ツールの数が増えすぎる。 MCP サーバーごとにツールがまとめて追加されるので、全部有効にしたところ Kiro から「89個のツールが有効」と警告が出ました。普段使わないサーバーは "disabled": true にして、必要なときだけ有効にしています 認証情報が PC に平文で残る。 クライアントシークレットと Backlog の API キーは設定ファイルに、トークンは .mcp-auth に保存されます。端末を紛失したときは、シークレットの無効化、トークンの取り消し、API キーの削除をする前提にしています Backlog の API キーは、発行した人と同じ権限を持つ。 AI が課題を更新・削除できるツールもあるので、ENABLE_TOOLSETS で絞り、更新系の操作は内容を確認してから実行させています 権限は最小限にする。 Google の許可画面では、Chat のスペース作成やメッセージ削除など、かなり広い権限を求められます。スコープは必要なものだけに絞っています パッケージのバージョンを固定する。 npx -y は起動のたびに最新版を取得するので、チームで使うならバージョンを固定したほうが安全です チャットに認証情報を貼らない。 設定のトラブルを AI に相談するとき、設定ファイルをそのまま貼るとシークレットや API キーも一緒に渡ってしまいます。貼る前に * で伏せる習慣をつけておきます まとめ Google Workspace の公式 MCP サーバーは、プレビュープログラムに参加すれば Kiro から使えます Kiro の IDE 版は公開クライアントにしか対応していないので、mcp-remote を挟んで OAuth を通します Backlog は公式の backlog-mcp-server を使えば、API キーだけで使えます 詰まったときは、エラー画面の URL(client_id や redirect_uri)、mcp-remote のキャッシュ(.mcp-auth)、そもそも認証が終わっているかを見ると原因を絞り込めます Chat・メール・ドライブ・カレンダー・課題管理を1つの AI から横断して扱えるようになると、「あの件どうなってたっけ」を探す時間がかなり減ります。同じことを試す方の参考にしていただければと思います。 参考 Configure the Google Workspace MCP servers Chat MCP サーバーを構成する Google Workspace デベロッパー プレビュー プログラム Kiro: MCP Configuration geelen/mcp-remote nulab/backlog-mcp-server Manage OAuth Clients(Google Cloud ヘルプ) 本記事の内容は個人の見解であり、所属組織の公式見解ではありません。記事内のプロジェクト ID・クライアント ID・ユーザー名などの識別情報は伏せて記載しています。 ※ 本記事に記載されている会社名、システム名、製品名、サービス名等は、各社の商標または登録商標です。(Google Workspace、Google Chat、Gmail、Google ドライブ、Google カレンダーは Google LLC の商標です。Backlog は株式会社ヌーラボの登録商標です。)

  2. DEV · · @fabwaseem

    How to Add a Remote MCP Server to Cursor, Claude Code, VS Code and Claude Desktop (Tested) A remote MCP server is a Model Context Protocol server you reach over HTTPS instead of starting it on your own machine. You add it with a URL, not a command. Every major AI coding client supports this now, but each one wants the URL in a slightly different shape. Cursor takes a bare url, Claude Code wants "type": "http", VS Code has two file formats, and Claude Desktop doesn't read a URL from its config file at all. This guide gives you the working setup for each client, using a real public server: Benchline, my open-source developer tools site, which serves its tools over MCP at https://benchline.fabwaseem.com/mcp with no API key and no session. I checked every config block against the official docs on October 23, 2026, ran the Claude Code commands for real, called a tool through the official TypeScript SDK and through mcp-remote, and measured what the server costs in latency and in tokens. All numbers below come from those runs. TL;DR: add a remote MCP server | Client | Where it goes | What to write | | --- | --- | --- | | Cursor | ~/.cursor/mcp.json or .cursor/mcp.json | "mcpServers": { "name": { "url": "…/mcp" } } | | Claude Code | claude mcp add or .mcp.json | claude mcp add --transport http name …/mcp (JSON needs "type": "http") | | VS Code | .vscode/mcp.json, or .mcp.json / ~/.copilot/mcp-config.json | "servers" with "type": "http", or "mcpServers" with "type": "http" | | Claude Desktop | Customize > Connectors | Add custom connector and paste the URL. Use mcp-remote in claude_desktop_config.json only for servers Anthropic's cloud can't reach | Before you blame the client, test the server with curl or the MCP Inspector. A remote server that answers tools/list will work in all four. | Measured from my build box, October 23, 2026 | Result | | --- | --- | | initialize, new connection per request (n=20) | median 1,487 ms, p95 1,867 ms | | initialize, one reused connection (n=20) | median 373 ms, p95 596 ms | | tools/list, one reused connection (n=20) | median 911 ms, p95 973 ms | | tools/list response size | 138,658 bytes raw, 24,174 bytes gzip | | Tool definitions the model reads (o200k_base) | 17,517 tokens | | tools/call through the TypeScript SDK, connected (n=20) | median 375 ms, p95 419 ms | | Claude Code 2.1.309, claude mcp add --transport http | ✔ Connected | What "remote" means in MCP MCP has two standard transports. With stdio, the client starts the server as a child process (npx some-server) and talks to it through stdin and stdout. The server runs on your machine, with your files and your environment variables. With Streamable HTTP, the server is a web endpoint. The client POSTs JSON-RPC messages to one URL and reads the answer as JSON or as a Server-Sent Events stream. The transport spec defines both. The older HTTP+SSE transport is deprecated, and Claude Code's docs say to use HTTP where you can. A remote server is just the second kind, hosted somewhere public. That has real advantages. You install nothing, the publisher ships fixes without asking you to update, and the same URL works in every client. It also means the server never sees your disk, which is a security win for tools that don't need it. Benchline's endpoint is stateless: each POST stands alone, it returns no Mcp-Session-Id, and it answers with plain JSON. I explain how that server is built in Building Benchline: a stateless MCP server, and what the newer stateless spec changes in Stateless MCP servers and the 2026-07-28 spec. For this guide, all you need is the URL. Check the server with curl first A Streamable HTTP server must get both application/json and text/event-stream in the Accept header. This call lists the tools: curl -sS -X POST https://benchline.fabwaseem.com/mcp \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' And this one calls a tool: curl -sS -X POST https://benchline.fabwaseem.com/mcp \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"format_json","arguments":{"json":"{\"a\":1}"}}}' Benchline accepts tools/list and tools/call without an initialize first, because it builds a fresh server for every request. A sessionful server would want initialize first and an Mcp-Session-Id header after that. When I sent initialize with protocol version 2025-06-18, the server answered with serverInfo benchline, the tools capability and no session header. If you prefer a real client to raw JSON-RPC, the MCP Inspector has a CLI mode. Version 2.12.0 needs Node.js 22.19 or newer: npx @modelcontextprotocol/inspector --cli \ --transport http --server-url https://benchline.fabwaseem.com/mcp \ --method tools/call --tool-name format_json --tool-arg 'json="{\"a\":1}"' One gotcha I hit: --tool-arg parses the value as JSON. My first try, json={"a":1}, sent an object, and the tool rejected it with -32602 Input validation error: expected string, received object. Wrapping the value in quotes makes it a JSON string. Cursor Cursor reads ~/.cursor/mcp.json for servers you want in every project, and .cursor/mcp.json in a project for that project only. A remote server needs only a url: { "mcpServers": { "benchline": { "url": "https://benchline.fabwaseem.com/mcp" } } } For a server that needs a token, add headers and read the value from your environment with Cursor's ${env:NAME} interpolation, so the secret never lands in the file: { "mcpServers": { "my-api": { "url": "https://api.example.com/mcp", "headers": { "Authorization": "Bearer ${env:MY_SERVICE_TOKEN}" } } } } Servers that use OAuth need no header. Cursor runs the sign-in itself, using PKCE and the server's protected resource metadata. If a server doesn't show up, open the Output panel and pick MCP Logs. Source: Cursor MCP docs. Claude Code Claude Code has a one-line command for remote servers: claude mcp add --transport http benchline https://benchline.fabwaseem.com/mcp claude mcp list On Claude Code 2.1.309 this printed Added HTTP MCP server benchline with URL: https://benchline.fabwaseem.com/mcp to local config, and claude mcp list showed benchline: https://benchline.fabwaseem.com/mcp (HTTP) - ✔ Connected. The default scope is local: the entry is saved in ~/.claude.json under the current project. Add --scope user to use it in every project, or --scope project to write it to .mcp.json and commit it for your team. For a token, pass --header "Authorization: Bearer …". For OAuth servers, run /mcp inside a session or claude mcp login <name>. The project file looks like this: { "mcpServers": { "benchline": { "type": "http", "url": "https://benchline.fabwaseem.com/mcp" } } } Don't paste a Cursor block into .mcp.json. Claude Code reads an entry without type as a stdio server. When I tried the Cursor-style block above, claude mcp list printed Skipped — invalid MCP server config for "benchline": command: expected string, received undefined, and the server was not loaded. Adding "type": "http" fixes it, and "streamable-http" works as an alias. Source: Claude Code MCP docs. VS Code VS Code now reads two formats, and it matters which file you edit. The VS Code format lives in .vscode/mcp.json in your workspace, or in your user profile. It uses a top-level servers object, and type is required: { "servers": { "benchline": { "type": "http", "url": "https://benchline.fabwaseem.com/mcp" } } } The portable format lives in .mcp.json at the workspace root, or in ~/.copilot/mcp-config.json for your user. It uses mcpServers, the same shape as Claude Code's file, so one committed .mcp.json can serve both tools: { "mcpServers": { "benchline": { "type": "http", "url": "https://benchline.fabwaseem.com/mcp" } } } The guided MCP: Add Server command now suggests the Copilot Global file first and labels .vscode/mcp.json as deprecated, though VS Code still reads it. The two formats handle secrets differently. .vscode/mcp.json supports ${input:…} prompts and ${env:NAME}, while portable files use ${NAME} and no input prompts. VS Code first tries Streamable HTTP and falls back to SSE. Source: VS Code MCP configuration reference. Claude Desktop This is where most copy-paste setups break. claude_desktop_config.json is for local stdio servers. The supported way to add a remote server is a custom connector: 1. Open Customize > Connectors (on the web, claude.ai/customize/connectors). 2. Click + Add, then Add custom connector. 3. Enter a name and the server URL, https://benchline.fabwaseem.com/mcp. 4. Under Authentication, pick No sign in for a public server like Benchline, or sign in for an OAuth server. There is also a Request headers section for API keys. 5. In a chat, enable it from + > Connectors. Custom connectors work on Free (one connector), Pro, Max, Team and Enterprise plans. On Team and Enterprise, an Owner adds the connector first. One detail matters a lot: Claude connects to a custom connector from Anthropic's cloud, not from your computer. The server has to be reachable from the public internet. A server on localhost, behind a VPN or on a company network won't connect, even if curl works on your laptop. Source: Claude Help Center. For those servers, bridge the URL to stdio with mcp-remote in claude_desktop_config.json (on macOS in ~/Library/Application Support/Claude/, on Windows in %APPDATA%\Claude\): { "mcpServers": { "benchline": { "command": "npx", "args": ["-y", "mcp-remote", "https://benchline.fabwaseem.com/mcp"] } } } Claude Desktop starts mcp-remote as a local process, and mcp-remote speaks Streamable HTTP to the server from your own network. I tested this by starting mcp-remote 0.15.2 from the official TypeScript SDK's stdio client, the way Claude Desktop would. The format_json call came back valid. The first start took 11.2 s, including npx fetching the package, and the call itself took 970 ms. For a token, use --header and keep the value in env, or --header-file so the secret stays out of the process list. Call a tool with the official TypeScript SDK To check a server from code, or to use one in your own agent, the official SDK client takes about ten lines: import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const client = new Client({ name: "remote-mcp-check", version: "1.0.0" }); await client.connect( new StreamableHTTPClientTransport(new URL("https://benchline.fabwaseem.com/mcp")), ); const { tools } = await client.listTools(); const result = await client.callTool({ name: "format_json", arguments: { json: '{"b":2,"a":[1,2]}' }, }); console.log(result.structuredContent); // { output: '{\n "b": 2, …', valid: true, errors: [] } await client.close(); With @modelcontextprotocol/sdk 1.32.1, the client negotiated protocol 2025-11-25, got no session id, and the call returned structuredContent with valid: true. Twenty calls on that connected client took a median of 375 ms and a p95 of 419 ms. The v2 client, @modelcontextprotocol/client 2.3.1, with versionNegotiation: { mode: "auto" } also connected and fell back to 2025-11-25, because Benchline's server doesn't speak 2026-07-28 yet. A direct 2026-07-28 request got Unsupported protocol version, and the list of versions the server does accept. Clients that negotiate handle this for you. Claude Code's v2 runtime, for example, asks each server which revision it supports and uses the newer one only where the server has it. What a remote MCP server costs your context window Speed is rarely the problem with MCP. Tokens are. Each tool's name, description and JSON Schema can end up in the model's context, and that's paid on every turn. So I measured Benchline's tools/list: - The full JSON-RPC response is 138,658 bytes. With curl --compressed the server sent 24,174 bytes of gzip. - Counted with the o200k_base tokenizer (via js-tiktoken), the whole response is 34,307 tokens. - Keep only what a model needs to choose and call a tool, meaning name, description and inputSchema, and it comes to 17,517 tokens (72,398 bytes of JSON). A rough characters-divided-by-4 estimate gives 18,100. Benchline's output schemas make up 52,458 bytes of the full response. - The largest single tool definition, build_open_graph, is 584 tokens. The smallest is 75. These are approximations. o200k_base is OpenAI's tokenizer, Claude and other models count differently, and each client decides which fields it forwards. Still, the order of magnitude holds. For comparison, the MCP server behind this site came to 5,949 tokens in my MCP vs API benchmark. Some clients soften the cost. Claude Code uses tool search by default, so Claude can look up tools when it needs them. VS Code lets you choose which tools a session can use, and Cursor lets you toggle whole servers off. Turn off what you aren't using. Latency: why the first request is slow I measured with curl from my build box, which reaches the internet through an egress proxy, so the absolute numbers include that path. Yours will differ. The pattern is the useful part: | Request (n=20 each) | New connection per request | One reused connection | | --- | --- | --- | | initialize | median 1,487 ms, p95 1,867 ms | median 373 ms, p95 596 ms | | tools/list | median 2,043 ms, p95 2,391 ms | median 911 ms, p95 973 ms | On a fresh connection, the TCP and TLS setup alone took a median of 928 ms before the first byte of the request went out. On a reused connection, tools/list sent its first byte after a median of 395 ms, and most of the remaining time went into downloading the uncompressed 138 KB body. Real clients keep connections open and fetch the tool list once per session, so you pay the slow path roughly once. Two practical points follow. A server with a large tool list should support compression. And MCP_TIMEOUT in Claude Code, or your client's equivalent, should allow a few seconds for the first connect. Troubleshooting remote MCP servers Every error below is one I triggered against the live server or found in the client docs: - 406 Not Acceptable: Client must accept both application/json and text/event-stream. Your Accept header is missing one of the two types. Real clients send both; hand-written curl and fetch calls often don't. - 405 Method not allowed on GET. Normal for a stateless server that offers no server-to-client stream. The spec allows it, and clients carry on. - Skipped — invalid MCP server config … command: expected string in Claude Code. You have a url without "type": "http". - A connector works in curl but not in Claude Desktop. Anthropic's cloud makes the connection, so it can't reach private networks. Use mcp-remote, or put the server somewhere public. - 401 Unauthorized. The server wants OAuth or a token. Claude Code flags the server under /mcp, where you can sign in, and Cursor and VS Code both support OAuth for HTTP servers. If you configured a static Authorization header and it's rejected, fix the token: Claude Code won't fall back to OAuth. - 429 Too many requests. Public servers rate-limit. Benchline allows 60 requests a minute per address and sends retry-after. - Unsupported protocol version. The client asked for a revision the server doesn't have. Use a client that negotiates, or pin a version both support. - Spaces in mcp-remote header args on Windows. The mcp-remote README warns that Cursor, Codex CLI and Claude Desktop on Windows don't escape spaces inside args. Write Authorization:${AUTH_HEADER} with no space and put Bearer … in env. Security checklist for remote MCP servers A remote server can't read your files, but it can still influence your agent. Before adding one: - Trust the publisher. Tool descriptions and tool output reach your model, and both can carry prompt injection. Servers that fetch web content are the main risk. - Keep secrets out of config files. Use ${env:NAME} in Cursor, ${NAME} in Claude Code and portable VS Code files, or ${input:…} in .vscode/mcp.json. Never commit a populated Authorization header. - Prefer OAuth over shared keys for anything multi-user, and read what scopes you grant. - Keep tool approval on for tools that write or delete, and approve one call at a time until you trust a server. - Pin mcp-remote (mcp-remote@0.15.2) in shared configs, so npx doesn't pull a new version silently. For the server side, including the OAuth SDK flaws I reproduced this month, read MCP security in 2026. If you want to build a remote server of your own, How to build an MCP server in Next.js covers the route handler, bearer auth and Origin checks. How I tested All tests ran on October 23, 2026, from my Linux build box against the live https://benchline.fabwaseem.com/mcp: - Latency: curl 8.14.1, 20 sequential initialize and 20 tools/list POSTs with a new connection each and a 1.5 s pause to stay under the rate limit. Then 20 of each on one connection with curl --next. Median and p95 come from time_total, using linear interpolation. - Size and tokens: the saved tools/list body, counted with js-tiktoken and the o200k_base ranks. - SDK: @modelcontextprotocol/sdk 1.32.1 and @modelcontextprotocol/client 2.3.1 on Node.js 20.19. Twenty format_json calls on one connected client, 1.2 s apart. - Clients: Claude Code 2.1.309 in a throwaway HOME. mcp-remote 0.15.2 started over stdio by the SDK. MCP Inspector 2.12.0 CLI. I checked the Cursor, VS Code and Claude Desktop syntax against their official docs on the same day, but didn't run those apps on the box. FAQ What is a remote MCP server? A Model Context Protocol server you reach over HTTPS with the Streamable HTTP transport, instead of a local process your client starts over stdio. You add it with a URL, nothing is installed on your machine, and the same URL works in Cursor, Claude Code, VS Code and Claude Desktop. How do I add a remote MCP server to Cursor? Add an entry with only a url under mcpServers in ~/.cursor/mcp.json for all projects, or .cursor/mcp.json for one project, for example "benchline": { "url": "benchline.fabwaseem.com" }. Add headers with ${env:NAME} for token auth. Cursor runs OAuth itself for servers that need it. What is the claude mcp add command for an HTTP server? claude mcp add --transport http <name> <url>, for example claude mcp add --transport http benchline benchline.fabwaseem.com. It saves to local scope by default. Add --scope user for every project or --scope project to write .mcp.json, and --header for a bearer token. Check it with claude mcp list. Why does Claude Code skip my MCP server from .mcp.json? An entry with a url but no type is read as a stdio server and skipped. In my test Claude Code 2.1.309 reported command: expected string, received undefined. Add "type": "http" (or the alias "streamable-http") next to the url. Can I put a remote URL in claude_desktop_config.json? No. That file is for local stdio servers. Add remote servers in Claude Desktop under Customize > Connectors > Add custom connector. For a server that Anthropic's cloud cannot reach, run npx -y mcp-remote <url> as a stdio command in claude_desktop_config.json. Why does my custom connector fail in Claude when curl works? Claude connects to custom connectors from Anthropic's cloud, not from your computer. A server on localhost, a VPN or a private network is unreachable from there. Host it publicly, allowlist Anthropic's IP ranges, or bridge it with mcp-remote, which connects from your own network. How many tokens does an MCP server add to the context? It depends on its tool schemas. Benchline's tool names, descriptions and input schemas came to 17,517 tokens with the o200k_base tokenizer, and the whole tools/list response to 34,307. The MCP server behind fabwaseem.com is 5,949 tokens. Turn off servers and tools you don't need. How do I test a remote MCP server without an AI client? POST a tools/list JSON-RPC request with curl, sending content-type: application/json and accept: application/json, text/event-stream, or run npx @modelcontextprotocol/inspector --cli --transport http --server-url <url> --method tools/list. A missing Accept type returns HTTP 406. Key takeaways - A remote MCP server is a Streamable HTTP endpoint. You add it with a URL, and nothing runs on your machine. - Cursor takes a bare url. Claude Code and VS Code need "type": "http", and Claude Code skips a url entry without it. - Claude Desktop adds remote servers as custom connectors, and the connection comes from Anthropic's cloud. Use mcp-remote in claude_desktop_config.json for servers that cloud can't reach. - Test with curl or the MCP Inspector first. The Accept header must list both application/json and text/event-stream. - Benchline's tool definitions came to 17,517 tokens (o200k_base). Context cost is the real price of adding a server, so turn off tools you don't use. - On one connection, a tools/call through the TypeScript SDK took a median of 375 ms. The first connect is the slow part. - Keep tokens in environment variables, prefer OAuth, and leave tool approval on for anything that writes. --- Originally published on fabwaseem.com, where I write about MCP, AI automation, Node.js and Next.js.

    1 reaction · 6 comments

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

1
PackageVersionDownloads · 30dTrend · 30d
v0.9.0
≥1.2M

README badges

Embed a badge in your README or website.

Live mentions · last 30 days
punkpeye/mcp-remote mentions in the last 30 days