Skip to content
Draft
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: 3 additions & 4 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
# Port the server should listen on (default is 3000 if not specified)
APP_PORT=3000
# Loopback by default; use a trusted gateway before exposing this prototype.
APP_HOST=127.0.0.1

# Optional metadata values
APP_VERSION=1.0.0
APP_VERSION=1.1.0
MCP_NAME="Data Science Services by Pierre-Henry Soria"
MCP_DESCRIPTION="Freelance data scientist providing machine learning models, statistical analysis, and data-driven services."
MCP_TAGS="data-science, machine-learning, statistical-analysis, data-visualization, freelance, MCP, AI, model-development, statistical-models"
MCP_CONTACT_EMAIL="hi@ph7.me"
MCP_CONTACT_WEBSITE="https://ph7.me"

# Base URL used to construct full links for metadata (e.g., https://api.retainr.io)
BASE_URL=http://localhost:3000
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
node_modules/
dist/
.env
.env.*
!.env.dist
*.log

# TypeScript
Expand Down
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
# Preserve the verbatim license and historical social draft.
LICENSE.md
threads.txt
12 changes: 6 additions & 6 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cff-version: 1.2.0
message: "If you use this project, please cite it as below."
title: "MCP Server"
message: 'If you use this project, please cite it as below.'
title: 'MCP Server'
authors:
- family-names: Soria
given-names: Pierre-Henry
orcid: "https://orcid.org/0000-0002-5641-1355"
orcid: 'https://orcid.org/0000-0002-5641-1355'
date-released: 2025-07-26
url: "https://github.com/pH-7/mcp-server"
repository-code: "https://github.com/pH-7/mcp-server"
license: MIT
url: 'https://github.com/OpenData4Science/MCP-Server-API'
repository-code: 'https://github.com/OpenData4Science/MCP-Server-API'
license: MIT
109 changes: 52 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,86 @@
# My Personal Machine-Consumable Protocol (MCP) Compliant API for ML Services
# ML Service Metadata API

MCP Server is a structured, standards-compliant API for serving metadata, service discovery endpoints, and machine learning content. It's designed to help AI and data science applications discover model context, training artefacts, research notebooks, and statistical methods efficiently.
A small Fastify and TypeScript **REST prototype** for exploring machine-readable ML service descriptions. The repository keeps its historical `MCP-Server-API` name.

This server follows the [MCP specification](https://www.modelcontext.org/spec) and is production-ready, built with clean TypeScript code and a modular design.
**This is not a Model Context Protocol implementation.** The [MCP specification](https://modelcontextprotocol.io/specification/2025-11-25/basic) requires JSON-RPC messages and lifecycle negotiation; this project exposes ordinary HTTP routes with an experimental JSON-LD context. It does not support MCP client connections, inference, model training or automatic discovery by AI services.

[![Build Your Own MCP Server. Walkthrough, Step-by-Step Guide!](https://i1.ytimg.com/vi/DEaSz8kVPH8/sddefault.jpg)](https://youtu.be/DEaSz8kVPH8 "How to Use MCP Servers (Full Workflow)")
## Run locally

📺 [Click here to watch on YouTube](https://youtu.be/DEaSz8kVPH8)

## Project Features 🚀

* `.well-known/model-context` for structured model-level context resolution
* `.well-known/v1.json` to define a public semantic schema using JSON-LD – this is your `@context` document, allowing linked data vocab reuse
* Service discovery endpoint at `/v1/discovery`
* `/v1/content` endpoint to list available ML resources and data science artefacts
* Clean Fastify setup using plugin architecture and async route loading
* `.env` support for flexible configuration, including versioning and metadata


## Get Started

1. `npm install` to install all dependencies.
2. `npm run dev` to start the server in development mode with auto-reload (`ts-node-dev`).
3. Copy `.env.dist` to `.env` and configure the variables to fit your environment.
Requires Node.js 22 or newer.

```sh
npm ci
cp .env.dist .env
npm run build
npm start
```

### Other Commands
The server binds to `127.0.0.1:3000` by default. `npm run dev` reloads TypeScript during development; `npm run prod` builds and starts the same server. `npm start` uses the existing compiled output.

* `npm run start` – start the compiled server in normal mode (no hot reload)
* `npm run prod` – full production build and run (builds and launches)
* `npm run build` – compile TypeScript source code into `dist/` JavaScript
```sh
curl http://127.0.0.1:3000/v1/discovery
curl http://127.0.0.1:3000/v1/content
```

## Implemented routes

### Utility
| Route | Behaviour |
| -------------------------------- | ------------------------------------------------------------------------ |
| `GET /.well-known/model-context` | Configured service name, description, version, tags and contact |
| `GET /v1/discovery` | Alias for the same metadata |
| `GET /.well-known/v1.json` | The single experimental JSON-LD context definition |
| `GET /v1/content` | Four static example service descriptions; no datasets or model artefacts |
| `GET /v1/model/churn` or `/eda` | Illustrative input/output descriptions with `example: true` |
| `GET /v1/model/:unknown` | 404 |
| `POST /v1/strava/activities` | Retrieves the caller's Strava activities using the supplied access token |

* `npm run prettier:check` – check formatting issues using Prettier
* `npm run prettier:fix` – auto-format source files
The model examples do not link to nonexistent prediction or notebook endpoints. Replace examples with verified resources before presenting them as delivered services.

## Strava request contract

## Environment Variables
The body is JSON: `accessToken` is a nonempty string without whitespace; optional integer `page` is 1–10,000 (default 1), and `per_page` is 1–200 (default 30). Unknown fields, custom destinations and malformed values return 400. The whole request body is limited to 16 KB; tokens are limited to 4,096 characters.

The `.env` file supports the following values:
The destination is fixed to [Strava's athlete activities endpoint](https://developers.strava.com/docs/reference/#api-Activities-getLoggedInAthleteActivities). Requests have a 10-second timeout, a 2 MB response limit and no redirects. Success returns the upstream activity JSON; upstream failures return a generic 502. Responses use `Cache-Control: no-store`.

```env
APP_PORT=3000
APP_VERSION=1.0.0
MCP_VERSION=1.0.0
MCP_NAME="Data Science Services by Pierre"
MCP_DESCRIPTION="Freelance data scientist providing machine learning models, statistical analysis, and data-driven consulting."
MCP_TAGS="data science,machine learning,statistics,freelance,MCP"
MCP_CONTACT_EMAIL=hi@ph7.me
MCP_CONTACT_WEBSITE=https://ph7.me
```
Tokens and activity data are sensitive. Use only your own authorised token over localhost or a trusted HTTPS deployment. The proxy forwards it only to Strava; it does not obtain, refresh, store or grant scopes to tokens. Tests mock every upstream call and do not access a real athlete's account.

## Follow My MCP Journey
## Configuration

I regularly share updates, deep dives, and tutorials on **building MCP servers** and related AI infrastructure on social media:
Copy `.env.dist` before starting. Metadata is read after environment loading, when routes are registered.

* Bluesky: [https://bsky.app/profile/ph7s.bsky.social](https://bsky.app/profile/ph7s.bsky.social)
* X: [https://x.com/phenrysay](https://x.com/phenrysay)
- `APP_PORT`: integer 1–65,535; defaults to 3000.
- `APP_HOST`: defaults to `127.0.0.1`. Public exposure requires separate deployment controls.
- `APP_VERSION`: metadata version; defaults to 1.1.0.
- `MCP_NAME`, `MCP_DESCRIPTION`, `MCP_TAGS`: display metadata; tags are trimmed and deduplicated.
- `MCP_CONTACT_EMAIL`, `MCP_CONTACT_WEBSITE`: optional public contact values.

Feel free to follow along, ask questions, and engage!
The `MCP_*` names are retained for compatibility and do not imply protocol support. Previously documented `MCP_VERSION` and `BASE_URL` were unused and are not supported.

## What is an MCP Server?
## Validation and boundaries

A **Model Context Protocol (MCP) server** is not just another REST API. Rather than simply exposing data, it provides **machine-readable context and metadata** about your ML services or models—using linked data formats like JSON-LD.
```sh
npm test
npm run prettier:check
npm audit
```

Its core purpose is to expose structured discovery endpoints—typically under `.well-known/`—which allow AI agents and tooling ecosystems to understand your capabilities without needing human interpretation.
Tests use Fastify injection with synthetic data for metadata, discovery, model examples, input validation and outbound-request restrictions. The build checks TypeScript; no AI model, database or external account is required.

## How is MCP different from a normal API?
This is not a production service: it has no per-user authentication, application-level rate limit, OAuth flow, persistent storage or deployment automation. CORS is permissive for local experimentation. Before public hosting, define the audience, add access and abuse controls, and verify real Strava scopes and quotas. Restricting the upstream URL is not a substitute for those controls.

* **Purpose:** Normal APIs deliver functional data. MCP servers deliver semantic metadata.
* **Endpoints:** MCP uses `.well-known/model-context` and `v1.json` for semantic discovery.
* **Format:** All responses are structured as JSON-LD (not plain JSON), enabling interoperability and reuse across systems.
* **Consumers:** Designed for machines, not people—MCP endpoints target **AI agents, search engines, or distributed tools**.
## Historical material

![Pierre-Henry Soria, author of the MCP Server project](assets/images/machine-consumable-protocol-mcp-compliant-api-for-ml-services.png)
[Original walkthrough](https://youtu.be/DEaSz8kVPH8) and [original illustration](assets/images/machine-consumable-protocol-mcp-compliant-api-for-ml-services.png) are preserved as project history. Their protocol/compliance claims are superseded by the implementation description above. `threads.txt` is a historical draft, not evidence of AI-platform indexing, deployment or delivered ML models.

A future real MCP implementation should be a separately specified change using the official protocol and SDK, with lifecycle and client interoperability tests.

## The Baker

[![Pierre-Henry Soria](https://avatars0.githubusercontent.com/u/1325411?s=200)](https://ph7.me "Pierre-Henry Soria, Software Developer")
[![Pierre-Henry Soria](https://avatars0.githubusercontent.com/u/1325411?s=200)](https://ph7.me 'Pierre-Henry Soria, Software Developer')

Made with ❤️ by **[Pierre-Henry Soria](https://pierrehenry.be)**. A super passionate & enthusiastic Problem-Solver / Senior Software Engineer. Also a true cheese 🧀, ristretto ☕️, and dark chocolate lover! 😋

[![@phenrysay](https://img.shields.io/badge/x-000000?style=for-the-badge&logo=x)](https://x.com/phenrysay "Follow Me on X") [![pH-7](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/pH-7 "My GitHub") [![YouTube Video](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://youtube.com/@pH7Programming "YouTube SucceedAI Video") [![BlueSky](https://img.shields.io/badge/BlueSky-00A8E8?style=for-the-badge&logo=bluesky&logoColor=white)](https://bsky.app/profile/ph7s.bsky.social "Follow Me on BlueSky")

[![@phenrysay](https://img.shields.io/badge/x-000000?style=for-the-badge&logo=x)](https://x.com/phenrysay 'Follow Me on X') [![pH-7](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/pH-7 'My GitHub') [![YouTube Video](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://youtube.com/@pH7Programming 'Pierre-Henry Soria programming channel') [![BlueSky](https://img.shields.io/badge/BlueSky-00A8E8?style=for-the-badge&logo=bluesky&logoColor=white)](https://bsky.app/profile/ph7s.bsky.social 'Follow Me on BlueSky')

## License

Expand Down
Loading