結論から言うと、できました。公開APIなら、ChatGPTのチャットからなんでも叩ける。
MCPサーバを自分で1枚かますだけ。意外とあっさり。
そもそもの動機:ChatGPT、外部APIを直接叩けない
ChatGPTと喋ってると、しょっちゅうこうなる。
「今のドル円教えて」→ 「リアルタイムの為替は取得できません…」。
「この郵便番号の住所は?」→ 「最新のデータにはアクセスできません…」。
いや知ってるけど! そりゃ ChatGPT は基本箱の中で喋ってるだけなので、こっちが用意した好きな REST API を勝手に叩いてはくれない。
昔のプラグインも畳まれたし、「自前のAPIに手を伸ばす手段」がパッと見ない。地味に不便。
…と思ってたら、カスタムコネクタっていう口があるじゃん。で、調べたらこのコネクタの正体、MCP(Model Context Protocol) だった。これ使えるのでは?
ひらめき
コネクタ=MCPサーバ。だったらMCPサーバを自作して、そこに「公開APIを叩くツール」を生やせばよくない? ChatGPTはそのツールを呼ぶだけ。ツールの中身はただの fetch()。
つまりサーバ側で叩ける公開APIは、ぜんぶChatGPTから叩けることになる。
要はChatGPTに「手」を生やすイメージ。
仕組みは超シンプル
やることを絵にするとこれだけ。ChatGPTとあなたのAPIの間に、薄いMCPサーバを1枚はさむ。

MCPは「AIにツール(関数)を生やすための共通規格」くらいのザックリ理解でOK。
ChatGPTのリモートコネクタは Streamable HTTP って方式で喋るので、結局やることは POST /mcp を1本立てるだけ。身構えなくていい。
最小のMCPサーバを書く
TypeScript+公式SDK(@modelcontextprotocol/sdk)+Expressでサクッと。
依存はこれだけ。軽い。
"@modelcontextprotocol/sdk": "^1.29.0",
"express": "^5.2.1",
"zod": "^4.4.3"
まず「ツール」を定義する。ここが本体っちゃ本体。といっても registerTool のハンドラの中で 好きな公開APIを fetch するだけ。
今回は例として、認証不要で使える為替APIを叩いてみる。
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
export function buildMcpServer() {
const server = new McpServer({ name: 'my-api', version: '0.1.0' });
server.registerTool(
'get_exchange_rate',
{
title: 'Get exchange rate',
description: '2通貨間の最新の為替レートを返す。例: base=USD, quote=JPY',
inputSchema: {
base: z.string().length(3).describe('基準通貨 (例: USD)'),
quote: z.string().length(3).describe('相手通貨 (例: JPY)'),
},
},
async ({ base, quote }) => {
// ★ここが心臓部:好きな公開APIをそのまま叩く
const r = await fetch(
`https://api.frankfurter.app/latest?from=${base}&to=${quote}`
);
const data = await r.json();
const rate = data.rates?.[quote];
return {
content: [{ type: 'text', text: `1 ${base} = ${rate} ${quote}` }],
};
},
);
return server;
}
地味に大事なのが「ツールの説明文(description / describe)」をちゃんと書くこと。 ChatGPTはこの自然言語の説明だけを読んで「お、今ユーザー為替聞いてるな。じゃあこのツールを base=USD, quote=JPY で呼ぶか」って判断してる。
なので説明が雑だと普通にスルーされる。ここケチると動かないので注意。
HTTPの口を立てる
あとは POST /mcp を1本生やすだけ。Streamable HTTPのトランスポートにさっきのサーバを繋ぐ。ステートレスで雑にOK。
import express from 'express';
import { StreamableHTTPServerTransport }
from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { buildMcpServer } from './mcp-tool.js';
const app = express();
app.use(express.json());
app.get('/healthz', (_req, res) => res.json({ ok: true }));
app.post('/mcp', async (req, res) => {
const server = buildMcpServer();
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
res.on('close', () => { transport.close(); server.close(); });
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000, () => console.log('MCP on :3000'));
これで http://localhost:3000/mcp に喋るMCPサーバが完成。MCP Inspector みたいなローカルクライアントで tools/list を叩くと、ちゃんと get_exchange_rate が見える。
おお、できてる。ここまでで「箱」は完成。
HTTPSで外に公開する(コネクタはhttps必須)
ChatGPTのコネクタは 公開された https:// のURL しか登録できない。localhost はもちろんダメ。
というわけで、どっかのVM(無料枠のクラウドで十分)に置いてTLS付けて外に出す。
証明書を手で取るのはダルいので Caddy に丸投げ。
設定これだけで Let’s Encrypt を勝手に取ってきてくれる。神。
api.example.com {
reverse_proxy localhost:3000
}
DNSで api.example.com をVMのIPに向けて(証明書発行のため一旦プロキシはオフ=DNSだけ通す)、Caddy起動。
あとはサーバを systemd でデーモン化しとけば、VM再起動しても勝手に立ち上がってくれる。これで https://api.example.com/mcp が世界に開通。
ChatGPTにコネクタとして登録する
ここまで来たら、あとはChatGPT側の設定 → コネクタ → カスタムコネクタを追加、でさっきのURLを入れるだけ。
- MCPサーバのURLに
https://api.example.com/mcpを入力 - 登録方法は DCR(動的クライアント登録)、スコープは自分で決めた文字列(例
mcp) - 接続すると、ChatGPTが
tools/listでツール一覧を取りに来る →get_exchange_rateが見えれば成功
で、チャットで「今のドル円は?」って聞く。するとChatGPTが裏で get_exchange_rate(base:"USD", quote:"JPY") を勝手に呼んで、自作サーバが公開APIを叩いて、生きた数字を返してくる。

「1ドル ≒ 158.2円です」とChatGPTが即答。
でもこの数字、ChatGPTは本当は知らない。自作サーバが今この瞬間に公開APIから取ってきた値。
地味だけど、ちょっと感動する。ChatGPTに手が生えた瞬間です。

そして本当の沼は、この先(OAuth)にあった
…と、ここまでは正直サクサクだった。問題はこの後。
ChatGPTにコネクタとして繋ごうとすると、「まず認証通してね」と OAuth を要求してくる。 「はいはいSDKに認証ルータ入ってるんでしょ、貼るだけっしょ」と舐めてたら、ここで半日溶けた。
リバースプロキシ背後の罠とか、トークンの有効期限を返し忘れて「再認証→失敗→再認証」の無限ループに叩き込まれたりとか、まあまあエグいハマり方を何点かしまして…。
この記事の本題(=公開APIを叩く)からは脱線するし、何よりOAuthの沼だけで普通に1記事ぶんのボリュームになったので。 → 【OAuth編】ChatGPTコネクタの認証で半日溶かした話(trust proxy / expiresAt 無限ループ)(執筆中)
ちなみに——自分専用でいい/他人には使わせないなら、実はOAuthまで作り込まなくても、さっきの「公開APIを叩くツール」までで普通に遊べます。
OAuthが効いてくるのは「他人にも配る」「ユーザーごとにデータを分ける」みたいな段階。
まず動かしてニヤニヤするぶんには、認証なしで十分。
まとめ:ChatGPTに「手」を生やせた
やったことを振り返るとシンプルで、
- 公式SDKで MCPサーバを1枚書く(ツールの中身は普通の
fetch) - VMに置いて Caddyで HTTPS 化して外に出す
- ChatGPTにカスタムコネクタとして登録する
たったこれだけで、ChatGPTから好きな公開APIが叩けるようになる。
為替でも天気でも、社内の在庫APIでも、自分で書いたAPIでも、サーバ側で fetch できるものは全部「ChatGPTの手の届く範囲」。
「ChatGPTって外部API叩けなくて不便〜」とか言ってた自分をひっぱたきたい。
コネクタ=MCPっていう口に気づいた瞬間、拡張性が一気に青天井になった。 気になるAPIがあったら、ツールを1個生やすだけ。
週末の工作にちょうどいいので、ぜひ。


