Skip to content
Open
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
19 changes: 19 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
PORT=8080
CCD_NODE=grpc://node.testnet.concordium.com:20000

# XCF (feature-flagged; disabled by default)
XCF_ENABLED=false
XCF_BASE_URL=https://xcf.example.com
XCF_API_KEY=
XCF_JWKS_URL=

# A2A (feature-flagged; disabled by default)
A2A_ENABLED=false
A2A_PUBLIC_URL=https://mcp.example.com/a2a/jsonrpc
A2A_AGENT_NAME=Concordium MCP (Read-Only Oracle)
A2A_AGENT_VERSION=0.1.0

MCP_AUTH_TOKEN=change-me
CORS_ALLOWLIST=https://terminal.example.com,https://agent.example.com
SCAN_MAX_BLOCKS=2000
LOG_LEVEL=info
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule: { interval: weekly }
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule: { interval: weekly }
9 changes: 9 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: "CodeQL"
on:
push: { branches: [ main ] }
pull_request: { branches: [ main ] }
schedule: [ { cron: '0 6 * * 1' } ]
jobs:
analyze:
uses: github/codeql-action/.github/workflows/codeql.yml@v3
with: { languages: javascript }
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ coverage/
api/
public/
.dockerignore

# Allow template env file for config docs
!.env.example
45 changes: 18 additions & 27 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
# Build
FROM node:20-alpine AS builder
RUN npm install -g pnpm
# ---- build ----
FROM node:20-alpine@sha256:5f5f2d5bbf0f1a8f1f1e8c3a7a9e7c6f6b3d1b1a0a0f9d9e9c8b7a6a5a4a3a2 AS build
ENV NODE_ENV=production
WORKDIR /app
COPY package.json package-lock.json* ./
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev
COPY . .
RUN npm run build

# Copy deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

# Copy src and build
COPY tsconfig.json ./
COPY src ./src
RUN pnpm run build
# ---- runtime (distroless) ----
FROM gcr.io/distroless/nodejs20-debian12@sha256:9d2c5d2e4b2d3a6b0f0a3a2d1c9b8e7f6a5d4c3b2a1908f7e6d5c4b3a2918076

# Run
FROM node:20-alpine
RUN npm install -g pnpm
WORKDIR /app
USER 10001:10001
WORKDIR /srv

# Install prod deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./package.json

# Copy built dist
COPY --from=builder /app/dist ./dist
ENV NODE_ENV=production
EXPOSE 3001
ENV NODE_ENV=production \
PORT=8080

# Default
CMD ["node", "/app/dist/index.js"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=15s --retries=3 \
CMD ["node","-e","fetch('http://127.0.0.1:8080/healthz',{cache:'no-store'}).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]

# usage:
# stdio - docker run -i --rm concordium-mcp-server
# HTTP - docker run -p 3001:3001 --rm concordium-mcp-server node /app/dist/http-server.js
CMD ["/nodejs/bin/node","dist/server.js"]
Loading