feat(mcp): add resource/prompt adapters and typed, bounded tool content by FenjuFu · Pull Request #1665 · iflytek/astron-agent · GitHub
Skip to content

feat(mcp): add resource/prompt adapters and typed, bounded tool content - #1665

Open
FenjuFu wants to merge 3 commits into
iflytek:mainfrom
FenjuFu:feat/mcp-resources-prompts
Open

FenjuFu wants to merge 3 commits into
iflytek:mainfrom
FenjuFu:feat/mcp-resources-prompts

Conversation

@FenjuFu

@FenjuFu FenjuFu commented Aug 30, 2026 •

Copy link
Copy Markdown
Member

Summary

This PR adds four plugin-link MCP operations (list/read resources, list/get prompts) and replaces the text/image-only tool-result adapter with typed, bounded content that preserves the full protocol shape.

Closes #1664. Refs #1662; this PR implements only part of #1662 (see "Remaining" below).

#1664 acceptance criteria

Criterion How it is met
Text and image responses remain backward compatible text/data keep the same fields. Image blocks still carry mineType.
Standard mimeType; legacy misspelling handled explicitly mimeType is the standard field on image and audio blocks. mineType is only on image blocks, filled from mimeType, and its schema description marks it deprecated.
Audio, embedded resource, resource-link survive Typed MCPAudioBlock, MCPEmbeddedResourceBlock (text and blob contents), and MCPResourceLinkBlock. Annotations, _meta, and unknown fields are kept (extra="allow").
structuredContent survives as JSON Forwarded unchanged when it fits the result budget. Top-level _meta is retained when it fits; omissions are explicit in data.truncation.
Unknown future block types never silently omitted The public union uses a callable discriminator. Unmodelled types become MCPUnsupportedBlock with unsupported: true and all their fields. The SDK (1.28) currently rejects unknown types while parsing, which already surfaces as MCP_SERVER_CALL_TOOL_ERR rather than silent loss.
Oversized counts/payloads bounded with metadata MCP_TOOL_RESULT_MAX_BLOCKS (default 128) and MCP_TOOL_RESULT_MAX_BYTES (default 4 MiB). The byte limit covers compact UTF-8 JSON for the complete data, including typed/compatibility fields, containers, _meta and truncation itself; it excludes the outer code/message/sid envelope. Priority is structuredContent, ordered content, then _meta. Omission is explicit through structuredContentOmitted, metaOmitted and block counts. If even truncation cannot fit, the call returns MCP_SERVER_CALL_TOOL_ERR with empty data.
Tool isError distinguishable from transport/session failure isError stays in data with envelope code = success. Call and transport failures use the error codes and have no content.
Tests use SDK models and FastAPI serialization mcp.types.CallToolResult with every block type goes through _call_mcp_tool. It is also posted through the real mcp_router with TestClient, and the JSON re-validates into the same typed models.

Implementation

  • service/community/tools/mcp/mcp_content.py (new): result conversion and limits. It is kept out of mcp_server.py to stay under the flake8 complexity gate.
  • SDK results are dumped with mode="json", by_alias=True. The SDK-model tests caught that the default python mode leaves resource URIs as AnyUrl, which failed the string fields. The resource/prompt operations now use the same mode.
  • The four resource/prompt routes are unchanged from the previous revision. They use the existing MCP URL checks and the initialized transport/session path.

Remaining (#1662)

  • Agent/workflow-to-server authorization and operation allowlists are not implemented for the resource/prompt routes.
  • Size bounds are not yet applied to read_resource/get_prompt payloads. They can reuse ResultLimits once [FEATURE] Support MCP resources and prompts for GitNexus context workflows #1662 settles the response shape.
  • Resource-template enumeration and finer protocol-error mapping are still open. Generic exceptions currently become MCP_SERVER_SESSION_ERR.

Validation (head 9280db7)

  • pytest tests in core/plugin/link: 264 passed; the MCP server module has 24 passing cases.
  • Regressions cover million-byte metadata, exact limits, typed compatibility/unsupported fields, UTF-8 and escaping, truncation overhead, tiny limits, and the real FastAPI route serialization.
  • Black 24.4.2, isort 5.13.2 and flake8 7.0.0 (complexity <= 10) pass. Pylint 3.1.0 scores 9.58/10. The converter/schema dependency-aware mypy check passes.
  • GitHub Check core-link and Test core-link passed on this head, including the repository's configured type checks. A broader local dependency-aware scan still reports pre-existing infrastructure/legacy fixture type errors outside this fix.
  • Limits apply to the returned result after SDK parsing; upstream transport buffering is outside this change.

@FenjuFu FenjuFu changed the title feat(mcp): add resources prompts and complete content feat(mcp): add resource and prompt adapters with content passthrough Sep 10, 2026
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
Complete the tool-result requirements of iflytek#1664.

- Replace the generic content block with typed public models for text,
  image, audio, embedded resource (text/blob) and resource_link blocks,
  selected by a callable discriminator. Block types the service does not
  model are passed through as explicit `unsupported: true` blocks, and
  annotations, _meta and unknown fields are preserved.
- Forward the top-level result _meta alongside structuredContent and the
  tool-level isError flag, which stays separate from the envelope code.
- Keep mimeType as the standard field and document mineType as a
  deprecated compatibility alias on image blocks.
- Dump SDK results in JSON mode so AnyUrl values (resource URIs) validate
  into the public schema; resource and prompt operations use the same
  mode.
- Bound forwarded results with MCP_TOOL_RESULT_MAX_BLOCKS (default 128)
  and MCP_TOOL_RESULT_MAX_BYTES (default 4 MiB). structuredContent is
  budgeted first; anything withheld is reported in `truncation` and
  logged instead of being dropped silently.
- Test with standard mcp.types result models, through the real FastAPI
  router, and re-validate the serialized JSON into the typed models.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
@FenjuFu
FenjuFu force-pushed the feat/mcp-resources-prompts branch from 3060884 to 7161be6 Compare September 19, 2026 03:48
@FenjuFu FenjuFu changed the title feat(mcp): add resource and prompt adapters with content passthrough feat(mcp): add resource/prompt adapters and typed, bounded tool content Sep 19, 2026
@FenjuFu

FenjuFu commented Oct 12, 2026

Copy link
Copy Markdown
Member Author

A follow-up self-review found a remaining gap before this can close #1664: build_call_tool_data budgets structuredContent and content blocks, but forwards top-level _meta without counting it. On head 7161be6d, a 1,000,000-character _meta value produces a 1,000,053-byte serialized result with max_bytes=100 and no truncation metadata.

The fix should include _meta and the final serialized representation in the byte budget, return explicit omission/error metadata, and add a regression. #1662 also remains partially implemented: resource/prompt authorization, bounds and protocol-error coverage need follow-up.

Include public fields, top-level metadata and truncation status in the final UTF-8 data budget. Return an explicit call error when even the omission status cannot fit. Cover metadata, serialization boundaries and the public route with regression tests.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
@FenjuFu

FenjuFu commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Preserve MCP structuredContent and all content block types

1 participant