Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.git
node_modules
dist
.env
public
specs
plans
47 changes: 47 additions & 0 deletions .docs-mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"$schema": "https://raw.githubusercontent.com/speakeasy-api/docs-mcp/main/schemas/docs-mcp.schema.json",
"version": "1",
"strategy": {
"chunk_by": "h2",
"max_chunk_size": 8000,
"min_chunk_size": 200
},
"taxonomy": {
"source": {
"vector_collapse": false
}
},
"mcpServerInstructions": "This server provides Speakeasy documentation: core product docs (SDK generation, Gram, Terraform providers), step-by-step guides, API design best practices, the MCP hub, and the OpenAPI hub. Use speakeasy_search_docs before answering Speakeasy implementation questions, and use speakeasy_get_doc when surrounding context is needed. Filter by source to narrow results to one hub.",
"overrides": [
{
"pattern": "docs/**/*.md",
"metadata": {
"source": "docs"
}
},
{
"pattern": "guides/**/*.md",
"metadata": {
"source": "guides"
}
},
{
"pattern": "api-design/**/*.md",
"metadata": {
"source": "api-design"
}
},
{
"pattern": "mcp/**/*.md",
"metadata": {
"source": "mcp"
}
},
{
"pattern": "openapi/**/*.md",
"metadata": {
"source": "openapi"
}
}
]
}
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TUNNEL_KEY=gram_tunnel_replace_me
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.DS_Store
node_modules/
dist/
.env
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM node:22-slim AS dependencies

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

FROM dependencies AS build

COPY .docs-mcp.json ./
COPY scripts ./scripts
COPY docs ./docs
COPY guides ./guides
COPY api-design ./api-design
COPY mcp ./mcp
COPY openapi ./openapi
RUN node scripts/build-corpus.mjs && \
./node_modules/.bin/docs-mcp validate --docs-dir ./dist/corpus && \
./node_modules/.bin/docs-mcp build \
--docs-dir ./dist/corpus \
--out /index \
--description "Speakeasy product, SDK, OpenAPI, and MCP documentation" \
--tool-description-search "Search Speakeasy documentation: product docs (SDK generation, Gram, Terraform providers), step-by-step guides, API design best practices, the MCP hub, and the OpenAPI hub. Filter by source to narrow to one hub. Use exact identifiers, CLI commands, and configuration keys." \
--embedding-provider none

FROM node:22-slim

WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY --from=build /index /index

EXPOSE 20310

HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:20310/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"

ENTRYPOINT ["./node_modules/.bin/docs-mcp-server"]
CMD ["--index-dir", "/index", "--name", "speakeasy-docs", "--tool-prefix", "speakeasy", "--transport", "http", "--port", "20310", "--stateless"]
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,65 @@ For example:
- Check existing issues and pull requests for similar questions

Thank you for contributing to our documentation! Your help makes our documentation better for everyone.

## Docs MCP server

This repository doubles as the corpus for a local [Speakeasy Docs MCP](https://github.com/speakeasy-api/docs-mcp) search server running in full-text-search mode, so it requires no API keys. The build copies the five content hubs into `dist/corpus/`, renaming `.mdx` to `.md`, then indexes them.

Build the search index:

```bash
npm install
npm run docs:build
```

Run it over MCP stdio:

```bash
npm run mcp:start
```

Or run the Streamable HTTP transport on port 20310:

```bash
npm run mcp:start:http
```

The HTTP MCP endpoint is `http://localhost:20310/mcp`, and the health check is `http://localhost:20310/healthz`.

The server identifies itself as `speakeasy-docs` and exposes `speakeasy_search_docs` and `speakeasy_get_doc`. Search results can be filtered by `source` (`docs`, `guides`, `api-design`, `mcp`, or `openapi`).

For an MCP client that launches local stdio servers, use this repository as the working directory and configure:

```json
{
"mcpServers": {
"speakeasy-docs": {
"command": "npm",
"args": ["run", "--silent", "mcp:start"]
}
}
}
```

The generated index lives under `dist/index/` and is ignored by Git. Re-run `npm run docs:build` after content changes.

### Docker

Build and run the self-contained HTTP server:

```bash
docker build -t speakeasy-developer-docs-mcp .
docker run --rm -p 20310:20310 speakeasy-developer-docs-mcp
```

To expose the server through the Speakeasy Gram tunnel, copy the environment template, set the issued tunnel key, and start both containers:

```bash
cp .env.example .env
# Edit .env and replace gram_tunnel_replace_me with the issued key.
docker compose up --build -d
docker compose logs -f gram-tunnel
```

The Compose network routes the tunnel agent to the MCP endpoint at `http://docs-mcp:20310/mcp`; the docs server is not published on a host port. Stop and remove both containers with `docker compose down`.
30 changes: 30 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: speakeasy-docs-mcp

services:
docs-mcp:
build:
context: .
image: speakeasy-developer-docs-mcp:local
container_name: speakeasy-docs-mcp
restart: unless-stopped
networks:
- gram-tunnel

gram-tunnel:
image: ghcr.io/speakeasy-api/gram-tunnel-agent:latest
container_name: gram-tunnel-speakeasy-docs
restart: unless-stopped
depends_on:
docs-mcp:
condition: service_healthy
environment:
TUNNEL_KEY: ${TUNNEL_KEY:?Set TUNNEL_KEY in .env}
TUNNEL_LOCAL_MCP_URL: http://docs-mcp:20310/mcp
TUNNEL_GATEWAY_URL: wss://tunnel.speakeasy.com/connect
TUNNEL_SERVICE_VERSION: 2026.06.1
networks:
- gram-tunnel

networks:
gram-tunnel:
name: gram-tunnel-speakeasy-docs
Loading
Loading