SuperAPI AI Directory

project-structure

Coding & development

View repository

Updated 10-18 05:08

About this skill

Project structure

The top-level tree, with each server's package name and registry, is in AGENTS.md under Project structure. This skill is the level below it: what is inside each server, and where a new file goes. Test placement and harnesses are /testing; building and running a server is /local-dev.

There is no shared library between servers. Each directory under src/ is a complete package that versions and publishes on its own, so a helper two servers need is written in both (expandHome exists in filesystem and in memory, and the copy in memory says so). Do not add a cross-server import.

The TypeScript servers

All four are npm workspaces of the root package.json and share one shape: the entry point is index.ts, sources sit at the workspace root (there is no src/ inside a server), tests are in __tests__/, and tsc writes dist/. Each has the same four config files: package.json, tsconfig.json (the build), tsconfig.test.json (the no-emit typecheck program, which also includes the tests) and vitest.config.ts.

Server Layout Where its features are registered
everything index.ts picks a transport from argv; server/ holds the factory; tools/, resources/, prompts/ hold one file per feature plus an index.ts; transports/ holds one file per transport; version.ts reads the package version; docs/ is shipped Each feature file exports a register… function, wired into its area's index.ts (registerTools, registerResources, registerPrompts), which server/index.ts calls from createServer()
filesystem index.ts is the stdio entry point (argv → allowed directories, main()); server.ts exports createServer(allowedDirectories); lib.ts holds the file operations and path validation, with the allow-list passed in rather than held globally; path-utils.ts, path-validation.ts and roots-utils.ts are focused helpers; version.ts reads the package version Inline in createServer() in server.ts, with server.registerTool(...)
memory index.ts holds the KnowledgeGraphManager, createServer(memoryFilePath) and the stdio main(); version.ts reads the package version Inline in createServer(); the resource and its subscription handlers are exported register… functions in the same file
sequentialthinking index.ts holds createServer() and the stdio main(); lib.ts holds SequentialThinkingServer, the logic; version.ts reads the package version Inline in createServer()

Three things about everything that the table cannot hold:

  • server/index.ts exports createServer(), which returns { server, cleanup }. Every transport file calls it, once per stdio process or once per HTTP session. A tool that depends on what the client can do (roots, sampling, elicitation) is registered through registerConditionalTools, which runs after initialize, not through registerTools.
  • docs/ is part of the server, not only documentation. The build copies it into dist/docs, every file in it is served as a static resource, and docs/instructions.md is returned as the server's instructions. A file added there becomes a resource a client can list.
  • Its own maps are src/everything/docs/structure.md and src/everything/docs/extension.md. A change to the server's files updates structure.md, and src/everything/AGENTS.md holds the rules that apply only inside that directory.

No server starts on import. Each one builds its server in a createServer(...) factory, and its entry file connects a transport only when it is the process entry point (an isEntryPoint() or isMainModule() check that compares real paths, so the npm bin symlink still starts it). Keep it that way: a module that binds a port, connects stdio or installs a signal handler at import cannot be driven in-process by the tests. /testing covers the in-process harness.

The Python servers

fetch, git and time are independent uv projects with the same layout:

src/<server>/
├── pyproject.toml            dependencies, the console script, pytest and coverage config
├── uv.lock, .python-version
├── src/mcp_server_<name>/
│   ├── __init__.py           main(): the command-line flags, then asyncio.run(serve(...))
│   ├── __main__.py           python -m mcp_server_<name>
│   └── server.py             everything else
└── tests/                    pytest suite, driving serve() in-process

server.py holds the Pydantic input models, the functions that do the work, and serve(). serve() constructs the Server, declares the tools (and, in fetch, the prompts) with the @server.list_tools() / @server.call_tool() decorators inside its body, and then runs it over stdio. So a new tool is a set of edits in server.py: its input model, its entry in list_tools, and its branch in call_tool. In git and time there is a fourth: tool names are members of an enum (GitTools, TimeTools) that list_tools and call_tool both dispatch on, so the new name is added there first. fetch has one tool and no enum. The Server object is local to serve() and not importable.

Where to put a new file

It is… It goes in
A tool, resource or prompt for everything Its own kebab-case file in tools/, resources/ or prompts/, exporting a register… function, wired into that directory's index.ts
A transport for everything src/everything/transports/, plus a case in src/everything/index.ts and a start:… script
A tool for filesystem, memory or sequentialthinking A server.registerTool(...) call inside that server's createServer() (server.ts in filesystem, index.ts in the other two); the logic it calls goes in lib.ts (or the class it extends)
A helper module for everything A kebab-case .ts file in the feature area it supports, beside its users (server/logging.ts, server/roots.ts, resources/session.ts), imported with the .js extension
A helper module for filesystem, memory or sequentialthinking A kebab-case .ts file at the workspace root, imported with the .js extension
A tool for a Python server server.py: the tool-name enum member (git, time), the model, the list_tools entry, the call_tool branch
A command-line flag for a Python server __init__.py, passed into serve()
A test /testing
Root tooling (a guard, a release helper) scripts/<name>.mjs, with a sibling <name>.test.mjs when it has logic worth testing; shared helpers in scripts/lib/
A design document docs/
A procedure for agents .claude/skills/<name>/SKILL.md, with a row in the Skills index

A new server directory is not on this list: the repository does not accept new servers (CONTRIBUTING.md).

What a new file is checked against

A TypeScript file in a new location is still inside the gate, because two guards enumerate tracked files rather than trusting a glob: verify:typecheck-coverage fails when a tracked .ts file is in no project that typecheck runs, and verify:format-coverage fails when a tracked source file matches no prettier --check glob. Both run in npm run validate:guards. If one fires on a file you added, the fix is to bring the file into the existing config, not to exclude it.

When a file or directory is added, removed, renamed or given a different purpose, every entry that describes it changes in the same PR (AGENTS.md, Maintenance rules): the root README.md, the server's own README.md, the tree in AGENTS.md, and for everything, docs/structure.md.