diff --git a/package.json b/package.json
index d888118bed..fbed94f829 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
 		"@types/cbor": "5.0.0",
 		"@types/dateformat": "3.0.1",
 		"@types/double-ended-queue": "2.1.1",
+		"@types/glob": "7.1.1",
 		"@types/gulp": "4.0.6",
 		"@types/gulp-mocha": "0.0.32",
 		"@types/gulp-rename": "0.0.33",
@@ -128,6 +129,7 @@
 		"fibers": "4.0.2",
 		"file-type": "13.1.2",
 		"fluent-ffmpeg": "2.1.2",
+		"glob": "7.1.6",
 		"gulp": "4.0.2",
 		"gulp-clean-css": "4.2.0",
 		"gulp-dart-sass": "0.9.1",
diff --git a/src/client/pages/docs.vue b/src/client/pages/docs.vue
index 049ef2ec02..a880e8abe4 100644
--- a/src/client/pages/docs.vue
+++ b/src/client/pages/docs.vue
@@ -4,6 +4,11 @@
 	<portal to="title">{{ $t('help') }}</portal>
 	<main class="_card">
 		<div class="_content">
+			<ul>
+				<li v-for="doc in docs" :key="doc.path">
+					<router-link :to="`/docs/${doc.path}`">{{ doc.title }}</router-link>
+				</li>
+			</ul>
 		</div>
 	</main>
 </div>
@@ -12,6 +17,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'
+import { url, lang } from '../config';
 
 export default Vue.extend({
 	metaInfo() {
@@ -22,8 +28,15 @@ export default Vue.extend({
 
 	data() {
 		return {
+			docs: [],
 			faQuestionCircle
 		}
 	},
+
+	created() {
+		fetch(`${url}/docs.json?lang=${lang}`).then(res => res.json()).then(docs => {
+			this.docs = docs;
+		});
+	},
 });
 </script>
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index ae31139014..7f2ecde914 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -3,12 +3,15 @@
  */
 
 import * as os from 'os';
+import * as fs from 'fs';
 import ms = require('ms');
 import * as Koa from 'koa';
 import * as Router from '@koa/router';
 import * as send from 'koa-send';
 import * as favicon from 'koa-favicon';
 import * as views from 'koa-views';
+import * as glob from 'glob';
+import * as MarkdownIt from 'markdown-it';
 
 import packFeed from './feed';
 import { fetchMeta } from '../../misc/fetch-meta';
@@ -20,6 +23,11 @@ import getNoteSummary from '../../misc/get-note-summary';
 import { ensure } from '../../prelude/ensure';
 import { getConnection } from 'typeorm';
 import redis from '../../db/redis';
+import locales = require('../../../locales');
+
+const markdown = MarkdownIt({
+	html: true
+});
 
 const client = `${__dirname}/../../client/`;
 
@@ -98,7 +106,39 @@ router.get('/api.json', async ctx => {
 
 router.get('/docs.json', async ctx => {
 	const lang = ctx.query.lang;
-	// TODO: glob mds and extract title
+	if (!Object.keys(locales).includes(lang)) {
+		ctx.body = [];
+		return;
+	}
+	const paths = glob.sync(__dirname + `/../../../src/docs/*.${lang}.md`);
+	const docs: { path: string; title: string; }[] = [];
+	for (const path of paths) {
+		const md = fs.readFileSync(path, { encoding: 'utf8' });
+		const parsed = markdown.parse(md, {});
+		if (parsed.length === 0) return;
+
+		const buf = [...parsed];
+		const headingTokens = [];
+
+		// もっとも上にある見出しを抽出する
+		while (buf[0].type !== 'heading_open') {
+			buf.shift();
+		}
+		buf.shift();
+		while (buf[0].type as string !== 'heading_close') {
+			const token = buf.shift();
+			if (token) {
+				headingTokens.push(token);
+			}
+		}
+
+		docs.push({
+			path: path.split('/').pop()!.split('.')[0],
+			title: markdown.renderer.render(headingTokens, {}, {})
+		});
+	}
+
+	ctx.body = docs;
 });
 
 const getFeed = async (acct: string) => {
diff --git a/yarn.lock b/yarn.lock
index 8a04517c35..de870e0f69 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -285,7 +285,7 @@
     "@types/glob" "*"
     "@types/node" "*"
 
-"@types/glob@*":
+"@types/glob@*", "@types/glob@7.1.1":
   version "7.1.1"
   resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
   integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
@@ -4246,7 +4246,7 @@ glob@7.1.3:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
+glob@7.1.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
   version "7.1.6"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==