---
title: 'HarnessAPI: Unified Skill Framework'
url: https://www.emergentmind.com/topics/harnessapi
type: topic
---

# HarnessAPI: Unified Skill Framework

Searching arXiv for the specified HarnessAPI paper and directly related work.
HarnessAPI is a Python framework that unifies HTTP streaming endpoints and Model Context Protocol (MCP) tool registrations from a single typed “skill” definition, using a `handler.py` plus Pydantic schemas as the single source of truth. It was introduced as a “skill-first” alternative to route-first frameworks in which the same business logic must otherwise be maintained separately as an HTTP endpoint and as an MCP tool, with duplicated routing, validation, serialisation, streaming, and schema maintenance. From one skill folder, HarnessAPI automatically derives a streaming HTTP endpoint with Server-Sent Events, an interactive OpenAPI/Swagger UI, and a zero-configuration MCP tool, all served from a single process; across six representative skills, the framework reports a 74% reduction in framework-facing boilerplate relative to a manually maintained FastAPI plus FastMCP dual stack [2605.22733].

## 1. Conceptual model and problem formulation

HarnessAPI is defined by a “skill-first inversion.” In conventional route-first frameworks, the developer writes an HTTP route such as `@app.post(...)` and then separately registers the same logic as an MCP tool. HarnessAPI inverts this arrangement by treating each skill folder as the authoritative artifact and projecting it onto multiple transports during startup discovery. The stated objective is to eliminate duplication between human-facing and agent-facing interfaces while preventing schema drift as the underlying code evolves [2605.22733].

A skill is represented as a directory containing exactly two required files and several optional artifacts. The required files are `handler.py`, containing an asynchronous `handle` function, and `models.py`, containing `Input` and `Output` classes that inherit from `SkillInput` and `SkillOutput`. Optional files include `skill.toml`, `SKILL.md`, and `defaults/` and `examples/` directories. The paper specifies the pattern as:

- `handler.py` for `async def handle(input: Input) -> Output` or a streaming variant that yields chunks.
- `models.py` for Pydantic schemas.
- `skill.toml` for metadata including `[skill] description`, `is_mcp=true/false`, `timeout_secs`, and `tags`.
- `SKILL.md` as optional front-matter for agentskills.io.
- `defaults/` and `examples/` as optional directories [2605.22733].

This organization makes the skill folder the unit of deployment and interface generation. A plausible implication is that the framework treats interface concerns as a projection problem rather than an application-structure problem: one typed skill is materialized as multiple externally visible surfaces without requiring separate transport-specific implementations.

## 2. Internal architecture and runtime composition

At startup, HarnessAPI performs discovery over a `skills/` directory and loads each skill into its own synthetic package, exemplified as `_harness_skills.summarize`. The stated reason is to avoid name collisions when multiple skills define classes named `Input` and `Output` [2605.22733]. This is a concrete packaging mechanism rather than a merely stylistic convention: the framework relies on isolated module namespaces to preserve independent schema identities across skills.

The runtime then projects each discovered skill onto two transports. The paper names these as an HTTP `SkillRoute` and an MCP tool mounted under a `/mcp` sub-application. Because both projections share the same Pydantic models, the framework argues that schema drift is made “structurally impossible” [2605.22733]. That claim is important to the framework’s rationale: the elimination of duplication is not only an ergonomic change but also a consistency guarantee induced by the architecture.

HarnessAPI subclasses `fastapi.FastAPI` rather than wrapping it as an external orchestration layer. Its constructor composes the user’s FastAPI lifespan and the FastMCP sub-application lifespan via a merged async context manager, and then mounts the MCP application at `/mcp`. The paper’s representative implementation is:

```python
@asynccontextmanager
async def merged_lifespan(app):
  async with mcp_app.lifespan(mcp_app):
    if user_lifespan:
      async with user_lifespan(app):
        yield
    else:
      yield

super().__init__(lifespan=merged_lifespan, **kwargs)
self.mount("/mcp", mcp_app)
```

This design means that HTTP and MCP can run in one Uvicorn worker while retaining FastAPI middleware, dependency injection, and third-party integrations [2605.22733]. In practical terms, HarnessAPI is not positioned as an alternative ASGI runtime; it is a FastAPI subclass that uses FastAPI as the host abstraction.

## 3. Skill specification, automatic derivation, and interface surfaces

The framework’s core contract is that one skill folder yields three automatically derived artifacts. The paper enumerates them explicitly: an HTTP `POST /skills/{name}` route with schema-validated JSON request, dual-mode SSE/JSON responses, and per-skill timeout; interactive Swagger UI via inherited FastAPI/OpenAPI; and a zero-configuration MCP tool registered under the same name, using the same schemas, mounted at `/mcp` [2605.22733].

The defining example uses Pydantic schemas in `models.py`:

```python
from harnessapi import SkillInput, SkillOutput
from pydantic import Field

class Input(SkillInput):
  text: str = Field(..., description="Text to summarise")
  max_length: int = Field(100, gt=0)

class Output(SkillOutput):
  summary: str
```

and a `handler.py` containing either a non-streaming or streaming implementation:

```python
async def handle(input: Input) -> Output:
  return Output(summary=input.text[: input.max_length])
```

or

```python
async def handle(input: Input):
  for sentence in split_into_sentences(input.text):
    yield sentence
```

with `skill.toml` metadata:

```toml
[skill]
description = "Summarise text to a target length"
is_mcp      = true
timeout_secs= 30
tags        = ["text", "nlp"]
```

The minimal server entrypoint is correspondingly compact:

```python
from harnessapi import HarnessAPI

app = HarnessAPI(skills_dir="skills")
```

served by:

```bash
uvicorn main:app --reload
```

The resulting surfaces are `POST /skills/summarize`, `/docs`, and `/mcp` [2605.22733].

This derivation model makes the typed skill the API-defining unit. This suggests a framework-level separation between domain logic and transport synthesis: business logic is encoded once in `handle`, while route declarations, registration code, and schema exposure are synthesized mechanically.

## 4. Streaming semantics and dynamic MCP registration

A central mechanism in HarnessAPI is dual-mode content negotiation for the same handler. The HTTP endpoint always invokes the same skill handler and then branches on the request’s `Accept` header. If the header includes `application/json`, the framework buffers all handler output, including asynchronous-generator yields, and returns a single JSON body such as `{ "chunks": ["first piece", "second piece", ...] }`. Otherwise, the default behavior is a Server-Sent Events stream in which each yielded chunk is emitted as `event: chunk`, normal termination emits `event: done`, and error or timeout emits `event: error` [2605.22733].

The paper’s concrete examples are:

```http
POST /skills/summarize
Accept: application/json
Content-Type: application/json

{ "text": "...", "max_length": 100 }
```

with response

```json
{
  "chunks": [
    "This is the first sentence.",
    "Here is the second."
  ]
}
```

and an SSE variant:

```http
POST /skills/summarize
Accept: text/event-stream
Content-Type: application/json
```

yielding

```text
event: chunk
data: This is the first sentence.

event: chunk
data: Here is the second.

event: done
data:
```

This design preserves a single handler implementation across interactive streaming and batch-style clients. A plausible implication is that the framework uses content negotiation as the compatibility layer between conventional HTTP clients, CI pipelines, and streaming front ends.

The MCP side requires a separate technical mechanism. FastMCP’s `@mcp.tool` decorator inspects a function’s `__annotations__` and resolves type names through the function’s `__globals__`. The paper states that a naïve closure fails because the Pydantic models live in an outer scope. HarnessAPI works around this limitation by dynamically generating a wrapper function through `exec`, explicitly injecting the `Input` model into the globals dictionary so that FastMCP’s introspection can resolve the type annotation correctly [2605.22733]. The paper’s illustrative pattern is:

```python
globs = {
  "asyncio": asyncio,
  "input_model": Input,
  "handler": handler_fn,
  "timeout": skill.meta.timeout_secs,
  "is_streaming": skill.is_streaming_handler(),
}
src = """
async def mcp_wrapper(input: input_model) -> Any:
    if is_streaming:
        chunks = []
        async for c in handler(input): chunks.append(str(c))
        return '\\n'.join(chunks)
    else:
        r = await asyncio.wait_for(handler(input), timeout)
        return r.model_dump()
"""
exec(compile(src, "<mcp_wrapper>", "exec"), globs)
mcp_wrapper = globs["mcp_wrapper"]
mcp_wrapper.__name__ = skill_name
mcp_wrapper.__doc__  = skill_desc
mcp.tool(name=skill_name, description=skill_desc)(mcp_wrapper)
```

The framework characterizes this `exec`-based wrapper as a workaround for a technical limitation in FastMCP rather than as a general design ideal. The paper further notes that future FastMCP versions are expected to accept explicit schema objects, which would remove the need for dynamic compilation [2605.22733].

## 5. Quantitative evaluation and scaling properties

HarnessAPI’s reported evaluation measures framework-facing boilerplate across six representative skills: Echo, Greet, Summarize, VectorNorm, Classify, and Translate. Two implementation conditions were compared: a manual dual stack using separate FastAPI and FastMCP servers with a route and an `@mcp.tool` per skill, and HarnessAPI consuming a skill folder. The measurement procedure used `cloc v2.0` to count non-empty, non-comment lines of framework-facing code only; business logic and model definitions were excluded because they were identical across conditions. Reduction was computed as

$$
\mathrm{Reduction}(\%) = \frac{\mathrm{LoC}_{manual} - \mathrm{LoC}_{HarnessAPI}}{\mathrm{LoC}_{manual}} \times 100\%
$$

[2605.22733].

The reported results are as follows.

| Skill | LoC (manual → HarnessAPI) | Reduction |
|---|---:|---:|
| Echo | 24 → 7 | 71% |
| Greet | 26 → 7 | 73% |
| Summarize | 31 → 8 | 74% |
| VectorNorm | 37 → 8 | 78% |
| Classify | 27 → 7 | 74% |
| Translate | 25 → 7 | 72% |
| Total | 170 → 44 | 74% |

The paper attributes the aggregate reduction to the fact that HarnessAPI’s only per-project boilerplate is the main entrypoint, approximately 44 lines, so framework overhead is described as $O(1)$ in the number of skills, whereas manual duplicate registrations grow as $O(n)$ [2605.22733]. Within the scope of this experiment, the result should be interpreted narrowly: it is a code-volume comparison for framework-facing definitions rather than a latency, throughput, or cost benchmark.

A common misconception would be to read the 74% figure as a general software-efficiency claim. The reported metric is specifically lines of framework-facing code measured under the paper’s exclusion criteria, not a claim about runtime performance or model quality.

## 6. Deployment, ecosystem integration, limitations, and derivatives

Because HarnessAPI subclasses FastAPI, the framework is explicitly positioned as compatible with the existing FastAPI deployment and extension ecosystem. The paper states that existing FastAPI middleware, authentication layers, Sentry integration, and Prometheus integration work identically, that unit tests can import and invoke application routes or MCP methods directly, and that any ASGI-compatible host—including Cloud Run, AWS ECS, GCP App Engine, and Netlify Functions—can serve the single process [2605.22733]. The paper also gives a container example:

```dockerfile
FROM python:3.11-slim
RUN pip install harnessapi uvicorn
COPY main.py skills/ ./
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
```

The deployment significance lies in process unification. Since HTTP and MCP share one process, health checks and autoscaling are also unified [2605.22733]. This suggests that HarnessAPI is intended not only to reduce code duplication but also to consolidate operational boundaries.

The paper records several limitations. The `exec`-based MCP wrapper is described as a temporary hack. The hot-swap `/skills/{name}/edit` endpoint for AI-driven local handler tweaking also uses `exec`, is gated to loopback only, and “must never be enabled in production.” Remaining edge cases include Pydantic-to-FastMCP annotation resolution for deeply nested `Union` types. The current MCP layer has no per-tool authentication, and multi-tenant scenarios are advised to front the `/mcp` endpoint with an auth proxy. Planned enhancements include file-system watchers for live skill addition, per-skill authentication configuration, and a central skill registry akin to PyPI [2605.22733].

A derivative system, SwarmHarness, builds directly on HarnessAPI. In that work, every HarnessAPI node is treated as a “skill node” that exposes a folder of typed skills as HTTP/MCP endpoints and participates in a decentralized network with a DHT-based `SwarmRegistry`, a `SwarmRouter`, and a `SwarmCredit` mechanism [2605.28764]. SwarmHarness defines a node as the tuple

$$
v = (\mathcal{S}_v, r_v, c_v, \tau_v)
$$

where $\mathcal{S}_v$ is the skill set, $r_v$ is the resource vector, $c_v$ is the credit balance, and $\tau_v$ is the trust score, and it routes tasks using

$$
U(v,T) = w_1 \cdot 1[s \in \mathcal{S}_v] + w_2 \cdot (1-\ell_v) + w_3 \cdot (1-d_v/d_{max}) + w_4 \cdot \tau_v
$$

with weights summing to 1 [2605.28764]. Although this protocol is distinct from HarnessAPI proper, it is significant because it treats the skill-first interface abstraction as a substrate for decentralized task routing and incentive accounting rather than only for local service unification.

In that sense, HarnessAPI occupies a specific niche in LLM tooling infrastructure: it is not merely an HTTP framework and not merely an MCP registration helper. Its defining contribution is a typed skill abstraction from which multiple transport and tooling surfaces are derived automatically, with the explicit goal of eliminating parallel definitions and the schema drift that accompanies them [2605.22733].

Source: https://www.emergentmind.com/topics/harnessapi