Phase 0: FastMCP scaffold with ping tool

Set up the familiar package (src layout, uv/hatchling) with a FastMCP
server exposing a read-only ping health tool. Add pytest smoke tests with
80% coverage gate. Flesh out the README with the project vision and roadmap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
LatteandClaude Opus 4.8 committed 2026-06-27 17:34:51 +02:00
1 parent f99b8a7884
commit ef27cd85f6
7 files changed
+1864 -1

No files matched your search

+56 -1
View File
@@ -1,3 +1,58 @@
# familiar
Your familiar across New Eden — a read-only EVE Online MCP server that lets a local AI see your entire account and find anything in EVE.
> Your familiar across New Eden — a read-only EVE Online MCP server that lets a local AI see your entire account and find anything in EVE.
In EVE, your familiar isn't a cat on the windowsill. It's the companion that rides along through New Eden, sees what you see, remembers what you can't, and fetches anything you ask for. `familiar` is exactly that: an [MCP](https://modelcontextprotocol.io) server that gives a local AI (Claude Code, Claude Desktop, Cowork) a complete, read-only window into your EVE Online account and the entire game universe.
Ask your familiar where your assets are, what your skill queue looks like, what Tritanium sells for in Jita, the safest route to a lowsec system, or whether a fit is worth building. It looks, it finds, it reports back.
## Principles
- **Read-only by design.** `familiar` only ever *reads*. No market orders, no fittings changes, no mail sent, no waypoints set. The AI can see everything and break nothing.
- **Local-first.** Runs on your own machine. Your refresh token and account data never leave your control.
- **Everything, eventually.** The goal is full coverage: every read scope ESI exposes, plus the complete static universe. Built in phases so it actually ships.
## How it works
Two data sources sit behind the server:
- **ESI** (the [EVE Swagger Interface](https://esi.evetech.net/)) — the official REST API. Public endpoints (market, universe, industry indices) need no login. Character and corp data (wallet, assets, skills, industry, contracts, mail, location) come through EVE SSO with **read-only OAuth2 scopes**.
- **SDE** (the [Static Data Export](https://developers.eveonline.com/resource/resources)) — the full static dataset of items, blueprints, systems and stations, cached locally for fast lookups and anything name- or recipe-based.
Built in **Python with FastMCP**, OAuth via PKCE with a localhost callback, refresh token stored encrypted on disk. ESI `Expires` headers are respected for caching, and the SDE is loaded into a local store.
## Roadmap
Built in phases. Each phase is independently useful, so the project stays shippable.
**Phase 0 — Skeleton**
- Repo, project scaffold, FastMCP server that starts and exposes a health/ping tool.
- App registered on [developers.eveonline.com](https://developers.eveonline.com/).
**Phase 1 — Public lookups (no auth)**
- Market: prices and order book for any item in any hub, spreads between hubs.
- Universe via SDE: items, systems, stations, security, basic route/jumps.
- Quick win: useful before any OAuth complexity exists.
**Phase 2 — Account read (OAuth)**
- EVE SSO login flow, encrypted refresh token storage.
- Wallet, assets (search across characters), skills + skill queue, current location and clones.
**Phase 3 — Industry & contracts**
- Industry jobs, blueprints (SDE-backed), manufacturing cost/profit lookups.
- Personal and corp contracts, market orders.
**Phase 4 — Everything else**
- Mail, planetary interaction, loyalty points, fittings, corp roles.
- zKillboard integration for kill/PvP data.
**Phase 5 — Polish**
- Caching, error-limit safety, packaging, setup docs. Optional: prep a public, generic single-user release as a portfolio case.
## Status
Phase 0. Just hatched.
## License
MIT
+45
View File
@@ -0,0 +1,45 @@
[project]
name = "familiar"
version = "0.0.1"
description = "Your familiar across New Eden — a read-only EVE Online MCP server."
readme = "README.md"
requires-python = ">=3.11"
license = { file = "LICENSE" }
dependencies = [
"fastmcp>=2.3.0",
"httpx>=0.27.0",
]
[project.scripts]
familiar = "familiar.__main__:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/familiar"]
[dependency-groups]
dev = [
"pytest>=8.0.0",
"pytest-cov>=5.0.0",
"ruff>=0.6.0",
]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=familiar --cov-report=term-missing --cov-fail-under=80"
[tool.coverage.run]
source = ["familiar"]
omit = ["*/__main__.py"]
[tool.coverage.report]
exclude_also = [
"if __name__ == .__main__.:",
]
+3
View File
@@ -0,0 +1,3 @@
"""familiar — a read-only EVE Online MCP server."""
__version__ = "0.0.1"
+17
View File
@@ -0,0 +1,17 @@
"""Entry point: `python -m familiar` or the `familiar` console script.
Runs the MCP server over stdio, which is how Claude Desktop / Claude Code /
Cowork launch and talk to it.
"""
from __future__ import annotations
from .server import mcp
def main() -> None:
mcp.run()
if __name__ == "__main__":
main()
+40
View File
@@ -0,0 +1,40 @@
"""The familiar MCP server.
Phase 0: a server that starts and exposes a single health/ping tool.
Later phases register more tools (market, universe, account, ...) onto this
same `mcp` instance.
"""
from __future__ import annotations
import datetime as _dt
from fastmcp import FastMCP
from . import __version__
mcp: FastMCP = FastMCP(
name="familiar",
instructions=(
"familiar is a read-only window into an EVE Online account and the New "
"Eden universe. It only ever reads — it never places orders, sends mail, "
"sets waypoints, or changes anything in-game. Use it to look up market "
"prices, the static universe (items, systems, stations), and — once the "
"user has authenticated — their assets, skills, wallet, and location."
),
)
@mcp.tool
def ping() -> dict[str, str]:
"""Health check. Confirms the familiar server is alive and reports its version.
Returns the server name, version, and current UTC time. Useful as a first
call to verify the MCP connection is working before trying real lookups.
"""
return {
"status": "ok",
"server": "familiar",
"version": __version__,
"time_utc": _dt.datetime.now(_dt.timezone.utc).isoformat(),
}
+19
View File
@@ -0,0 +1,19 @@
"""Phase 0 smoke tests."""
import asyncio
from familiar import __version__
from familiar.server import mcp, ping
def test_ping_reports_ok():
result = ping()
assert result["status"] == "ok"
assert result["server"] == "familiar"
assert result["version"] == __version__
assert "time_utc" in result
def test_server_exposes_ping_tool():
tools = asyncio.run(mcp.list_tools())
assert "ping" in {t.name for t in tools}
Generated
+1684
View File
File diff suppressed because it is too large. Load diff